Check-in [6a463e7df6]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:update curl to version 8.9.0
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6a463e7df6d45e4cdcf10d21cad67c39bc58ae0a
User & Date: chw 2024-07-24 13:42:32.098
Context
2024-07-25
05:15
fix in tksvg tcl only mode check-in: c7f5f61ba3 user: chw tags: trunk
2024-07-24
13:55
merge with trunk check-in: e78b5a567d user: chw tags: wtf-8-experiment
13:42
update curl to version 8.9.0 check-in: 6a463e7df6 user: chw tags: trunk
07:23
tweak some build scripts check-in: 1bbdac2aa5 user: chw tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to jni/curl/CHANGES.

more than 10,000 changes

Changes to jni/curl/CMake/CurlSymbolHiding.cmake.
22
23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
38
#
###########################################################################
include(CheckCSourceCompiles)

option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON)
mark_as_advanced(CURL_HIDDEN_SYMBOLS)

if(WIN32 AND ENABLE_CURLDEBUG)
  # We need to export internal debug functions (e.g. curl_dbg_*), so disable

  # symbol hiding for debug builds.
  set(CURL_HIDDEN_SYMBOLS OFF)
endif()

if(CURL_HIDDEN_SYMBOLS)
  set(SUPPORTS_SYMBOL_HIDING FALSE)

  if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT MSVC)







|
|
>
|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#
###########################################################################
include(CheckCSourceCompiles)

option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON)
mark_as_advanced(CURL_HIDDEN_SYMBOLS)

if(WIN32 AND (ENABLE_DEBUG OR ENABLE_CURLDEBUG))
  # We need to export internal debug functions,
  # e.g. curl_easy_perform_ev() or curl_dbg_*(),
  # so disable symbol hiding for debug builds and for memory tracking.
  set(CURL_HIDDEN_SYMBOLS OFF)
endif()

if(CURL_HIDDEN_SYMBOLS)
  set(SUPPORTS_SYMBOL_HIDING FALSE)

  if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT MSVC)
Changes to jni/curl/CMake/CurlTests.c.
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  return 0;
}
#endif

#ifdef HAVE_BUILTIN_AVAILABLE
int main(void)
{
  if(__builtin_available(macOS 10.12, *)) {}
  return 0;
}
#endif

#ifdef HAVE_ATOMIC
/* includes start */
#ifdef HAVE_SYS_TYPES_H







|







376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  return 0;
}
#endif

#ifdef HAVE_BUILTIN_AVAILABLE
int main(void)
{
  if(__builtin_available(macOS 10.12, iOS 5.0, *)) {}
  return 0;
}
#endif

#ifdef HAVE_ATOMIC
/* includes start */
#ifdef HAVE_SYS_TYPES_H
Changes to jni/curl/CMake/FindBearSSL.cmake.
23
24
25
26
27
28
29
30
31
32
###########################################################################
find_path(BEARSSL_INCLUDE_DIRS bearssl.h)

find_library(BEARSSL_LIBRARY bearssl)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(BEARSSL DEFAULT_MSG
    BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)

mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)







|


23
24
25
26
27
28
29
30
31
32
###########################################################################
find_path(BEARSSL_INCLUDE_DIRS bearssl.h)

find_library(BEARSSL_LIBRARY bearssl)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(BEARSSL DEFAULT_MSG
  BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)

mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)
Changes to jni/curl/CMake/FindBrotli.cmake.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

find_path(BROTLI_INCLUDE_DIR "brotli/decode.h")

find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
find_library(BROTLIDEC_LIBRARY NAMES brotlidec)

find_package_handle_standard_args(Brotli
    FOUND_VAR
      BROTLI_FOUND
    REQUIRED_VARS
      BROTLIDEC_LIBRARY
      BROTLICOMMON_LIBRARY
      BROTLI_INCLUDE_DIR
    FAIL_MESSAGE
      "Could NOT find Brotli"
)

set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
set(BROTLI_LIBRARIES ${BROTLICOMMON_LIBRARY} ${BROTLIDEC_LIBRARY})







|
|
|
|
|
|
|
|



|
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

find_path(BROTLI_INCLUDE_DIR "brotli/decode.h")

find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
find_library(BROTLIDEC_LIBRARY NAMES brotlidec)

find_package_handle_standard_args(Brotli
  FOUND_VAR
    BROTLI_FOUND
  REQUIRED_VARS
    BROTLIDEC_LIBRARY
    BROTLICOMMON_LIBRARY
    BROTLI_INCLUDE_DIR
  FAIL_MESSAGE
    "Could NOT find Brotli"
)

set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARY} ${BROTLICOMMON_LIBRARY})
Changes to jni/curl/CMake/FindCARES.cmake.
35
36
37
38
39
40
41
42
43
44
45
46
47
set(CARES_NAMES ${CARES_NAMES} cares)
find_library(CARES_LIBRARY
  NAMES ${CARES_NAMES}
  )

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CARES
    REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR)

mark_as_advanced(
  CARES_LIBRARY
  CARES_INCLUDE_DIR
  )







|





35
36
37
38
39
40
41
42
43
44
45
46
47
set(CARES_NAMES ${CARES_NAMES} cares)
find_library(CARES_LIBRARY
  NAMES ${CARES_NAMES}
  )

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CARES
  REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR)

mark_as_advanced(
  CARES_LIBRARY
  CARES_INCLUDE_DIR
  )
Changes to jni/curl/CMake/FindGSS.cmake.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
set(_HEIMDAL_MODNAME heimdal-gssapi)

include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckTypeSize)

set(_GSS_ROOT_HINTS
    "${GSS_ROOT_DIR}"
    "$ENV{GSS_ROOT_DIR}"
)

# try to find library using system pkg-config if user didn't specify root dir
if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
  if(UNIX)
    find_package(PkgConfig QUIET)
    pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME})
    list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}")
  elseif(WIN32)
    list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
  endif()
endif()

if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach.
  find_file(_GSS_CONFIGURE_SCRIPT
      NAMES
          "krb5-config"
      HINTS
          ${_GSS_ROOT_HINTS}
      PATH_SUFFIXES
          bin
      NO_CMAKE_PATH
      NO_CMAKE_ENVIRONMENT_PATH
  )

  # if not found in user-supplied directories, maybe system knows better
  find_file(_GSS_CONFIGURE_SCRIPT
      NAMES
          "krb5-config"
      PATH_SUFFIXES
          bin
  )

  if(_GSS_CONFIGURE_SCRIPT)
    execute_process(
          COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi"
          OUTPUT_VARIABLE _GSS_CFLAGS
          RESULT_VARIABLE _GSS_CONFIGURE_FAILED
          OUTPUT_STRIP_TRAILING_WHITESPACE
      )
    message(STATUS "CFLAGS: ${_GSS_CFLAGS}")
    if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
      # should also work in an odd case when multiple directories are given
      string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
      string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
      string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")

      foreach(_flag ${_GSS_CFLAGS})
        if(_flag MATCHES "^-I.*")
          string(REGEX REPLACE "^-I" "" _val "${_flag}")
          list(APPEND _GSS_INCLUDE_DIR "${_val}")
        else()
          list(APPEND _GSS_COMPILER_FLAGS "${_flag}")
        endif()
      endforeach()
    endif()

    execute_process(
        COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi"
        OUTPUT_VARIABLE _GSS_LIB_FLAGS
        RESULT_VARIABLE _GSS_CONFIGURE_FAILED
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )
    message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}")

    if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
      # this script gives us libraries and link directories. Blah. We have to deal with it.
      string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS)
      string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")







|
|















|
|
|
|
|
|
|
|




|
|
|
|




|
|
|
|



















|
|
|
|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
set(_HEIMDAL_MODNAME heimdal-gssapi)

include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckTypeSize)

set(_GSS_ROOT_HINTS
  "${GSS_ROOT_DIR}"
  "$ENV{GSS_ROOT_DIR}"
)

# try to find library using system pkg-config if user didn't specify root dir
if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
  if(UNIX)
    find_package(PkgConfig QUIET)
    pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME})
    list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}")
  elseif(WIN32)
    list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
  endif()
endif()

if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach.
  find_file(_GSS_CONFIGURE_SCRIPT
    NAMES
      "krb5-config"
    HINTS
      ${_GSS_ROOT_HINTS}
    PATH_SUFFIXES
      bin
    NO_CMAKE_PATH
    NO_CMAKE_ENVIRONMENT_PATH
  )

  # if not found in user-supplied directories, maybe system knows better
  find_file(_GSS_CONFIGURE_SCRIPT
    NAMES
      "krb5-config"
    PATH_SUFFIXES
      bin
  )

  if(_GSS_CONFIGURE_SCRIPT)
    execute_process(
      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi"
      OUTPUT_VARIABLE _GSS_CFLAGS
      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
      OUTPUT_STRIP_TRAILING_WHITESPACE
      )
    message(STATUS "CFLAGS: ${_GSS_CFLAGS}")
    if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
      # should also work in an odd case when multiple directories are given
      string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
      string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
      string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")

      foreach(_flag ${_GSS_CFLAGS})
        if(_flag MATCHES "^-I.*")
          string(REGEX REPLACE "^-I" "" _val "${_flag}")
          list(APPEND _GSS_INCLUDE_DIR "${_val}")
        else()
          list(APPEND _GSS_COMPILER_FLAGS "${_flag}")
        endif()
      endforeach()
    endif()

    execute_process(
      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi"
      OUTPUT_VARIABLE _GSS_LIB_FLAGS
      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
      OUTPUT_STRIP_TRAILING_WHITESPACE
    )
    message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}")

    if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
      # this script gives us libraries and link directories. Blah. We have to deal with it.
      string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS)
      string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
        else()
          list(APPEND _GSS_LINKER_FLAGS "${_flag}")
        endif()
      endforeach()
    endif()

    execute_process(
        COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version"
        OUTPUT_VARIABLE _GSS_VERSION
        RESULT_VARIABLE _GSS_CONFIGURE_FAILED
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )

    # older versions may not have the "--version" parameter. In this case we just don't care.
    if(_GSS_CONFIGURE_FAILED)
      set(_GSS_VERSION 0)
    endif()

    execute_process(
        COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor"
        OUTPUT_VARIABLE _GSS_VENDOR
        RESULT_VARIABLE _GSS_CONFIGURE_FAILED
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )

    # older versions may not have the "--vendor" parameter. In this case we just don't care.
    if(_GSS_CONFIGURE_FAILED)
      set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter
    else()
      if(_GSS_VENDOR MATCHES ".*H|heimdal.*")
        set(GSS_FLAVOUR "Heimdal")
      else()
        set(GSS_FLAVOUR "MIT")
      endif()
    endif()

  else() # either there is no config script or we are on a platform that doesn't provide one (Windows?)

    find_path(_GSS_INCLUDE_DIR
        NAMES
            "gssapi/gssapi.h"
        HINTS
            ${_GSS_ROOT_HINTS}
        PATH_SUFFIXES
            include
            inc
    )

    if(_GSS_INCLUDE_DIR) #jay, we've found something
      set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}")
      check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS)

      if(_GSS_HAVE_MIT_HEADERS)







|
|
|
|








|
|
|
|
















|
|
|
|
|
|
|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
        else()
          list(APPEND _GSS_LINKER_FLAGS "${_flag}")
        endif()
      endforeach()
    endif()

    execute_process(
      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version"
      OUTPUT_VARIABLE _GSS_VERSION
      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
      OUTPUT_STRIP_TRAILING_WHITESPACE
    )

    # older versions may not have the "--version" parameter. In this case we just don't care.
    if(_GSS_CONFIGURE_FAILED)
      set(_GSS_VERSION 0)
    endif()

    execute_process(
      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor"
      OUTPUT_VARIABLE _GSS_VENDOR
      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
      OUTPUT_STRIP_TRAILING_WHITESPACE
    )

    # older versions may not have the "--vendor" parameter. In this case we just don't care.
    if(_GSS_CONFIGURE_FAILED)
      set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter
    else()
      if(_GSS_VENDOR MATCHES ".*H|heimdal.*")
        set(GSS_FLAVOUR "Heimdal")
      else()
        set(GSS_FLAVOUR "MIT")
      endif()
    endif()

  else() # either there is no config script or we are on a platform that doesn't provide one (Windows?)

    find_path(_GSS_INCLUDE_DIR
      NAMES
        "gssapi/gssapi.h"
      HINTS
        ${_GSS_ROOT_HINTS}
      PATH_SUFFIXES
        include
        inc
    )

    if(_GSS_INCLUDE_DIR) #jay, we've found something
      set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}")
      check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS)

      if(_GSS_HAVE_MIT_HEADERS)
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
          set(GSS_FLAVOUR "Heimdal")
        endif()
        list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D__ROKEN_H__)
      endif()
    else()
      # I'm not convinced if this is the right way but this is what autotools do at the moment
      find_path(_GSS_INCLUDE_DIR
          NAMES
              "gssapi.h"
          HINTS
              ${_GSS_ROOT_HINTS}
          PATH_SUFFIXES
              include
              inc
      )

      if(_GSS_INCLUDE_DIR)
        set(GSS_FLAVOUR "Heimdal")
      endif()
    endif()








|
|
|
|
|
|
|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
          set(GSS_FLAVOUR "Heimdal")
        endif()
        list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D__ROKEN_H__)
      endif()
    else()
      # I'm not convinced if this is the right way but this is what autotools do at the moment
      find_path(_GSS_INCLUDE_DIR
        NAMES
          "gssapi.h"
        HINTS
          ${_GSS_ROOT_HINTS}
        PATH_SUFFIXES
          include
          inc
      )

      if(_GSS_INCLUDE_DIR)
        set(GSS_FLAVOUR "Heimdal")
      endif()
    endif()

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
          set(_GSS_LIBNAME "gssapi_krb5")
        else()
          set(_GSS_LIBNAME "gssapi")
        endif()
      endif()

      find_library(_GSS_LIBRARIES
          NAMES
              ${_GSS_LIBNAME}
          HINTS
              ${_GSS_LIBDIR_HINTS}
          PATH_SUFFIXES
              ${_GSS_LIBDIR_SUFFIXES}
      )

    endif()
  endif()
else()
  if(_GSS_PKG_${_MIT_MODNAME}_VERSION)
    set(GSS_FLAVOUR "MIT")







|
|
|
|
|
|







236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
          set(_GSS_LIBNAME "gssapi_krb5")
        else()
          set(_GSS_LIBNAME "gssapi")
        endif()
      endif()

      find_library(_GSS_LIBRARIES
        NAMES
          ${_GSS_LIBNAME}
        HINTS
          ${_GSS_LIBDIR_HINTS}
        PATH_SUFFIXES
          ${_GSS_LIBDIR_SUFFIXES}
      )

    endif()
  endif()
else()
  if(_GSS_PKG_${_MIT_MODNAME}_VERSION)
    set(GSS_FLAVOUR "MIT")
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
endif()

include(FindPackageHandleStandardArgs)

set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR)

find_package_handle_standard_args(GSS
    REQUIRED_VARS
        ${_GSS_REQUIRED_VARS}
    VERSION_VAR
        GSS_VERSION
    FAIL_MESSAGE
        "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
)

mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES)







|
|
|
|
|
|



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
endif()

include(FindPackageHandleStandardArgs)

set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR)

find_package_handle_standard_args(GSS
  REQUIRED_VARS
    ${_GSS_REQUIRED_VARS}
  VERSION_VAR
    GSS_VERSION
  FAIL_MESSAGE
    "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
)

mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES)
Changes to jni/curl/CMake/FindLibPSL.cmake.
35
36
37
38
39
40
41
42
43
44
45
if(LIBPSL_INCLUDE_DIR)
  file(STRINGS "${LIBPSL_INCLUDE_DIR}/libpsl.h" libpsl_version_str REGEX "^#define[\t ]+PSL_VERSION[\t ]+\"(.*)\"")
  string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1"  LIBPSL_VERSION "${libpsl_version_str}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibPSL
    REQUIRED_VARS LIBPSL_LIBRARY LIBPSL_INCLUDE_DIR
    VERSION_VAR LIBPSL_VERSION)

mark_as_advanced(LIBPSL_INCLUDE_DIR LIBPSL_LIBRARY)







|
|


35
36
37
38
39
40
41
42
43
44
45
if(LIBPSL_INCLUDE_DIR)
  file(STRINGS "${LIBPSL_INCLUDE_DIR}/libpsl.h" libpsl_version_str REGEX "^#define[\t ]+PSL_VERSION[\t ]+\"(.*)\"")
  string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1"  LIBPSL_VERSION "${libpsl_version_str}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibPSL
  REQUIRED_VARS LIBPSL_LIBRARY LIBPSL_INCLUDE_DIR
  VERSION_VAR LIBPSL_VERSION)

mark_as_advanced(LIBPSL_INCLUDE_DIR LIBPSL_LIBRARY)
Changes to jni/curl/CMake/FindLibSSH2.cmake.
35
36
37
38
39
40
41
42
43
44
45
if(LIBSSH2_INCLUDE_DIR)
  file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION[\t ]+\"(.*)\"")
  string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1"  LIBSSH2_VERSION "${libssh2_version_str}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibSSH2
    REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR
    VERSION_VAR LIBSSH2_VERSION)

mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)







|
|


35
36
37
38
39
40
41
42
43
44
45
if(LIBSSH2_INCLUDE_DIR)
  file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION[\t ]+\"(.*)\"")
  string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1"  LIBSSH2_VERSION "${libssh2_version_str}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibSSH2
  REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR
  VERSION_VAR LIBSSH2_VERSION)

mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)
Changes to jni/curl/CMake/FindMbedTLS.cmake.
27
28
29
30
31
32
33
34
35
36
find_library(MBEDX509_LIBRARY mbedx509)
find_library(MBEDCRYPTO_LIBRARY mbedcrypto)

set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MbedTLS DEFAULT_MSG
    MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)

mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)







|


27
28
29
30
31
32
33
34
35
36
find_library(MBEDX509_LIBRARY mbedx509)
find_library(MBEDCRYPTO_LIBRARY mbedcrypto)

set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MbedTLS DEFAULT_MSG
  MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)

mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
Changes to jni/curl/CMake/FindNGHTTP2.cmake.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
include(FindPackageHandleStandardArgs)

find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h")

find_library(NGHTTP2_LIBRARY NAMES nghttp2 nghttp2_static)

find_package_handle_standard_args(NGHTTP2
    FOUND_VAR
      NGHTTP2_FOUND
    REQUIRED_VARS
      NGHTTP2_LIBRARY
      NGHTTP2_INCLUDE_DIR
)

set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR})
set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY})

mark_as_advanced(NGHTTP2_INCLUDE_DIRS NGHTTP2_LIBRARIES)







|
|
|
|
|






24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
include(FindPackageHandleStandardArgs)

find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h")

find_library(NGHTTP2_LIBRARY NAMES nghttp2 nghttp2_static)

find_package_handle_standard_args(NGHTTP2
  FOUND_VAR
    NGHTTP2_FOUND
  REQUIRED_VARS
    NGHTTP2_LIBRARY
    NGHTTP2_INCLUDE_DIR
)

set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR})
set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY})

mark_as_advanced(NGHTTP2_INCLUDE_DIRS NGHTTP2_LIBRARIES)
Changes to jni/curl/CMake/FindWolfSSL.cmake.
17
18
19
20
21
22
23




24




25




26







27
28
29
30



31
32
33
34
35
36


#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################




find_path(WolfSSL_INCLUDE_DIR NAMES wolfssl/ssl.h)




find_library(WolfSSL_LIBRARY NAMES wolfssl)




mark_as_advanced(WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY)








include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WolfSSL
  REQUIRED_VARS WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY



  )

if(WolfSSL_FOUND)
  set(WolfSSL_INCLUDE_DIRS ${WolfSSL_INCLUDE_DIR})
  set(WolfSSL_LIBRARIES ${WolfSSL_LIBRARY})
endif()









>
>
>
>
|
>
>
>
>
|
>
>
>
>
|
>
>
>
>
>
>
>



|
>
>
>
|



|

>
>
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################

find_package(PkgConfig QUIET)
pkg_check_modules(PC_WOLFSSL QUIET "wolfssl")

find_path(WolfSSL_INCLUDE_DIR
  NAMES "wolfssl/ssl.h"
  HINTS ${PC_WOLFSSL_INCLUDE_DIRS}
)

find_library(WolfSSL_LIBRARY
  NAMES "wolfssl"
  HINTS ${PC_WOLFSSL_LIBRARY_DIRS}
)

if(WolfSSL_INCLUDE_DIR)
  set(_version_regex "^#define[ \t]+LIBWOLFSSL_VERSION_STRING[ \t]+\"([^\"]+)\".*")
  file(STRINGS "${WolfSSL_INCLUDE_DIR}/wolfssl/version.h"
    WolfSSL_VERSION REGEX "${_version_regex}")
  string(REGEX REPLACE "${_version_regex}" "\\1"
    WolfSSL_VERSION "${WolfSSL_VERSION}")
  unset(_version_regex)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WolfSSL
  REQUIRED_VARS
    WolfSSL_INCLUDE_DIR
    WolfSSL_LIBRARY
  VERSION_VAR WolfSSL_VERSION
)

if(WolfSSL_FOUND)
  set(WolfSSL_INCLUDE_DIRS ${WolfSSL_INCLUDE_DIR})
  set(WolfSSL_LIBRARIES    ${WolfSSL_LIBRARY})
endif()

mark_as_advanced(WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY)
Changes to jni/curl/CMake/OtherTests.cmake.
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  add_header_include(HAVE_NETDB_H "netdb.h")
  check_c_source_compiles("${_source_epilogue}
    int main(void)
    {
    #ifdef h_errno
      return 0;
    #else
      force compilation error
    #endif
    }" HAVE_H_ERRNO)

  if(NOT HAVE_H_ERRNO)
    check_c_source_compiles("${_source_epilogue}
      int main(void)
      {
        h_errno = 2;
        return h_errno != 0 ? 1 : 0;
      }" HAVE_H_ERRNO_ASSIGNABLE)

    if(NOT HAVE_H_ERRNO_ASSIGNABLE)
      check_c_source_compiles("${_source_epilogue}
        int main(void)
        {
        #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
          return 0;
        #elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
          return 0;
        #else
          force compilation error
        #endif
        }" HAVE_H_ERRNO_SBS_ISSUE_7)
    endif()
  endif()

  if(HAVE_H_ERRNO OR HAVE_H_ERRNO_ASSIGNABLE OR HAVE_H_ERRNO_SBS_ISSUE_7)
    set(HAVE_GETADDRINFO_THREADSAFE TRUE)







|




















|







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  add_header_include(HAVE_NETDB_H "netdb.h")
  check_c_source_compiles("${_source_epilogue}
    int main(void)
    {
    #ifdef h_errno
      return 0;
    #else
      #error force compilation error
    #endif
    }" HAVE_H_ERRNO)

  if(NOT HAVE_H_ERRNO)
    check_c_source_compiles("${_source_epilogue}
      int main(void)
      {
        h_errno = 2;
        return h_errno != 0 ? 1 : 0;
      }" HAVE_H_ERRNO_ASSIGNABLE)

    if(NOT HAVE_H_ERRNO_ASSIGNABLE)
      check_c_source_compiles("${_source_epilogue}
        int main(void)
        {
        #if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
          return 0;
        #elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
          return 0;
        #else
          #error force compilation error
        #endif
        }" HAVE_H_ERRNO_SBS_ISSUE_7)
    endif()
  endif()

  if(HAVE_H_ERRNO OR HAVE_H_ERRNO_ASSIGNABLE OR HAVE_H_ERRNO_SBS_ISSUE_7)
    set(HAVE_GETADDRINFO_THREADSAFE TRUE)
Changes to jni/curl/CMake/PickyWarnings.cmake.
28
29
30
31
32
33
34










35
36
37
38
39
40
41
if(CURL_WERROR AND
   ((CMAKE_COMPILER_IS_GNUCC AND
     NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0 AND
     NOT CMAKE_VERSION VERSION_LESS 3.23.0) OR  # check_symbol_exists() incompatible with GCC -pedantic-errors in earlier CMake versions
   CMAKE_C_COMPILER_ID MATCHES "Clang"))
  set(WPICKY "${WPICKY} -pedantic-errors")
endif()











if(PICKY_COMPILER)
  if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")

    # https://clang.llvm.org/docs/DiagnosticsReference.html
    # https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html








>
>
>
>
>
>
>
>
>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
if(CURL_WERROR AND
   ((CMAKE_COMPILER_IS_GNUCC AND
     NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0 AND
     NOT CMAKE_VERSION VERSION_LESS 3.23.0) OR  # check_symbol_exists() incompatible with GCC -pedantic-errors in earlier CMake versions
   CMAKE_C_COMPILER_ID MATCHES "Clang"))
  set(WPICKY "${WPICKY} -pedantic-errors")
endif()

if(APPLE AND
   (CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
   (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
  set(WPICKY "${WPICKY} -Werror=partial-availability")  # clang 3.6  appleclang 6.3
endif()

if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
  set(WPICKY "${WPICKY} -Werror-implicit-function-declaration")  # clang 1.0  gcc 2.95
endif()

if(PICKY_COMPILER)
  if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")

    # https://clang.llvm.org/docs/DiagnosticsReference.html
    # https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Changes to jni/curl/CMake/Platforms/WindowsCache.cmake.
84
85
86
87
88
89
90

91
92
93
94
95
96
97
set(HAVE_FCNTL 0)
set(HAVE_GETPPID 0)
set(HAVE_UTIMES 0)
set(HAVE_GETPWUID_R 0)
set(HAVE_STRERROR_R 0)
set(HAVE_SIGINTERRUPT 0)
set(HAVE_PIPE 0)

set(HAVE_IF_NAMETOINDEX 0)
set(HAVE_GETRLIMIT 0)
set(HAVE_SETRLIMIT 0)
set(HAVE_FSETXATTR 0)
set(HAVE_LIBSOCKET 0)
set(HAVE_SETLOCALE 1)
set(HAVE_SETMODE 1)







>







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
set(HAVE_FCNTL 0)
set(HAVE_GETPPID 0)
set(HAVE_UTIMES 0)
set(HAVE_GETPWUID_R 0)
set(HAVE_STRERROR_R 0)
set(HAVE_SIGINTERRUPT 0)
set(HAVE_PIPE 0)
set(HAVE_EVENTFD 0)
set(HAVE_IF_NAMETOINDEX 0)
set(HAVE_GETRLIMIT 0)
set(HAVE_SETRLIMIT 0)
set(HAVE_FSETXATTR 0)
set(HAVE_LIBSOCKET 0)
set(HAVE_SETLOCALE 1)
set(HAVE_SETMODE 1)
117
118
119
120
121
122
123

124
125
126
127
128
129
130
set(HAVE_NETINET_UDP_H 0)
set(HAVE_NET_IF_H 0)
set(HAVE_IOCTL_SIOCGIFADDR 0)
set(HAVE_POLL_H 0)
set(HAVE_POLL_FINE 0)
set(HAVE_PWD_H 0)
set(HAVE_STRINGS_H 0)  # mingw-w64 has it (wrapper to string.h)

set(HAVE_SYS_FILIO_H 0)
set(HAVE_SYS_WAIT_H 0)
set(HAVE_SYS_IOCTL_H 0)
set(HAVE_SYS_POLL_H 0)
set(HAVE_SYS_RESOURCE_H 0)
set(HAVE_SYS_SELECT_H 0)
set(HAVE_SYS_SOCKET_H 0)







>







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
set(HAVE_NETINET_UDP_H 0)
set(HAVE_NET_IF_H 0)
set(HAVE_IOCTL_SIOCGIFADDR 0)
set(HAVE_POLL_H 0)
set(HAVE_POLL_FINE 0)
set(HAVE_PWD_H 0)
set(HAVE_STRINGS_H 0)  # mingw-w64 has it (wrapper to string.h)
set(HAVE_SYS_EVENTFD_H 0)
set(HAVE_SYS_FILIO_H 0)
set(HAVE_SYS_WAIT_H 0)
set(HAVE_SYS_IOCTL_H 0)
set(HAVE_SYS_POLL_H 0)
set(HAVE_SYS_RESOURCE_H 0)
set(HAVE_SYS_SELECT_H 0)
set(HAVE_SYS_SOCKET_H 0)
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
set(HAVE_IOCTLSOCKET 1)
set(HAVE_IOCTLSOCKET_CAMEL 0)
set(HAVE_IOCTLSOCKET_CAMEL_FIONBIO 0)
set(HAVE_IOCTLSOCKET_FIONBIO 1)
set(HAVE_IOCTL_FIONBIO 0)
set(HAVE_SETSOCKOPT_SO_NONBLOCK 0)
set(HAVE_POSIX_STRERROR_R 0)
set(HAVE_BUILTIN_AVAILABLE 0)
set(HAVE_MSG_NOSIGNAL 0)
set(HAVE_STRUCT_TIMEVAL 1)
set(HAVE_STRUCT_SOCKADDR_STORAGE 1)

set(HAVE_GETHOSTBYNAME_R_3 0)
set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
set(HAVE_GETHOSTBYNAME_R_5 0)







<







169
170
171
172
173
174
175

176
177
178
179
180
181
182
set(HAVE_IOCTLSOCKET 1)
set(HAVE_IOCTLSOCKET_CAMEL 0)
set(HAVE_IOCTLSOCKET_CAMEL_FIONBIO 0)
set(HAVE_IOCTLSOCKET_FIONBIO 1)
set(HAVE_IOCTL_FIONBIO 0)
set(HAVE_SETSOCKOPT_SO_NONBLOCK 0)
set(HAVE_POSIX_STRERROR_R 0)

set(HAVE_MSG_NOSIGNAL 0)
set(HAVE_STRUCT_TIMEVAL 1)
set(HAVE_STRUCT_SOCKADDR_STORAGE 1)

set(HAVE_GETHOSTBYNAME_R_3 0)
set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
set(HAVE_GETHOSTBYNAME_R_5 0)
Changes to jni/curl/CMake/curl-config.cmake.in.
34
35
36
37
38
39
40




include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
check_required_components("@PROJECT_NAME@")

# Alias for either shared or static library
if(NOT TARGET @PROJECT_NAME@::libcurl)
  add_library(@PROJECT_NAME@::libcurl ALIAS @PROJECT_NAME@::@LIB_SELECTED@)
endif()











>
>
>
>
34
35
36
37
38
39
40
41
42
43
44
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
check_required_components("@PROJECT_NAME@")

# Alias for either shared or static library
if(NOT TARGET @PROJECT_NAME@::libcurl)
  add_library(@PROJECT_NAME@::libcurl ALIAS @PROJECT_NAME@::@LIB_SELECTED@)
endif()

# For compatibility with CMake's FindCURL.cmake
set(CURL_LIBRARIES @PROJECT_NAME@::libcurl)
set_and_check(CURL_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
Changes to jni/curl/CMakeLists.txt.
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
string(REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION})
string(REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+"
  CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS})
string(REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM})


# Setup package meta-data
# SET(PACKAGE "curl")
message(STATUS "curl version=[${CURL_VERSION}]")
# SET(PACKAGE_TARNAME "curl")
# SET(PACKAGE_NAME "curl")
# SET(PACKAGE_VERSION "-")
# SET(PACKAGE_STRING "curl-")
# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.se/mail/")
set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
if(CMAKE_C_COMPILER_TARGET)
  set(OS "\"${CMAKE_C_COMPILER_TARGET}\"")
else()
  set(OS "\"${CMAKE_SYSTEM_NAME}\"")
endif()








|

|
|
|
|
|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
string(REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION})
string(REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+"
  CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS})
string(REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM})


# Setup package meta-data
# set(PACKAGE "curl")
message(STATUS "curl version=[${CURL_VERSION}]")
# set(PACKAGE_TARNAME "curl")
# set(PACKAGE_NAME "curl")
# set(PACKAGE_VERSION "-")
# set(PACKAGE_STRING "curl-")
# set(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.se/mail/")
set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
if(CMAKE_C_COMPILER_TARGET)
  set(OS "\"${CMAKE_C_COMPILER_TARGET}\"")
else()
  set(OS "\"${CMAKE_SYSTEM_NAME}\"")
endif()

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120



121
122
123
124
125
126
127
128
129
130
131
      add_compile_options(-municode)
    endif()
  endif()
endif()
option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF)

cmake_dependent_option(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup"
        ON "NOT ENABLE_ARES"
        OFF)

option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF)
option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF)

include(PickyWarnings)




if(ENABLE_DEBUG)
  # DEBUGBUILD will be defined only for Debug builds
  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUGBUILD>)
  set(ENABLE_CURLDEBUG ON)
endif()

if(ENABLE_CURLDEBUG)
  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG)
endif()

# For debug libs and exes, add "-d" postfix







|
|
<
<
<



>
>
>

<
|
<







106
107
108
109
110
111
112
113
114



115
116
117
118
119
120
121

122

123
124
125
126
127
128
129
      add_compile_options(-municode)
    endif()
  endif()
endif()
option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF)

cmake_dependent_option(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup"
  ON "NOT ENABLE_ARES"
  OFF)




include(PickyWarnings)

option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF)
option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" ${ENABLE_DEBUG})

if(ENABLE_DEBUG)

  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS DEBUGBUILD)

endif()

if(ENABLE_CURLDEBUG)
  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG)
endif()

# For debug libs and exes, add "-d" postfix
157
158
159
160
161
162
163

164
165
166
167
168

169
170
171
172
173
174
175
  set(LIB_SELECTED ${LIB_SHARED})
else()
  set(LIB_SELECTED ${LIB_STATIC})
endif()

# initialize CURL_LIBS
set(CURL_LIBS "")


if(ENABLE_ARES)
  set(USE_ARES 1)
  find_package(CARES REQUIRED)
  list(APPEND CURL_LIBS ${CARES_LIBRARY})

endif()

include(CurlSymbolHiding)

option(CURL_ENABLE_EXPORT_TARGET "to enable cmake export target" ON)
mark_as_advanced(CURL_ENABLE_EXPORT_TARGET)








>





>







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  set(LIB_SELECTED ${LIB_SHARED})
else()
  set(LIB_SELECTED ${LIB_STATIC})
endif()

# initialize CURL_LIBS
set(CURL_LIBS "")
set(LIBCURL_PC_REQUIRES_PRIVATE "")

if(ENABLE_ARES)
  set(USE_ARES 1)
  find_package(CARES REQUIRED)
  list(APPEND CURL_LIBS ${CARES_LIBRARY})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libcares")
endif()

include(CurlSymbolHiding)

option(CURL_ENABLE_EXPORT_TARGET "to enable cmake export target" ON)
mark_as_advanced(CURL_ENABLE_EXPORT_TARGET)

273
274
275
276
277
278
279




280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  set(CURL_DISABLE_POP3 ON)
  set(CURL_DISABLE_RTSP ON)
  set(CURL_DISABLE_SMB ON)
  set(CURL_DISABLE_SMTP ON)
  set(CURL_DISABLE_TELNET ON)
  set(CURL_DISABLE_TFTP ON)
endif()





option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
mark_as_advanced(ENABLE_IPV6)
if(ENABLE_IPV6 AND NOT WIN32)
  include(CheckStructHasMember)
  check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h"
                          HAVE_SOCKADDR_IN6_SIN6_ADDR)
  check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h"
                          HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
  if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR)
    message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support")
    # Force the feature off as this name is used as guard macro...
    set(ENABLE_IPV6 OFF
        CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
  endif()

  if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT ENABLE_ARES)
    set(use_core_foundation_and_core_services ON)

    find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
    if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
      message(FATAL_ERROR "SystemConfiguration framework not found")
    endif()








>
>
>
>
















|







273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  set(CURL_DISABLE_POP3 ON)
  set(CURL_DISABLE_RTSP ON)
  set(CURL_DISABLE_SMB ON)
  set(CURL_DISABLE_SMTP ON)
  set(CURL_DISABLE_TELNET ON)
  set(CURL_DISABLE_TFTP ON)
endif()

if(WINDOWS_STORE)
  set(CURL_DISABLE_TELNET ON)  # telnet code needs fixing to compile for UWP.
endif()

option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
mark_as_advanced(ENABLE_IPV6)
if(ENABLE_IPV6 AND NOT WIN32)
  include(CheckStructHasMember)
  check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h"
                          HAVE_SOCKADDR_IN6_SIN6_ADDR)
  check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h"
                          HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
  if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR)
    message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support")
    # Force the feature off as this name is used as guard macro...
    set(ENABLE_IPV6 OFF
        CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
  endif()

  if(APPLE AND NOT ENABLE_ARES)
    set(use_core_foundation_and_core_services ON)

    find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
    if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
      message(FATAL_ERROR "SystemConfiguration framework not found")
    endif()

418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
)
if(enabled_ssl_options_count GREATER "1")
  set(CURL_WITH_MULTI_SSL ON)
endif()

if(CURL_USE_SCHANNEL)
  set(SSL_ENABLED ON)
  set(USE_SCHANNEL ON) # Windows native SSL/TLS support
  set(USE_WINDOWS_SSPI ON) # CURL_USE_SCHANNEL implies CURL_WINDOWS_SSPI

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "schannel")
    set(valid_default_ssl_backend TRUE)
  endif()
endif()
if(CURL_WINDOWS_SSPI)
  set(USE_WINDOWS_SSPI ON)







|
|







422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
)
if(enabled_ssl_options_count GREATER "1")
  set(CURL_WITH_MULTI_SSL ON)
endif()

if(CURL_USE_SCHANNEL)
  set(SSL_ENABLED ON)
  set(USE_SCHANNEL ON)  # Windows native SSL/TLS support
  set(USE_WINDOWS_SSPI ON)  # CURL_USE_SCHANNEL implies CURL_WINDOWS_SSPI

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "schannel")
    set(valid_default_ssl_backend TRUE)
  endif()
endif()
if(CURL_WINDOWS_SSPI)
  set(USE_WINDOWS_SSPI ON)
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480

481
482
483
484

485
486
487
488
489
490
491
492
493
494
495
496
497
498
499

500
501
502
503
504

505
506
507
508
509
510
511
512
513
514
515
516

517
518
519
520
521
522
523

524
525
526
527
528

529
530
531
532
533
534
535

536
537
538
539
540

541
542
543
544
545
546
547
  if(NOT COREFOUNDATION_FRAMEWORK)
    message(FATAL_ERROR "CoreFoundation framework not found")
  endif()
  if(NOT CORESERVICES_FRAMEWORK)
    message(FATAL_ERROR "CoreServices framework not found")
  endif()

  list(APPEND CURL_LIBS "-framework CoreFoundation -framework CoreServices")
endif()

if(CURL_USE_OPENSSL)
  find_package(OpenSSL REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_OPENSSL ON)

  # Depend on OpenSSL via imported targets if supported by the running
  # version of CMake.  This allows our dependents to get our dependencies
  # transitively.
  if(NOT CMAKE_VERSION VERSION_LESS 3.4)
    list(APPEND CURL_LIBS OpenSSL::SSL OpenSSL::Crypto)
  else()
    list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
    include_directories(${OPENSSL_INCLUDE_DIR})
  endif()


  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "openssl")
    set(valid_default_ssl_backend TRUE)
  endif()


  set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
  if(NOT DEFINED HAVE_BORINGSSL)
    check_symbol_exists(OPENSSL_IS_BORINGSSL "openssl/base.h" HAVE_BORINGSSL)
  endif()
  if(NOT DEFINED HAVE_AWSLC)
    check_symbol_exists(OPENSSL_IS_AWSLC "openssl/base.h" HAVE_AWSLC)
  endif()
endif()

if(CURL_USE_MBEDTLS)
  find_package(MbedTLS REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_MBEDTLS ON)
  list(APPEND CURL_LIBS ${MBEDTLS_LIBRARIES})

  include_directories(${MBEDTLS_INCLUDE_DIRS})

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "mbedtls")
    set(valid_default_ssl_backend TRUE)
  endif()

endif()

if(CURL_USE_BEARSSL)
  find_package(BearSSL REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_BEARSSL ON)
  list(APPEND CURL_LIBS ${BEARSSL_LIBRARY})
  include_directories(${BEARSSL_INCLUDE_DIRS})

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "bearssl")
    set(valid_default_ssl_backend TRUE)
  endif()

endif()

if(CURL_USE_WOLFSSL)
  find_package(WolfSSL REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_WOLFSSL ON)
  list(APPEND CURL_LIBS ${WolfSSL_LIBRARIES})

  include_directories(${WolfSSL_INCLUDE_DIRS})

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "wolfssl")
    set(valid_default_ssl_backend TRUE)
  endif()

endif()

if(CURL_USE_GNUTLS)
  find_package(GnuTLS REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_GNUTLS ON)
  list(APPEND CURL_LIBS ${GNUTLS_LIBRARIES} "nettle")

  include_directories(${GNUTLS_INCLUDE_DIRS})

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "gnutls")
    set(valid_default_ssl_backend TRUE)
  endif()


  if(NOT DEFINED HAVE_GNUTLS_SRP AND NOT CURL_DISABLE_SRP)
    cmake_push_check_state()
    set(CMAKE_REQUIRED_INCLUDES ${GNUTLS_INCLUDE_DIRS})
    set(CMAKE_REQUIRED_LIBRARIES ${GNUTLS_LIBRARIES})
    check_symbol_exists(gnutls_srp_verifier "gnutls/gnutls.h" HAVE_GNUTLS_SRP)
    cmake_pop_check_state()







|








|







>




>















>





>












>







>





>







>





>







461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
  if(NOT COREFOUNDATION_FRAMEWORK)
    message(FATAL_ERROR "CoreFoundation framework not found")
  endif()
  if(NOT CORESERVICES_FRAMEWORK)
    message(FATAL_ERROR "CoreServices framework not found")
  endif()

  list(APPEND CURL_LIBS "-framework CoreFoundation" "-framework CoreServices")
endif()

if(CURL_USE_OPENSSL)
  find_package(OpenSSL REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_OPENSSL ON)

  # Depend on OpenSSL via imported targets if supported by the running
  # version of CMake. This allows our dependents to get our dependencies
  # transitively.
  if(NOT CMAKE_VERSION VERSION_LESS 3.4)
    list(APPEND CURL_LIBS OpenSSL::SSL OpenSSL::Crypto)
  else()
    list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
    include_directories(${OPENSSL_INCLUDE_DIR})
  endif()
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "openssl")

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "openssl")
    set(valid_default_ssl_backend TRUE)
  endif()
  set(curl_ca_bundle_supported TRUE)

  set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
  if(NOT DEFINED HAVE_BORINGSSL)
    check_symbol_exists(OPENSSL_IS_BORINGSSL "openssl/base.h" HAVE_BORINGSSL)
  endif()
  if(NOT DEFINED HAVE_AWSLC)
    check_symbol_exists(OPENSSL_IS_AWSLC "openssl/base.h" HAVE_AWSLC)
  endif()
endif()

if(CURL_USE_MBEDTLS)
  find_package(MbedTLS REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_MBEDTLS ON)
  list(APPEND CURL_LIBS ${MBEDTLS_LIBRARIES})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "mbedtls")
  include_directories(${MBEDTLS_INCLUDE_DIRS})

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "mbedtls")
    set(valid_default_ssl_backend TRUE)
  endif()
  set(curl_ca_bundle_supported TRUE)
endif()

if(CURL_USE_BEARSSL)
  find_package(BearSSL REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_BEARSSL ON)
  list(APPEND CURL_LIBS ${BEARSSL_LIBRARY})
  include_directories(${BEARSSL_INCLUDE_DIRS})

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "bearssl")
    set(valid_default_ssl_backend TRUE)
  endif()
  set(curl_ca_bundle_supported TRUE)
endif()

if(CURL_USE_WOLFSSL)
  find_package(WolfSSL REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_WOLFSSL ON)
  list(APPEND CURL_LIBS ${WolfSSL_LIBRARIES})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "wolfssl")
  include_directories(${WolfSSL_INCLUDE_DIRS})

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "wolfssl")
    set(valid_default_ssl_backend TRUE)
  endif()
  set(curl_ca_bundle_supported TRUE)
endif()

if(CURL_USE_GNUTLS)
  find_package(GnuTLS REQUIRED)
  set(SSL_ENABLED ON)
  set(USE_GNUTLS ON)
  list(APPEND CURL_LIBS ${GNUTLS_LIBRARIES} "nettle")
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "gnutls")
  include_directories(${GNUTLS_INCLUDE_DIRS})

  if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "gnutls")
    set(valid_default_ssl_backend TRUE)
  endif()
  set(curl_ca_bundle_supported TRUE)

  if(NOT DEFINED HAVE_GNUTLS_SRP AND NOT CURL_DISABLE_SRP)
    cmake_push_check_state()
    set(CMAKE_REQUIRED_INCLUDES ${GNUTLS_INCLUDE_DIRS})
    set(CMAKE_REQUIRED_LIBRARIES ${GNUTLS_LIBRARIES})
    check_symbol_exists(gnutls_srp_verifier "gnutls/gnutls.h" HAVE_GNUTLS_SRP)
    cmake_pop_check_state()
567
568
569
570
571
572
573

574
575
576
577
578
579
580
581
582
583
584

585
586
587
588
589
590
591
592
593
594
595
596

597
598
599
600
601
602
603
  # transitively.
  if(NOT CMAKE_VERSION VERSION_LESS 3.4)
    list(APPEND CURL_LIBS ZLIB::ZLIB)
  else()
    list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
    include_directories(${ZLIB_INCLUDE_DIRS})
  endif()

  list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
endif()

option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
set(HAVE_BROTLI OFF)
if(CURL_BROTLI)
  find_package(Brotli REQUIRED)
  if(BROTLI_FOUND)
    set(HAVE_BROTLI ON)
    set(CURL_LIBS "${BROTLI_LIBRARIES};${CURL_LIBS}")  # For 'ld' linker. Emulate `list(PREPEND ...)` to stay compatible with <v3.15 CMake.
    list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})

    include_directories(${BROTLI_INCLUDE_DIRS})
    list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
  endif()
endif()

option(CURL_ZSTD "Set to ON to enable building curl with zstd support." OFF)
set(HAVE_ZSTD OFF)
if(CURL_ZSTD)
  find_package(Zstd REQUIRED)
  if(Zstd_FOUND AND NOT Zstd_VERSION VERSION_LESS "1.0.0")
    set(HAVE_ZSTD ON)
    list(APPEND CURL_LIBS ${Zstd_LIBRARIES})

    include_directories(${Zstd_INCLUDE_DIRS})
  else()
    message(WARNING "zstd v1.0.0 or newer is required, disabling zstd support.")
  endif()
endif()

# Check symbol in an OpenSSL-like TLS backend, or in EXTRA_LIBS depending on it.







>









<

>












>







580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596

597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  # transitively.
  if(NOT CMAKE_VERSION VERSION_LESS 3.4)
    list(APPEND CURL_LIBS ZLIB::ZLIB)
  else()
    list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
    include_directories(${ZLIB_INCLUDE_DIRS})
  endif()
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "zlib")
  list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
endif()

option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
set(HAVE_BROTLI OFF)
if(CURL_BROTLI)
  find_package(Brotli REQUIRED)
  if(BROTLI_FOUND)
    set(HAVE_BROTLI ON)

    list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libbrotlidec")
    include_directories(${BROTLI_INCLUDE_DIRS})
    list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
  endif()
endif()

option(CURL_ZSTD "Set to ON to enable building curl with zstd support." OFF)
set(HAVE_ZSTD OFF)
if(CURL_ZSTD)
  find_package(Zstd REQUIRED)
  if(Zstd_FOUND AND NOT Zstd_VERSION VERSION_LESS "1.0.0")
    set(HAVE_ZSTD ON)
    list(APPEND CURL_LIBS ${Zstd_LIBRARIES})
    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libzstd")
    include_directories(${Zstd_INCLUDE_DIRS})
  else()
    message(WARNING "zstd v1.0.0 or newer is required, disabling zstd support.")
  endif()
endif()

# Check symbol in an OpenSSL-like TLS backend, or in EXTRA_LIBS depending on it.
641
642
643
644
645
646
647





648
649
650
651
652
653
654
      openssl_check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD "")
    endif()
  endif()
  if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD)
    message(FATAL_ERROR "QUIC support is missing in OpenSSL fork. Try setting -DOPENSSL_ROOT_DIR")
  endif()
endmacro()






if(USE_OPENSSL OR USE_WOLFSSL)
  if(NOT DEFINED HAVE_SSL_SET0_WBIO)
    openssl_check_symbol_exists(SSL_set0_wbio "openssl/ssl.h" HAVE_SSL_SET0_WBIO "")
  endif()
  if(NOT DEFINED HAVE_OPENSSL_SRP AND NOT CURL_DISABLE_SRP)
    openssl_check_symbol_exists(SSL_CTX_set_srp_username "openssl/ssl.h" HAVE_OPENSSL_SRP "")







>
>
>
>
>







656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
      openssl_check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD "")
    endif()
  endif()
  if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD)
    message(FATAL_ERROR "QUIC support is missing in OpenSSL fork. Try setting -DOPENSSL_ROOT_DIR")
  endif()
endmacro()

if(USE_WOLFSSL)
  openssl_check_symbol_exists(wolfSSL_DES_ecb_encrypt "wolfssl/openssl/des.h" HAVE_WOLFSSL_DES_ECB_ENCRYPT "")
  openssl_check_symbol_exists(wolfSSL_BIO_set_shutdown "wolfssl/ssl.h" HAVE_WOLFSSL_FULL_BIO "")
endif()

if(USE_OPENSSL OR USE_WOLFSSL)
  if(NOT DEFINED HAVE_SSL_SET0_WBIO)
    openssl_check_symbol_exists(SSL_set0_wbio "openssl/ssl.h" HAVE_SSL_SET0_WBIO "")
  endif()
  if(NOT DEFINED HAVE_OPENSSL_SRP AND NOT CURL_DISABLE_SRP)
    openssl_check_symbol_exists(SSL_CTX_set_srp_username "openssl/ssl.h" HAVE_OPENSSL_SRP "")
680
681
682
683
684
685
686

687
688
689
690
691
692
693

694
695

696
697

698
699
700
701

702
703
704
705
706
707

708
709
710
711
712

713
714
715
716
717
718
719
720
721
722
723
724
725
726
727

728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744

745
746
747
748
749
750
751
752
753
754
755
756
757

758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
endif()

option(USE_NGHTTP2 "Use nghttp2 library" OFF)
if(USE_NGHTTP2)
  find_package(NGHTTP2 REQUIRED)
  include_directories(${NGHTTP2_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES})

endif()

option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF)
if(USE_NGTCP2)
  if(USE_OPENSSL OR USE_WOLFSSL)
    if(USE_WOLFSSL)
      find_package(NGTCP2 REQUIRED wolfSSL)

    elseif(HAVE_BORINGSSL OR HAVE_AWSLC)
      find_package(NGTCP2 REQUIRED BoringSSL)

    else()
      find_package(NGTCP2 REQUIRED quictls)

    endif()
    openssl_check_quic()
  elseif(USE_GNUTLS)
    find_package(NGTCP2 REQUIRED GnuTLS)

  else()
    message(FATAL_ERROR "ngtcp2 requires OpenSSL, wolfSSL or GnuTLS")
  endif()
  set(USE_NGTCP2 ON)
  include_directories(${NGTCP2_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${NGTCP2_LIBRARIES})


  find_package(NGHTTP3 REQUIRED)
  set(USE_NGHTTP3 ON)
  include_directories(${NGHTTP3_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})

endif()

option(USE_QUICHE "Use quiche library for HTTP/3 support" OFF)
if(USE_QUICHE)
  if(USE_NGTCP2)
    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
  endif()
  find_package(QUICHE REQUIRED)
  if(NOT HAVE_BORINGSSL)
    message(FATAL_ERROR "quiche requires BoringSSL")
  endif()
  openssl_check_quic()
  set(USE_QUICHE ON)
  include_directories(${QUICHE_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${QUICHE_LIBRARIES})

  if(NOT DEFINED HAVE_QUICHE_CONN_SET_QLOG_FD)
    cmake_push_check_state()
    set(CMAKE_REQUIRED_INCLUDES   "${QUICHE_INCLUDE_DIRS}")
    set(CMAKE_REQUIRED_LIBRARIES  "${QUICHE_LIBRARIES}")
    check_symbol_exists(quiche_conn_set_qlog_fd "quiche.h" HAVE_QUICHE_CONN_SET_QLOG_FD)
    cmake_pop_check_state()
  endif()
endif()

option(USE_MSH3 "Use msquic library for HTTP/3 support" OFF)
if(USE_MSH3)
  if(USE_NGTCP2 OR USE_QUICHE)
    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
  endif()
  set(USE_MSH3 ON)
  include_directories(${MSH3_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${MSH3_LIBRARIES})

endif()

option(USE_OPENSSL_QUIC "Use openssl and nghttp3 libraries for HTTP/3 support" OFF)
if(USE_OPENSSL_QUIC)
  if(USE_NGTCP2 OR USE_QUICHE OR USE_MSH3)
    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
  endif()
  find_package(OpenSSL 3.2.0 REQUIRED)

  find_package(NGHTTP3 REQUIRED)
  set(USE_NGHTTP3 ON)
  include_directories(${NGHTTP3_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})

endif()

if(USE_MBEDTLS OR
   USE_BEARSSL OR
   USE_SECTRANSP)
  message(WARNING "A selected TLS library does not support TLS 1.3.")
endif()

if(CURL_WITH_MULTI_SSL AND (USE_NGTCP2 OR USE_QUICHE OR USE_MSH3 OR USE_OPENSSL_QUIC))
  message(FATAL_ERROR "MultiSSL cannot be enabled with HTTP/3 and vice versa.")
endif()

if(NOT CURL_DISABLE_SRP AND (HAVE_GNUTLS_SRP OR HAVE_OPENSSL_SRP))
  set(USE_TLS_SRP 1)
endif()

if(NOT CURL_DISABLE_LDAP)
  if(WIN32)
    option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
    if(USE_WIN32_LDAP)
      list(APPEND CURL_LIBS "wldap32")
      if(NOT CURL_DISABLE_LDAPS)
        set(HAVE_LDAP_SSL ON)
      endif()
    endif()







>







>


>


>




>






>





>















>

















>







|





>

















|







700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
endif()

option(USE_NGHTTP2 "Use nghttp2 library" OFF)
if(USE_NGHTTP2)
  find_package(NGHTTP2 REQUIRED)
  include_directories(${NGHTTP2_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp2")
endif()

option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF)
if(USE_NGTCP2)
  if(USE_OPENSSL OR USE_WOLFSSL)
    if(USE_WOLFSSL)
      find_package(NGTCP2 REQUIRED wolfSSL)
      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2_crypto_wolfssl")
    elseif(HAVE_BORINGSSL OR HAVE_AWSLC)
      find_package(NGTCP2 REQUIRED BoringSSL)
      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2_crypto_boringssl")
    else()
      find_package(NGTCP2 REQUIRED quictls)
      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2_crypto_quictls")
    endif()
    openssl_check_quic()
  elseif(USE_GNUTLS)
    find_package(NGTCP2 REQUIRED GnuTLS)
    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2_crypto_gnutls")
  else()
    message(FATAL_ERROR "ngtcp2 requires OpenSSL, wolfSSL or GnuTLS")
  endif()
  set(USE_NGTCP2 ON)
  include_directories(${NGTCP2_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${NGTCP2_LIBRARIES})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2")

  find_package(NGHTTP3 REQUIRED)
  set(USE_NGHTTP3 ON)
  include_directories(${NGHTTP3_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp3")
endif()

option(USE_QUICHE "Use quiche library for HTTP/3 support" OFF)
if(USE_QUICHE)
  if(USE_NGTCP2)
    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
  endif()
  find_package(QUICHE REQUIRED)
  if(NOT HAVE_BORINGSSL)
    message(FATAL_ERROR "quiche requires BoringSSL")
  endif()
  openssl_check_quic()
  set(USE_QUICHE ON)
  include_directories(${QUICHE_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${QUICHE_LIBRARIES})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "quiche")
  if(NOT DEFINED HAVE_QUICHE_CONN_SET_QLOG_FD)
    cmake_push_check_state()
    set(CMAKE_REQUIRED_INCLUDES   "${QUICHE_INCLUDE_DIRS}")
    set(CMAKE_REQUIRED_LIBRARIES  "${QUICHE_LIBRARIES}")
    check_symbol_exists(quiche_conn_set_qlog_fd "quiche.h" HAVE_QUICHE_CONN_SET_QLOG_FD)
    cmake_pop_check_state()
  endif()
endif()

option(USE_MSH3 "Use msquic library for HTTP/3 support" OFF)
if(USE_MSH3)
  if(USE_NGTCP2 OR USE_QUICHE)
    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
  endif()
  set(USE_MSH3 ON)
  include_directories(${MSH3_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${MSH3_LIBRARIES})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libmsh3")
endif()

option(USE_OPENSSL_QUIC "Use openssl and nghttp3 libraries for HTTP/3 support" OFF)
if(USE_OPENSSL_QUIC)
  if(USE_NGTCP2 OR USE_QUICHE OR USE_MSH3)
    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
  endif()
  find_package(OpenSSL 3.3.0 REQUIRED)

  find_package(NGHTTP3 REQUIRED)
  set(USE_NGHTTP3 ON)
  include_directories(${NGHTTP3_INCLUDE_DIRS})
  list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})
  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp3")
endif()

if(USE_MBEDTLS OR
   USE_BEARSSL OR
   USE_SECTRANSP)
  message(WARNING "A selected TLS library does not support TLS 1.3.")
endif()

if(CURL_WITH_MULTI_SSL AND (USE_NGTCP2 OR USE_QUICHE OR USE_MSH3 OR USE_OPENSSL_QUIC))
  message(FATAL_ERROR "MultiSSL cannot be enabled with HTTP/3 and vice versa.")
endif()

if(NOT CURL_DISABLE_SRP AND (HAVE_GNUTLS_SRP OR HAVE_OPENSSL_SRP))
  set(USE_TLS_SRP 1)
endif()

if(NOT CURL_DISABLE_LDAP)
  if(WIN32 AND NOT WINDOWS_STORE)
    option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
    if(USE_WIN32_LDAP)
      list(APPEND CURL_LIBS "wldap32")
      if(NOT CURL_DISABLE_LDAPS)
        set(HAVE_LDAP_SSL ON)
      endif()
    endif()
881
882
883
884
885
886
887
888
889
890













891
892
893
894
895
896
897
endif()

# Check for idn2
option(USE_LIBIDN2 "Use libidn2 for IDN support" ON)
if(USE_LIBIDN2)
  check_library_exists("idn2" "idn2_lookup_ul" "" HAVE_LIBIDN2)
  if(HAVE_LIBIDN2)
    set(CURL_LIBS "idn2;${CURL_LIBS}")
    check_include_file_concat("idn2.h" HAVE_IDN2_H)
  endif()













else()
  set(HAVE_LIBIDN2 OFF)
endif()

if(WIN32)
  option(USE_WIN32_IDN "Use WinIDN for IDN support" OFF)
  if(USE_WIN32_IDN)







|


>
>
>
>
>
>
>
>
>
>
>
>
>







911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
endif()

# Check for idn2
option(USE_LIBIDN2 "Use libidn2 for IDN support" ON)
if(USE_LIBIDN2)
  check_library_exists("idn2" "idn2_lookup_ul" "" HAVE_LIBIDN2)
  if(HAVE_LIBIDN2)
    set(LIBIDN2_LINK_LIBRARIES "idn2")
    check_include_file_concat("idn2.h" HAVE_IDN2_H)
  endif()
  if(NOT HAVE_LIBIDN2 OR NOT HAVE_IDN2_H)
    find_package(PkgConfig QUIET)
    pkg_check_modules(LIBIDN2 "libidn2")
    if(LIBIDN2_FOUND)
      include_directories(${LIBIDN2_INCLUDE_DIRS})
      set(HAVE_LIBIDN2 ON)
      set(HAVE_IDN2_H ON)
    endif()
  endif()
  if(HAVE_LIBIDN2 AND HAVE_IDN2_H)
    set(CURL_LIBS "${LIBIDN2_LINK_LIBRARIES};${CURL_LIBS}")
    set(LIBCURL_PC_REQUIRES_PRIVATE "libidn2;${LIBCURL_PC_REQUIRES_PRIVATE}")
  endif()
else()
  set(HAVE_LIBIDN2 OFF)
endif()

if(WIN32)
  option(USE_WIN32_IDN "Use WinIDN for IDN support" OFF)
  if(USE_WIN32_IDN)
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925

926
927
928
929
930
931
932
933
934
935
936
937
938
939
940

941
942
943
944
945
946
947
948
949
950
951
952
953
954
955

956
957
958









959
960
961
962
963
964
965
      list(APPEND CURL_LIBS "icucore")
    else()
      set(USE_APPLE_IDN OFF)
    endif()
  endif()
endif()

#libpsl
option(CURL_USE_LIBPSL "Use libPSL" ON)
mark_as_advanced(CURL_USE_LIBPSL)
set(USE_LIBPSL OFF)

if(CURL_USE_LIBPSL)
  find_package(LibPSL)
  if(LIBPSL_FOUND)
    list(APPEND CURL_LIBS ${LIBPSL_LIBRARY})

    list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBPSL_INCLUDE_DIR}")
    include_directories("${LIBPSL_INCLUDE_DIR}")
    set(USE_LIBPSL ON)
  endif()
endif()

#libSSH2
option(CURL_USE_LIBSSH2 "Use libSSH2" ON)
mark_as_advanced(CURL_USE_LIBSSH2)
set(USE_LIBSSH2 OFF)

if(CURL_USE_LIBSSH2)
  find_package(LibSSH2)
  if(LIBSSH2_FOUND)
    list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})

    list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}")
    include_directories("${LIBSSH2_INCLUDE_DIR}")
    set(USE_LIBSSH2 ON)
  endif()
endif()

# libssh
option(CURL_USE_LIBSSH "Use libSSH" OFF)
mark_as_advanced(CURL_USE_LIBSSH)
if(NOT USE_LIBSSH2 AND CURL_USE_LIBSSH)
  find_package(libssh CONFIG)
  if(libssh_FOUND)
    message(STATUS "Found libssh ${libssh_VERSION}")
    # Use imported target for include and library paths.
    list(APPEND CURL_LIBS ssh)

    set(USE_LIBSSH ON)
  endif()
endif()










option(CURL_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
mark_as_advanced(CURL_USE_GSSAPI)

if(CURL_USE_GSSAPI)
  find_package(GSS)








|
|







>






|
|







>







|







>



>
>
>
>
>
>
>
>
>







953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
      list(APPEND CURL_LIBS "icucore")
    else()
      set(USE_APPLE_IDN OFF)
    endif()
  endif()
endif()

# libpsl
option(CURL_USE_LIBPSL "Use libpsl" ON)
mark_as_advanced(CURL_USE_LIBPSL)
set(USE_LIBPSL OFF)

if(CURL_USE_LIBPSL)
  find_package(LibPSL)
  if(LIBPSL_FOUND)
    list(APPEND CURL_LIBS ${LIBPSL_LIBRARY})
    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libpsl")
    list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBPSL_INCLUDE_DIR}")
    include_directories("${LIBPSL_INCLUDE_DIR}")
    set(USE_LIBPSL ON)
  endif()
endif()

# libssh2
option(CURL_USE_LIBSSH2 "Use libssh2" ON)
mark_as_advanced(CURL_USE_LIBSSH2)
set(USE_LIBSSH2 OFF)

if(CURL_USE_LIBSSH2)
  find_package(LibSSH2)
  if(LIBSSH2_FOUND)
    list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libssh2")
    list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}")
    include_directories("${LIBSSH2_INCLUDE_DIR}")
    set(USE_LIBSSH2 ON)
  endif()
endif()

# libssh
option(CURL_USE_LIBSSH "Use libssh" OFF)
mark_as_advanced(CURL_USE_LIBSSH)
if(NOT USE_LIBSSH2 AND CURL_USE_LIBSSH)
  find_package(libssh CONFIG)
  if(libssh_FOUND)
    message(STATUS "Found libssh ${libssh_VERSION}")
    # Use imported target for include and library paths.
    list(APPEND CURL_LIBS ssh)
    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libssh")
    set(USE_LIBSSH ON)
  endif()
endif()

option(CURL_USE_GSASL "Use GSASL implementation" OFF)
mark_as_advanced(CURL_USE_GSASL)
if(CURL_USE_GSASL)
  find_package(PkgConfig REQUIRED)
  pkg_check_modules(GSASL REQUIRED libgsasl)
  list(APPEND CURL_LIBS ${GSASL_LINK_LIBRARIES})
  set(USE_GSASL ON)
endif()

option(CURL_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
mark_as_advanced(CURL_USE_GSSAPI)

if(CURL_USE_GSSAPI)
  find_package(GSS)

1007
1008
1009
1010
1011
1012
1013
1014


1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030

1031
1032
1033
1034
1035
1036
1037
    include_directories(${GSS_INCLUDE_DIR})
    link_directories(${GSS_LINK_DIRECTORIES})
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
    string(REPLACE ";" " " GSS_LINKER_FLAGS "${GSS_LINKER_FLAGS}")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
    list(APPEND CURL_LIBS ${GSS_LIBRARIES})



  else()
    message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.")
  endif()
endif()

option(USE_LIBRTMP "Enable librtmp from rtmpdump" OFF)
if(USE_LIBRTMP)
  cmake_push_check_state()
  set(_extra_libs "rtmp")
  if(WIN32)
    list(APPEND _extra_libs "winmm")
  endif()
  openssl_check_symbol_exists("RTMP_Init" "librtmp/rtmp.h" HAVE_LIBRTMP "${_extra_libs}")
  cmake_pop_check_state()
  if(HAVE_LIBRTMP)
    list(APPEND CURL_LIBS "rtmp")

    if(WIN32)
      list(APPEND CURL_LIBS "winmm")
    endif()
  else()
    message(WARNING "librtmp requested, but not found or missing OpenSSL. Skipping.")
    set(USE_LIBRTMP OFF)
  endif()







|
>
>
















>







1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
    include_directories(${GSS_INCLUDE_DIR})
    link_directories(${GSS_LINK_DIRECTORIES})
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
    string(REPLACE ";" " " GSS_LINKER_FLAGS "${GSS_LINKER_FLAGS}")
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
    list(APPEND CURL_LIBS ${GSS_LIBRARIES})
    if(GSS_FLAVOUR STREQUAL "MIT")
      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "mit-krb5-gssapi")
    endif()
  else()
    message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.")
  endif()
endif()

option(USE_LIBRTMP "Enable librtmp from rtmpdump" OFF)
if(USE_LIBRTMP)
  cmake_push_check_state()
  set(_extra_libs "rtmp")
  if(WIN32)
    list(APPEND _extra_libs "winmm")
  endif()
  openssl_check_symbol_exists("RTMP_Init" "librtmp/rtmp.h" HAVE_LIBRTMP "${_extra_libs}")
  cmake_pop_check_state()
  if(HAVE_LIBRTMP)
    list(APPEND CURL_LIBS "rtmp")
    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "librtmp")
    if(WIN32)
      list(APPEND CURL_LIBS "winmm")
    endif()
  else()
    message(WARNING "librtmp requested, but not found or missing OpenSSL. Skipping.")
    set(USE_LIBRTMP OFF)
  endif()
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055

1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116




1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
  else()
    check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS)
  endif()
else()
  unset(USE_UNIX_SOCKETS CACHE)
endif()


#
# CA handling
#

set(CURL_CA_BUNDLE "auto" CACHE STRING
    "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
set(CURL_CA_FALLBACK OFF CACHE BOOL
    "Set ON to use built-in CA store of TLS backend. Defaults to OFF")
set(CURL_CA_PATH "auto" CACHE STRING
    "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")

if("${CURL_CA_BUNDLE}" STREQUAL "")
  message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
elseif("${CURL_CA_BUNDLE}" STREQUAL "none")
  unset(CURL_CA_BUNDLE CACHE)
elseif("${CURL_CA_BUNDLE}" STREQUAL "auto")
  unset(CURL_CA_BUNDLE CACHE)
  if(NOT CMAKE_CROSSCOMPILING)
    set(CURL_CA_BUNDLE_AUTODETECT TRUE)
  endif()
else()
  set(CURL_CA_BUNDLE_SET TRUE)
endif()

if("${CURL_CA_PATH}" STREQUAL "")
  message(FATAL_ERROR "Invalid value of CURL_CA_PATH. Use 'none', 'auto' or directory path.")
elseif("${CURL_CA_PATH}" STREQUAL "none")
  unset(CURL_CA_PATH CACHE)
elseif("${CURL_CA_PATH}" STREQUAL "auto")
  unset(CURL_CA_PATH CACHE)
  if(NOT CMAKE_CROSSCOMPILING)
    set(CURL_CA_PATH_AUTODETECT TRUE)
  endif()
else()
  set(CURL_CA_PATH_SET TRUE)
endif()

if(CURL_CA_BUNDLE_SET AND CURL_CA_PATH_AUTODETECT)
  # Skip autodetection of unset CA path because CA bundle is set explicitly
elseif(CURL_CA_PATH_SET AND CURL_CA_BUNDLE_AUTODETECT)
  # Skip autodetection of unset CA bundle because CA path is set explicitly
elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT)
  # first try autodetecting a CA bundle, then a CA path

  if(CURL_CA_BUNDLE_AUTODETECT)
    set(SEARCH_CA_BUNDLE_PATHS
        /etc/ssl/certs/ca-certificates.crt
        /etc/pki/tls/certs/ca-bundle.crt
        /usr/share/ssl/certs/ca-bundle.crt
        /usr/local/share/certs/ca-root-nss.crt
        /etc/ssl/cert.pem)

    foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS})
      if(EXISTS "${SEARCH_CA_BUNDLE_PATH}")
        message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}")
        set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}" CACHE STRING
            "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
        set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
        break()
      endif()
    endforeach()
  endif()

  if(CURL_CA_PATH_AUTODETECT AND (NOT CURL_CA_PATH_SET))
    if(EXISTS "/etc/ssl/certs")




      set(CURL_CA_PATH "/etc/ssl/certs" CACHE STRING
          "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
      set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
    endif()
  endif()
endif()

if(CURL_CA_PATH_SET AND
   NOT USE_OPENSSL AND
   NOT USE_WOLFSSL AND
   NOT USE_GNUTLS AND
   NOT USE_MBEDTLS)
  message(STATUS
          "CA path only supported by OpenSSL, wolfSSL, GnuTLS or mbedTLS. "
          "Set CURL_CA_PATH=none or enable one of those TLS backends.")
endif()

# Check for header files
if(WIN32)
  set(CURL_INCLUDES ${CURL_INCLUDES} "winsock2.h")
  set(CURL_INCLUDES ${CURL_INCLUDES} "ws2tcpip.h")
  set(CURL_INCLUDES ${CURL_INCLUDES} "windows.h")







<



>
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|

|
|
|
|
|
|
|
<
<
|
|
|
|
|
|
|
|
|

|
|
>
>
>
>
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<







1103
1104
1105
1106
1107
1108
1109

1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160


1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182









1183
1184
1185
1186
1187
1188
1189
  else()
    check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS)
  endif()
else()
  unset(USE_UNIX_SOCKETS CACHE)
endif()


#
# CA handling
#
if(curl_ca_bundle_supported)
  set(CURL_CA_BUNDLE "auto" CACHE STRING
      "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
  set(CURL_CA_FALLBACK OFF CACHE BOOL
      "Set ON to use built-in CA store of TLS backend. Defaults to OFF")
  set(CURL_CA_PATH "auto" CACHE STRING
      "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")

  if(CURL_CA_BUNDLE STREQUAL "")
    message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
  elseif(CURL_CA_BUNDLE STREQUAL "none")
    unset(CURL_CA_BUNDLE CACHE)
  elseif(CURL_CA_BUNDLE STREQUAL "auto")
    unset(CURL_CA_BUNDLE CACHE)
    if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32)
      set(CURL_CA_BUNDLE_AUTODETECT TRUE)
    endif()
  else()
    set(CURL_CA_BUNDLE_SET TRUE)
  endif()

  if(CURL_CA_PATH STREQUAL "")
    message(FATAL_ERROR "Invalid value of CURL_CA_PATH. Use 'none', 'auto' or directory path.")
  elseif(CURL_CA_PATH STREQUAL "none")
    unset(CURL_CA_PATH CACHE)
  elseif(CURL_CA_PATH STREQUAL "auto")
    unset(CURL_CA_PATH CACHE)
    if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32)
      set(CURL_CA_PATH_AUTODETECT TRUE)
    endif()
  else()
    set(CURL_CA_PATH_SET TRUE)
  endif()

  if(CURL_CA_BUNDLE_SET AND CURL_CA_PATH_AUTODETECT)
    # Skip auto-detection of unset CA path because CA bundle is set explicitly
  elseif(CURL_CA_PATH_SET AND CURL_CA_BUNDLE_AUTODETECT)
    # Skip auto-detection of unset CA bundle because CA path is set explicitly
  elseif(CURL_CA_BUNDLE_AUTODETECT OR CURL_CA_PATH_AUTODETECT)
    # First try auto-detecting a CA bundle, then a CA path

    if(CURL_CA_BUNDLE_AUTODETECT)
      foreach(SEARCH_CA_BUNDLE_PATH IN ITEMS
          "/etc/ssl/certs/ca-certificates.crt"
          "/etc/pki/tls/certs/ca-bundle.crt"
          "/usr/share/ssl/certs/ca-bundle.crt"
          "/usr/local/share/certs/ca-root-nss.crt"
          "/etc/ssl/cert.pem")


        if(EXISTS "${SEARCH_CA_BUNDLE_PATH}")
          message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}")
          set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}" CACHE STRING
              "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
          set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
          break()
        endif()
      endforeach()
    endif()

    if(CURL_CA_PATH_AUTODETECT AND NOT CURL_CA_PATH_SET)
      set(SEARCH_CA_PATH "/etc/ssl/certs")
      file(GLOB curl_ca_files_found "${SEARCH_CA_PATH}/[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].0")
      if(curl_ca_files_found)
        unset(curl_ca_files_found)
        message(STATUS "Found CA path: ${SEARCH_CA_PATH}")
        set(CURL_CA_PATH "${SEARCH_CA_PATH}" CACHE STRING
            "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
        set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
      endif()
    endif()
  endif()









endif()

# Check for header files
if(WIN32)
  set(CURL_INCLUDES ${CURL_INCLUDES} "winsock2.h")
  set(CURL_INCLUDES ${CURL_INCLUDES} "ws2tcpip.h")
  set(CURL_INCLUDES ${CURL_INCLUDES} "windows.h")
1168
1169
1170
1171
1172
1173
1174

1175
1176
1177
1178
1179
1180
1181
      endif()
      unset(HAVE_INET_NTOP CACHE)
      unset(HAVE_INET_PTON CACHE)
    endif()
  endif()
endif()


check_include_file_concat("sys/filio.h"      HAVE_SYS_FILIO_H)
check_include_file_concat("sys/wait.h"       HAVE_SYS_WAIT_H)
check_include_file_concat("sys/ioctl.h"      HAVE_SYS_IOCTL_H)
check_include_file_concat("sys/param.h"      HAVE_SYS_PARAM_H)
check_include_file_concat("sys/poll.h"       HAVE_SYS_POLL_H)
check_include_file_concat("sys/resource.h"   HAVE_SYS_RESOURCE_H)
check_include_file_concat("sys/select.h"     HAVE_SYS_SELECT_H)







>







1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
      endif()
      unset(HAVE_INET_NTOP CACHE)
      unset(HAVE_INET_PTON CACHE)
    endif()
  endif()
endif()

check_include_file_concat("sys/eventfd.h"    HAVE_SYS_EVENTFD_H)
check_include_file_concat("sys/filio.h"      HAVE_SYS_FILIO_H)
check_include_file_concat("sys/wait.h"       HAVE_SYS_WAIT_H)
check_include_file_concat("sys/ioctl.h"      HAVE_SYS_IOCTL_H)
check_include_file_concat("sys/param.h"      HAVE_SYS_PARAM_H)
check_include_file_concat("sys/poll.h"       HAVE_SYS_POLL_H)
check_include_file_concat("sys/resource.h"   HAVE_SYS_RESOURCE_H)
check_include_file_concat("sys/select.h"     HAVE_SYS_SELECT_H)
1288
1289
1290
1291
1292
1293
1294

1295
1296
1297
1298
1299
1300
1301
check_symbol_exists(strerror_r     "${CURL_INCLUDES};stdlib.h;string.h" HAVE_STRERROR_R)
check_symbol_exists(sigaction      "signal.h" HAVE_SIGACTION)
check_symbol_exists(siginterrupt   "${CURL_INCLUDES};signal.h" HAVE_SIGINTERRUPT)
check_symbol_exists(getaddrinfo    "${CURL_INCLUDES};stdlib.h;string.h" HAVE_GETADDRINFO)
check_symbol_exists(getifaddrs     "${CURL_INCLUDES};stdlib.h" HAVE_GETIFADDRS)
check_symbol_exists(freeaddrinfo   "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
check_symbol_exists(pipe           "${CURL_INCLUDES}" HAVE_PIPE)

check_symbol_exists(ftruncate      "${CURL_INCLUDES}" HAVE_FTRUNCATE)
check_symbol_exists(_fseeki64      "${CURL_INCLUDES};stdio.h" HAVE__FSEEKI64)
check_symbol_exists(getpeername    "${CURL_INCLUDES}" HAVE_GETPEERNAME)
check_symbol_exists(getsockname    "${CURL_INCLUDES}" HAVE_GETSOCKNAME)
check_symbol_exists(if_nametoindex "${CURL_INCLUDES}" HAVE_IF_NAMETOINDEX)
check_symbol_exists(getrlimit      "${CURL_INCLUDES}" HAVE_GETRLIMIT)
check_symbol_exists(setlocale      "${CURL_INCLUDES}" HAVE_SETLOCALE)







>







1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
check_symbol_exists(strerror_r     "${CURL_INCLUDES};stdlib.h;string.h" HAVE_STRERROR_R)
check_symbol_exists(sigaction      "signal.h" HAVE_SIGACTION)
check_symbol_exists(siginterrupt   "${CURL_INCLUDES};signal.h" HAVE_SIGINTERRUPT)
check_symbol_exists(getaddrinfo    "${CURL_INCLUDES};stdlib.h;string.h" HAVE_GETADDRINFO)
check_symbol_exists(getifaddrs     "${CURL_INCLUDES};stdlib.h" HAVE_GETIFADDRS)
check_symbol_exists(freeaddrinfo   "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
check_symbol_exists(pipe           "${CURL_INCLUDES}" HAVE_PIPE)
check_symbol_exists(eventfd        "${CURL_INCLUDES};sys/eventfd.h" HAVE_EVENTFD)
check_symbol_exists(ftruncate      "${CURL_INCLUDES}" HAVE_FTRUNCATE)
check_symbol_exists(_fseeki64      "${CURL_INCLUDES};stdio.h" HAVE__FSEEKI64)
check_symbol_exists(getpeername    "${CURL_INCLUDES}" HAVE_GETPEERNAME)
check_symbol_exists(getsockname    "${CURL_INCLUDES}" HAVE_GETSOCKNAME)
check_symbol_exists(if_nametoindex "${CURL_INCLUDES}" HAVE_IF_NAMETOINDEX)
check_symbol_exists(getrlimit      "${CURL_INCLUDES}" HAVE_GETRLIMIT)
check_symbol_exists(setlocale      "${CURL_INCLUDES}" HAVE_SETLOCALE)
1437
1438
1439
1440
1441
1442
1443

1444
1445

1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
endif()

if(NOT WIN32)
  # Check clock_gettime(CLOCK_MONOTONIC, x) support
  curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC)
endif()


# Check compiler support of __builtin_available()
curl_internal_test(HAVE_BUILTIN_AVAILABLE)


# Some other minor tests

if(NOT HAVE_IN_ADDR_T)
  set(in_addr_t "unsigned long")
endif()

# Check for nonblocking
set(HAVE_DISABLED_NONBLOCKING 1)
if(HAVE_FIONBIO OR
    HAVE_IOCTLSOCKET OR
    HAVE_IOCTLSOCKET_CASE OR
    HAVE_O_NONBLOCK)
  set(HAVE_DISABLED_NONBLOCKING)
endif()

if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
  include(CheckCCompilerFlag)
  check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double)
  if(HAVE_C_FLAG_Wno_long_double)
    # The Mac version of GCC warns about use of long double.  Disable it.
    get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS)
    if(MPRINTF_COMPILE_FLAGS)
      set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double")
    else()
      set(MPRINTF_COMPILE_FLAGS "-Wno-long-double")
    endif()
    set_source_files_properties(mprintf.c PROPERTIES







>
|
|
>










|
|
|







|







1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
endif()

if(NOT WIN32)
  # Check clock_gettime(CLOCK_MONOTONIC, x) support
  curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC)
endif()

if(APPLE)
  # Check compiler support of __builtin_available()
  curl_internal_test(HAVE_BUILTIN_AVAILABLE)
endif()

# Some other minor tests

if(NOT HAVE_IN_ADDR_T)
  set(in_addr_t "unsigned long")
endif()

# Check for nonblocking
set(HAVE_DISABLED_NONBLOCKING 1)
if(HAVE_FIONBIO OR
   HAVE_IOCTLSOCKET OR
   HAVE_IOCTLSOCKET_CASE OR
   HAVE_O_NONBLOCK)
  set(HAVE_DISABLED_NONBLOCKING)
endif()

if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
  include(CheckCCompilerFlag)
  check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double)
  if(HAVE_C_FLAG_Wno_long_double)
    # The Mac version of GCC warns about use of long double. Disable it.
    get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS)
    if(MPRINTF_COMPILE_FLAGS)
      set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double")
    else()
      set(MPRINTF_COMPILE_FLAGS "-Wno-long-double")
    endif()
    set_source_files_properties(mprintf.c PROPERTIES
1536
1537
1538
1539
1540
1541
1542
1543

1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
    message(STATUS "LTO supported and enabled")
  else()
    message(FATAL_ERROR "LTO was requested - but compiler doesn't support it\n${CURL_LTO_ERROR}")
  endif()
endif()


# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).

function(transform_makefile_inc INPUT_FILE OUTPUT_FILE)
  file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT)
  string(REPLACE "$(top_srcdir)"   "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
  string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})

  string(REGEX REPLACE "\\\\\n" "!π!α!" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
  string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
  string(REPLACE "!π!α!" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})

  string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})    # Replace $() with ${}
  string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})    # Replace @@ with ${}, even if that may not be read by CMake scripts.
  file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT})
  set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${INPUT_FILE}")
endfunction()

include(GNUInstallDirs)

set(CURL_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})







|
>









|
|







1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
    message(STATUS "LTO supported and enabled")
  else()
    message(FATAL_ERROR "LTO was requested - but compiler doesn't support it\n${CURL_LTO_ERROR}")
  endif()
endif()


# Ugly (but functional) way to include "Makefile.inc" by transforming it
# (= regenerate it).
function(transform_makefile_inc INPUT_FILE OUTPUT_FILE)
  file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT)
  string(REPLACE "$(top_srcdir)"   "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
  string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})

  string(REGEX REPLACE "\\\\\n" "!π!α!" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
  string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
  string(REPLACE "!π!α!" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})

  string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})  # Replace $() with ${}
  string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})  # Replace @@ with ${}, even if that may not be read by CMake scripts.
  file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT})
  set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${INPUT_FILE}")
endfunction()

include(GNUInstallDirs)

set(CURL_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608

1609
1610





1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
  install(FILES "${PROJECT_SOURCE_DIR}/scripts/mk-ca-bundle.pl"
          DESTINATION ${CMAKE_INSTALL_BINDIR}
          PERMISSIONS
            OWNER_READ OWNER_WRITE OWNER_EXECUTE
            GROUP_READ GROUP_EXECUTE
            WORLD_READ WORLD_EXECUTE)

  # Helper to populate a list (_items) with a label when conditions (the remaining
  # args) are satisfied
  macro(_add_if label)
    # needs to be a macro to allow this indirection
    if(${ARGN})
      set(_items ${_items} "${label}")
    endif()
  endmacro()

  # NTLM support requires crypto function adaptions from various SSL libs

  if(NOT (CURL_DISABLE_NTLM) AND
      (USE_OPENSSL OR USE_MBEDTLS OR USE_DARWINSSL OR USE_WIN32_CRYPTO OR USE_GNUTLS))





    set(use_curl_ntlm_core ON)
  endif()

  # Clear list and try to detect available features
  set(_items)
  _add_if("SSL"           SSL_ENABLED)
  _add_if("IPv6"          ENABLE_IPV6)
  _add_if("UnixSockets"   USE_UNIX_SOCKETS)
  _add_if("libz"          HAVE_LIBZ)
  _add_if("brotli"        HAVE_BROTLI)
  _add_if("zstd"          HAVE_ZSTD)
  _add_if("AsynchDNS"     USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
  _add_if("IDN"           HAVE_LIBIDN2 OR USE_WIN32_IDN OR USE_APPLE_IDN)
  _add_if("Largefile"     (SIZEOF_CURL_OFF_T GREATER 4) AND
                          ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
  _add_if("SSPI"          USE_WINDOWS_SSPI)
  _add_if("GSS-API"       HAVE_GSSAPI)
  _add_if("alt-svc"       NOT CURL_DISABLE_ALTSVC)
  _add_if("HSTS"          NOT CURL_DISABLE_HSTS)
  _add_if("SPNEGO"        NOT CURL_DISABLE_NEGOTIATE_AUTH AND
                          (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
  _add_if("Kerberos"      NOT CURL_DISABLE_KERBEROS_AUTH AND
                          (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
  _add_if("NTLM"          NOT (CURL_DISABLE_NTLM) AND
                          (use_curl_ntlm_core OR USE_WINDOWS_SSPI))
  _add_if("TLS-SRP"       USE_TLS_SRP)
  _add_if("HTTP2"         USE_NGHTTP2)
  _add_if("HTTP3"         USE_NGTCP2 OR USE_QUICHE OR USE_OPENSSL_QUIC)
  _add_if("MultiSSL"      CURL_WITH_MULTI_SSL)
  # TODO wolfSSL only support this from v5.0.0 onwards
  _add_if("HTTPS-proxy"   SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS
                          OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
                          USE_MBEDTLS OR USE_SECTRANSP))
  _add_if("unicode"       ENABLE_UNICODE)
  _add_if("threadsafe"    HAVE_ATOMIC OR
                          (USE_THREADS_POSIX AND HAVE_PTHREAD_H) OR
                          (WIN32 AND HAVE_WIN32_WINNT GREATER_EQUAL 0x600))
  _add_if("PSL"           USE_LIBPSL)
  string(REPLACE ";" " " SUPPORT_FEATURES "${_items}")
  message(STATUS "Enabled features: ${SUPPORT_FEATURES}")

  # Clear list and try to detect available protocols
  set(_items)
  _add_if("HTTP"          NOT CURL_DISABLE_HTTP)
  _add_if("IPFS"          NOT CURL_DISABLE_HTTP)
  _add_if("IPNS"          NOT CURL_DISABLE_HTTP)
  _add_if("HTTPS"         NOT CURL_DISABLE_HTTP AND SSL_ENABLED)
  _add_if("ECH"           HAVE_ECH)
  _add_if("HTTPSRR"       HAVE_ECH)
  _add_if("FTP"           NOT CURL_DISABLE_FTP)
  _add_if("FTPS"          NOT CURL_DISABLE_FTP AND SSL_ENABLED)
  _add_if("FILE"          NOT CURL_DISABLE_FILE)
  _add_if("TELNET"        NOT CURL_DISABLE_TELNET)
  _add_if("LDAP"          NOT CURL_DISABLE_LDAP)
  # CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS
  _add_if("LDAPS"         NOT CURL_DISABLE_LDAPS AND







|
|







|
>
|
|
>
>
>
>
>



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






<
<







1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675






































1676
1677
1678
1679
1680
1681


1682
1683
1684
1685
1686
1687
1688
  install(FILES "${PROJECT_SOURCE_DIR}/scripts/mk-ca-bundle.pl"
          DESTINATION ${CMAKE_INSTALL_BINDIR}
          PERMISSIONS
            OWNER_READ OWNER_WRITE OWNER_EXECUTE
            GROUP_READ GROUP_EXECUTE
            WORLD_READ WORLD_EXECUTE)

  # Helper to populate a list (_items) with a label when conditions
  # (the remaining args) are satisfied
  macro(_add_if label)
    # needs to be a macro to allow this indirection
    if(${ARGN})
      set(_items ${_items} "${label}")
    endif()
  endmacro()

  # NTLM support requires crypto functions from various SSL libs.
  # These conditions must match those in lib/curl_setup.h.
  if(NOT CURL_DISABLE_NTLM AND
     (USE_OPENSSL OR
      USE_MBEDTLS OR
      USE_GNUTLS OR
      USE_SECTRANSP OR
      USE_WIN32_CRYPTO OR
      (USE_WOLFSSL AND HAVE_WOLFSSL_DES_ECB_ENCRYPT)))
    set(use_curl_ntlm_core ON)
  endif()







































  # Clear list and try to detect available protocols
  set(_items)
  _add_if("HTTP"          NOT CURL_DISABLE_HTTP)
  _add_if("IPFS"          NOT CURL_DISABLE_HTTP)
  _add_if("IPNS"          NOT CURL_DISABLE_HTTP)
  _add_if("HTTPS"         NOT CURL_DISABLE_HTTP AND SSL_ENABLED)


  _add_if("FTP"           NOT CURL_DISABLE_FTP)
  _add_if("FTPS"          NOT CURL_DISABLE_FTP AND SSL_ENABLED)
  _add_if("FILE"          NOT CURL_DISABLE_FILE)
  _add_if("TELNET"        NOT CURL_DISABLE_TELNET)
  _add_if("LDAP"          NOT CURL_DISABLE_LDAP)
  # CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS
  _add_if("LDAPS"         NOT CURL_DISABLE_LDAPS AND
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693

1694



















































1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706



1707

1708
1709
1710
1711
1712
1713
1714
  _add_if("SMTPS"         NOT CURL_DISABLE_SMTP AND SSL_ENABLED)
  _add_if("SCP"           USE_LIBSSH2 OR USE_LIBSSH)
  _add_if("SFTP"          USE_LIBSSH2 OR USE_LIBSSH)
  _add_if("RTSP"          NOT CURL_DISABLE_RTSP)
  _add_if("RTMP"          USE_LIBRTMP)
  _add_if("MQTT"          NOT CURL_DISABLE_MQTT)
  _add_if("WS"            USE_WEBSOCKETS)
  _add_if("WSS"           USE_WEBSOCKETS)
  if(_items)
    list(SORT _items)
  endif()
  string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}")

  message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}")




















































  # Clear list and collect SSL backends
  set(_items)
  _add_if("Schannel"         SSL_ENABLED AND USE_SCHANNEL)
  _add_if("OpenSSL"          SSL_ENABLED AND USE_OPENSSL)
  _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP)
  _add_if("mbedTLS"          SSL_ENABLED AND USE_MBEDTLS)
  _add_if("BearSSL"          SSL_ENABLED AND USE_BEARSSL)
  _add_if("wolfSSL"          SSL_ENABLED AND USE_WOLFSSL)
  _add_if("GnuTLS"           SSL_ENABLED AND USE_GNUTLS)

  if(_items)



    list(SORT _items)

  endif()
  string(REPLACE ";" " " SSL_BACKENDS "${_items}")
  message(STATUS "Enabled SSL backends: ${SSL_BACKENDS}")
  if(CURL_DEFAULT_SSL_BACKEND)
    message(STATUS "Default SSL backend: ${CURL_DEFAULT_SSL_BACKEND}")
  endif()








|




>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












>
>
>
|
>







1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
  _add_if("SMTPS"         NOT CURL_DISABLE_SMTP AND SSL_ENABLED)
  _add_if("SCP"           USE_LIBSSH2 OR USE_LIBSSH)
  _add_if("SFTP"          USE_LIBSSH2 OR USE_LIBSSH)
  _add_if("RTSP"          NOT CURL_DISABLE_RTSP)
  _add_if("RTMP"          USE_LIBRTMP)
  _add_if("MQTT"          NOT CURL_DISABLE_MQTT)
  _add_if("WS"            USE_WEBSOCKETS)
  _add_if("WSS"           USE_WEBSOCKETS AND SSL_ENABLED)
  if(_items)
    list(SORT _items)
  endif()
  string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}")
  string(TOLOWER "${SUPPORT_PROTOCOLS}" SUPPORT_PROTOCOLS_LOWER)
  message(STATUS "Protocols: ${SUPPORT_PROTOCOLS_LOWER}")

  # Clear list and try to detect available features
  set(_items)
  _add_if("SSL"           SSL_ENABLED)
  _add_if("IPv6"          ENABLE_IPV6)
  _add_if("UnixSockets"   USE_UNIX_SOCKETS)
  _add_if("libz"          HAVE_LIBZ)
  _add_if("brotli"        HAVE_BROTLI)
  _add_if("gsasl"         USE_GSASL)
  _add_if("zstd"          HAVE_ZSTD)
  _add_if("AsynchDNS"     USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
  _add_if("IDN"           (HAVE_LIBIDN2 AND HAVE_IDN2_H) OR
                          USE_WIN32_IDN OR
                          USE_APPLE_IDN)
  _add_if("Largefile"     (SIZEOF_CURL_OFF_T GREATER 4) AND
                          ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
  _add_if("SSPI"          USE_WINDOWS_SSPI)
  _add_if("GSS-API"       HAVE_GSSAPI)
  _add_if("alt-svc"       NOT CURL_DISABLE_ALTSVC)
  _add_if("HSTS"          NOT CURL_DISABLE_HSTS)
  _add_if("SPNEGO"        NOT CURL_DISABLE_NEGOTIATE_AUTH AND
                          (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
  _add_if("Kerberos"      NOT CURL_DISABLE_KERBEROS_AUTH AND
                          (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
  _add_if("NTLM"          NOT (CURL_DISABLE_NTLM) AND
                          (use_curl_ntlm_core OR USE_WINDOWS_SSPI))
  _add_if("TLS-SRP"       USE_TLS_SRP)
  _add_if("HTTP2"         USE_NGHTTP2)
  _add_if("HTTP3"         USE_NGTCP2 OR USE_QUICHE OR USE_OPENSSL_QUIC)
  _add_if("MultiSSL"      CURL_WITH_MULTI_SSL)
  _add_if("HTTPS-proxy"   SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS
                          OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
                          USE_MBEDTLS OR USE_SECTRANSP OR
                          (USE_WOLFSSL AND HAVE_WOLFSSL_FULL_BIO)))
  _add_if("Unicode"       ENABLE_UNICODE)
  _add_if("threadsafe"    HAVE_ATOMIC OR
                          (USE_THREADS_POSIX AND HAVE_PTHREAD_H) OR
                          (WIN32 AND HAVE_WIN32_WINNT GREATER_EQUAL 0x600))
  _add_if("Debug"         ENABLE_DEBUG)
  _add_if("TrackMemory"   ENABLE_CURLDEBUG)
  _add_if("ECH"           SSL_ENABLED AND HAVE_ECH)
  _add_if("PSL"           USE_LIBPSL)
  if(_items)
    if(NOT CMAKE_VERSION VERSION_LESS 3.13)
      list(SORT _items CASE INSENSITIVE)
    else()
      list(SORT _items)
    endif()
  endif()
  string(REPLACE ";" " " SUPPORT_FEATURES "${_items}")
  message(STATUS "Features: ${SUPPORT_FEATURES}")

  # Clear list and collect SSL backends
  set(_items)
  _add_if("Schannel"         SSL_ENABLED AND USE_SCHANNEL)
  _add_if("OpenSSL"          SSL_ENABLED AND USE_OPENSSL)
  _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP)
  _add_if("mbedTLS"          SSL_ENABLED AND USE_MBEDTLS)
  _add_if("BearSSL"          SSL_ENABLED AND USE_BEARSSL)
  _add_if("wolfSSL"          SSL_ENABLED AND USE_WOLFSSL)
  _add_if("GnuTLS"           SSL_ENABLED AND USE_GNUTLS)

  if(_items)
    if(NOT CMAKE_VERSION VERSION_LESS 3.13)
      list(SORT _items CASE INSENSITIVE)
    else()
      list(SORT _items)
    endif()
  endif()
  string(REPLACE ";" " " SSL_BACKENDS "${_items}")
  message(STATUS "Enabled SSL backends: ${SSL_BACKENDS}")
  if(CURL_DEFAULT_SSL_BACKEND)
    message(STATUS "Default SSL backend: ${CURL_DEFAULT_SSL_BACKEND}")
  endif()

1779
1780
1781
1782
1783
1784
1785







1786
1787

1788
1789
1790
1791

1792
1793
1794
1795
1796
1797
1798
      else()
        set(LIBCURL_LIBS          "${LIBCURL_LIBS} ${_lib}")
      endif()
    else()
      set(LIBCURL_LIBS          "${LIBCURL_LIBS} -l${_lib}")
    endif()
  endforeach()







  if(BUILD_SHARED_LIBS)
    set(ENABLE_SHARED         "yes")

    set(LIBCURL_NO_SHARED     "")
    set(CPPFLAG_CURL_STATICLIB "")
  else()
    set(ENABLE_SHARED         "no")

    set(LIBCURL_NO_SHARED     "${LIBCURL_LIBS}")
    set(CPPFLAG_CURL_STATICLIB "-DCURL_STATICLIB")
  endif()
  if(BUILD_STATIC_LIBS)
    set(ENABLE_STATIC         "yes")
  else()
    set(ENABLE_STATIC         "no")







>
>
>
>
>
>
>


>




>







1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
      else()
        set(LIBCURL_LIBS          "${LIBCURL_LIBS} ${_lib}")
      endif()
    else()
      set(LIBCURL_LIBS          "${LIBCURL_LIBS} -l${_lib}")
    endif()
  endforeach()

  # Export a .pc file for client projects not using CMake
  if(LIBCURL_PC_REQUIRES_PRIVATE)
    string(REPLACE ";" "," LIBCURL_PC_REQUIRES_PRIVATE "${LIBCURL_PC_REQUIRES_PRIVATE}")
  endif()

  # Merge pkg-config private fields into public ones when static-only
  if(BUILD_SHARED_LIBS)
    set(ENABLE_SHARED         "yes")
    set(LIBCURL_PC_REQUIRES   "")
    set(LIBCURL_NO_SHARED     "")
    set(CPPFLAG_CURL_STATICLIB "")
  else()
    set(ENABLE_SHARED         "no")
    set(LIBCURL_PC_REQUIRES   "${LIBCURL_PC_REQUIRES_PRIVATE}")
    set(LIBCURL_NO_SHARED     "${LIBCURL_LIBS}")
    set(CPPFLAG_CURL_STATICLIB "-DCURL_STATICLIB")
  endif()
  if(BUILD_STATIC_LIBS)
    set(ENABLE_STATIC         "yes")
  else()
    set(ENABLE_STATIC         "no")
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854

1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
  set(VERSIONNUM              "${CURL_VERSION_NUM}")

  # Finally generate a "curl-config" matching this config
  # Use:
  # * ENABLE_SHARED
  # * ENABLE_STATIC
  configure_file("${CURL_SOURCE_DIR}/curl-config.in"
                "${CURL_BINARY_DIR}/curl-config" @ONLY)
  install(FILES "${CURL_BINARY_DIR}/curl-config"
          DESTINATION ${CMAKE_INSTALL_BINDIR}
          PERMISSIONS
            OWNER_READ OWNER_WRITE OWNER_EXECUTE
            GROUP_READ GROUP_EXECUTE
            WORLD_READ WORLD_EXECUTE)

  # Finally generate a pkg-config file matching this config
  configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in"
                "${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
  install(FILES "${CURL_BINARY_DIR}/libcurl.pc"
          DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

  # install headers
  install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl"
      DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
      FILES_MATCHING PATTERN "*.h")

  include(CMakePackageConfigHelpers)
  write_basic_package_version_file(
      "${version_config}"
      VERSION ${CURL_VERSION}
      COMPATIBILITY SameMajorVersion
  )
  file(READ "${version_config}" generated_version_config)
  file(WRITE "${version_config}"
  "if(NOT PACKAGE_FIND_VERSION_RANGE AND PACKAGE_FIND_VERSION_MAJOR STREQUAL \"7\")
      # Version 8 satisfies version 7... requirements
      set(PACKAGE_FIND_VERSION_MAJOR 8)
      set(PACKAGE_FIND_VERSION_COUNT 1)
  endif()
  ${generated_version_config}"
  )

  # Use:
  # * TARGETS_EXPORT_NAME
  # * PROJECT_NAME
  configure_package_config_file(CMake/curl-config.cmake.in
          "${project_config}"
          INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR}

  )

  if(CURL_ENABLE_EXPORT_TARGET)
    install(
            EXPORT "${TARGETS_EXPORT_NAME}"
            NAMESPACE "${PROJECT_NAME}::"
            DESTINATION ${CURL_INSTALL_CMAKE_DIR}
    )
  endif()

  install(
          FILES ${version_config} ${project_config}
          DESTINATION ${CURL_INSTALL_CMAKE_DIR}
  )

  # Workaround for MSVS10 to avoid the Dialog Hell
  # FIXME: This could be removed with future version of CMake.
  if(MSVC_VERSION EQUAL 1600)
    set(CURL_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/CURL.sln")
    if(EXISTS "${CURL_SLN_FILENAME}")
      file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n")
    endif()
  endif()

  if(NOT TARGET curl_uninstall)
    configure_file(
        ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in
        ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake
        IMMEDIATE @ONLY)

    add_custom_target(curl_uninstall
        COMMAND ${CMAKE_COMMAND} -P
        ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake)
  endif()
endif()







|









|















|
|
|
|
|








|
|
>



<
|





<
|














|
|
|


|
|


1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945

1946
1947
1948
1949
1950
1951

1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
  set(VERSIONNUM              "${CURL_VERSION_NUM}")

  # Finally generate a "curl-config" matching this config
  # Use:
  # * ENABLE_SHARED
  # * ENABLE_STATIC
  configure_file("${CURL_SOURCE_DIR}/curl-config.in"
                 "${CURL_BINARY_DIR}/curl-config" @ONLY)
  install(FILES "${CURL_BINARY_DIR}/curl-config"
          DESTINATION ${CMAKE_INSTALL_BINDIR}
          PERMISSIONS
            OWNER_READ OWNER_WRITE OWNER_EXECUTE
            GROUP_READ GROUP_EXECUTE
            WORLD_READ WORLD_EXECUTE)

  # Finally generate a pkg-config file matching this config
  configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in"
                 "${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
  install(FILES "${CURL_BINARY_DIR}/libcurl.pc"
          DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

  # install headers
  install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl"
      DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
      FILES_MATCHING PATTERN "*.h")

  include(CMakePackageConfigHelpers)
  write_basic_package_version_file(
      "${version_config}"
      VERSION ${CURL_VERSION}
      COMPATIBILITY SameMajorVersion
  )
  file(READ "${version_config}" generated_version_config)
  file(WRITE "${version_config}" "
  if(NOT PACKAGE_FIND_VERSION_RANGE AND PACKAGE_FIND_VERSION_MAJOR STREQUAL \"7\")
    # Version 8 satisfies version 7... requirements
    set(PACKAGE_FIND_VERSION_MAJOR 8)
    set(PACKAGE_FIND_VERSION_COUNT 1)
  endif()
  ${generated_version_config}"
  )

  # Use:
  # * TARGETS_EXPORT_NAME
  # * PROJECT_NAME
  configure_package_config_file(CMake/curl-config.cmake.in
    "${project_config}"
    INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR}
    PATH_VARS CMAKE_INSTALL_INCLUDEDIR
  )

  if(CURL_ENABLE_EXPORT_TARGET)

    install(EXPORT "${TARGETS_EXPORT_NAME}"
            NAMESPACE "${PROJECT_NAME}::"
            DESTINATION ${CURL_INSTALL_CMAKE_DIR}
    )
  endif()


  install(FILES ${version_config} ${project_config}
          DESTINATION ${CURL_INSTALL_CMAKE_DIR}
  )

  # Workaround for MSVS10 to avoid the Dialog Hell
  # FIXME: This could be removed with future version of CMake.
  if(MSVC_VERSION EQUAL 1600)
    set(CURL_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/CURL.sln")
    if(EXISTS "${CURL_SLN_FILENAME}")
      file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n")
    endif()
  endif()

  if(NOT TARGET curl_uninstall)
    configure_file(
      ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in
      ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake
      IMMEDIATE @ONLY)

    add_custom_target(curl_uninstall
      COMMAND ${CMAKE_COMMAND} -P
      ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake)
  endif()
endif()
Changes to jni/curl/Dockerfile.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#   docker run --rm -it -u $(id -u):$(id -g) -v (pwd):/usr/src -w /usr/src curl/curl bash
#   $ autoreconf -fi
#   $ ./configure --without-ssl --without-libpsl
#   $ make
#   $ ./maketgz 8.7.1

# To update, get the latest digest e.g. from https://hub.docker.com/_/debian/tags
FROM debian:bookworm-slim@sha256:911821c26cc366231183098f489068afff2d55cf56911cb5b7bd32796538dfe1

RUN apt-get update -qq && apt-get install -qq -y --no-install-recommends \
    build-essential make autoconf automake libtool git perl zip zlib1g-dev gawk && \
    rm -rf /var/lib/apt/lists/*

ARG UID=1000 GID=1000








|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#   docker run --rm -it -u $(id -u):$(id -g) -v (pwd):/usr/src -w /usr/src curl/curl bash
#   $ autoreconf -fi
#   $ ./configure --without-ssl --without-libpsl
#   $ make
#   $ ./maketgz 8.7.1

# To update, get the latest digest e.g. from https://hub.docker.com/_/debian/tags
FROM debian:bookworm-slim@sha256:39868a6f452462b70cf720a8daff250c63e7342970e749059c105bf7c1e8eeaf

RUN apt-get update -qq && apt-get install -qq -y --no-install-recommends \
    build-essential make autoconf automake libtool git perl zip zlib1g-dev gawk && \
    rm -rf /var/lib/apt/lists/*

ARG UID=1000 GID=1000

Changes to jni/curl/Makefile.am.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 projects/build-wolfssl.bat                            \
 projects/checksrc.bat                                 \
 projects/generate.bat                                 \
 projects/wolfssl_options.h                            \
 projects/wolfssl_override.props

WINBUILD_DIST = winbuild/README.md winbuild/gen_resp_file.bat \
 winbuild/MakefileBuild.vc winbuild/Makefile.vc winbuild/makedebug.cmd

PLAN9_DIST = plan9/include/mkfile \
 plan9/include/mkfile             \
 plan9/mkfile.proto               \
 plan9/mkfile                     \
 plan9/README                     \
 plan9/lib/mkfile.inc             \







|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 projects/build-wolfssl.bat                            \
 projects/checksrc.bat                                 \
 projects/generate.bat                                 \
 projects/wolfssl_options.h                            \
 projects/wolfssl_override.props

WINBUILD_DIST = winbuild/README.md winbuild/gen_resp_file.bat \
 winbuild/MakefileBuild.vc winbuild/Makefile.vc winbuild/makedebug.bat

PLAN9_DIST = plan9/include/mkfile \
 plan9/include/mkfile             \
 plan9/mkfile.proto               \
 plan9/mkfile                     \
 plan9/README                     \
 plan9/lib/mkfile.inc             \
Changes to jni/curl/Makefile.in.
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







186
187
188
189
190
191
192

193
194
195
196
197
198
199
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
421
422
423
424
425
426
427


428
429
430
431
432
433
434
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
 projects/build-wolfssl.bat                            \
 projects/checksrc.bat                                 \
 projects/generate.bat                                 \
 projects/wolfssl_options.h                            \
 projects/wolfssl_override.props

WINBUILD_DIST = winbuild/README.md winbuild/gen_resp_file.bat \
 winbuild/MakefileBuild.vc winbuild/Makefile.vc winbuild/makedebug.cmd

PLAN9_DIST = plan9/include/mkfile \
 plan9/include/mkfile             \
 plan9/mkfile.proto               \
 plan9/mkfile                     \
 plan9/README                     \
 plan9/lib/mkfile.inc             \







|







595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
 projects/build-wolfssl.bat                            \
 projects/checksrc.bat                                 \
 projects/generate.bat                                 \
 projects/wolfssl_options.h                            \
 projects/wolfssl_override.props

WINBUILD_DIST = winbuild/README.md winbuild/gen_resp_file.bat \
 winbuild/MakefileBuild.vc winbuild/Makefile.vc winbuild/makedebug.bat

PLAN9_DIST = plan9/include/mkfile \
 plan9/include/mkfile             \
 plan9/mkfile.proto               \
 plan9/mkfile                     \
 plan9/README                     \
 plan9/lib/mkfile.inc             \
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000

# libcurl sources to include in curltool lib we use for test binaries
CURLTOOL_LIBCURL_CFILES = \
  ../lib/base64.c \
  ../lib/dynbuf.c


# libcurl has sources that provide functions named curlx_* that aren't part of
# the official API, but we reuse the code here to avoid duplication.
CURLX_CFILES = \
  ../lib/base64.c \
  ../lib/curl_multibyte.c \
  ../lib/dynbuf.c \
  ../lib/nonblock.c \
  ../lib/strtoofft.c \







|







987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001

# libcurl sources to include in curltool lib we use for test binaries
CURLTOOL_LIBCURL_CFILES = \
  ../lib/base64.c \
  ../lib/dynbuf.c


# libcurl has sources that provide functions named curlx_* that are not part of
# the official API, but we reuse the code here to avoid duplication.
CURLX_CFILES = \
  ../lib/base64.c \
  ../lib/curl_multibyte.c \
  ../lib/dynbuf.c \
  ../lib/nonblock.c \
  ../lib/strtoofft.c \
1011
1012
1013
1014
1015
1016
1017

1018
1019
1020
1021
1022
1023
1024

1025
1026
1027
1028
1029
1030
1031
  ../lib/strtoofft.h \
  ../lib/timediff.h \
  ../lib/version_win32.h \
  ../lib/warnless.h

CURL_CFILES = \
  slist_wc.c \

  tool_binmode.c \
  tool_bname.c \
  tool_cb_dbg.c \
  tool_cb_hdr.c \
  tool_cb_prg.c \
  tool_cb_rea.c \
  tool_cb_see.c \

  tool_cb_wrt.c \
  tool_cfgable.c \
  tool_dirhie.c \
  tool_doswin.c \
  tool_easysrc.c \
  tool_filetime.c \
  tool_findfile.c \







>







>







1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
  ../lib/strtoofft.h \
  ../lib/timediff.h \
  ../lib/version_win32.h \
  ../lib/warnless.h

CURL_CFILES = \
  slist_wc.c \
  terminal.c \
  tool_binmode.c \
  tool_bname.c \
  tool_cb_dbg.c \
  tool_cb_hdr.c \
  tool_cb_prg.c \
  tool_cb_rea.c \
  tool_cb_see.c \
  tool_cb_soc.c \
  tool_cb_wrt.c \
  tool_cfgable.c \
  tool_dirhie.c \
  tool_doswin.c \
  tool_easysrc.c \
  tool_filetime.c \
  tool_findfile.c \
1055
1056
1057
1058
1059
1060
1061

1062
1063
1064
1065
1066
1067
1068

1069
1070
1071
1072
1073
1074
1075
  tool_writeout.c \
  tool_writeout_json.c \
  tool_xattr.c \
  var.c

CURL_HFILES = \
  slist_wc.h \

  tool_binmode.h \
  tool_bname.h \
  tool_cb_dbg.h \
  tool_cb_hdr.h \
  tool_cb_prg.h \
  tool_cb_rea.h \
  tool_cb_see.h \

  tool_cb_wrt.h \
  tool_cfgable.h \
  tool_dirhie.h \
  tool_doswin.h \
  tool_easysrc.h \
  tool_filetime.h \
  tool_findfile.h \







>







>







1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
  tool_writeout.c \
  tool_writeout_json.c \
  tool_xattr.c \
  var.c

CURL_HFILES = \
  slist_wc.h \
  terminal.h \
  tool_binmode.h \
  tool_bname.h \
  tool_cb_dbg.h \
  tool_cb_hdr.h \
  tool_cb_prg.h \
  tool_cb_rea.h \
  tool_cb_see.h \
  tool_cb_soc.h \
  tool_cb_wrt.h \
  tool_cfgable.h \
  tool_dirhie.h \
  tool_doswin.h \
  tool_easysrc.h \
  tool_filetime.h \
  tool_findfile.h \
Changes to jni/curl/RELEASE-NOTES.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15

16
17
18

19
20
21
22
23
24
25


26
27
28
29
30
31
32
33
34
35
36
37
38

39


40
41

42


43

44
45
46
47
48
49
50

51


52
53

54

55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76





77
78
79
80

81
82
83
84
85
86









87
88




89

90
91
92
93
94
95
96

97
98
99
100
101
102
103
104


105





106







107
108
109
110
111
112
113
114
115
116


117
118
119
120
121
122


123
124
125
126
127
128
129
130
131
132
133


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

154






155
156
157
158
159

160
161
162
163
164
165
166
167
168

169
170
171
172

173
174
175
176
177


178
179
180
181
182
183
184



185


186
187
188
189
190
191
192
193
194
195

196
197
198






199


200
201
202

203
204
205

206

207
208
209
210
211
212
213
214
215

216

217
218
219
220
221

222
223


224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239



240





241

242
243
244
245
246
247
248
249
250
251
252
253
254
255

256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334










335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363



364
365
366
367
368
369
370
371
372
373
374
375
376
377
378

379

380
381
382
383
384

385
386
387
388
389
390
391

392
393
394
395
396



397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448









449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476



477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503

504
505


curl and libcurl 8.8.0

 Public curl releases:         257
 Command line options:         259
 curl_easy_setopt() options:   305
 Public functions in libcurl:  94
 Contributors:                 3173

This release includes the following changes:

 o curl_version_info: provide librtmp version [73]
 o file: add support for directory listings [63]
 o idn: add native AppleIDN (icucore) support for macOS/iOS [95]
 o lib: add curl_multi_waitfds [34]

 o mbedTLS: implement CURLOPT_SSL_CIPHER_LIST option [103]

 o NTLM_WB: drop support [67]
 o TLS: add support for ECH (Encrypted Client Hello) [109]
 o urlapi: add CURLU_GET_EMPTY for empty queries and fragments [111]


This release includes the following bugfixes:

 o appveyor: drop unnecessary `--clean-first` cmake option [197]
 o appveyor: guard against crash-build with VS2008 [193]
 o appveyor: make gcc 6 mingw64 job build-only [152]
 o asyn-thread: fix curl_global_cleanup crash in Windows [161]


 o asyn-thread: fix Curl_thread_create result check [162]
 o autotools: delete unused functions [177]
 o autotools: fix `HAVE_IOCTLSOCKET_FIONBIO` test for gcc 14 [186]
 o autotools: only probe for SGI MIPS compilers on IRIX [213]
 o bearssl: fix compiler warnings [43]
 o bearssl: use common code for cipher suite lookup [126]
 o bufq: remove duplicate word in comment [154]
 o BUG-BOUNTY.md: clarify the third party situation [210]
 o build: prefer `USE_IPV6` macro internally (was: `ENABLE_IPV6`) [85]
 o build: remove MacOSX-Framework script [60]
 o cd2nroff/manage: use UTC when SOURCE_DATE_EPOCH is set [36]
 o cf-https-connect: use timeouts as unsigned ints [143]
 o cf-socket: don't try getting local IP without socket [188]

 o cf-socket: remove references to l_ip, l_port [9]


 o ci: add curl-for-win builds: Linux MUSL, macOS, Windows [68]
 o cmake: add `BUILD_EXAMPLES` option to build examples [128]

 o cmake: add librtmp/rtmpdump option and detection [108]


 o cmake: check fseeko after detecting HAVE_FILE_OFFSET_BITS [64]

 o cmake: do not pass linker flags to the static library tool [203]
 o cmake: enable `-pedantic-errors` for clang when `CURL_WERROR=ON` [47]
 o cmake: FindNGHTTP2 add static lib name to find_library call [141]
 o cmake: fix `CURL_WERROR=ON` for old CMake and use it in GHA/linux-old [48]
 o cmake: fix `HAVE_IOCTLSOCKET_FIONBIO` test with gcc 14 [179]
 o cmake: fixup `DEPENDS` filename [51]
 o cmake: forward `USE_LIBRTMP` option to C [59]

 o cmake: generate misc manpages and install `mk-ca-bundle.pl` [24]


 o cmake: initialize `BUILD_TESTING` before first use [227]
 o cmake: speed up libcurl doc building again [15]

 o cmake: tidy-up to use `WORKING_DIRECTORY` [23]

 o cmake: use namespaced custom target names [80]

 o cmdline-docs: fix make install with configure --disable-docs [1]
 o configure: error on missing perl if docs or manual is enabled [135]
 o configure: make --disable-docs imply --disable-manual [2]
 o content_encoding: brotli and others, pass through 0-length writes [5]
 o content_encoding: ignore duplicate chunked encoding [137]
 o content_encoding: reject transfer-encoding after chunked [200]
 o contrithanks: honor `CURLWWW` variable [69]
 o curl-confopts.m4: define CARES_NO_DEPRECATED when c-ares is used [17]
 o curl.h: change CURL_SSLVERSION_* from enum to defines [132]
 o curl: make --help adapt to the terminal width [11]
 o curl: use curl_getenv instead of the curlx_ version [20]
 o Curl_creader_read: init two variables to avoid using them uninited [99]
 o curl_easy_pause.md: use correct defines in example [187]
 o curl_getdate.md: document two-digit year handling [127]
 o curl_global_trace.md: shorten the description [29]
 o curl_multibyte: remove access() function wrapper for Windows [163]
 o curl_path: make Curl_get_pathname use dynbuf [158]
 o curl_setup.h: add support for IAR compiler [191]
 o curl_setup.h: detect 'inline' support [133]
 o curl_sha512_256: do not use workaround for NetBSD when not needed [21]
 o curl_sha512_256: fix detection of OpenSSL 1.1.1 or later [8]





 o curl_url_get.md: clarify queries and fragments and CURLU_GET_EMPTY [105]
 o CURLINFO_REQUEST_SIZE: fixed, add tests for transfer infos reported [52]
 o CURLOPT_WRITEFUNCTION.md: fix the callback proto in the example [215]
 o cw-out: improved error handling [104]

 o DEPRECATE.md: TLS libraries without 1.3 support [199]
 o digest: replace strcpy for empty string with simple assignment [185]
 o dist: `set -eu`, fix shellcheck, make reproducible and smaller tarballs [38]
 o dist: add files missing from release tarball [53]
 o dist: add reproducible dir entries to tarballs [56]
 o dist: do not require Perl in `maketgz` [71]









 o dist: remove the curl-config.1 from the tarball [28]
 o dist: verify tarball reproducibility in CI [40]




 o DISTROS: add patch and issues link for curl-for-win [110]

 o DISTROS: Cygwin updates [44]
 o dllmain: Call OpenSSL thread cleanup for Windows and Cygwin [114]
 o doc: pytest `--repeat` -> `--count` [58]
 o docs/cmdline-opts: invoke managen using a relative path [30]
 o docs/cmdline-opts: mention STARTTLS for --ssl and --ssl-reqd [175]
 o docs: add CURLOPT_NOPROGRESS to CURLOPT_XFERINFOFUNCTION example [61]
 o docs: clarify CURLOPT_MAXFILESIZE and CURLOPT_MAXFILESIZE_LARGE [74]

 o docs: fix some CURLINFO examples [147]
 o doh: fix typo in comment [173]
 o doh: remove unused function prototype [169]
 o dynbuf: fix returncode on memory error [174]
 o examples: fix/silence `-Wsign-conversion` [178]
 o EXPERIMENTAL: add graduation requirements for each feature [166]
 o file: remove useless assignment [89]
 o ftp: add tracing support [181]


 o ftp: fix build for CURL_DISABLE_VERBOSE_STRINGS





 o ftp: fix socket leak on rare error [102]







 o GHA: add NetBSD, OpenBSD, FreeBSD/arm64 and OmniOS jobs [201]
 o GHA: add shellcheck job and fix warnings, shell tidy-ups [70]
 o GHA: add valgrind to a wolfSSL build [37]
 o GHA: on macOS remove $HOME/.curlrc [50]
 o GHA: pin dependencies [194]
 o gnutls: lazy init the trust settings [75]
 o h3/ngtcp2: improve error handling [140]
 o hash: change 'slots' to size_t from int [144]
 o hash: delete unused debug function [198]
 o hsts: explicitly skip blank lines [212]


 o hsts: remove single-use single-line function [151]
 o http tests: in CI skip test_02_23* for quiche [211]
 o http2 + ngtcp2: pass CURLcode errors from callbacks [94]
 o http2, http3: decouple stream state from easy handle [92]
 o http2: emit RST when client write fails [65]
 o http3: quiche+ngtcp2 improvements [129]


 o http: acknowledge a returned error code [123]
 o http: HEAD response body tolerance [170]
 o http: reject HTTP major version switch mid connection [100]
 o http: remove redundant check [182]
 o http: with chunked POST forced, disable length check on read callback [31]
 o http_aws_sigv4: remove useless assignment [88]
 o idn: make Curl_idnconvert_hostname() use Curl_idn_decode() [16]
 o if2ip: make the buf_size arg a size_t [142]
 o INSTALL-CMAKE.md: explain `cmake -G <generator-name>` [32]
 o krb5: use dynbuf [149]
 o ldap: fix unused variables (seen on OmniOS) [183]


 o lib/cf-h1-proxy: silence compiler warnings (gcc 14) [155]
 o lib: add trace support for client reads and writes [45]
 o lib: bump hash sizes to `size_t` [153]
 o lib: clear the easy handle's saved errno before transfer [180]
 o lib: fix compiler warnings (gcc) [222]
 o lib: make protocol handlers store scheme name lowercase [159]
 o lib: merge `ENABLE_QUIC` C macro into `USE_HTTP3` [84]
 o lib: remove two instances of "only only" messages [160]
 o lib: silence `-Wsign-conversion` in base64, strcase, mprintf [139]
 o lib: silence warnings on comma misuse [91]
 o lib: use `#error` instead of invalid syntax in `curl_setup_once.h` [49]
 o lib: use multi instead of multi_easy for the active multi [41]
 o libcurl-opts: mention pipelining less [33]
 o libssh2: delete redundant feature guard [171]
 o libssh2: replace `access()` with `stat()` [145]
 o libssh2: set length to 0 if strdup failed [6]
 o m4: fix rustls pkg-config codepath [22]
 o MAIL-ETIQUETTE: convert to markdown [12]
 o makefile: remove the sorting from the vc-ide action [42]
 o maketgz: put docs/RELEASE-TOOL.md into the tarball [35]

 o managen: fix the option sort order [150]






 o mbedtls: call mbedtls_ssl_setup() after RNG callback is set [66]
 o mbedtls: cut off trailing newlines from debug logs [87]
 o mbedtls: fix building with v3 in CMake Unity mode [107]
 o mbedtls: support TLS 1.3 [156]
 o mime: avoid using access() [125]

 o misc: fix typos [62]
 o misc: fix typos, quoting and spelling [167]
 o mprintf: check fputc error rather than matching returned character [82]
 o mqtt: when Curl_xfer_recv returns error, don't use nread [101]
 o multi: avoid memory-leak risk [134]
 o multi: introduce SETUP state for better timeouts [26]
 o multi: multi_wait improvements [131]
 o multi: remove the unused Curl_preconnect function [98]
 o multi: remove useless assignment [146]

 o multi: timeout handles even without connection [81]
 o openldap: create ldap URLs correctly for IPv6 addresses [19]
 o openssl: do not set SSL_MODE_RELEASE_BUFFERS [10]
 o openssl: revert keylog_callback support for LibreSSL [192]

 o OS400: fix shellcheck warnings in scripts [72]
 o projects: drop MSVC project files for recent versions [79]
 o pytest: add DELETE tests, check server version [225]
 o pytest: fixes for recent python, add FTP tests [206]
 o quic: fixup duplicate static function name (for cmake unity) [77]


 o quiche: expire all active transfers on connection close [116]
 o quiche: trust its timeout handling [190]
 o RELEASE-PROCEDURE: mention an initial working build [7]
 o request: make Curl_req_init return void [96]
 o request: paused upload on completed download, assess connection [54]
 o reuse: add copyright + license info to individual docs/*.md files [13]
 o ROADMAP: remove completed entries, mention websocket



 o rustls: fix handshake done handling [207]


 o rustls: fix partial send handling [224]
 o rustls: remove incorrect SSLSUPP_TLS13_CIPHERSUITES flag [115]
 o rustsls: fix error code on receive [230]
 o sendf: fix two typos in comments [90]
 o sendf: useless assignment in cr_lc_read() [120]
 o setopt: acknowledge errors proper for CURLOPT_COOKIEJAR [216]
 o setopt: make the setstropt_userpwd args compulsory [221]
 o setopt: remove check for 'option' that is always true [219]
 o setopt: warn on Curl_set*opt() uses not using the return value [176]
 o smtp: result of Curl_bufq_cread was not used [78]

 o socket: remove redundant call to getsockname [195]
 o socketpair: fix compilation when USE_UNIX_SOCKETS is not defined [229]
 o src: tidy up types, add necessary casts [217]






 o telnet: check return code from fileno() [112]


 o tests/http: fix compiler warning [39]
 o tests: add -q as first option when invoking curl for tests [97]
 o tests: check caddy server version to match test expectations [106]

 o tests: enable test 1117 for hyper [119]
 o tests: fix feature case in test1481 [117]
 o tests: fix test 1167 to skip digit-only symbols [214]

 o tests: make the unit test result type `CURLcode` [165]

 o tests: Mark tftpd timer function as noreturn [168]
 o tests: tidy up types in server code [220]
 o tls: fix SecureTransport + BearSSL cmake unity builds [113]
 o tls: remove EXAMPLEs from deprecated options [164]
 o tls: use shared init code for TCP+QUIC [57]
 o tool: move tool_ftruncate64 to tool_util.c [138]
 o tool_cb_rea: limit rate unpause for -T . uploads [136]
 o tool_cfgable: free {proxy_}cipher13_list on exit [172]
 o tool_getparam: output warning for leading unicode quote character [14]

 o tool_getparam: remove two redundant conditions [189]

 o tool_operate: don't truncate the etag save file by default [118]
 o tool_operate: init vars unconditionally in post_per_transfer [124]
 o tool_paramhlp: remove duplicate assign [121]
 o tool_xattr: "guess" URL scheme if none is provided [3]
 o tool_xattr: in debug builds, act normally if CURL_FAKE_XATTR is not set [4]

 o transfer: remove useless assignment [122]
 o url: do not URL decode proxy crendentials [55]


 o url: fix use of an uninitialized variable [86]
 o url: make parse_login_details use memdup0 [184]
 o url: remove duplicate call to Curl_conncache_remove_conn when pruning [196]
 o urlapi: allow setting port number zero [76]
 o urlapi: fix relative redirects to fragment-only [83]
 o urldata: remove fields not used depending on used features [46]
 o vauth: make two functions void that always just returned OK [218]
 o version: use msnprintf instead of strncpy [157]
 o vquic-tls: use correct cert name check API for wolfSSL [226]
 o vquic: use CURL_FORMAT_CURL_OFF_T for 64 bit printf output [18]
 o vtls: TLS session storage overhaul [130]
 o wakeup_create: use FD_CLOEXEC/SOCK_CLOEXEC [223]
 o warnless: delete orphan declarations [209]
 o websocket: avoid memory leak in error path [148]
 o winbuild: add ENABLE_WEBSOCKETS option [93]
 o winbuild: use $(RC) correctly [27]



 o wolfssl: plug memory leak in wolfssl_connect_step2() [25]





 o x509asn1: return error on missing OID [208]


This release includes the following known bugs:

 o see docs/KNOWN_BUGS (https://curl.se/docs/knownbugs.html)

Planned upcoming removals include:

 o support for space-separated NOPROXY patterns

 See https://curl.se/dev/deprecate.html for details

This release would not have looked like this without help, code, reports and
advice from friends like these:


  Abdullah Alyan, Andrew, Antoine Bollengier, blankie, Brian Inglis,
  Carlos Henrique Lima Melara, Ch40zz on github, Christian Schmitz, Chris Webb,
  Colin Leroy-Mira, Dagfinn Ilmari Mannsåker, Dan Fandrich, Daniel Gustafsson,
  Daniel J. H., Daniel McCarney, Daniel Stenberg, Dmitry Karpov,
  Emanuele Torre, Evgeny Grin (Karlson2k), Fabian Keil, farazrbx on github,
  fuzzard, Gisle Vanem, Gonçalo Carvalho, Gusted, hammlee96 on github,
  Harmen Stoppels, Harry Sintonen, Hongfei Li, Ivan, Jan Macku, Jan Venekamp,
  Jeff King, Jeroen Ooms, Jérôme Leclercq, Jiwoo Park,
  Johann Sebastian Schicho, Jonatan Vela, Joseph Chen, Juliusz Sosinowicz,
  Kailun Qin, kalvdans on github, Keitagit-kun on github, Konstantin Kuzov,
  kpcyrd on github, Laramie Leavitt, LigH, Lucas Nussbaum,
  magisterquis on hackerone, Marcel Raad, Matt Jolly, Max Dymond, Mel Zuser,
  Michael Kaufmann, Michael Litwak, Michał Antoniak, Nathan Moinvaziri,
  Orgad Shaneh, Patrick Monnerat, Paul Gilmartin, Paul Howarth,
  Pavel Kropachev, Pavel Pavlov, Philip Heiduck, Rahul Krishna M, RainRat,
  Ray Satiro, renovate[bot], riastradh on github, Robert Moreton,
  Sanjay Pujare, Sergey Bronnikov, Sergey Ogryzkov, Sergio Durigan Junior,
  southernedge on github, Stefan Eissing, Stephen Farrell, Tal Regev,
  Tatsuhiro Tsujikawa, Tobias Stoeckmann, Toon Claes, Trumeet on github,
  Trzik on github, Viktor Szakats, zmcx16 on github
  (85 contributors)

References to bug reports and discussions on issues:

 [1] = https://curl.se/bug/?i=13198
 [2] = https://curl.se/bug/?i=13191
 [3] = https://curl.se/bug/?i=13205
 [4] = https://curl.se/bug/?i=13220
 [5] = https://curl.se/bug/?i=13209
 [6] = https://curl.se/bug/?i=13213
 [7] = https://curl.se/bug/?i=13216
 [8] = https://curl.se/bug/?i=13208
 [9] = https://curl.se/bug/?i=13210
 [10] = https://curl.se/bug/?i=13203
 [11] = https://curl.se/bug/?i=13171
 [12] = https://curl.se/bug/?i=13247
 [13] = https://curl.se/bug/?i=13245
 [14] = https://curl.se/bug/?i=13214
 [15] = https://curl.se/bug/?i=13207
 [16] = https://curl.se/bug/?i=13236
 [17] = https://curl.se/bug/?i=13240
 [18] = https://curl.se/bug/?i=13224
 [19] = https://curl.se/bug/?i=13228
 [20] = https://curl.se/bug/?i=13230
 [21] = https://curl.se/bug/?i=13225
 [22] = https://curl.se/bug/?i=13200
 [23] = https://curl.se/bug/?i=13206
 [24] = https://curl.se/bug/?i=13197
 [25] = https://curl.se/bug/?i=13272
 [26] = https://curl.se/bug/?i=13371
 [27] = https://curl.se/bug/?i=13267
 [28] = https://curl.se/bug/?i=13268
 [29] = https://curl.se/bug/?i=13263
 [30] = https://curl.se/bug/?i=13281
 [31] = https://curl.se/bug/?i=13229
 [32] = https://curl.se/bug/?i=13244
 [33] = https://curl.se/bug/?i=13254
 [34] = https://curl.se/bug/?i=13135
 [35] = https://curl.se/bug/?i=13239
 [36] = https://curl.se/bug/?i=13242
 [37] = https://curl.se/bug/?i=13274
 [38] = https://curl.se/bug/?i=13299
 [39] = https://curl.se/bug/?i=13301
 [40] = https://curl.se/bug/?i=13327
 [41] = https://curl.se/bug/?i=12665
 [42] = https://curl.se/bug/?i=13294
 [43] = https://curl.se/bug/?i=13290
 [44] = https://curl.se/bug/?i=13258
 [45] = https://curl.se/bug/?i=13223
 [46] = https://curl.se/bug/?i=13188
 [47] = https://curl.se/bug/?i=13286
 [48] = https://curl.se/bug/?i=13282
 [49] = https://curl.se/bug/?i=13287
 [50] = https://curl.se/bug/?i=13284
 [51] = https://curl.se/bug/?i=13283
 [52] = https://curl.se/bug/?i=13269
 [53] = https://curl.se/bug/?i=13346
 [54] = https://curl.se/bug/?i=13260
 [55] = https://curl.se/bug/?i=13265










 [56] = https://curl.se/bug/?i=13322
 [57] = https://curl.se/bug/?i=13172
 [58] = https://curl.se/bug/?i=13218
 [59] = https://curl.se/bug/?i=13364
 [60] = https://curl.se/bug/?i=13313
 [61] = https://curl.se/bug/?i=13348
 [62] = https://curl.se/bug/?i=13344
 [63] = https://curl.se/bug/?i=13137
 [64] = https://curl.se/bug/?i=13264
 [65] = https://curl.se/bug/?i=13292
 [66] = https://curl.se/bug/?i=13314
 [67] = https://curl.se/bug/?i=13249
 [68] = https://curl.se/bug/?i=13335
 [69] = https://curl.se/bug/?i=13315
 [70] = https://curl.se/bug/?i=13307
 [71] = https://curl.se/bug/?i=13310
 [72] = https://curl.se/bug/?i=13309
 [73] = https://curl.se/bug/?i=13368
 [74] = https://curl.se/bug/?i=13372
 [75] = https://curl.se/bug/?i=13339
 [76] = https://curl.se/bug/?i=13427
 [77] = https://curl.se/bug/?i=13332
 [78] = https://curl.se/bug/?i=13398
 [79] = https://curl.se/bug/?i=13311
 [80] = https://curl.se/bug/?i=13324
 [81] = https://curl.se/bug/?i=13276
 [82] = https://curl.se/bug/?i=13367
 [83] = https://curl.se/bug/?i=13394
 [84] = https://curl.se/bug/?i=13352



 [85] = https://curl.se/bug/?i=13349
 [86] = https://curl.se/bug/?i=13399
 [87] = https://curl.se/bug/?i=13321
 [88] = https://curl.se/bug/?i=13426
 [89] = https://curl.se/bug/?i=13425
 [90] = https://curl.se/bug/?i=13393
 [91] = https://curl.se/bug/?i=13392
 [92] = https://curl.se/bug/?i=13204
 [93] = https://curl.se/bug/?i=13232
 [94] = https://curl.se/bug/?i=13411
 [95] = https://curl.se/bug/?i=13246
 [96] = https://curl.se/bug/?i=13423
 [97] = https://curl.se/bug/?i=13387
 [98] = https://curl.se/bug/?i=13422
 [99] = https://curl.se/bug/?i=13419

 [100] = https://curl.se/bug/?i=13421

 [101] = https://curl.se/bug/?i=13418
 [102] = https://curl.se/bug/?i=13417
 [103] = https://curl.se/bug/?i=13442
 [104] = https://curl.se/bug/?i=13337
 [105] = https://curl.se/bug/?i=13407

 [106] = https://curl.se/bug/?i=13405
 [107] = https://curl.se/bug/?i=13377
 [108] = https://curl.se/bug/?i=13373
 [109] = https://curl.se/bug/?i=11922
 [110] = https://curl.se/bug/?i=13499
 [111] = https://curl.se/bug/?i=13396
 [112] = https://curl.se/bug/?i=13457

 [113] = https://curl.se/bug/?i=13450
 [114] = https://curl.se/bug/?i=12327
 [115] = https://curl.se/bug/?i=13452
 [116] = https://curl.se/bug/?i=13439
 [117] = https://curl.se/bug/?i=13445



 [118] = https://curl.se/bug/?i=13432
 [119] = https://curl.se/bug/?i=13436
 [120] = https://curl.se/bug/?i=13437
 [121] = https://curl.se/bug/?i=13433
 [122] = https://curl.se/bug/?i=13435
 [123] = https://curl.se/bug/?i=13434
 [124] = https://curl.se/bug/?i=13430
 [125] = https://curl.se/bug/?i=13497
 [126] = https://curl.se/bug/?i=13464
 [127] = https://curl.se/bug/?i=13494
 [128] = https://curl.se/bug/?i=13491
 [129] = https://curl.se/bug/?i=13475
 [130] = https://curl.se/bug/?i=13386
 [131] = https://curl.se/bug/?i=13150
 [132] = https://curl.se/bug/?i=13510
 [133] = https://curl.se/bug/?i=13355
 [134] = https://curl.se/bug/?i=13471
 [135] = https://curl.se/bug/?i=13508
 [136] = https://curl.se/bug/?i=13174
 [137] = https://curl.se/bug/?i=13451
 [138] = https://curl.se/bug/?i=13458
 [139] = https://curl.se/bug/?i=13467
 [140] = https://curl.se/bug/?i=13562
 [141] = https://curl.se/bug/?i=13495
 [142] = https://curl.se/bug/?i=13505
 [143] = https://curl.se/bug/?i=13503
 [144] = https://curl.se/bug/?i=13502
 [145] = https://curl.se/bug/?i=13498
 [146] = https://curl.se/bug/?i=13500
 [147] = https://curl.se/bug/?i=13557
 [148] = https://curl.se/bug/?i=13602
 [149] = https://curl.se/bug/?i=13568
 [150] = https://curl.se/bug/?i=13567
 [151] = https://curl.se/bug/?i=13604
 [152] = https://curl.se/bug/?i=13566
 [153] = https://curl.se/bug/?i=13601
 [154] = https://curl.se/bug/?i=13554
 [155] = https://curl.se/bug/?i=13237
 [156] = https://curl.se/bug/?i=13539
 [157] = https://curl.se/bug/?i=13549
 [158] = https://curl.se/bug/?i=13550
 [159] = https://curl.se/bug/?i=13553
 [160] = https://curl.se/bug/?i=13551
 [161] = https://curl.se/bug/?i=13509
 [162] = https://curl.se/bug/?i=13542
 [163] = https://curl.se/bug/?i=13529
 [164] = https://curl.se/bug/?i=13540
 [165] = https://curl.se/bug/?i=13600
 [166] = https://curl.se/bug/?i=13541
 [167] = https://curl.se/bug/?i=13538
 [168] = https://curl.se/bug/?i=13534
 [169] = https://curl.se/bug/?i=13536









 [170] = https://curl.se/bug/?i=13725
 [171] = https://curl.se/bug/?i=13537
 [172] = https://curl.se/bug/?i=13531
 [173] = https://curl.se/bug/?i=13504
 [174] = https://curl.se/bug/?i=13533
 [175] = https://curl.se/bug/?i=13590
 [176] = https://curl.se/bug/?i=13591
 [177] = https://curl.se/bug/?i=13605
 [178] = https://curl.se/bug/?i=13501
 [179] = https://curl.se/bug/?i=13578
 [180] = https://curl.se/bug/?i=13574
 [181] = https://curl.se/bug/?i=13580
 [182] = https://curl.se/bug/?i=13582
 [183] = https://curl.se/bug/?i=13588
 [184] = https://curl.se/bug/?i=13584
 [185] = https://curl.se/bug/?i=13586
 [186] = https://curl.se/bug/?i=13579
 [187] = https://curl.se/bug/?i=13664
 [188] = https://curl.se/bug/?i=13577
 [189] = https://curl.se/bug/?i=13576
 [190] = https://curl.se/bug/?i=13581
 [191] = https://curl.se/bug/?i=13728
 [192] = https://curl.se/bug/?i=13672
 [193] = https://curl.se/bug/?i=13654
 [194] = https://curl.se/bug/?i=13628
 [195] = https://curl.se/bug/?i=13655
 [196] = https://curl.se/bug/?i=13710
 [197] = https://curl.se/bug/?i=13707



 [198] = https://curl.se/bug/?i=13729
 [199] = https://curl.se/bug/?i=13544
 [200] = https://curl.se/bug/?i=13733
 [201] = https://curl.se/bug/?i=13583
 [203] = https://curl.se/bug/?i=13697
 [206] = https://curl.se/bug/?i=13661
 [207] = https://curl.se/bug/?i=13686
 [208] = https://curl.se/bug/?i=13684
 [209] = https://curl.se/bug/?i=13639
 [210] = https://curl.se/bug/?i=13560
 [211] = https://curl.se/bug/?i=13638
 [212] = https://curl.se/bug/?i=13603
 [213] = https://curl.se/bug/?i=13611
 [214] = https://curl.se/bug/?i=13634
 [215] = https://curl.se/bug/?i=13681
 [216] = https://curl.se/bug/?i=13624
 [217] = https://curl.se/bug/?i=13614
 [218] = https://curl.se/bug/?i=13621
 [219] = https://curl.se/bug/?i=13619
 [220] = https://curl.se/bug/?i=13610
 [221] = https://curl.se/bug/?i=13608
 [222] = https://curl.se/bug/?i=13643
 [223] = https://curl.se/bug/?i=13618
 [224] = https://curl.se/bug/?i=13676
 [225] = https://curl.se/bug/?i=13679
 [226] = https://curl.se/bug/?i=13487
 [227] = https://curl.se/bug/?i=13668

 [229] = https://curl.se/bug/?i=13666
 [230] = https://curl.se/bug/?i=13670


|

|
|
|

|



|
|
|
|
>
|
>
|
|
|
>



|
<
<
|
>
>
|
|
|
|
|
|
<
<
|
|
|
|
|
>
|
>
>
|
|
>
|
>
>
|
>
|
|
|
|
|
|
|
>
|
>
>
|
|
>
|
>
|
>
|
<
|
<
<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
|
|
<
|
>
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
|
<
>
>
>
>
|
>
|
<
<
|
|
<
|
>
|
<
<
<
<
<
<
<
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
|
|
|
|
|
<
|
<
<
<
>
>
|
<
<
<
<
|
>
>
|
|
|
|
|
<
<
<
<
<
|
>
>
|
|
|
<
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
>
|
>
>
>
>
>
>
|
|
|
|
|
>
|
<
|
<
|
|
|
|
|
>
|
|
|
|
>
|
<
|
|
|
>
>
|
|
<
|
|
|
<
>
>
>
|
>
>
|
|
|
|
<
<
<
<
<
|
>
|
|
|
>
>
>
>
>
>
|
>
>
|
|
|
>
|
|
|
>
|
>
|
|
<
<
|
<
<
<
<
>
|
>
|
|
|
<
|
>
|
|
>
>
|
<
<
|
|
<
|
|
|
|
|
|
<
<
|
|
>
>
>
|
>
>
>
>
>
|
>














>
|
|
|
|
|
|
|
<
|
|
<
|
<
|
|
|
|
|
|
|
|



|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
>
|
|
|
|
|
>
|
|
|
|
|
|
|
>
|
|
|
|
|
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25


26
27
28
29
30
31
32
33
34


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

71





72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

110
111
112
113
114
115
116


117
118

119
120
121







122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143



144
145
146




147
148
149
150
151
152
153
154





155
156
157
158
159
160

161
162
163
164
165
166

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190

191

192
193
194
195
196
197
198
199
200
201
202
203

204
205
206
207
208
209
210

211
212
213

214
215
216
217
218
219
220
221
222
223





224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249


250




251
252
253
254
255
256

257
258
259
260
261
262
263


264
265

266
267
268
269
270
271


272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306

307
308

309

310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
curl and libcurl 8.9.0

 Public curl releases:         258
 Command line options:         263
 curl_easy_setopt() options:   306
 Public functions in libcurl:  94
 Contributors:                 3211

This release includes the following changes:

 o curl: add --ip-tos (IP Type of Service / Traffic Class) [42]
 o curl: add --mptcp [29]
 o curl: add --vlan-priority [107]
 o curl: add -w '%{num_retries} [65]
 o gnutls: support CA caching [90]
 o mbedtls: support CURLOPT_CERTINFO [116]
 o noproxy: patterns need to be comma separated [75]
 o socket: support binding to interface *AND* IP [80]
 o tcpkeepalive: add CURLOPT_TCP_KEEPCNT and --keepalive-cnt [103]
 o urlapi: add CURLU_NO_GUESS_SCHEME [72]
 o wolfssl: support CA caching [73]

This release includes the following bugfixes:

 o (lib)curl.rc: set debug flag also for `CURLDEBUG` and `UNITTESTS` [2]


 o asyn-thread: avoid using GetAddrInfoExW with impersonation [7]
 o aws-sigv4: url encode the canonical path [55]
 o BINDINGS: update java link to one that exists [115]
 o build: add Debug, TrackMemory, ECH to feature list [218]
 o build: add more supported attributes to the IAR compiler [46]
 o build: fix llvm 16 or older + Xcode 15 or newer, and gcc [240]
 o build: fix llvm 17 and older + macOS SDK 14.4 and newer [230]
 o build: sync warning options between autotools, cmake & compilers [244]
 o build: tidy up `__builtin_available` feature checks (Apple) [241]


 o build: untangle `CURLDEBUG` and `DEBUGBUILD` macros [9]
 o build: use `#error` instead of invalid syntax [212]
 o cd2nroff: convert two warnings to errors [135]
 o cd2nroff: use an empty "##" to signal end of .IP sequence [56]
 o cf-socket: improve SO_SNDBUF update for Winsock [27]
 o cf-socket: optimize curlx_nonblock() and check its return error [151]
 o cf-socket: remove obsolete recvbuf [203]
 o cf-socket: remove two "useless" assignments [238]
 o cfilters: make Curl_conn_connect always assign 'done' [60]
 o cmake: add CURL_USE_GSASL option with detection + CI test [133]
 o cmake: allow `ENABLE_CURLDEBUG=OFF` with `ENABLE_DEBUG=ON` [26]
 o cmake: allow SOVERSION override with `CURL_LIBCURL_SOVERSION` [120]
 o cmake: alpha-sort feature list [161]
 o cmake: always build unit tests with the `testdeps` target [20]
 o cmake: bring `curl-config.cmake` closer to `FindCURL` [130]
 o cmake: create `configurehelp.pm` like autotools does [252]
 o cmake: delete unused `HAVE_LIBSSH2`, `HAVE_LIBSOCKET` macros [251]
 o cmake: detect `libidn2` also via `pkg-config` [239]
 o cmake: enable SOVERSION for Cygwin and `CMAKE_DLL_NAME_WITH_SOVERSION` [119]
 o cmake: fix `-Wredundant-decls` in unity/mingw-w64 builds [15]
 o cmake: fix brotli lib order [3]
 o cmake: fix building `unit1600` due to missing `ssl/openssl.h` [222]
 o cmake: fix building in unity mode [4]
 o cmake: fix building with both md4 and md5 in unity mode [13]
 o cmake: fix builds with detected libidn2 lib but undetected header [221]
 o cmake: fix feature and protocol lists for SecureTransport [194]
 o cmake: fix quotes when appending multiple options (SecureTransport) [139]
 o cmake: fix test 1013 with websockets enabled and no TLS [47]
 o cmake: improve wolfSSL detection [190]
 o cmake: show protocols, then features [180]
 o cmake: stop setting SOVERSION for the static lib target [127]
 o cmake: sync CA bundle/path detection with autotools [253]
 o cmake: sync protocol/feature list with `curl -V` output [182]
 o cmake: use `APPLE` instead of `CMAKE_SYSTEM_NAME` string [24]
 o cmake: whitespace, formatting/tidy-up in comments [25]
 o cmdline-docs: "added in" cleanups [171]

 o cmdline-docs: fix `--proxy-ca-native` example + tidy-ups [181]





 o cmdline-opts/_PROTOCOLS.md: mention WS(S) [94]
 o cmdline-opts/ech.md: shorten the help text [93]
 o cmdline-opts/fail.md: expand and clarify [95]
 o cmdline-opts/interface.md: expand the documentation [66]
 o cmdline-opts: category cleanup [196]
 o cmdline-opts: expand the parallel explanations [98]
 o cmdline-opts: shorten six help texts [178]
 o cmdline: expand proxy option explanations [97]
 o code: language cleanup in comments [186]
 o configure: CA bundle/path detection fixes [254]
 o configure: fix `SystemConfiguration` detection [243]
 o configure: fix pkg-config library name 'libnghttp3' [138]
 o configure: fix pkg-config names (zstd, ngtcp2*) [170]
 o configure: limit `SystemConfiguration` test to non-c-ares, IPv6 builds [242]
 o configure: remove 'deeper' checks for `AC_CHECK_FUNCS` [23]
 o configure: require a QUIC library if nghttp3 is used [142]
 o configure: sort feature list, lowercase protocols, use backticks [206]
 o configure: use `$EGREP` in place of `grep -E` [41]
 o configure: use AC_MSG_WARN for TLS/experimental warning texts [122]
 o connect-to.md: expand with examples [147]

 o connection: shutdown TLS (for FTP) better [104]
 o cookie-jar.md: see also --junk-session-cookies [144]
 o curl-config: revert to backticks to support old target envs [88]
 o curl: allow etag and content-disposition for 3xx reply [117]
 o curl: bsearch the --write-out variable name [102]
 o curl: check for --disable case *sensitively* [199]
 o curl: list categories in --help [219]
 o curl: make warnings and other messages aware of terminal width [58]
 o curl: output "flying saucers" with leading carriage return [121]
 o curl_easy_escape: elaborate a little on encoding a URL [193]
 o curl_mprintf.md: add missing comma
 o curl_multi_poll.md: expand the example with an custom file descriptor [21]
 o curl_str[n]equal.md: tidy up text to make them stand-alone [195]
 o curl_url_set.md: libcurl only parses :// URLs [48]
 o curl_url_set: elaborate on scheme guessing [191]
 o curldown: make 'added-in:' a mandatory header field [226]
 o CURLOPT_CONNECTTIMEOUT*: clarify, document the milliseond version [105]
 o CURLOPT_ECH.md: remove repeated 'if' [109]

 o CURLOPT_NETRC.md: clarify what it does on Windows [140]
 o CURLOPT_RESOLVE.md: mention hostname can be wildcard ('*') [150]
 o CURLOPT_SSL_VERIFYHOST.md: refresh [224]
 o CURLOPT_TLSAUTH_PASSWORD/USERNAME.md: language fixups [155]
 o DISTROS: add a link to the list archive [22]
 o DISTROS: add AlmaLinux package source link
 o DISTROS: add MSYS2 (native) links [100]


 o docs/cmdline-opts: fix mail-auth example TLD typo [35]
 o docs/cmdline-opts: remove two superfluous "Added in" mentions [143]

 o docs/libcurl: polish the single-line descriptions [159]
 o docs/Makefile.am: make curl-config.1 install [14]
 o docs: reference non deprecated libcurl options [113]







 o docs: start markdown headers with capital letter where applicable [236]
 o doh-insecure.md: expand [96]
 o doh: fix cleanup [228]
 o doh: fix leak and zero-length HTTPS RR crash [227]
 o dump-header.md: mention minus for stdout [149]
 o examples/threaded-ssl: remove locking callback code [83]
 o examples: add missing binaries to .gitignore [106]
 o examples: delete unused includes [10]
 o examples: fix compiling with MSVC [34]
 o examples: suppress deprecation warnings locally [211]
 o FEATURES.md: refresh [208]
 o file: separate fake headers and body with a stand-alone CRLF [137]
 o ftp: remove redundant null pointer check in loop condition [256]
 o get.d: clarify the explanation [32]
 o GHA/windows: add MSVC wolfSSL job with test [250]
 o GHA/windows: ignore FTP test results for old-mingw-w64
 o GHA: add MSVC UWP job, expand jobs with more options [216]
 o GHA: detect and warn for more English contractions [123]
 o GHA: disable MQTT and WebSocket tests in Windows jobs [63]
 o GHA: disable TFTP tests in Windows jobs
 o GHA: enable tests 1139, 1177, 1477 on Windows [59]

 o GHA: improve vcpkg cache, add BoringSSL ECH and LibreSSL MSVC jobs [215]



 o GHA: unify http3 workflows into one [77]
 o GHA: use vcpkg to install packages for MSVC jobs [145]
 o GIT-INFO.md: remove version requirements [209]




 o gnutls: improve TLS shutdown [62]
 o gnutls: pass in SNI name, not hostname when checking cert [114]
 o help: add flags to output and ssh categories [202]
 o hostip: skip error check for infallible function call [237]
 o http/3: add shutdown support [154]
 o http/3: resume upload on ack if we have more data to send [232]
 o http: remove "struct HTTP" [134]
 o http: write last header line late [44]





 o idn: fix ß with AppleIDN [220]
 o idn: make macidn fail before trying conversion if name too long [235]
 o idn: tweak buffer use when converting with macidn [245]
 o lib/v*: tidy up types and casts [64]
 o lib: add a few DEBUGASSERT(data) to aid code analyzers [187]
 o lib: add failure reason on bind errors [247]

 o lib: fix gcc warning in certain debug builds [19]
 o lib: fix thread entry point to return `DWORD` on WinCE [85]
 o lib: graceful connection shutdown [162]
 o lib: prefer `var = time(NULL)` over `time(&var)` [52]
 o lib: tidy up types and casts [92]
 o lib: xfer_setup and non-blocking shutdown [111]

 o libcurl-docs: make option lists alpha-sorted [214]
 o libcurl-easy.md: now *more* than 300 options [233]
 o libcurl.pc: add `Requires.private`, `Requires` for static linking [129]
 o libcurl.pc: add more `Requires.private`/`Requires` dependencies [189]
 o libssh: remove CURLOPT_SSL_VERIFYHOST check [36]
 o macos: add workaround for gcc, non-c-ares, IPv6, compile error [213]
 o macos: undo `availability` macro enabled by Homebrew gcc [231]
 o managen: "added in" fixes [131]
 o managen: cleanups to generate nicer-looking output [141]
 o managen: error on trailing blank lines in input files [165]
 o managen: fix removing backticks from subtitles [179]
 o managen: insert final .fi for files ending with a quote [174]
 o managen: introduce "Multi: per-URL" [176]
 o managen: only output .RE for manpage output [156]
 o managen: output tabs for each 8 leading spaces [164]
 o managen: warn on excessively long help texts [87]
 o MANUAL.md: wrap two example urls that overrun styling [234]
 o mbedtls: check version before getting tls version [261]
 o mbedtls: check version for cipher id [12]
 o mbedtls: correct the error message for cert blob parsing failure [225]
 o mbedtls: send close-notify on close [11]
 o mbedtls: v3.6.0 workarounds [89]
 o md4: fix compilation with OpenSSL 1.x with md4 disabled [255]
 o misc: fix typos [108]

 o mk-ca-bundle.pl: delay 'curl -V' execution until it is needed [168]

 o multi: add multi->proto_hash, a key-value store for protocol data [37]
 o multi: do a final progress update on connect failure [248]
 o multi: fix multi_wait() timeout handling [51]
 o multi: fix pollset during RESOLVING phase [166]
 o multi: multi_getsock(), check correct socket [167]
 o ngtcp2+quictls: fix cert-status use [173]
 o noproxy: test bad ipv6 net size first [82]
 o openssl/gnutls: rectify the TLS version checks for QUIC [61]
 o openssl: fix %-specifier in infof() call [57]
 o openssl: fix hostname handling when using ECH [78]
 o openssl: stop duplicate ssl key logging for legacy OpenSSL [49]
 o os400: make it compilable again [128]

 o pytest: add ftp upload tests [16]
 o pytest: include testenv/vsftpd.py in dist tarball [99]
 o quic: enable UDP GRO [157]
 o quic: openssl quic, cmake and doc version update to 3.3.0 [148]
 o quic: require at least OpenSSL 3.3 for QUIC [158]
 o quic: update to quiche 0.22.0 [175]
 o quiche: fix operand of ‘?:’ changes signedness [177]

 o request.md: language fix [70]
 o request: change the struct field bodywrites to a bool, only for hyper [132]
 o reuse: switch to REUSE 3.2 and REUSE.toml [184]

 o runtests: show name and keywords for failed tests in summary [249]
 o runtests: sort test IDs in summary lines [33]
 o runtests: support %DATE for YYYY-MM-DD of right now
 o runtests: support %VERNUM
 o runtests: support crlf="yes" for the <stderr> section
 o sectransp: fix `HAVE_BUILTIN_AVAILABLE` checks to not emit warnings [210]
 o sectransp: fix clang compiler warnings, stop silencing them [223]
 o sectransp: remove large cipher table [76]
 o sectransp: use common code for cipher suite lookup [54]
 o sendf: fix CRLF conversion of input [258]





 o smtp: for starttls, do full upgrade [260]
 o socket: change TCP keepalive from ms to seconds on DragonFly BSD [74]
 o socket: use SOCK_NONBLOCK to eliminate extra system call [86]
 o socketpair: add `eventfd` and use `SOCK_NONBLOCK` for `socketpair()` [81]
 o src/Makefile.am: remove SUBDIRS assignment [172]
 o system_win32: add missing curl.h include [160]
 o tcpkeepalive: support TCP keep-alive parameters on Solaris <11.4 [91]
 o test1119: adapt for `.md` input [204]
 o test1139: scan .md files instead of .3 ones [197]
 o test1175: scan libcurl-errors.md, not the generated .3 version [188]
 o test1486: verify that write-out.md and tool_writeout.c are in sync [112]
 o test2600: disable on win32 [259]
 o test: add test1484, for HEAD with content [18]
 o test: add test1546, chunked not last transfer encoding [17]
 o tests/scripts: call it 'manpage' (single word) [229]
 o tests: add pytest for --ciphers and --tls13-ciphers options [38]
 o tests: delete `CharConv` remains [201]
 o tests: delete redundant `!MSDOS` guard [84]
 o tests: extend user/password parsing test1620 [40]
 o tests: fix sshd IdentityFile path for MinGW/Cygwin [217]
 o tests: fix sshd UserKnownHostsFile path for MinGW/Cygwin
 o tests: include current directory when running test Perl commands [205]
 o tests: log "Throwing away" messages before throwing away
 o tests: run with "--trace-config all" to provide even more info [6]
 o tests: sync feature names with `curl -V` [257]
 o tests: test_17_ssl_use.py clarify mbedTLS TLSv1.3 support [43]


 o tests: use exec when spawning nghttpx [45]




 o tidy-up: use consistent casing for Windows directories [28]
 o TODO: remove some old, clarify, add something [31]
 o tool_cb_hdr: return error for failed header writes [30]
 o tool_operate: avoid explicitly setting verifypeer to 1 [39]
 o tool_operate: simplify return code handling from url_proto() [198]
 o tool_writeout: get certinfo only when needing it [101]

 o trace-ascii.md: mention "%" for stderr [146]
 o transfer: avoid polling socket every transfer loop [200]
 o transfer: conn close on paused upload [8]
 o transfer: do not use EXPIRE_NOW while blocked [124]
 o transfer: remove curl_upload_refill_watermark, no longer used [50]
 o transfer: set CSELECT_IN if there is data pending [118]
 o unit2604: use 'unitfail' instead of 'error' variable [153]


 o url: allow DoH transfers to override max connection limit [68]
 o urlapi: remove unused definition of HOST_BAD [262]

 o variable.md: make example use expand [207]
 o verify-synopsis.pl: work with .md files [185]
 o vms: fixed language in comment [110]
 o vtls: deprioritize Secure Transport [71]
 o vtls: replace addsessionid with set_sessionid [183]
 o winbuild: fix PE version info debug flag [1]


 o winbuild: MS-DOS batch tidy-ups [163]
 o winbuild: remove outdated WIN32 defines [5]
 o windows: fix UWP builds, add GHA job [79]
 o winsock: move SO_SNDBUF update into cf-socket [53]
 o wolfssl: assume key_file equal to clientcert if no key_file [169]
 o wolfssl: use larger error buffer when formatting errors [246]
 o x509asn1: add some common ECDSA OIDs [67]
 o x509asn1: ASN1tostr() should fail when 'constructed' is set [125]
 o x509asn1: fallback to dotted OID representation [69]
 o x509asn1: make Curl_extract_certinfo store error message [136]
 o x509asn1: prevent NULL dereference [152]
 o x509asn1: remove superfluous free()
 o x509asn1: remove two static variables [126]

This release includes the following known bugs:

 o see docs/KNOWN_BUGS (https://curl.se/docs/knownbugs.html)

Planned upcoming removals include:

 o support for space-separated NOPROXY patterns

 See https://curl.se/dev/deprecate.html for details

This release would not have looked like this without help, code, reports and
advice from friends like these:

  Alejandro R. Sedeño, alervd on github, Alexander Shtuchkin, Alex Snast,
  Andy Pan, Andy Reitz, Aurélien Pierre, Ayesh Karunaratne, Bhanu Prakash,
  Bo Anderson, brian m. carlson, calvin2021y on github, Christian Heusel,
  Christian Schmitz, Chris Webb, CMD, Dan Fandrich, Daniel Gustafsson,
  Daniel Stenberg, dependabot[bot], Dexter Gerig, dogma, Dominik Piątkowski,
  Dorian Craps, edmcln on github, Eli Schwartz, Elliott Balsley,
  fds242 on github, Guilherme Puida, Harry Sintonen, icy17 on github,
  James Abbatiello, Jan Venekamp, Jay Guerette, Jiang Wenjian,

  Jonathan Matthews, Joseph Chen, Junho Choi, Justin Maggard, Kai Pastor,
  kartatz, Keerthi Timmaraju, Lee Li, Luke Hamburg, Marcel Raad, martinevsky,

  Martin Peck, Matthias Gatto, Matthieu Baerts, Matt Jolly, Max Mehl,

  Morgan Willcock, Olivier Bonaventure, Orgad Shaneh, Patrick Monnerat,
  Pavel Pavlov, Philip Heiduck, pszlazak on github, RainRat, Ray Satiro,
  renovate[bot], Ryan Carsten Schmidt, Samuel Chiang,
  saurabhsingh-dev on github, Sebastian Andersson, Sergey Bronnikov,
  Sergey Markelov, Sertonix, Stefan Eissing, Stephen Farrell, Tal Regev,
  Tatsuhiro Tsujikawa, tomy2105 on github, Viktor Szakats,
  vuonganh1993 on github, vvb2060, Yedaya Katsman, z2_, 李四, 罗朝辉
  (80 contributors)

References to bug reports and discussions on issues:

 [1] = https://curl.se/bug/?i=13739
 [2] = https://curl.se/bug/?i=13730
 [3] = https://curl.se/bug/?i=13761
 [4] = https://curl.se/bug/?i=13751
 [5] = https://curl.se/bug/?i=13739
 [6] = https://curl.se/bug/?i=13791
 [7] = https://curl.se/bug/?i=13612
 [8] = https://curl.se/bug/?i=13740
 [9] = https://curl.se/bug/?i=13718
 [10] = https://curl.se/bug/?i=13785
 [11] = https://curl.se/bug/?i=13745
 [12] = https://curl.se/bug/?i=13749
 [13] = https://curl.se/bug/?i=13737
 [14] = https://curl.se/bug/?i=13741
 [15] = https://curl.se/bug/?i=13705
 [16] = https://curl.se/bug/?i=13734
 [17] = https://curl.se/bug/?i=13736
 [18] = https://curl.se/bug/?i=13735
 [19] = https://curl.se/bug/?i=13800
 [20] = https://curl.se/bug/?i=13698
 [21] = https://curl.se/bug/?i=13842
 [22] = https://curl.se/bug/?i=13843
 [23] = https://bugs.gentoo.org/932827
 [24] = https://curl.se/bug/?i=13713
 [25] = https://curl.se/bug/?i=13711
 [26] = https://curl.se/bug/?i=13792
 [27] = https://curl.se/bug/?i=13827
 [28] = https://curl.se/bug/?i=13832
 [29] = https://curl.se/bug/?i=13278
 [30] = https://curl.se/bug/?i=13836
 [31] = https://curl.se/bug/?i=13788
 [32] = https://curl.se/bug/?i=13706
 [33] = https://curl.se/bug/?i=13774
 [34] = https://curl.se/bug/?i=13771
 [35] = https://curl.se/bug/?i=13784
 [36] = https://curl.se/bug/?i=13767
 [37] = https://curl.se/bug/?i=13345
 [38] = https://curl.se/bug/?i=13530
 [39] = https://curl.se/bug/?i=13704
 [40] = https://curl.se/bug/?i=13756
 [41] = https://curl.se/bug/?i=13780
 [42] = https://curl.se/bug/?i=13606
 [43] = https://curl.se/bug/?i=13779
 [44] = https://curl.se/bug/?i=13752
 [45] = https://curl.se/bug/?i=13772
 [46] = https://curl.se/bug/?i=13744
 [47] = https://curl.se/bug/?i=13769
 [48] = https://curl.se/bug/?i=13821
 [49] = https://curl.se/bug/?i=13683
 [50] = https://curl.se/bug/?i=13764
 [51] = https://curl.se/bug/?i=13782
 [52] = https://curl.se/bug/?i=13815
 [53] = https://curl.se/bug/?i=13763
 [54] = https://curl.se/bug/?i=13521
 [55] = https://curl.se/bug/?i=13754
 [56] = https://curl.se/bug/?i=13803
 [57] = https://curl.se/bug/?i=13816
 [58] = https://curl.se/bug/?i=13804
 [59] = https://curl.se/bug/?i=13817
 [60] = https://curl.se/bug/?i=13884
 [61] = https://curl.se/bug/?i=13799
 [62] = https://curl.se/bug/?i=13790
 [63] = https://curl.se/bug/?i=13860
 [64] = https://curl.se/bug/?i=13622
 [65] = https://curl.se/bug/?i=13910
 [66] = https://curl.se/bug/?i=13882
 [67] = https://curl.se/bug/?i=13857
 [68] = https://curl.se/mail/lib-2024-06/0001.html
 [69] = https://curl.se/bug/?i=13845
 [70] = https://curl.se/bug/?i=13854
 [71] = https://curl.se/bug/?i=13547
 [72] = https://curl.se/bug/?i=13616
 [73] = https://curl.se/bug/?i=13786
 [74] = https://curl.se/bug/?i=13847
 [75] = https://curl.se/bug/?i=13789
 [76] = https://curl.se/bug/?i=13823
 [77] = https://curl.se/bug/?i=13841
 [78] = https://curl.se/bug/?i=13818
 [79] = https://curl.se/bug/?i=13870
 [80] = https://curl.se/bug/?i=13719
 [81] = https://curl.se/bug/?i=13874
 [82] = https://curl.se/bug/?i=13902
 [83] = https://curl.se/bug/?i=13851
 [84] = https://curl.se/bug/?i=13878
 [85] = https://curl.se/bug/?i=13877
 [86] = https://curl.se/bug/?i=13855
 [87] = https://curl.se/bug/?i=13895
 [88] = https://curl.se/bug/?i=13871
 [89] = https://curl.se/bug/?i=13653
 [90] = https://curl.se/bug/?i=13795
 [91] = https://curl.se/bug/?i=13864
 [92] = https://curl.se/bug/?i=13862
 [93] = https://curl.se/bug/?i=13894
 [94] = https://curl.se/bug/?i=13891
 [95] = https://curl.se/bug/?i=13890
 [96] = https://curl.se/bug/?i=13889
 [97] = https://curl.se/bug/?i=13887
 [98] = https://curl.se/bug/?i=13886
 [99] = https://curl.se/bug/?i=13918
 [100] = https://curl.se/bug/?i=13915
 [101] = https://curl.se/bug/?i=13914
 [102] = https://curl.se/bug/?i=13914
 [103] = https://curl.se/bug/?i=13885
 [104] = https://curl.se/bug/?i=13904
 [105] = https://curl.se/bug/?i=13905
 [106] = https://curl.se/bug/?i=13952
 [107] = https://curl.se/bug/?i=13907
 [108] = https://curl.se/bug/?i=13923
 [109] = https://curl.se/bug/?i=13922
 [110] = https://curl.se/bug/?i=13921
 [111] = https://curl.se/bug/?i=13913
 [112] = https://curl.se/bug/?i=13920
 [113] = https://curl.se/bug/?i=13951
 [114] = https://curl.se/bug/?i=13428
 [115] = https://github.com/curl/everything-curl/issues/456
 [116] = https://curl.se/bug/?i=13113
 [117] = https://curl.se/bug/?i=13302
 [118] = https://curl.se/bug/?i=13695
 [119] = https://curl.se/bug/?i=13898
 [120] = https://curl.se/bug/?i=13944
 [121] = https://curl.se/bug/?i=14213
 [122] = https://curl.se/bug/?i=13941
 [123] = https://curl.se/bug/?i=13940
 [124] = https://curl.se/bug/?i=13908
 [125] = https://curl.se/bug/?i=13972
 [126] = https://curl.se/bug/?i=13971
 [127] = https://curl.se/bug/?i=13936
 [128] = https://curl.se/bug/?i=13930
 [129] = https://curl.se/bug/?i=864
 [130] = https://curl.se/bug/?i=13897
 [131] = https://curl.se/bug/?i=14002
 [132] = https://curl.se/bug/?i=13928
 [133] = https://curl.se/bug/?i=13948
 [134] = https://curl.se/bug/?i=13927
 [135] = https://curl.se/bug/?i=13929
 [136] = https://curl.se/bug/?i=13959
 [137] = https://curl.se/mail/lib-2024-06/0033.html
 [138] = https://curl.se/bug/?i=13994
 [139] = https://curl.se/bug/?i=13953
 [140] = https://curl.se/bug/?i=13956
 [141] = https://curl.se/bug/?i=14001
 [142] = https://curl.se/bug/?i=13995
 [143] = https://curl.se/bug/?i=14000
 [144] = https://curl.se/bug/?i=13996
 [145] = https://curl.se/bug/?i=13979
 [146] = https://curl.se/bug/?i=13991
 [147] = https://curl.se/bug/?i=13989
 [148] = https://curl.se/bug/?i=14028
 [149] = https://curl.se/bug/?i=13985
 [150] = https://curl.se/bug/?i=13983
 [151] = https://curl.se/bug/?i=13942
 [152] = https://curl.se/bug/?i=13978
 [153] = https://curl.se/bug/?i=13967
 [154] = https://curl.se/bug/?i=14022
 [155] = https://curl.se/bug/?i=14061
 [156] = https://curl.se/bug/?i=14025
 [157] = https://curl.se/bug/?i=14012
 [158] = https://curl.se/bug/?i=14026
 [159] = https://curl.se/bug/?i=14062
 [160] = https://curl.se/bug/?i=14019
 [161] = https://curl.se/bug/?i=14063
 [162] = https://curl.se/bug/?i=13976
 [163] = https://curl.se/bug/?i=14084
 [164] = https://curl.se/bug/?i=14016
 [165] = https://curl.se/bug/?i=14015
 [166] = https://curl.se/bug/?i=14047
 [167] = https://curl.se/bug/?i=13998
 [168] = https://curl.se/bug/?i=14060
 [169] = https://curl.se/bug/?i=14007
 [170] = https://curl.se/bug/?i=14005
 [171] = https://curl.se/bug/?i=14003
 [172] = https://curl.se/bug/?i=14054
 [173] = https://curl.se/bug/?i=14049
 [174] = https://curl.se/bug/?i=14048
 [175] = https://curl.se/bug/?i=14030
 [176] = https://curl.se/bug/?i=14045
 [177] = https://curl.se/bug/?i=14041
 [178] = https://curl.se/bug/?i=14075
 [179] = https://curl.se/bug/?i=14081
 [180] = https://curl.se/bug/?i=14082
 [181] = https://curl.se/bug/?i=14078
 [182] = https://curl.se/bug/?i=14066
 [183] = https://curl.se/bug/?i=14121
 [184] = https://curl.se/bug/?i=14107
 [185] = https://curl.se/bug/?i=14038
 [186] = https://curl.se/bug/?i=14073
 [187] = https://curl.se/bug/?i=14033
 [188] = https://curl.se/bug/?i=14133
 [189] = https://curl.se/bug/?i=14072
 [190] = https://curl.se/bug/?i=14064
 [191] = https://curl.se/bug/?i=14071
 [193] = https://curl.se/bug/?i=14069
 [194] = https://curl.se/bug/?i=13963
 [195] = https://curl.se/bug/?i=14068
 [196] = https://curl.se/bug/?i=14101
 [197] = https://curl.se/bug/?i=14132
 [198] = https://curl.se/bug/?i=14104
 [199] = https://curl.se/bug/?i=14103
 [200] = https://curl.se/bug/?i=14098
 [201] = https://curl.se/bug/?i=14100
 [202] = https://curl.se/bug/?i=14076
 [203] = https://curl.se/bug/?i=14138
 [204] = https://curl.se/bug/?i=14125
 [205] = https://curl.se/bug/?i=14124
 [206] = https://curl.se/bug/?i=14117
 [207] = https://curl.se/bug/?i=14118
 [208] = https://curl.se/bug/?i=14086
 [209] = https://curl.se/bug/?i=14112
 [210] = https://curl.se/bug/?i=14122
 [211] = https://curl.se/bug/?i=14123
 [212] = https://curl.se/bug/?i=14181
 [213] = https://curl.se/bug/?i=14119
 [214] = https://curl.se/bug/?i=14156
 [215] = https://curl.se/bug/?i=14090
 [216] = https://curl.se/bug/?i=14077
 [217] = https://curl.se/bug/?i=14113
 [218] = https://curl.se/bug/?i=14096
 [219] = https://curl.se/bug/?i=14055
 [220] = https://curl.se/bug/?i=14176
 [221] = https://curl.se/bug/?i=14175
 [222] = https://curl.se/bug/?i=14172
 [223] = https://curl.se/bug/?i=14162
 [224] = https://curl.se/bug/?i=14241
 [225] = https://curl.se/bug/?i=14224
 [226] = https://curl.se/bug/?i=14217
 [227] = https://curl.se/bug/?i=14151
 [228] = https://curl.se/bug/?i=14207
 [229] = https://curl.se/bug/?i=14216
 [230] = https://curl.se/bug/?i=14159
 [231] = https://curl.se/bug/?i=13700
 [232] = https://curl.se/bug/?i=14198
 [233] = https://curl.se/bug/?i=14153
 [234] = https://curl.se/bug/?i=14149
 [235] = https://curl.se/bug/?i=14215
 [236] = https://curl.se/bug/?i=14115
 [237] = https://curl.se/bug/?i=14147
 [238] = https://curl.se/bug/?i=14145
 [239] = https://curl.se/bug/?i=14137
 [240] = https://curl.se/bug/?i=14134
 [241] = https://curl.se/bug/?i=14127
 [242] = https://curl.se/bug/?i=14126
 [243] = https://curl.se/bug/?i=14130
 [244] = https://curl.se/bug/?i=14128
 [245] = https://curl.se/bug/?i=14215
 [246] = https://curl.se/bug/?i=14114
 [247] = https://curl.se/bug/?i=14221
 [248] = https://curl.se/bug/?i=14204
 [249] = https://curl.se/bug/?i=14174
 [250] = https://curl.se/bug/?i=14193
 [251] = https://curl.se/bug/?i=14178
 [252] = https://curl.se/bug/?i=14129
 [253] = https://curl.se/bug/?i=14182
 [254] = https://curl.se/bug/?i=14186
 [255] = https://curl.se/bug/?i=14218
 [256] = https://curl.se/bug/?i=14234
 [257] = https://curl.se/bug/?i=14183
 [258] = https://curl.se/bug/?i=14165
 [259] = https://curl.se/bug/?i=14177
 [260] = https://curl.se/bug/?i=14166
 [261] = https://curl.se/bug/?i=14228
 [262] = https://curl.se/bug/?i=14235
Changes to jni/curl/acinclude.m4.
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    AC_LANG_SOURCE(
ifelse($2,,,[$2])[[
int main (void)
{
#ifdef $1
  return 0;
#else
  force compilation error
#endif
}
    ]])
  ],[
    tst_symbol_defined="yes"
  ],[
    tst_symbol_defined="no"







|







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    AC_LANG_SOURCE(
ifelse($2,,,[$2])[[
int main (void)
{
#ifdef $1
  return 0;
#else
  #error force compilation error
#endif
}
    ]])
  ],[
    tst_symbol_defined="yes"
  ],[
    tst_symbol_defined="no"
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
int main (void)
{
#if defined(__hpux) && defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600)
  return 0;
#elif defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)
  return 0;
#else
  force compilation error
#endif
}
    ]])
  ],[
    tst_lib_xnet_required="yes"
    LIBS="-lxnet $LIBS"
  ])







|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
int main (void)
{
#if defined(__hpux) && defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600)
  return 0;
#elif defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)
  return 0;
#else
  #error force compilation error
#endif
}
    ]])
  ],[
    tst_lib_xnet_required="yes"
    LIBS="-lxnet $LIBS"
  ])
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272

1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
    capath="$want_capath"
  elif test "x$want_ca" != "xno" -a "x$want_ca" != "xunset"; then
    dnl --with-ca-bundle given
    ca="$want_ca"
    capath="no"
  elif test "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then
    dnl --with-ca-path given
    if test "x$OPENSSL_ENABLED" != "x1" -a \
            "x$GNUTLS_ENABLED" != "x1" -a \
            "x$MBEDTLS_ENABLED" != "x1" -a \
            "x$WOLFSSL_ENABLED" != "x1"; then
      AC_MSG_ERROR([--with-ca-path only works with OpenSSL, GnuTLS, mbedTLS or wolfSSL])
    fi
    capath="$want_capath"
    ca="no"
  else
    dnl first try autodetecting a CA bundle , then a CA path
    dnl both autodetections can be skipped by --without-ca-*
    ca="no"
    capath="no"
    if test "x$cross_compiling" != "xyes"; then

      dnl NOT cross-compiling and...
      dnl neither of the --with-ca-* options are provided
      if test "x$want_ca" = "xunset"; then
        dnl the path we previously would have installed the curl ca bundle
        dnl to, and thus we now check for an already existing cert in that
        dnl place in case we find no other
        if test "x$prefix" != xNONE; then
          cac="${prefix}/share/curl/curl-ca-bundle.crt"
        else
          cac="$ac_default_prefix/share/curl/curl-ca-bundle.crt"
        fi







<
<
<
<
<
<



|
|


|
>



|







1252
1253
1254
1255
1256
1257
1258






1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
    capath="$want_capath"
  elif test "x$want_ca" != "xno" -a "x$want_ca" != "xunset"; then
    dnl --with-ca-bundle given
    ca="$want_ca"
    capath="no"
  elif test "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then
    dnl --with-ca-path given






    capath="$want_capath"
    ca="no"
  else
    dnl First try auto-detecting a CA bundle, then a CA path.
    dnl Both auto-detections can be skipped by --without-ca-*
    ca="no"
    capath="no"
    if test "x$cross_compiling" != "xyes" -a \
            "x$curl_cv_native_windows" != "xyes"; then
      dnl NOT cross-compiling and...
      dnl neither of the --with-ca-* options are provided
      if test "x$want_ca" = "xunset"; then
        dnl the path we previously would have installed the curl CA bundle
        dnl to, and thus we now check for an already existing cert in that
        dnl place in case we find no other
        if test "x$prefix" != xNONE; then
          cac="${prefix}/share/curl/curl-ca-bundle.crt"
        else
          cac="$ac_default_prefix/share/curl/curl-ca-bundle.crt"
        fi
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
            ca="$a"
            break
          fi
        done
      fi
      AC_MSG_NOTICE([want $want_capath ca $ca])
      if test "x$want_capath" = "xunset"; then
        if test "x$OPENSSL_ENABLED" = "x1" -o \
                "x$GNUTLS_ENABLED" = "x1" -o \
                "x$MBEDTLS_ENABLED" = "x1" -o \
                "x$WOLFSSL_ENABLED" = "x1"; then
          check_capath="/etc/ssl/certs"
        fi
      fi
    else
      dnl no option given and cross-compiling
      AC_MSG_WARN([skipped the ca-cert path detection when cross-compiling])
    fi
  fi








<
<
<
<
|
<







1287
1288
1289
1290
1291
1292
1293




1294

1295
1296
1297
1298
1299
1300
1301
            ca="$a"
            break
          fi
        done
      fi
      AC_MSG_NOTICE([want $want_capath ca $ca])
      if test "x$want_capath" = "xunset"; then




        check_capath="/etc/ssl/certs"

      fi
    else
      dnl no option given and cross-compiling
      AC_MSG_WARN([skipped the ca-cert path detection when cross-compiling])
    fi
  fi

1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
dnl purpose is to return true if the code is running under a certain OS version
dnl or later.

AC_DEFUN([CURL_SUPPORTS_BUILTIN_AVAILABLE], [
  AC_MSG_CHECKING([to see if the compiler supports __builtin_available()])
  AC_COMPILE_IFELSE([
    AC_LANG_PROGRAM([[
#include <stdlib.h>
    ]],[[
      if (__builtin_available(macOS 10.8, iOS 5.0, *)) {}
    ]])
  ],[
    AC_MSG_RESULT([yes])
    AC_DEFINE_UNQUOTED(HAVE_BUILTIN_AVAILABLE, 1,
        [Define to 1 if you have the __builtin_available function.])
  ],[
    AC_MSG_RESULT([no])
  ])
])







<

|









1635
1636
1637
1638
1639
1640
1641

1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
dnl purpose is to return true if the code is running under a certain OS version
dnl or later.

AC_DEFUN([CURL_SUPPORTS_BUILTIN_AVAILABLE], [
  AC_MSG_CHECKING([to see if the compiler supports __builtin_available()])
  AC_COMPILE_IFELSE([
    AC_LANG_PROGRAM([[

    ]],[[
      if(__builtin_available(macOS 10.12, iOS 5.0, *)) {}
    ]])
  ],[
    AC_MSG_RESULT([yes])
    AC_DEFINE_UNQUOTED(HAVE_BUILTIN_AVAILABLE, 1,
        [Define to 1 if you have the __builtin_available function.])
  ],[
    AC_MSG_RESULT([no])
  ])
])
Changes to jni/curl/aclocal.m4.
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
m4_include([m4/ltoptions.m4])
m4_include([m4/ltsugar.m4])
m4_include([m4/ltversion.m4])
m4_include([m4/lt~obsolete.m4])
m4_include([m4/xc-am-iface.m4])
m4_include([m4/xc-cc-check.m4])
m4_include([m4/xc-lt-iface.m4])
m4_include([m4/xc-translit.m4])
m4_include([m4/xc-val-flgs.m4])
m4_include([m4/zz40-xc-ovr.m4])
m4_include([m4/zz50-xc-ovr.m4])
m4_include([m4/zz60-xc-ovr.m4])
m4_include([acinclude.m4])







<





1240
1241
1242
1243
1244
1245
1246

1247
1248
1249
1250
1251
m4_include([m4/ltoptions.m4])
m4_include([m4/ltsugar.m4])
m4_include([m4/ltversion.m4])
m4_include([m4/lt~obsolete.m4])
m4_include([m4/xc-am-iface.m4])
m4_include([m4/xc-cc-check.m4])
m4_include([m4/xc-lt-iface.m4])

m4_include([m4/xc-val-flgs.m4])
m4_include([m4/zz40-xc-ovr.m4])
m4_include([m4/zz50-xc-ovr.m4])
m4_include([m4/zz60-xc-ovr.m4])
m4_include([acinclude.m4])
Changes to jni/curl/configure.
902
903
904
905
906
907
908


909
910
911
912
913
914
915
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
SSL_BACKENDS
SUPPORT_PROTOCOLS
SUPPORT_FEATURES
LIBCURL_NO_SHARED


ENABLE_STATIC
ENABLE_SHARED
CROSSCOMPILING_FALSE
CROSSCOMPILING_TRUE
BLANK_AT_MAKETIME
CURL_NETWORK_AND_TIME_LIBS
CURL_NETWORK_LIBS







>
>







902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
am__EXEEXT_TRUE
LTLIBOBJS
LIBOBJS
SSL_BACKENDS
SUPPORT_PROTOCOLS
SUPPORT_FEATURES
LIBCURL_NO_SHARED
LIBCURL_PC_REQUIRES
LIBCURL_PC_REQUIRES_PRIVATE
ENABLE_STATIC
ENABLE_SHARED
CROSSCOMPILING_FALSE
CROSSCOMPILING_TRUE
BLANK_AT_MAKETIME
CURL_NETWORK_AND_TIME_LIBS
CURL_NETWORK_LIBS
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
HAVE_WINDRES_FALSE
HAVE_WINDRES_TRUE
USE_WIN32_CRYPTO
USE_WIN32_SMALL_FILES
USE_WIN32_LARGE_FILES
BUILD_UNITTESTS_FALSE
BUILD_UNITTESTS_TRUE
CURLDEBUG_FALSE
CURLDEBUG_TRUE
CURL_CFLAG_EXTRAS
DOING_NATIVE_WINDOWS_FALSE
DOING_NATIVE_WINDOWS_TRUE
USE_EXPLICIT_LIB_DEPS_FALSE
USE_EXPLICIT_LIB_DEPS_TRUE
REQUIRE_LIB_DEPS
CPPFLAG_CURL_STATICLIB







<
<







1009
1010
1011
1012
1013
1014
1015


1016
1017
1018
1019
1020
1021
1022
HAVE_WINDRES_FALSE
HAVE_WINDRES_TRUE
USE_WIN32_CRYPTO
USE_WIN32_SMALL_FILES
USE_WIN32_LARGE_FILES
BUILD_UNITTESTS_FALSE
BUILD_UNITTESTS_TRUE


CURL_CFLAG_EXTRAS
DOING_NATIVE_WINDOWS_FALSE
DOING_NATIVE_WINDOWS_TRUE
USE_EXPLICIT_LIB_DEPS_FALSE
USE_EXPLICIT_LIB_DEPS_TRUE
REQUIRE_LIB_DEPS
CPPFLAG_CURL_STATICLIB
1117
1118
1119
1120
1121
1122
1123


1124
1125
1126
1127
1128
1129
1130
INSTALL_PROGRAM
libext
AR
EGREP
GREP
SED
CONFIGURE_OPTIONS


AM_BACKSLASH
AM_DEFAULT_VERBOSITY
AM_DEFAULT_V
AM_V
MAINT
MAINTAINER_MODE_FALSE
MAINTAINER_MODE_TRUE







>
>







1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
INSTALL_PROGRAM
libext
AR
EGREP
GREP
SED
CONFIGURE_OPTIONS
DEBUGBUILD_FALSE
DEBUGBUILD_TRUE
AM_BACKSLASH
AM_DEFAULT_VERBOSITY
AM_DEFAULT_V
AM_V
MAINT
MAINTAINER_MODE_FALSE
MAINTAINER_MODE_TRUE
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
                          installation (default: /usr/local/ssl); when
                          possible, set the PKG_CONFIG_PATH environment
                          variable instead of using this option
  --with-gnutls=PATH      where to look for GnuTLS, PATH points to the
                          installation root
  --with-mbedtls=PATH     where to look for mbedTLS, PATH points to the
                          installation root
  --with-wolfssl=PATH     where to look for WolfSSL, PATH points to the
                          installation root (default: system lib default)
  --with-bearssl=PATH     where to look for BearSSL, PATH points to the
                          installation root
  --with-rustls=PATH      where to look for rustls, PATH points to the
                          installation root
  --with-test-nghttpx=PATH
                          where to find nghttpx for testing







|







2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
                          installation (default: /usr/local/ssl); when
                          possible, set the PKG_CONFIG_PATH environment
                          variable instead of using this option
  --with-gnutls=PATH      where to look for GnuTLS, PATH points to the
                          installation root
  --with-mbedtls=PATH     where to look for mbedTLS, PATH points to the
                          installation root
  --with-wolfssl=PATH     where to look for wolfSSL, PATH points to the
                          installation root (default: system lib default)
  --with-bearssl=PATH     where to look for BearSSL, PATH points to the
                          installation root
  --with-rustls=PATH      where to look for rustls, PATH points to the
                          installation root
  --with-test-nghttpx=PATH
                          where to find nghttpx for testing
3597
3598
3599
3600
3601
3602
3603








3604
3605
3606
3607
3608
3609
3610
printf "%s\n" "#define DEBUGBUILD 1" >>confdefs.h

      ;;
  esac
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_debug" >&5
printf "%s\n" "$want_debug" >&6; }










      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable compiler optimizer" >&5
printf %s "checking whether to enable compiler optimizer... " >&6; }
  OPT_COMPILER_OPTIMIZE="default"
  # Check whether --enable-optimize was given.
if test ${enable_optimize+y}
then :







>
>
>
>
>
>
>
>







3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
printf "%s\n" "#define DEBUGBUILD 1" >>confdefs.h

      ;;
  esac
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_debug" >&5
printf "%s\n" "$want_debug" >&6; }

 if test x$want_debug = xyes; then
  DEBUGBUILD_TRUE=
  DEBUGBUILD_FALSE='#'
else
  DEBUGBUILD_TRUE='#'
  DEBUGBUILD_FALSE=
fi


      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable compiler optimizer" >&5
printf %s "checking whether to enable compiler optimizer... " >&6; }
  OPT_COMPILER_OPTIMIZE="default"
  # Check whether --enable-optimize was given.
if test ${enable_optimize+y}
then :
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
      curl_httpsrr_msg="no      (--enable-httpsrr)"
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
      ;;
    *)
            want_httpsrr="yes"
      curl_httpsrr_msg="enabled (--disable-httpsrr)"
      experimental="httpsrr"
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
      ;;
  esac


  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable ECH support" >&5







<







3838
3839
3840
3841
3842
3843
3844

3845
3846
3847
3848
3849
3850
3851
      curl_httpsrr_msg="no      (--enable-httpsrr)"
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
      ;;
    *)
            want_httpsrr="yes"
      curl_httpsrr_msg="enabled (--disable-httpsrr)"

      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
      ;;
  esac


  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable ECH support" >&5
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
      curl_ech_msg="no      (--enable-ech)"
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
      ;;
    *)
            want_ech="yes"
      curl_ech_msg="enabled (--disable-ech)"
      experimental="ech"
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
      ;;
  esac


#







<







3869
3870
3871
3872
3873
3874
3875

3876
3877
3878
3879
3880
3881
3882
      curl_ech_msg="no      (--enable-ech)"
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
      ;;
    *)
            want_ech="yes"
      curl_ech_msg="enabled (--disable-ech)"

      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
      ;;
  esac


#
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340

Select from these:

  --with-amissl
  --with-bearssl
  --with-gnutls
  --with-mbedtls
  --with-openssl (also works for BoringSSL and libressl)
  --with-rustls
  --with-schannel
  --with-secure-transport
  --with-wolfssl
" "$LINENO" 5
  fi
fi







|







7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348

Select from these:

  --with-amissl
  --with-bearssl
  --with-gnutls
  --with-mbedtls
  --with-openssl (also works for BoringSSL and LibreSSL)
  --with-rustls
  --with-schannel
  --with-secure-transport
  --with-wolfssl
" "$LINENO" 5
  fi
fi
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630

int main (void)
{

#ifdef _THREAD_SAFE
      int dummy=1;
#else
      force compilation error
#endif

 ;
 return 0;
}

_ACEOF







|







7624
7625
7626
7627
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638

int main (void)
{

#ifdef _THREAD_SAFE
      int dummy=1;
#else
      #error force compilation error
#endif

 ;
 return 0;
}

_ACEOF
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716

int main (void)
{

#ifdef _REENTRANT
      int dummy=1;
#else
      force compilation error
#endif

 ;
 return 0;
}

_ACEOF







|







7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724

int main (void)
{

#ifdef _REENTRANT
      int dummy=1;
#else
      #error force compilation error
#endif

 ;
 return 0;
}

_ACEOF
7782
7783
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796

int main (void)
{

#ifdef errno
        int dummy=1;
#else
        force compilation error
#endif

 ;
 return 0;
}

_ACEOF







|







7790
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804

int main (void)
{

#ifdef errno
        int dummy=1;
#else
        #error force compilation error
#endif

 ;
 return 0;
}

_ACEOF
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824

int main (void)
{

#ifdef errno
          int dummy=1;
#else
          force compilation error
#endif

 ;
 return 0;
}

_ACEOF







|







7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832

int main (void)
{

#ifdef errno
          int dummy=1;
#else
          #error force compilation error
#endif

 ;
 return 0;
}

_ACEOF
18478
18479
18480
18481
18482
18483
18484

18485
18486
18487
18488
18489
18490
18491
    tmp_CFLAGS=""
    #
    case "$compiler_id" in
        #
      CLANG)
        #
                                tmp_CFLAGS="$tmp_CFLAGS -Qunused-arguments"

        ;;
        #
      DEC_C)
        #
                tmp_CFLAGS="$tmp_CFLAGS -std1"
                tmp_CFLAGS="$tmp_CFLAGS -noansi_alias"
                tmp_CFLAGS="$tmp_CFLAGS -warnprotos"







>







18486
18487
18488
18489
18490
18491
18492
18493
18494
18495
18496
18497
18498
18499
18500
    tmp_CFLAGS=""
    #
    case "$compiler_id" in
        #
      CLANG)
        #
                                tmp_CFLAGS="$tmp_CFLAGS -Qunused-arguments"
        tmp_CFLAGS="$tmp_CFLAGS -Werror-implicit-function-declaration"
        ;;
        #
      DEC_C)
        #
                tmp_CFLAGS="$tmp_CFLAGS -std1"
                tmp_CFLAGS="$tmp_CFLAGS -noansi_alias"
                tmp_CFLAGS="$tmp_CFLAGS -warnprotos"
19982
19983
19984
19985
19986
19987
19988
19989
19990
19991
19992
19993
19994
19995
19996
  squeeze tmp_CFLAGS

          fi
                    if test "$compiler_num" -ge "1000"; then
            tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough"  # we have silencing markup for clang 10.0 and above only
          fi
        fi
                                tmp_CFLAGS="$tmp_CFLAGS -Wno-pointer-bool-conversion"
        ;;
        #
      DEC_C)
        #
        if test "$want_warnings" = "yes"; then
                    tmp_CFLAGS="$tmp_CFLAGS -msg_enable level3"
        fi







<







19991
19992
19993
19994
19995
19996
19997

19998
19999
20000
20001
20002
20003
20004
  squeeze tmp_CFLAGS

          fi
                    if test "$compiler_num" -ge "1000"; then
            tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough"  # we have silencing markup for clang 10.0 and above only
          fi
        fi

        ;;
        #
      DEC_C)
        #
        if test "$want_warnings" = "yes"; then
                    tmp_CFLAGS="$tmp_CFLAGS -msg_enable level3"
        fi
21213
21214
21215
21216
21217
21218
21219


21220
21221
21222
21223
21224
21225
21226
CURL_CFLAG_EXTRAS=""
if test X"$want_werror" = Xyes; then
  CURL_CFLAG_EXTRAS="-Werror"
  if test "$compiler_id" = "GNU_C"; then
            if test "$compiler_num" -ge "500"; then
      CURL_CFLAG_EXTRAS="$CURL_CFLAG_EXTRAS -pedantic-errors"
    fi


  fi
fi



  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler halts on compilation errors" >&5
printf %s "checking if compiler halts on compilation errors... " >&6; }







>
>







21221
21222
21223
21224
21225
21226
21227
21228
21229
21230
21231
21232
21233
21234
21235
21236
CURL_CFLAG_EXTRAS=""
if test X"$want_werror" = Xyes; then
  CURL_CFLAG_EXTRAS="-Werror"
  if test "$compiler_id" = "GNU_C"; then
            if test "$compiler_num" -ge "500"; then
      CURL_CFLAG_EXTRAS="$CURL_CFLAG_EXTRAS -pedantic-errors"
    fi
  elif test "$compiler_id" = "CLANG"; then
    CURL_CFLAG_EXTRAS="$CURL_CFLAG_EXTRAS -pedantic-errors"
  fi
fi



  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler halts on compilation errors" >&5
printf %s "checking if compiler halts on compilation errors... " >&6; }
21459
21460
21461
21462
21463
21464
21465
21466
21467
21468
21469
21470
21471
21472
21473
21474
21475
21476
21477
21478
21479
21480
21481
21482
21483
21484
21485
21486
21487
21488
21489
21490
21491
21492
21493
21494
21495
21496
21497
21498
21499
21500
21501
21502
21503
21504
21505
21506
21507
21508
21509
21510
21511
21512
21513
21514
21515
21516
21517
21518
21519
    symbol_hiding_EXTERN="$tmp_EXTERN"
  else
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
  fi



      supports_curldebug="unknown"
  if test "$want_curldebug" = "yes"; then
    if test "x$enable_shared" != "xno" &&
      test "x$enable_shared" != "xyes"; then
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unknown enable_shared setting." >&5
printf "%s\n" "$as_me: WARNING: unknown enable_shared setting." >&2;}
      supports_curldebug="no"
    fi
    if test "x$enable_static" != "xno" &&
      test "x$enable_static" != "xyes"; then
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unknown enable_static setting." >&5
printf "%s\n" "$as_me: WARNING: unknown enable_static setting." >&2;}
      supports_curldebug="no"
    fi
    if test "$supports_curldebug" != "no"; then
      if test "$enable_shared" = "yes" &&
        test "x$xc_lt_shlib_use_no_undefined" = 'xyes'; then
        supports_curldebug="no"
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: shared library does not support undefined symbols." >&5
printf "%s\n" "$as_me: WARNING: shared library does not support undefined symbols." >&2;}
      fi
    fi
  fi
  #
  if test "$want_curldebug" = "yes"; then
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if curl debug memory tracking can be enabled" >&5
printf %s "checking if curl debug memory tracking can be enabled... " >&6; }
    test "$supports_curldebug" = "no" || supports_curldebug="yes"
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $supports_curldebug" >&5
printf "%s\n" "$supports_curldebug" >&6; }
    if test "$supports_curldebug" = "no"; then
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot enable curl debug memory tracking." >&5
printf "%s\n" "$as_me: WARNING: cannot enable curl debug memory tracking." >&2;}
      want_curldebug="no"
    fi
  fi

 if test x$want_curldebug = xyes; then
  CURLDEBUG_TRUE=
  CURLDEBUG_FALSE='#'
else
  CURLDEBUG_TRUE='#'
  CURLDEBUG_FALSE=
fi


supports_unittests=yes
# cross-compilation of unit tests static library/programs fails when
# libcurl shared library is built. This might be due to a libtool or
# automake issue. In this case we disable unit tests.
if test "x$cross_compiling" != "xno" &&
   test "x$enable_shared" != "xno"; then
  supports_unittests=no







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







21469
21470
21471
21472
21473
21474
21475















































21476
21477
21478
21479
21480
21481
21482
    symbol_hiding_EXTERN="$tmp_EXTERN"
  else
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
  fi

















































supports_unittests=yes
# cross-compilation of unit tests static library/programs fails when
# libcurl shared library is built. This might be due to a libtool or
# automake issue. In this case we disable unit tests.
if test "x$cross_compiling" != "xno" &&
   test "x$enable_shared" != "xno"; then
  supports_unittests=no
21735
21736
21737
21738
21739
21740
21741
21742
21743
21744
21745
21746
21747
21748
21749
21750
21751
21752
21753
21754
21755
21756
21757
21758
21759
21760
21761
21762
21763
21764
21765
21766
21767
21768
21769
21770
21771
21772
21773
21774
21775
21776
21777
21778
21779
21780
21781
21782
21783
21784
21785
21786
21787
21788
21789
21790
21791
21792
21793
21794
21795
21796
21797
21798
21799
21800
21801
21802
21803
21804
21805
21806
21807
21808
21809
21810
21811
printf "%s\n" "no" >&6; }
      CFLAGS=$old_CFLAGS
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
  fi



{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks" >&5
printf %s "checking whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks... " >&6; }
case $host_os in
  darwin*)
    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


#include <TargetConditionals.h>

int main (void)
{

#if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
      return 0;
#else
#error Not macOS
#endif

 ;
 return 0;
}

_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :

      build_for_macos="yes"

else $as_nop

      build_for_macos="no"

fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
    if test "x$build_for_macos" != xno; then
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
      LDFLAGS="$LDFLAGS -framework CoreFoundation -framework CoreServices -framework SystemConfiguration"
    else
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
    fi
    ;;
  *)
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
esac


  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking to see if the compiler supports __builtin_available()" >&5
printf %s "checking to see if the compiler supports __builtin_available()... " >&6; }
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


#include <stdlib.h>

int main (void)
{

      if (__builtin_available(macOS 10.8, iOS 5.0, *)) {}

 ;
 return 0;
}

_ACEOF
if ac_fn_c_try_compile "$LINENO"







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







<




|







21698
21699
21700
21701
21702
21703
21704


















































21705
21706
21707
21708
21709
21710
21711

21712
21713
21714
21715
21716
21717
21718
21719
21720
21721
21722
21723
printf "%s\n" "no" >&6; }
      CFLAGS=$old_CFLAGS
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
  fi





















































  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking to see if the compiler supports __builtin_available()" >&5
printf %s "checking to see if the compiler supports __builtin_available()... " >&6; }
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */




int main (void)
{

      if(__builtin_available(macOS 10.12, iOS 5.0, *)) {}

 ;
 return 0;
}

_ACEOF
if ac_fn_c_try_compile "$LINENO"
22293
22294
22295
22296
22297
22298
22299


22300
22301
22302
22303
22304
22305
22306

          USE_HYPER=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_HYPER"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_HYPER to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_HYPER to CURL_LIBRARY_PATH" >&6;}


fi

done

else $as_nop
  for d in `echo $DIR_HYPER | $SED -e 's/:/ /'`; do
        if test -f "$d/libhyper.a"; then







>
>







22205
22206
22207
22208
22209
22210
22211
22212
22213
22214
22215
22216
22217
22218
22219
22220

          USE_HYPER=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_HYPER"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_HYPER to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_HYPER to CURL_LIBRARY_PATH" >&6;}
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE hyper"

fi

done

else $as_nop
  for d in `echo $DIR_HYPER | $SED -e 's/:/ /'`; do
        if test -f "$d/libhyper.a"; then
22734
22735
22736
22737
22738
22739
22740
22741
22742
22743
22744
22745
22746
22747
22748
int main (void)
{
#if defined(__hpux) && defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600)
  return 0;
#elif defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)
  return 0;
#else
  force compilation error
#endif
}


_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :







|







22648
22649
22650
22651
22652
22653
22654
22655
22656
22657
22658
22659
22660
22661
22662
int main (void)
{
#if defined(__hpux) && defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600)
  return 0;
#elif defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED)
  return 0;
#else
  #error force compilation error
#endif
}


_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
23967
23968
23969
23970
23971
23972
23973

23974
23975
23976
23977
23978
23979
23980
printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h

    LIBS="$ZLIB_LIBS $clean_LIBS"

        AMFIXLIB="1"
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: found both libz and libz.h header" >&5
printf "%s\n" "$as_me: found both libz and libz.h header" >&6;}

    curl_zlib_msg="enabled"
  fi
fi

 if test x"$AMFIXLIB" = x1; then
  HAVE_LIBZ_TRUE=
  HAVE_LIBZ_FALSE='#'







>







23881
23882
23883
23884
23885
23886
23887
23888
23889
23890
23891
23892
23893
23894
23895
printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h

    LIBS="$ZLIB_LIBS $clean_LIBS"

        AMFIXLIB="1"
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: found both libz and libz.h header" >&5
printf "%s\n" "$as_me: found both libz and libz.h header" >&6;}
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE zlib"
    curl_zlib_msg="enabled"
  fi
fi

 if test x"$AMFIXLIB" = x1; then
  HAVE_LIBZ_TRUE=
  HAVE_LIBZ_FALSE='#'
24240
24241
24242
24243
24244
24245
24246

24247
24248
24249
24250
24251
24252
24253
       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_BROTLI"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_BROTLI to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_BROTLI to CURL_LIBRARY_PATH" >&6;}
       fi
    fi

  else
        LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi








>







24155
24156
24157
24158
24159
24160
24161
24162
24163
24164
24165
24166
24167
24168
24169
       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_BROTLI"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_BROTLI to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_BROTLI to CURL_LIBRARY_PATH" >&6;}
       fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libbrotlidec"
  else
        LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi

24505
24506
24507
24508
24509
24510
24511

24512
24513
24514
24515
24516
24517
24518
       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_ZSTD"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_ZSTD to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_ZSTD to CURL_LIBRARY_PATH" >&6;}
       fi
    fi

  else
        LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi








>







24421
24422
24423
24424
24425
24426
24427
24428
24429
24430
24431
24432
24433
24434
24435
       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_ZSTD"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_ZSTD to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_ZSTD to CURL_LIBRARY_PATH" >&6;}
       fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libzstd"
  else
        LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi

27040
27041
27042
27043
27044
27045
27046
27047
27048
27049
27050
27051
27052
27053
27054
27055

        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }

fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext

    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libressl" >&5
printf %s "checking for libressl... " >&6; }
    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


#include <openssl/opensslv.h>

int main (void)







|
|







26957
26958
26959
26960
26961
26962
26963
26964
26965
26966
26967
26968
26969
26970
26971
26972

        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }

fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext

    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for LibreSSL" >&5
printf %s "checking for LibreSSL... " >&6; }
    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


#include <openssl/opensslv.h>

int main (void)
27066
27067
27068
27069
27070
27071
27072
27073
27074
27075
27076
27077
27078
27079
27080
then :

      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }

printf "%s\n" "#define HAVE_LIBRESSL 1" >>confdefs.h

      ssl_msg="libressl"

else $as_nop

      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }

fi







|







26983
26984
26985
26986
26987
26988
26989
26990
26991
26992
26993
26994
26995
26996
26997
then :

      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }

printf "%s\n" "#define HAVE_LIBRESSL 1" >>confdefs.h

      ssl_msg="LibreSSL"

else $as_nop

      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }

fi
27146
27147
27148
27149
27150
27151
27152

27153
27154
27155
27156
27157
27158
27159
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_OPENSSL"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $LIB_OPENSSL to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $LIB_OPENSSL to CURL_LIBRARY_PATH" >&6;}
       fi
    fi
    check_for_ca_bundle=1

  fi

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi

if test X"$OPT_OPENSSL" != Xno &&
  test "$OPENSSL_ENABLED" != "1"; then







>







27063
27064
27065
27066
27067
27068
27069
27070
27071
27072
27073
27074
27075
27076
27077
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_OPENSSL"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $LIB_OPENSSL to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $LIB_OPENSSL to CURL_LIBRARY_PATH" >&6;}
       fi
    fi
    check_for_ca_bundle=1
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE openssl"
  fi

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi

if test X"$OPT_OPENSSL" != Xno &&
  test "$OPENSSL_ENABLED" != "1"; then
27267
27268
27269
27270
27271
27272
27273
27274
27275
27276
27277
27278
27279
27280
27281
27282
27283
27284



27285
27286
27287
27288
27289
27290
27291
  fi

fi

fi

if test "$OPENSSL_ENABLED" = "1"; then
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for QUIC support in OpenSSL" >&5
printf %s "checking for QUIC support in OpenSSL... " >&6; }
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


#include <openssl/ssl.h>

int main (void)
{




      OSSL_QUIC_client_method();

 ;
 return 0;
}

_ACEOF







|
|









>
>
>







27185
27186
27187
27188
27189
27190
27191
27192
27193
27194
27195
27196
27197
27198
27199
27200
27201
27202
27203
27204
27205
27206
27207
27208
27209
27210
27211
27212
  fi

fi

fi

if test "$OPENSSL_ENABLED" = "1"; then
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for QUIC support and OpenSSL >= 3.3" >&5
printf %s "checking for QUIC support and OpenSSL >= 3.3... " >&6; }
  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


#include <openssl/ssl.h>

int main (void)
{

      #if (OPENSSL_VERSION_NUMBER < 0x30300000L)
      #error need at least version 3.3.0
      #endif
      OSSL_QUIC_client_method();

 ;
 return 0;
}

_ACEOF
27573
27574
27575
27576
27577
27578
27579

27580
27581
27582
27583
27584
27585
27586
                                                  if test "x$cross_compiling" != "xyes"; then
            CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$gtlslib"
            export CURL_LIBRARY_PATH
            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $gtlslib to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $gtlslib to CURL_LIBRARY_PATH" >&6;}
          fi
        fi

      fi

    fi

  fi
  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi







>







27494
27495
27496
27497
27498
27499
27500
27501
27502
27503
27504
27505
27506
27507
27508
                                                  if test "x$cross_compiling" != "xyes"; then
            CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$gtlslib"
            export CURL_LIBRARY_PATH
            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $gtlslib to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $gtlslib to CURL_LIBRARY_PATH" >&6;}
          fi
        fi
        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE gnutls"
      fi

    fi

  fi
  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi
27879
27880
27881
27882
27883
27884
27885

27886
27887
27888
27889
27890
27891
27892
                                        if test "x$cross_compiling" != "xyes"; then
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$mbedtlslib"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $mbedtlslib to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $mbedtlslib to CURL_LIBRARY_PATH" >&6;}
        fi
      fi

    fi

  fi
  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi









>







27801
27802
27803
27804
27805
27806
27807
27808
27809
27810
27811
27812
27813
27814
27815
                                        if test "x$cross_compiling" != "xyes"; then
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$mbedtlslib"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $mbedtlslib to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $mbedtlslib to CURL_LIBRARY_PATH" >&6;}
        fi
      fi
      LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE mbedtls"
    fi

  fi
  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi


28112
28113
28114
28115
28116
28117
28118
28119
28120
28121
28122
28123
28124
28125
28126

      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wolfSSL_Init in -lwolfssl" >&5
printf %s "checking for wolfSSL_Init in -lwolfssl... " >&6; }
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


/* These aren't needed for detection and confuse WolfSSL.
   They are set up properly later if it is detected.  */
#undef SIZEOF_LONG
#undef SIZEOF_LONG_LONG
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>

int main (void)







|







28035
28036
28037
28038
28039
28040
28041
28042
28043
28044
28045
28046
28047
28048
28049

      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wolfSSL_Init in -lwolfssl" >&5
printf %s "checking for wolfSSL_Init in -lwolfssl... " >&6; }
      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


/* These are not needed for detection and confuse wolfSSL.
   They are set up properly later if it is detected.  */
#undef SIZEOF_LONG
#undef SIZEOF_LONG_LONG
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>

int main (void)
28141
28142
28143
28144
28145
28146
28147
28148
28149
28150
28151
28152
28153
28154
28155

printf "%s\n" "#define USE_WOLFSSL 1" >>confdefs.h

         USE_WOLFSSL=1

         WOLFSSL_ENABLED=1
         USE_WOLFSSL="yes"
         ssl_msg="WolfSSL"
         QUIC_ENABLED=yes
         test wolfssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes

else $as_nop

         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }







|







28064
28065
28066
28067
28068
28069
28070
28071
28072
28073
28074
28075
28076
28077
28078

printf "%s\n" "#define USE_WOLFSSL 1" >>confdefs.h

         USE_WOLFSSL=1

         WOLFSSL_ENABLED=1
         USE_WOLFSSL="yes"
         ssl_msg="wolfSSL"
         QUIC_ENABLED=yes
         test wolfssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes

else $as_nop

         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
28205
28206
28207
28208
28209
28210
28211
28212
28213
28214
28215
28216
28217
28218
28219
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of long long" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=$(echo "ac_cv_sizeof_long long" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_LONG_LONG $r" >>confdefs.h










|







28128
28129
28130
28131
28132
28133
28134
28135
28136
28137
28138
28139
28140
28141
28142
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of long long" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=`echo "ac_cv_sizeof_long long" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_LONG_LONG $r" >>confdefs.h



28264
28265
28266
28267
28268
28269
28270

28271
28272
28273
28274
28275
28276
28277
                                        if test "x$cross_compiling" != "xyes"; then
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$wolfssllibpath"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $wolfssllibpath to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $wolfssllibpath to CURL_LIBRARY_PATH" >&6;}
        fi
      fi

    else
        as_fn_error $? "--with-wolfssl but wolfSSL was not found or doesn't work" "$LINENO" 5
    fi

  fi
  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi







>







28187
28188
28189
28190
28191
28192
28193
28194
28195
28196
28197
28198
28199
28200
28201
                                        if test "x$cross_compiling" != "xyes"; then
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$wolfssllibpath"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $wolfssllibpath to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $wolfssllibpath to CURL_LIBRARY_PATH" >&6;}
        fi
      fi
      LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE wolfssl"
    else
        as_fn_error $? "--with-wolfssl but wolfSSL was not found or doesn't work" "$LINENO" 5
    fi

  fi
  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi
28755
28756
28757
28758
28759
28760
28761

28762
28763
28764
28765
28766
28767
28768
                              if test "x$cross_compiling" != "xyes"; then
        CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_RUSTLS"
        export CURL_LIBRARY_PATH
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $LIB_RUSTLS to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $LIB_RUSTLS to CURL_LIBRARY_PATH" >&6;}
      fi
    fi

  fi

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"

  if test X"$OPT_RUSTLS" != Xno &&
    test "$RUSTLS_ENABLED" != "1"; then
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OPT_RUSTLS: $OPT_RUSTLS" >&5







>







28679
28680
28681
28682
28683
28684
28685
28686
28687
28688
28689
28690
28691
28692
28693
                              if test "x$cross_compiling" != "xyes"; then
        CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_RUSTLS"
        export CURL_LIBRARY_PATH
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $LIB_RUSTLS to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $LIB_RUSTLS to CURL_LIBRARY_PATH" >&6;}
      fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE rustls"
  fi

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"

  if test X"$OPT_RUSTLS" != Xno &&
    test "$RUSTLS_ENABLED" != "1"; then
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: OPT_RUSTLS: $OPT_RUSTLS" >&5
28880
28881
28882
28883
28884
28885
28886
28887
28888
28889
28890
28891
28892
28893
28894
28895
28896
28897
28898

28899
28900
28901
28902
28903
28904
28905
          "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then
        ca="$want_ca"
    capath="$want_capath"
  elif test "x$want_ca" != "xno" -a "x$want_ca" != "xunset"; then
        ca="$want_ca"
    capath="no"
  elif test "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then
        if test "x$OPENSSL_ENABLED" != "x1" -a \
            "x$GNUTLS_ENABLED" != "x1" -a \
            "x$MBEDTLS_ENABLED" != "x1" -a \
            "x$WOLFSSL_ENABLED" != "x1"; then
      as_fn_error $? "--with-ca-path only works with OpenSSL, GnuTLS, mbedTLS or wolfSSL" "$LINENO" 5
    fi
    capath="$want_capath"
    ca="no"
  else
            ca="no"
    capath="no"
    if test "x$cross_compiling" != "xyes"; then

                  if test "x$want_ca" = "xunset"; then
                                if test "x$prefix" != xNONE; then
          cac="${prefix}/share/curl/curl-ca-bundle.crt"
        else
          cac="$ac_default_prefix/share/curl/curl-ca-bundle.crt"
        fi








<
<
<
<
<
<
|




|
>







28805
28806
28807
28808
28809
28810
28811






28812
28813
28814
28815
28816
28817
28818
28819
28820
28821
28822
28823
28824
28825
          "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then
        ca="$want_ca"
    capath="$want_capath"
  elif test "x$want_ca" != "xno" -a "x$want_ca" != "xunset"; then
        ca="$want_ca"
    capath="no"
  elif test "x$want_capath" != "xno" -a "x$want_capath" != "xunset"; then






        capath="$want_capath"
    ca="no"
  else
            ca="no"
    capath="no"
    if test "x$cross_compiling" != "xyes" -a \
            "x$curl_cv_native_windows" != "xyes"; then
                  if test "x$want_ca" = "xunset"; then
                                if test "x$prefix" != xNONE; then
          cac="${prefix}/share/curl/curl-ca-bundle.crt"
        else
          cac="$ac_default_prefix/share/curl/curl-ca-bundle.crt"
        fi

28914
28915
28916
28917
28918
28919
28920
28921
28922
28923
28924
28925
28926
28927
28928
28929
28930
28931
28932
28933
            break
          fi
        done
      fi
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: want $want_capath ca $ca" >&5
printf "%s\n" "$as_me: want $want_capath ca $ca" >&6;}
      if test "x$want_capath" = "xunset"; then
        if test "x$OPENSSL_ENABLED" = "x1" -o \
                "x$GNUTLS_ENABLED" = "x1" -o \
                "x$MBEDTLS_ENABLED" = "x1" -o \
                "x$WOLFSSL_ENABLED" = "x1"; then
          check_capath="/etc/ssl/certs"
        fi
      fi
    else
            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: skipped the ca-cert path detection when cross-compiling" >&5
printf "%s\n" "$as_me: WARNING: skipped the ca-cert path detection when cross-compiling" >&2;}
    fi
  fi








<
<
<
<
|
<







28834
28835
28836
28837
28838
28839
28840




28841

28842
28843
28844
28845
28846
28847
28848
            break
          fi
        done
      fi
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: want $want_capath ca $ca" >&5
printf "%s\n" "$as_me: want $want_capath ca $ca" >&6;}
      if test "x$want_capath" = "xunset"; then




        check_capath="/etc/ssl/certs"

      fi
    else
            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: skipped the ca-cert path detection when cross-compiling" >&5
printf "%s\n" "$as_me: WARNING: skipped the ca-cert path detection when cross-compiling" >&2;}
    fi
  fi

29233
29234
29235
29236
29237
29238
29239

29240
29241
29242
29243
29244
29245
29246
 curl_psl_msg="enabled"
        LIBPSL_ENABLED=1

printf "%s\n" "#define USE_LIBPSL 1" >>confdefs.h

        USE_LIBPSL=1



fi

done

else $as_nop
        LDFLAGS=$CLEANLDFLAGS







>







29148
29149
29150
29151
29152
29153
29154
29155
29156
29157
29158
29159
29160
29161
29162
 curl_psl_msg="enabled"
        LIBPSL_ENABLED=1

printf "%s\n" "#define USE_LIBPSL 1" >>confdefs.h

        USE_LIBPSL=1

        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libpsl"

fi

done

else $as_nop
        LDFLAGS=$CLEANLDFLAGS
29612
29613
29614
29615
29616
29617
29618
29619
29620
29621
29622
29623
29624
29625
29626
29627
29628
29629
29630
29631
29632
29633
29634
29635
29636
29637
29638
29639
29640
29641
29642
29643
29644

29645
29646
29647
29648
29649
29650
29651

fi


  ac_fn_c_check_header_compile "$LINENO" "libssh2.h" "ac_cv_header_libssh2_h" "$ac_includes_default"
if test "x$ac_cv_header_libssh2_h" = xyes
then :
  curl_ssh_msg="enabled (libSSH2)"
    LIBSSH2_ENABLED=1

printf "%s\n" "#define USE_LIBSSH2 1" >>confdefs.h

    USE_LIBSSH2=1


fi


  if test X"$OPT_LIBSSH2" != Xoff &&
     test "$LIBSSH2_ENABLED" != "1"; then
    as_fn_error $? "libSSH2 libs and/or directories were not found where specified!" "$LINENO" 5
  fi

  if test "$LIBSSH2_ENABLED" = "1"; then
    if test -n "$DIR_SSH2"; then

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH2"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_SSH2 to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_SSH2 to CURL_LIBRARY_PATH" >&6;}
       fi
    fi

  else
        LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_LIBSSH" != Xno; then
    CLEANLDFLAGS="$LDFLAGS"







|












|












>







29528
29529
29530
29531
29532
29533
29534
29535
29536
29537
29538
29539
29540
29541
29542
29543
29544
29545
29546
29547
29548
29549
29550
29551
29552
29553
29554
29555
29556
29557
29558
29559
29560
29561
29562
29563
29564
29565
29566
29567
29568

fi


  ac_fn_c_check_header_compile "$LINENO" "libssh2.h" "ac_cv_header_libssh2_h" "$ac_includes_default"
if test "x$ac_cv_header_libssh2_h" = xyes
then :
  curl_ssh_msg="enabled (libssh2)"
    LIBSSH2_ENABLED=1

printf "%s\n" "#define USE_LIBSSH2 1" >>confdefs.h

    USE_LIBSSH2=1


fi


  if test X"$OPT_LIBSSH2" != Xoff &&
     test "$LIBSSH2_ENABLED" != "1"; then
    as_fn_error $? "libssh2 libs and/or directories were not found where specified!" "$LINENO" 5
  fi

  if test "$LIBSSH2_ENABLED" = "1"; then
    if test -n "$DIR_SSH2"; then

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH2"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_SSH2 to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_SSH2 to CURL_LIBRARY_PATH" >&6;}
       fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libssh2"
  else
        LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_LIBSSH" != Xno; then
    CLEANLDFLAGS="$LDFLAGS"
29861
29862
29863
29864
29865
29866
29867
29868
29869
29870
29871
29872
29873
29874
29875
29876
29877
29878
29879
29880
29881
29882
29883
29884
29885
29886
29887
29888
29889
29890
29891
29892
29893

29894
29895
29896
29897
29898
29899
29900

fi


  ac_fn_c_check_header_compile "$LINENO" "libssh/libssh.h" "ac_cv_header_libssh_libssh_h" "$ac_includes_default"
if test "x$ac_cv_header_libssh_libssh_h" = xyes
then :
  curl_ssh_msg="enabled (libSSH)"
    LIBSSH_ENABLED=1

printf "%s\n" "#define USE_LIBSSH 1" >>confdefs.h

    USE_LIBSSH=1


fi


  if test X"$OPT_LIBSSH" != Xoff &&
     test "$LIBSSH_ENABLED" != "1"; then
    as_fn_error $? "libSSH libs and/or directories were not found where specified!" "$LINENO" 5
  fi

  if test "$LIBSSH_ENABLED" = "1"; then
    if test -n "$DIR_SSH"; then

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_SSH to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_SSH to CURL_LIBRARY_PATH" >&6;}
       fi
    fi

  else
        LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_WOLFSSH" != Xno; then
    CLEANLDFLAGS="$LDFLAGS"







|












|












>







29778
29779
29780
29781
29782
29783
29784
29785
29786
29787
29788
29789
29790
29791
29792
29793
29794
29795
29796
29797
29798
29799
29800
29801
29802
29803
29804
29805
29806
29807
29808
29809
29810
29811
29812
29813
29814
29815
29816
29817
29818

fi


  ac_fn_c_check_header_compile "$LINENO" "libssh/libssh.h" "ac_cv_header_libssh_libssh_h" "$ac_includes_default"
if test "x$ac_cv_header_libssh_libssh_h" = xyes
then :
  curl_ssh_msg="enabled (libssh)"
    LIBSSH_ENABLED=1

printf "%s\n" "#define USE_LIBSSH 1" >>confdefs.h

    USE_LIBSSH=1


fi


  if test X"$OPT_LIBSSH" != Xoff &&
     test "$LIBSSH_ENABLED" != "1"; then
    as_fn_error $? "libssh libs and/or directories were not found where specified!" "$LINENO" 5
  fi

  if test "$LIBSSH_ENABLED" = "1"; then
    if test -n "$DIR_SSH"; then

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH"
         export CURL_LIBRARY_PATH
         { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_SSH to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_SSH to CURL_LIBRARY_PATH" >&6;}
       fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libssh"
  else
        LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_WOLFSSH" != Xno; then
    CLEANLDFLAGS="$LDFLAGS"
30203
30204
30205
30206
30207
30208
30209

30210
30211
30212
30213
30214
30215
30216
 curl_rtmp_msg="enabled (librtmp)"
        LIBRTMP_ENABLED=1

printf "%s\n" "#define USE_LIBRTMP 1" >>confdefs.h

        USE_LIBRTMP=1



fi

done

else $as_nop
        LDFLAGS=$CLEANLDFLAGS







>







30121
30122
30123
30124
30125
30126
30127
30128
30129
30130
30131
30132
30133
30134
30135
 curl_rtmp_msg="enabled (librtmp)"
        LIBRTMP_ENABLED=1

printf "%s\n" "#define USE_LIBRTMP 1" >>confdefs.h

        USE_LIBRTMP=1

        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE librtmp"

fi

done

else $as_nop
        LDFLAGS=$CLEANLDFLAGS
30874
30875
30876
30877
30878
30879
30880

30881
30882
30883
30884
30885
30886
30887
    curl_idn_msg="enabled (libidn2)"
    if test -n "$IDN_DIR" -a "x$cross_compiling" != "xyes"; then
      CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$IDN_DIR"
      export CURL_LIBRARY_PATH
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $IDN_DIR to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $IDN_DIR to CURL_LIBRARY_PATH" >&6;}
    fi

  else
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find libraries for IDN support: IDN disabled" >&5
printf "%s\n" "$as_me: WARNING: Cannot find libraries for IDN support: IDN disabled" >&2;}
    CPPFLAGS="$clean_CPPFLAGS"
    LDFLAGS="$clean_LDFLAGS"
    LIBS="$clean_LIBS"
  fi







>







30793
30794
30795
30796
30797
30798
30799
30800
30801
30802
30803
30804
30805
30806
30807
    curl_idn_msg="enabled (libidn2)"
    if test -n "$IDN_DIR" -a "x$cross_compiling" != "xyes"; then
      CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$IDN_DIR"
      export CURL_LIBRARY_PATH
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $IDN_DIR to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $IDN_DIR to CURL_LIBRARY_PATH" >&6;}
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="libidn2 $LIBCURL_PC_REQUIRES_PRIVATE"
  else
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find libraries for IDN support: IDN disabled" >&5
printf "%s\n" "$as_me: WARNING: Cannot find libraries for IDN support: IDN disabled" >&2;}
    CPPFLAGS="$clean_CPPFLAGS"
    LDFLAGS="$clean_LDFLAGS"
    LIBS="$clean_LIBS"
  fi
31155
31156
31157
31158
31159
31160
31161

31162
31163
31164
31165
31166
31167
31168
 curl_h2_msg="enabled (nghttp2)"
        NGHTTP2_ENABLED=1

printf "%s\n" "#define USE_NGHTTP2 1" >>confdefs.h

        USE_NGHTTP2=1



fi

done

     CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_H2"
     export CURL_LIBRARY_PATH







>







31075
31076
31077
31078
31079
31080
31081
31082
31083
31084
31085
31086
31087
31088
31089
 curl_h2_msg="enabled (nghttp2)"
        NGHTTP2_ENABLED=1

printf "%s\n" "#define USE_NGHTTP2 1" >>confdefs.h

        USE_NGHTTP2=1

        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libnghttp2"

fi

done

     CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_H2"
     export CURL_LIBRARY_PATH
31442
31443
31444
31445
31446
31447
31448

31449
31450
31451
31452
31453
31454
31455

          USE_NGTCP2=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_TCP2"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_TCP2 to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_TCP2 to CURL_LIBRARY_PATH" >&6;}


fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS







>







31363
31364
31365
31366
31367
31368
31369
31370
31371
31372
31373
31374
31375
31376
31377

          USE_NGTCP2=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_TCP2"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_TCP2 to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_TCP2 to CURL_LIBRARY_PATH" >&6;}
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2"

fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS
31696
31697
31698
31699
31700
31701
31702

31703
31704
31705
31706
31707
31708
31709

          USE_NGTCP2_CRYPTO_QUICTLS=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_QUICTLS"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH" >&6;}


fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS







>







31618
31619
31620
31621
31622
31623
31624
31625
31626
31627
31628
31629
31630
31631
31632

          USE_NGTCP2_CRYPTO_QUICTLS=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_QUICTLS"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH" >&6;}
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2_crypto_quictls"

fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS
31949
31950
31951
31952
31953
31954
31955

31956
31957
31958
31959
31960
31961
31962

          USE_NGTCP2_CRYPTO_BORINGSSL=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_BORINGSSL"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH" >&6;}


fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS







>







31872
31873
31874
31875
31876
31877
31878
31879
31880
31881
31882
31883
31884
31885
31886

          USE_NGTCP2_CRYPTO_BORINGSSL=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_BORINGSSL"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH" >&6;}
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2_crypto_boringssl"

fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS
32202
32203
32204
32205
32206
32207
32208

32209
32210
32211
32212
32213
32214
32215

          USE_NGTCP2_CRYPTO_GNUTLS=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_GNUTLS"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH" >&6;}


fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS







>







32126
32127
32128
32129
32130
32131
32132
32133
32134
32135
32136
32137
32138
32139
32140

          USE_NGTCP2_CRYPTO_GNUTLS=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_GNUTLS"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH" >&6;}
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2_crypto_gnutls"

fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS
32455
32456
32457
32458
32459
32460
32461

32462
32463
32464
32465
32466
32467
32468

          USE_NGTCP2_CRYPTO_WOLFSSL=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_WOLFSSL"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH" >&6;}


fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS







>







32380
32381
32382
32383
32384
32385
32386
32387
32388
32389
32390
32391
32392
32393
32394

          USE_NGTCP2_CRYPTO_WOLFSSL=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_WOLFSSL"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH" >&6;}
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2_crypto_wolfssl"

fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS
32506
32507
32508
32509
32510
32511
32512
32513
32514
32515
32516
32517
32518
32519
32520
curl_openssl_quic_msg="no      (--with-openssl-quic)"
if test "x$want_openssl_quic" = "xyes"; then

  if test "$NGTCP2_ENABLED" = 1; then
    as_fn_error $? "--with-openssl-quic and --with-ngtcp2 are mutually exclusive" "$LINENO" 5
  fi
  if test "$HAVE_OPENSSL_QUIC" != 1; then
    as_fn_error $? "--with-openssl-quic requires quic support in OpenSSL" "$LINENO" 5
  fi

printf "%s\n" "#define USE_OPENSSL_QUIC 1" >>confdefs.h

  USE_OPENSSL_QUIC=1

fi







|







32432
32433
32434
32435
32436
32437
32438
32439
32440
32441
32442
32443
32444
32445
32446
curl_openssl_quic_msg="no      (--with-openssl-quic)"
if test "x$want_openssl_quic" = "xyes"; then

  if test "$NGTCP2_ENABLED" = 1; then
    as_fn_error $? "--with-openssl-quic and --with-ngtcp2 are mutually exclusive" "$LINENO" 5
  fi
  if test "$HAVE_OPENSSL_QUIC" != 1; then
    as_fn_error $? "--with-openssl-quic requires quic support and OpenSSL >= 3.3.0" "$LINENO" 5
  fi

printf "%s\n" "#define USE_OPENSSL_QUIC 1" >>confdefs.h

  USE_OPENSSL_QUIC=1

fi
32547
32548
32549
32550
32551
32552
32553





32554
32555
32556
32557
32558
32559
32560
        want_nghttp3="yes"
    want_nghttp3_path="$withval/lib/pkgconfig"
    ;;
esac

curl_http3_msg="no      (--with-nghttp3)"
if test X"$want_nghttp3" != Xno; then






    CLEANLDFLAGS="$LDFLAGS"
  CLEANCPPFLAGS="$CPPFLAGS"
  CLEANLIBS="$LIBS"


    if test -n "$PKG_CONFIG"; then







>
>
>
>
>







32473
32474
32475
32476
32477
32478
32479
32480
32481
32482
32483
32484
32485
32486
32487
32488
32489
32490
32491
        want_nghttp3="yes"
    want_nghttp3_path="$withval/lib/pkgconfig"
    ;;
esac

curl_http3_msg="no      (--with-nghttp3)"
if test X"$want_nghttp3" != Xno; then

  if test "x$USE_NGTCP2" != "x1" -a "x$USE_OPENSSL_QUIC" != "x1"; then
    # without ngtcp2 or openssl quic, nghttp3 is of no use for us
    as_fn_error $? "nghttp3 enabled without a QUIC library; enable ngtcp2 or OpenSSL-QUIC" "$LINENO" 5
  fi

    CLEANLDFLAGS="$LDFLAGS"
  CLEANCPPFLAGS="$CPPFLAGS"
  CLEANLIBS="$LIBS"


    if test -n "$PKG_CONFIG"; then
32779
32780
32781
32782
32783
32784
32785

32786
32787
32788
32789
32790
32791
32792

          USE_NGHTTP3=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGHTTP3"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH" >&6;}


fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS







>







32710
32711
32712
32713
32714
32715
32716
32717
32718
32719
32720
32721
32722
32723
32724

          USE_NGHTTP3=1

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGHTTP3"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH" >&6;}
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libnghttp3"

fi

done

else $as_nop
          LDFLAGS=$CLEANLDFLAGS
33112
33113
33114
33115
33116
33117
33118

33119
33120
33121
33122
33123
33124
33125

fi

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_QUICHE"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_QUICHE to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_QUICHE to CURL_LIBRARY_PATH" >&6;}

fi

done

else $as_nop
          as_fn_error $? "couldn't use quiche" "$LINENO" 5








>







33044
33045
33046
33047
33048
33049
33050
33051
33052
33053
33054
33055
33056
33057
33058

fi

          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_QUICHE"
          export CURL_LIBRARY_PATH
          { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_QUICHE to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_QUICHE to CURL_LIBRARY_PATH" >&6;}
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE quiche"
fi

done

else $as_nop
          as_fn_error $? "couldn't use quiche" "$LINENO" 5

33243
33244
33245
33246
33247
33248
33249
33250
33251
33252
33253
33254
33255
33256
33257
33258

        USE_MSH3=1

        CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_MSH3"
        export CURL_LIBRARY_PATH
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_MSH3 to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_MSH3 to CURL_LIBRARY_PATH" >&6;}
else $as_nop
  experimental="$experimental HTTP3"

fi

done

else $as_nop
        LDFLAGS=$CLEANLDFLAGS







|
|







33176
33177
33178
33179
33180
33181
33182
33183
33184
33185
33186
33187
33188
33189
33190
33191

        USE_MSH3=1

        CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_MSH3"
        export CURL_LIBRARY_PATH
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Added $DIR_MSH3 to CURL_LIBRARY_PATH" >&5
printf "%s\n" "$as_me: Added $DIR_MSH3 to CURL_LIBRARY_PATH" >&6;}
        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libmsh3"
        experimental="$experimental HTTP3"

fi

done

else $as_nop
        LDFLAGS=$CLEANLDFLAGS
33439
33440
33441
33442
33443
33444
33445
33446
33447
33448
33449
33450
33451
33452
33453
      else
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5
printf "%s\n" "found" >&6; }
      fi
    fi

    if test "$PKGCONFIG" != "no" ; then
      FISH_FUNCTIONS_DIR="$($PKGCONFIG --variable completionsdir fish)"
    else
      FISH_FUNCTIONS_DIR="$datarootdir/fish/vendor_completions.d"
    fi

    ;;
  *)
        FISH_FUNCTIONS_DIR="$withval"







|







33372
33373
33374
33375
33376
33377
33378
33379
33380
33381
33382
33383
33384
33385
33386
      else
        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5
printf "%s\n" "found" >&6; }
      fi
    fi

    if test "$PKGCONFIG" != "no" ; then
      FISH_FUNCTIONS_DIR=`$PKGCONFIG --variable completionsdir fish`
    else
      FISH_FUNCTIONS_DIR="$datarootdir/fish/vendor_completions.d"
    fi

    ;;
  *)
        FISH_FUNCTIONS_DIR="$withval"
34578
34579
34580
34581
34582
34583
34584
































34585
34586
34587
34588
34589
34590
34591


"
if test "x$ac_cv_header_sys_wait_h" = xyes
then :
  printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h

































fi
ac_fn_c_check_header_compile "$LINENO" "setjmp.h" "ac_cv_header_setjmp_h" "
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







34511
34512
34513
34514
34515
34516
34517
34518
34519
34520
34521
34522
34523
34524
34525
34526
34527
34528
34529
34530
34531
34532
34533
34534
34535
34536
34537
34538
34539
34540
34541
34542
34543
34544
34545
34546
34547
34548
34549
34550
34551
34552
34553
34554
34555
34556


"
if test "x$ac_cv_header_sys_wait_h" = xyes
then :
  printf "%s\n" "#define HAVE_SYS_WAIT_H 1" >>confdefs.h

fi
ac_fn_c_check_header_compile "$LINENO" "sys/eventfd.h" "ac_cv_header_sys_eventfd_h" "
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#elif defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif


"
if test "x$ac_cv_header_sys_eventfd_h" = xyes
then :
  printf "%s\n" "#define HAVE_SYS_EVENTFD_H 1" >>confdefs.h

fi
ac_fn_c_check_header_compile "$LINENO" "setjmp.h" "ac_cv_header_setjmp_h" "
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
34917
34918
34919
34920
34921
34922
34923
34924
34925
34926
34927
34928
34929
34930
34931
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of size_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=$(echo "ac_cv_sizeof_size_t" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_SIZE_T $r" >>confdefs.h










|







34882
34883
34884
34885
34886
34887
34888
34889
34890
34891
34892
34893
34894
34895
34896
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of size_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=`echo "ac_cv_sizeof_size_t" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_SIZE_T $r" >>confdefs.h



34966
34967
34968
34969
34970
34971
34972
34973
34974
34975
34976
34977
34978
34979
34980
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of long" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=$(echo "ac_cv_sizeof_long" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_LONG $r" >>confdefs.h










|







34931
34932
34933
34934
34935
34936
34937
34938
34939
34940
34941
34942
34943
34944
34945
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of long" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=`echo "ac_cv_sizeof_long" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_LONG $r" >>confdefs.h



35015
35016
35017
35018
35019
35020
35021
35022
35023
35024
35025
35026
35027
35028
35029
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of int" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=$(echo "ac_cv_sizeof_int" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_INT $r" >>confdefs.h










|







34980
34981
34982
34983
34984
34985
34986
34987
34988
34989
34990
34991
34992
34993
34994
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of int" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=`echo "ac_cv_sizeof_int" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_INT $r" >>confdefs.h



35064
35065
35066
35067
35068
35069
35070
35071
35072
35073
35074
35075
35076
35077
35078
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of time_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=$(echo "ac_cv_sizeof_time_t" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_TIME_T $r" >>confdefs.h










|







35029
35030
35031
35032
35033
35034
35035
35036
35037
35038
35039
35040
35041
35042
35043
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of time_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=`echo "ac_cv_sizeof_time_t" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_TIME_T $r" >>confdefs.h



35113
35114
35115
35116
35117
35118
35119
35120
35121
35122
35123
35124
35125
35126
35127
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of off_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=$(echo "ac_cv_sizeof_off_t" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_OFF_T $r" >>confdefs.h










|







35078
35079
35080
35081
35082
35083
35084
35085
35086
35087
35088
35089
35090
35091
35092
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of off_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=`echo "ac_cv_sizeof_off_t" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_OFF_T $r" >>confdefs.h



35167
35168
35169
35170
35171
35172
35173
35174
35175
35176
35177
35178
35179
35180
35181
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of curl_off_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=$(echo "ac_cv_sizeof_curl_off_t" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_CURL_OFF_T $r" >>confdefs.h










|







35132
35133
35134
35135
35136
35137
35138
35139
35140
35141
35142
35143
35144
35145
35146
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of curl_off_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=`echo "ac_cv_sizeof_curl_off_t" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_CURL_OFF_T $r" >>confdefs.h



35218
35219
35220
35221
35222
35223
35224
35225
35226
35227
35228
35229
35230
35231
35232
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of curl_socket_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=$(echo "ac_cv_sizeof_curl_socket_t" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_CURL_SOCKET_T $r" >>confdefs.h










|







35183
35184
35185
35186
35187
35188
35189
35190
35191
35192
35193
35194
35195
35196
35197
    fi
  done
  if test $r -eq 0; then
    as_fn_error $? "Failed to find size of curl_socket_t" "$LINENO" 5
  fi
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $r" >&5
printf "%s\n" "$r" >&6; }
    tname=`echo "ac_cv_sizeof_curl_socket_t" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"


printf "%s\n" "#define SIZEOF_CURL_SOCKET_T $r" >>confdefs.h



37841
37842
37843
37844
37845
37846
37847
37848
37849
37850
37851
37852
37853
37854
37855
        $curl_includes_netdb

int main (void)
{
#ifdef h_errno
  return 0;
#else
  force compilation error
#endif
}


_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :







|







37806
37807
37808
37809
37810
37811
37812
37813
37814
37815
37816
37817
37818
37819
37820
        $curl_includes_netdb

int main (void)
{
#ifdef h_errno
  return 0;
#else
  #error force compilation error
#endif
}


_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
37914
37915
37916
37917
37918
37919
37920
37921
37922
37923
37924
37925
37926
37927
37928
{

#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
          return 0;
#elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
          return 0;
#else
          force compilation error
#endif

 ;
 return 0;
}

_ACEOF







|







37879
37880
37881
37882
37883
37884
37885
37886
37887
37888
37889
37890
37891
37892
37893
{

#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
          return 0;
#elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
          return 0;
#else
          #error force compilation error
#endif

 ;
 return 0;
}

_ACEOF
44166
44167
44168
44169
44170
44171
44172




44173
44174



44175

44176

44177
44178
44179
44180
44181
44182
44183





44184



44185

44186
44187
44188
44189
44190
44191
44192

44193
44194
44195
44196

44197

44198





44199
44200
44201



44202



44203

44204
44205
44206
44207

44208

44209

44210


44211
44212
44213




44214
44215





44216





44217





44218





44219





44220

44221


44222
44223
44224




44225





44226
44227




44228
44229




44230

44231
44232
44233
44234
44235
44236
44237
44238
else $as_nop

printf "%s\n" "#define HAVE_DECL_GETPWUID_R_MISSING 1" >>confdefs.h

fi







  for ac_func in _fseeki64 arc4random fnmatch fseeko geteuid getpass_r getppid getpwuid getpwuid_r getrlimit gettimeofday if_nametoindex mach_absolute_time pipe sched_yield sendmsg setlocale setmode setrlimit snprintf utime utimes



do :

  as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh`

ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
if eval test \"x\$"$as_ac_var"\" = x"yes"
then :
  cat >>confdefs.h <<_ACEOF
#define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF










else $as_nop


  func="$ac_func"
  eval skipcheck=\$skipcheck_$func
  if test "x$skipcheck" != "xyes"; then
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking deeper for $func" >&5
printf %s "checking deeper for $func... " >&6; }
    cat confdefs.h - <<_ACEOF >conftest.$ac_ext

/* end confdefs.h.  */




int main (void)

{






        $func ();




 ;



 return 0;

}

_ACEOF
if ac_fn_c_try_link "$LINENO"

then :



      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5


printf "%s\n" "yes" >&6; }
      eval "ac_cv_func_$func=yes"





cat >>confdefs.h <<_ACEOF
#define `echo "HAVE_$func" | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' | sed 's/^A-Z0-9_/_/g'` 1





_ACEOF

















else $as_nop







      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: but still no" >&5


printf "%s\n" "but still no" >&6; }

fi




rm -f core conftest.err conftest.$ac_objext conftest.beam \





    conftest$ac_exeext conftest.$ac_ext
  fi





fi






done

ac_fn_check_decl "$LINENO" "fseeko" "ac_cv_have_decl_fseeko" "#include <stdio.h>
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_fseeko" = xyes
then :

printf "%s\n" "#define HAVE_DECL_FSEEKO 1" >>confdefs.h







>
>
>
>

<
>
>
>
|
>
|
>
|
|

|
<
<

>
>
>
>
>

>
>
>
|
>

|
|
|
<
<
<
>
|

|
|
>
|
>
|
>
>
>
>
>

|
|
>
>
>
|
>
>
>
|
>
|
|
<
|
>

>

>
|
>
>
|
<

>
>
>
>
|
|
>
>
>
>
>
|
>
>
>
>
>

>
>
>
>
>

>
>
>
>
>
|
>
>
>
>
>

>
|
>
>
|


>
>
>
>
|
>
>
>
>
>
|
|
>
>
>
>


>
>
>
>

>
|







44131
44132
44133
44134
44135
44136
44137
44138
44139
44140
44141
44142

44143
44144
44145
44146
44147
44148
44149
44150
44151
44152
44153


44154
44155
44156
44157
44158
44159
44160
44161
44162
44163
44164
44165
44166
44167
44168
44169



44170
44171
44172
44173
44174
44175
44176
44177
44178
44179
44180
44181
44182
44183
44184
44185
44186
44187
44188
44189
44190
44191
44192
44193
44194
44195
44196
44197

44198
44199
44200
44201
44202
44203
44204
44205
44206
44207

44208
44209
44210
44211
44212
44213
44214
44215
44216
44217
44218
44219
44220
44221
44222
44223
44224
44225
44226
44227
44228
44229
44230
44231
44232
44233
44234
44235
44236
44237
44238
44239
44240
44241
44242
44243
44244
44245
44246
44247
44248
44249
44250
44251
44252
44253
44254
44255
44256
44257
44258
44259
44260
44261
44262
44263
44264
44265
44266
44267
44268
44269
44270
44271
44272
44273
44274
44275
44276
44277
44278
44279
44280
44281
44282
44283
else $as_nop

printf "%s\n" "#define HAVE_DECL_GETPWUID_R_MISSING 1" >>confdefs.h

fi


ac_fn_c_check_func "$LINENO" "_fseeki64" "ac_cv_func__fseeki64"
if test "x$ac_cv_func__fseeki64" = xyes
then :
  printf "%s\n" "#define HAVE__FSEEKI64 1" >>confdefs.h


fi
ac_fn_c_check_func "$LINENO" "arc4random" "ac_cv_func_arc4random"
if test "x$ac_cv_func_arc4random" = xyes
then :
  printf "%s\n" "#define HAVE_ARC4RANDOM 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "eventfd" "ac_cv_func_eventfd"
if test "x$ac_cv_func_eventfd" = xyes
then :
  printf "%s\n" "#define HAVE_EVENTFD 1" >>confdefs.h



fi
ac_fn_c_check_func "$LINENO" "fnmatch" "ac_cv_func_fnmatch"
if test "x$ac_cv_func_fnmatch" = xyes
then :
  printf "%s\n" "#define HAVE_FNMATCH 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "fseeko" "ac_cv_func_fseeko"
if test "x$ac_cv_func_fseeko" = xyes
then :
  printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "geteuid" "ac_cv_func_geteuid"
if test "x$ac_cv_func_geteuid" = xyes



then :
  printf "%s\n" "#define HAVE_GETEUID 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "getpass_r" "ac_cv_func_getpass_r"
if test "x$ac_cv_func_getpass_r" = xyes
then :
  printf "%s\n" "#define HAVE_GETPASS_R 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "getppid" "ac_cv_func_getppid"
if test "x$ac_cv_func_getppid" = xyes
then :
  printf "%s\n" "#define HAVE_GETPPID 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "getpwuid" "ac_cv_func_getpwuid"
if test "x$ac_cv_func_getpwuid" = xyes
then :
  printf "%s\n" "#define HAVE_GETPWUID 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "getpwuid_r" "ac_cv_func_getpwuid_r"
if test "x$ac_cv_func_getpwuid_r" = xyes
then :
  printf "%s\n" "#define HAVE_GETPWUID_R 1" >>confdefs.h

fi

ac_fn_c_check_func "$LINENO" "getrlimit" "ac_cv_func_getrlimit"
if test "x$ac_cv_func_getrlimit" = xyes
then :
  printf "%s\n" "#define HAVE_GETRLIMIT 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
if test "x$ac_cv_func_gettimeofday" = xyes
then :
  printf "%s\n" "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h


fi
ac_fn_c_check_func "$LINENO" "if_nametoindex" "ac_cv_func_if_nametoindex"
if test "x$ac_cv_func_if_nametoindex" = xyes
then :
  printf "%s\n" "#define HAVE_IF_NAMETOINDEX 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "mach_absolute_time" "ac_cv_func_mach_absolute_time"
if test "x$ac_cv_func_mach_absolute_time" = xyes
then :
  printf "%s\n" "#define HAVE_MACH_ABSOLUTE_TIME 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "pipe" "ac_cv_func_pipe"
if test "x$ac_cv_func_pipe" = xyes
then :
  printf "%s\n" "#define HAVE_PIPE 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "sched_yield" "ac_cv_func_sched_yield"
if test "x$ac_cv_func_sched_yield" = xyes
then :
  printf "%s\n" "#define HAVE_SCHED_YIELD 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "sendmsg" "ac_cv_func_sendmsg"
if test "x$ac_cv_func_sendmsg" = xyes
then :
  printf "%s\n" "#define HAVE_SENDMSG 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "setlocale" "ac_cv_func_setlocale"
if test "x$ac_cv_func_setlocale" = xyes
then :
  printf "%s\n" "#define HAVE_SETLOCALE 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "setmode" "ac_cv_func_setmode"
if test "x$ac_cv_func_setmode" = xyes
then :
  printf "%s\n" "#define HAVE_SETMODE 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "setrlimit" "ac_cv_func_setrlimit"
if test "x$ac_cv_func_setrlimit" = xyes
then :
  printf "%s\n" "#define HAVE_SETRLIMIT 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf"
if test "x$ac_cv_func_snprintf" = xyes
then :
  printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "utime" "ac_cv_func_utime"
if test "x$ac_cv_func_utime" = xyes
then :
  printf "%s\n" "#define HAVE_UTIME 1" >>confdefs.h

fi
ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes"
if test "x$ac_cv_func_utimes" = xyes
then :
  printf "%s\n" "#define HAVE_UTIMES 1" >>confdefs.h

fi


ac_fn_check_decl "$LINENO" "fseeko" "ac_cv_have_decl_fseeko" "#include <stdio.h>
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_fseeko" = xyes
then :

printf "%s\n" "#define HAVE_DECL_FSEEKO 1" >>confdefs.h
44734
44735
44736
44737
44738
44739
44740

44741
44742
44743
44744
44745
44746
44747
printf "%s\n" "#define USE_ARES 1" >>confdefs.h


printf "%s\n" "#define CARES_NO_DEPRECATED 1" >>confdefs.h

      USE_ARES=1


      curl_res_msg="c-ares"
    fi
  fi


if test "x$curl_cv_native_windows" != "xyes" &&
   test "x$enable_shared" = "xyes"; then







>







44779
44780
44781
44782
44783
44784
44785
44786
44787
44788
44789
44790
44791
44792
44793
printf "%s\n" "#define USE_ARES 1" >>confdefs.h


printf "%s\n" "#define CARES_NO_DEPRECATED 1" >>confdefs.h

      USE_ARES=1

      LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libcares"
      curl_res_msg="c-ares"
    fi
  fi


if test "x$curl_cv_native_windows" != "xyes" &&
   test "x$enable_shared" = "xyes"; then
44776
44777
44778
44779
44780
44781
44782






















































44783
44784
44785
44786
44787
44788
44789
    *)
            want_thres="yes"
      ;;
  esac
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_thres" >&5
printf "%s\n" "$want_thres" >&6; }























































fi

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use POSIX threads for threaded resolver" >&5
printf %s "checking whether to use POSIX threads for threaded resolver... " >&6; }
# Check whether --enable-pthreads was given.
if test ${enable_pthreads+y}
then :







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







44822
44823
44824
44825
44826
44827
44828
44829
44830
44831
44832
44833
44834
44835
44836
44837
44838
44839
44840
44841
44842
44843
44844
44845
44846
44847
44848
44849
44850
44851
44852
44853
44854
44855
44856
44857
44858
44859
44860
44861
44862
44863
44864
44865
44866
44867
44868
44869
44870
44871
44872
44873
44874
44875
44876
44877
44878
44879
44880
44881
44882
44883
44884
44885
44886
44887
44888
44889
    *)
            want_thres="yes"
      ;;
  esac
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $want_thres" >&5
printf "%s\n" "$want_thres" >&6; }


  if test "$ipv6" = yes; then

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks" >&5
printf %s "checking whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks... " >&6; }
case $host_os in
  darwin*)
    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h.  */


#include <sys/types.h>
#include <TargetConditionals.h>

int main (void)
{

#if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
      return 0;
#else
#error Not macOS
#endif

 ;
 return 0;
}

_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :

      build_for_macos="yes"

else $as_nop

      build_for_macos="no"

fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
    if test "x$build_for_macos" != xno; then
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
      LDFLAGS="$LDFLAGS -framework CoreFoundation -framework CoreServices -framework SystemConfiguration"
    else
      { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
    fi
    ;;
  *)
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
esac

  fi
fi

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use POSIX threads for threaded resolver" >&5
printf %s "checking whether to use POSIX threads for threaded resolver... " >&6; }
# Check whether --enable-pthreads was given.
if test ${enable_pthreads+y}
then :
45762
45763
45764
45765
45766
45767
45768
45769
45770
45771
45772
45773
45774
45775
45776
45777
45778
45779
45780
45781
45782
45783
45784
45785
45786
45787
45788
45789
45790

  for ac_func in SSL_set1_ech_config_list
do :
  ac_fn_c_check_func "$LINENO" "SSL_set1_ech_config_list" "ac_cv_func_SSL_set1_ech_config_list"
if test "x$ac_cv_func_SSL_set1_ech_config_list" = xyes
then :
  printf "%s\n" "#define HAVE_SSL_SET1_ECH_CONFIG_LIST 1" >>confdefs.h
 ECH_SUPPORT="ECH support available via boringssl with SSL_set1_ech_config_list"
      ECH_ENABLED=1
fi

done
  fi
  if test "x$WOLFSSL_ENABLED" = "x1"; then

  for ac_func in wolfSSL_CTX_GenerateEchConfig
do :
  ac_fn_c_check_func "$LINENO" "wolfSSL_CTX_GenerateEchConfig" "ac_cv_func_wolfSSL_CTX_GenerateEchConfig"
if test "x$ac_cv_func_wolfSSL_CTX_GenerateEchConfig" = xyes
then :
  printf "%s\n" "#define HAVE_WOLFSSL_CTX_GENERATEECHCONFIG 1" >>confdefs.h
 ECH_SUPPORT="ECH support available via WolfSSL with wolfSSL_CTX_GenerateEchConfig"
      ECH_ENABLED=1
fi

done
  fi

    if test "x$ECH_ENABLED" = "x1"; then







|













|







45862
45863
45864
45865
45866
45867
45868
45869
45870
45871
45872
45873
45874
45875
45876
45877
45878
45879
45880
45881
45882
45883
45884
45885
45886
45887
45888
45889
45890

  for ac_func in SSL_set1_ech_config_list
do :
  ac_fn_c_check_func "$LINENO" "SSL_set1_ech_config_list" "ac_cv_func_SSL_set1_ech_config_list"
if test "x$ac_cv_func_SSL_set1_ech_config_list" = xyes
then :
  printf "%s\n" "#define HAVE_SSL_SET1_ECH_CONFIG_LIST 1" >>confdefs.h
 ECH_SUPPORT="ECH support available via BoringSSL with SSL_set1_ech_config_list"
      ECH_ENABLED=1
fi

done
  fi
  if test "x$WOLFSSL_ENABLED" = "x1"; then

  for ac_func in wolfSSL_CTX_GenerateEchConfig
do :
  ac_fn_c_check_func "$LINENO" "wolfSSL_CTX_GenerateEchConfig" "ac_cv_func_wolfSSL_CTX_GenerateEchConfig"
if test "x$ac_cv_func_wolfSSL_CTX_GenerateEchConfig" = xyes
then :
  printf "%s\n" "#define HAVE_WOLFSSL_CTX_GENERATEECHCONFIG 1" >>confdefs.h
 ECH_SUPPORT="ECH support available via wolfSSL with wolfSSL_CTX_GenerateEchConfig"
      ECH_ENABLED=1
fi

done
  fi

    if test "x$ECH_ENABLED" = "x1"; then
45899
45900
45901
45902
45903
45904
45905
45906





45907

45908
45909

45910
45911

45912
45913
45914
45915
45916
45917
45918


ENABLE_SHARED="$enable_shared"


ENABLE_STATIC="$enable_static"







if test "x$enable_shared" = "xno"; then

  LIBCURL_NO_SHARED=$LIBCURL_LIBS
else

  LIBCURL_NO_SHARED=
fi



rm $compilersh


if test "x$OPENSSL_ENABLED" = "x1"; then
  SUPPORT_FEATURES="$SUPPORT_FEATURES SSL"








>
>
>
>
>

>


>


>







45999
46000
46001
46002
46003
46004
46005
46006
46007
46008
46009
46010
46011
46012
46013
46014
46015
46016
46017
46018
46019
46020
46021
46022
46023
46024
46025
46026


ENABLE_SHARED="$enable_shared"


ENABLE_STATIC="$enable_static"


squeeze LIBCURL_PC_REQUIRES_PRIVATE
LIBCURL_PC_REQUIRES_PRIVATE=`echo $LIBCURL_PC_REQUIRES_PRIVATE | tr ' ' ','`



if test "x$enable_shared" = "xno"; then
  LIBCURL_PC_REQUIRES=$LIBCURL_PC_REQUIRES_PRIVATE
  LIBCURL_NO_SHARED=$LIBCURL_LIBS
else
  LIBCURL_PC_REQUIRES=
  LIBCURL_NO_SHARED=
fi



rm $compilersh


if test "x$OPENSSL_ENABLED" = "x1"; then
  SUPPORT_FEATURES="$SUPPORT_FEATURES SSL"
46038
46039
46040
46041
46042
46043
46044






46045
46046
46047
46048
46049
46050
46051
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
  fi
else
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi







if test ${ac_cv_sizeof_curl_off_t} -gt 4; then
  if test ${ac_cv_sizeof_off_t} -gt 4 -o \
     "$curl_win32_file_api" = "win32_large_files"; then
    SUPPORT_FEATURES="$SUPPORT_FEATURES Largefile"
  fi
fi







>
>
>
>
>
>







46146
46147
46148
46149
46150
46151
46152
46153
46154
46155
46156
46157
46158
46159
46160
46161
46162
46163
46164
46165
    { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
  fi
else
  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi

if test "x$OPENSSL_ENABLED" = "x1" -o -n "$SSL_ENABLED"; then
  if test "x$ECH_ENABLED" = "x1"; then
    SUPPORT_FEATURES="$SUPPORT_FEATURES ECH"
  fi
fi

if test ${ac_cv_sizeof_curl_off_t} -gt 4; then
  if test ${ac_cv_sizeof_off_t} -gt 4 -o \
     "$curl_win32_file_api" = "win32_large_files"; then
    SUPPORT_FEATURES="$SUPPORT_FEATURES Largefile"
  fi
fi
46079
46080
46081
46082
46083
46084
46085










46086

46087
46088
46089
46090
46091
46092
46093

     SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"

fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi











SUPPORT_FEATURES=`echo $SUPPORT_FEATURES | tr ' ' '\012' | sort | tr '\012' ' '`



if test "x$CURL_DISABLE_HTTP" != "x1"; then
  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTP IPFS IPNS"
  if test "x$SSL_ENABLED" = "x1"; then
    SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTPS"
  fi







>
>
>
>
>
>
>
>
>
>
|
>







46193
46194
46195
46196
46197
46198
46199
46200
46201
46202
46203
46204
46205
46206
46207
46208
46209
46210
46211
46212
46213
46214
46215
46216
46217
46218

     SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"

fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi

if test "x$want_debug" = "xyes"; then
  SUPPORT_FEATURES="$SUPPORT_FEATURES Debug"
fi
if test "x$want_curldebug" = "xyes"; then
  SUPPORT_FEATURES="$SUPPORT_FEATURES TrackMemory"
fi

if sort -f </dev/null >/dev/null 2>&1; then
  SUPPORT_FEATURES=`echo $SUPPORT_FEATURES | tr ' ' '\012' | sort -f | tr '\012' ' '`
else
  SUPPORT_FEATURES=`echo $SUPPORT_FEATURES | tr ' ' '\012' | sort | tr '\012' ' '`
fi


if test "x$CURL_DISABLE_HTTP" != "x1"; then
  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTP IPFS IPNS"
  if test "x$SSL_ENABLED" = "x1"; then
    SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTPS"
  fi
46476
46477
46478
46479
46480
46481
46482




46483
46484
46485
46486
46487
46488
46489
LTLIBOBJS=$ac_ltlibobjs


if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
  as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi




{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
printf %s "checking that generated files are newer than configure... " >&6; }
   if test -n "$am_sleep_pid"; then
     # Hide warnings about reused PIDs.
     wait $am_sleep_pid 2>/dev/null
   fi
   { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5







>
>
>
>







46601
46602
46603
46604
46605
46606
46607
46608
46609
46610
46611
46612
46613
46614
46615
46616
46617
46618
LTLIBOBJS=$ac_ltlibobjs


if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
  as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${DEBUGBUILD_TRUE}" && test -z "${DEBUGBUILD_FALSE}"; then
  as_fn_error $? "conditional \"DEBUGBUILD\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
printf %s "checking that generated files are newer than configure... " >&6; }
   if test -n "$am_sleep_pid"; then
     # Hide warnings about reused PIDs.
     wait $am_sleep_pid 2>/dev/null
   fi
   { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5
46522
46523
46524
46525
46526
46527
46528
46529
46530
46531
46532
46533
46534
46535
46536
46537
46538
46539
fi
if test -z "${USE_EXPLICIT_LIB_DEPS_TRUE}" && test -z "${USE_EXPLICIT_LIB_DEPS_FALSE}"; then
  as_fn_error $? "conditional \"USE_EXPLICIT_LIB_DEPS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${DOING_NATIVE_WINDOWS_TRUE}" && test -z "${DOING_NATIVE_WINDOWS_FALSE}"; then
  as_fn_error $? "conditional \"DOING_NATIVE_WINDOWS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${CURLDEBUG_TRUE}" && test -z "${CURLDEBUG_FALSE}"; then
  as_fn_error $? "conditional \"CURLDEBUG\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${BUILD_UNITTESTS_TRUE}" && test -z "${BUILD_UNITTESTS_FALSE}"; then
  as_fn_error $? "conditional \"BUILD_UNITTESTS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${HAVE_WINDRES_TRUE}" && test -z "${HAVE_WINDRES_FALSE}"; then







<
<
<
<







46651
46652
46653
46654
46655
46656
46657




46658
46659
46660
46661
46662
46663
46664
fi
if test -z "${USE_EXPLICIT_LIB_DEPS_TRUE}" && test -z "${USE_EXPLICIT_LIB_DEPS_FALSE}"; then
  as_fn_error $? "conditional \"USE_EXPLICIT_LIB_DEPS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${DOING_NATIVE_WINDOWS_TRUE}" && test -z "${DOING_NATIVE_WINDOWS_FALSE}"; then
  as_fn_error $? "conditional \"DOING_NATIVE_WINDOWS\" was never defined.




Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${BUILD_UNITTESTS_TRUE}" && test -z "${BUILD_UNITTESTS_FALSE}"; then
  as_fn_error $? "conditional \"BUILD_UNITTESTS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
if test -z "${HAVE_WINDRES_TRUE}" && test -z "${HAVE_WINDRES_FALSE}"; then
49014
49015
49016
49017
49018
49019
49020


49021
49022
49023
49024
49025
49026
49027

49028
49029
49030
49031
49032
49033
49034
    );

\$Cpreprocessor = '$tmp_cpp';

1;
_EOF




{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configured to build curl/libcurl:

  Host setup:       ${host}
  Install prefix:   ${prefix}
  Compiler:         ${CC}
   CFLAGS:          ${CFLAGS}

   CPPFLAGS:        ${CPPFLAGS}
   LDFLAGS:         ${LDFLAGS}
   LIBS:            ${LIBS}

  curl version:     ${CURLVERSION}
  SSL:              ${curl_ssl_msg}
  SSH:              ${curl_ssh_msg}







>
>







>







49139
49140
49141
49142
49143
49144
49145
49146
49147
49148
49149
49150
49151
49152
49153
49154
49155
49156
49157
49158
49159
49160
49161
49162
    );

\$Cpreprocessor = '$tmp_cpp';

1;
_EOF


SUPPORT_PROTOCOLS_LOWER=`echo "$SUPPORT_PROTOCOLS" | tr A-Z a-z`

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Configured to build curl/libcurl:

  Host setup:       ${host}
  Install prefix:   ${prefix}
  Compiler:         ${CC}
   CFLAGS:          ${CFLAGS}
   CFLAGS extras:   ${CURL_CFLAG_EXTRAS}
   CPPFLAGS:        ${CPPFLAGS}
   LDFLAGS:         ${LDFLAGS}
   LIBS:            ${LIBS}

  curl version:     ${CURLVERSION}
  SSL:              ${curl_ssl_msg}
  SSH:              ${curl_ssh_msg}
49061
49062
49063
49064
49065
49066
49067
49068
49069
49070
49071
49072
49073
49074
49075
49076

49077
49078
49079
49080
49081
49082
49083
  Headers API:      ${curl_headers_msg}
  HSTS:             ${curl_hsts_msg}
  HTTP1:            ${curl_h1_msg}
  HTTP2:            ${curl_h2_msg}
  HTTP3:            ${curl_h3_msg}
  ECH:              ${curl_ech_msg}
  WebSockets:       ${curl_ws_msg}
  Protocols:        ${SUPPORT_PROTOCOLS}
  Features:         ${SUPPORT_FEATURES}
" >&5
printf "%s\n" "$as_me: Configured to build curl/libcurl:

  Host setup:       ${host}
  Install prefix:   ${prefix}
  Compiler:         ${CC}
   CFLAGS:          ${CFLAGS}

   CPPFLAGS:        ${CPPFLAGS}
   LDFLAGS:         ${LDFLAGS}
   LIBS:            ${LIBS}

  curl version:     ${CURLVERSION}
  SSL:              ${curl_ssl_msg}
  SSH:              ${curl_ssh_msg}







|








>







49189
49190
49191
49192
49193
49194
49195
49196
49197
49198
49199
49200
49201
49202
49203
49204
49205
49206
49207
49208
49209
49210
49211
49212
  Headers API:      ${curl_headers_msg}
  HSTS:             ${curl_hsts_msg}
  HTTP1:            ${curl_h1_msg}
  HTTP2:            ${curl_h2_msg}
  HTTP3:            ${curl_h3_msg}
  ECH:              ${curl_ech_msg}
  WebSockets:       ${curl_ws_msg}
  Protocols:        ${SUPPORT_PROTOCOLS_LOWER}
  Features:         ${SUPPORT_FEATURES}
" >&5
printf "%s\n" "$as_me: Configured to build curl/libcurl:

  Host setup:       ${host}
  Install prefix:   ${prefix}
  Compiler:         ${CC}
   CFLAGS:          ${CFLAGS}
   CFLAGS extras:   ${CURL_CFLAG_EXTRAS}
   CPPFLAGS:        ${CPPFLAGS}
   LDFLAGS:         ${LDFLAGS}
   LIBS:            ${LIBS}

  curl version:     ${CURLVERSION}
  SSL:              ${curl_ssl_msg}
  SSH:              ${curl_ssh_msg}
49110
49111
49112
49113
49114
49115
49116
49117
49118
49119
49120
49121
49122
49123
49124
49125

49126
49127
49128
49129

49130
49131

49132
49133
  Headers API:      ${curl_headers_msg}
  HSTS:             ${curl_hsts_msg}
  HTTP1:            ${curl_h1_msg}
  HTTP2:            ${curl_h2_msg}
  HTTP3:            ${curl_h3_msg}
  ECH:              ${curl_ech_msg}
  WebSockets:       ${curl_ws_msg}
  Protocols:        ${SUPPORT_PROTOCOLS}
  Features:         ${SUPPORT_FEATURES}
" >&6;}

non13=`echo "$TLSCHOICE" | grep -Ei 'bearssl|secure-transport|mbedtls'`;
if test -n "$non13"; then
 cat >&2 << _EOF
  WARNING: A selected TLS library ($TLSCHOICE) does not support TLS 1.3!
_EOF

fi

if test -n "$experimental"; then
 cat >&2 << _EOF

  WARNING: $experimental enabled but marked EXPERIMENTAL. Use with caution!
_EOF

fi








|



|

|
|
|
>



|
>
|
<
>


49239
49240
49241
49242
49243
49244
49245
49246
49247
49248
49249
49250
49251
49252
49253
49254
49255
49256
49257
49258
49259
49260
49261

49262
49263
49264
  Headers API:      ${curl_headers_msg}
  HSTS:             ${curl_hsts_msg}
  HTTP1:            ${curl_h1_msg}
  HTTP2:            ${curl_h2_msg}
  HTTP3:            ${curl_h3_msg}
  ECH:              ${curl_ech_msg}
  WebSockets:       ${curl_ws_msg}
  Protocols:        ${SUPPORT_PROTOCOLS_LOWER}
  Features:         ${SUPPORT_FEATURES}
" >&6;}

non13=`echo "$TLSCHOICE" | $EGREP -io 'bearssl|secure-transport'`;
if test -n "$non13"; then
 for a in $non13; do
   { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $a is enabled for TLS but it does not support TLS 1.3" >&5
printf "%s\n" "$as_me: WARNING: $a is enabled for TLS but it does not support TLS 1.3" >&2;}
 done
fi

if test -n "$experimental"; then
 for a in $experimental; do
   { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $a is enabled but marked EXPERIMENTAL. Use with caution!" >&5
printf "%s\n" "$as_me: WARNING: $a is enabled but marked EXPERIMENTAL. Use with caution!" >&2;}

 done
fi

Changes to jni/curl/configure.ac.
40
41
42
43
44
45
46

47
48
49
50
51
52
53
AC_CONFIG_SRCDIR([lib/urldata.h])
AC_CONFIG_HEADERS(lib/curl_config.h)
AC_CONFIG_MACRO_DIR([m4])
AM_MAINTAINER_MODE
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])

CURL_CHECK_OPTION_DEBUG

CURL_CHECK_OPTION_OPTIMIZE
CURL_CHECK_OPTION_WARNINGS
CURL_CHECK_OPTION_WERROR
CURL_CHECK_OPTION_CURLDEBUG
CURL_CHECK_OPTION_SYMBOL_HIDING
CURL_CHECK_OPTION_ARES
CURL_CHECK_OPTION_RT







>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
AC_CONFIG_SRCDIR([lib/urldata.h])
AC_CONFIG_HEADERS(lib/curl_config.h)
AC_CONFIG_MACRO_DIR([m4])
AM_MAINTAINER_MODE
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])

CURL_CHECK_OPTION_DEBUG
AM_CONDITIONAL(DEBUGBUILD, test x$want_debug = xyes)
CURL_CHECK_OPTION_OPTIMIZE
CURL_CHECK_OPTION_WARNINGS
CURL_CHECK_OPTION_WERROR
CURL_CHECK_OPTION_CURLDEBUG
CURL_CHECK_OPTION_SYMBOL_HIDING
CURL_CHECK_OPTION_ARES
CURL_CHECK_OPTION_RT
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  if test X"$withval" != Xno; then
    TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }mbedTLS"
  fi
])

OPT_WOLFSSL=no
AC_ARG_WITH(wolfssl,dnl
AS_HELP_STRING([--with-wolfssl=PATH],[where to look for WolfSSL, PATH points to the installation root (default: system lib default)]),[
  OPT_WOLFSSL=$withval
  if test X"$withval" != Xno; then
    TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }wolfSSL"
  fi
])

OPT_BEARSSL=no







|







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  if test X"$withval" != Xno; then
    TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }mbedTLS"
  fi
])

OPT_WOLFSSL=no
AC_ARG_WITH(wolfssl,dnl
AS_HELP_STRING([--with-wolfssl=PATH],[where to look for wolfSSL, PATH points to the installation root (default: system lib default)]),[
  OPT_WOLFSSL=$withval
  if test X"$withval" != Xno; then
    TLSCHOICE="${TLSCHOICE:+$TLSCHOICE, }wolfSSL"
  fi
])

OPT_BEARSSL=no
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427

Select from these:

  --with-amissl
  --with-bearssl
  --with-gnutls
  --with-mbedtls
  --with-openssl (also works for BoringSSL and libressl)
  --with-rustls
  --with-schannel
  --with-secure-transport
  --with-wolfssl
])
  fi
fi







|







414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

Select from these:

  --with-amissl
  --with-bearssl
  --with-gnutls
  --with-mbedtls
  --with-openssl (also works for BoringSSL and LibreSSL)
  --with-rustls
  --with-schannel
  --with-secure-transport
  --with-wolfssl
])
  fi
fi
535
536
537
538
539
540
541


542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
  CURL_CFLAG_EXTRAS="-Werror"
  if test "$compiler_id" = "GNU_C"; then
    dnl enable -pedantic-errors for GCC 5 and later,
    dnl as before that it was the same as -Werror=pedantic
    if test "$compiler_num" -ge "500"; then
      CURL_CFLAG_EXTRAS="$CURL_CFLAG_EXTRAS -pedantic-errors"
    fi


  fi
fi
AC_SUBST(CURL_CFLAG_EXTRAS)

CURL_CHECK_COMPILER_HALT_ON_ERROR
CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE
CURL_CHECK_COMPILER_PROTOTYPE_MISMATCH
CURL_CHECK_COMPILER_SYMBOL_HIDING

CURL_CHECK_CURLDEBUG
AM_CONDITIONAL(CURLDEBUG, test x$want_curldebug = xyes)

supports_unittests=yes
# cross-compilation of unit tests static library/programs fails when
# libcurl shared library is built. This might be due to a libtool or
# automake issue. In this case we disable unit tests.
if test "x$cross_compiling" != "xno" &&
   test "x$enable_shared" != "xno"; then
  supports_unittests=no







>
>









<
<
<







536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553



554
555
556
557
558
559
560
  CURL_CFLAG_EXTRAS="-Werror"
  if test "$compiler_id" = "GNU_C"; then
    dnl enable -pedantic-errors for GCC 5 and later,
    dnl as before that it was the same as -Werror=pedantic
    if test "$compiler_num" -ge "500"; then
      CURL_CFLAG_EXTRAS="$CURL_CFLAG_EXTRAS -pedantic-errors"
    fi
  elif test "$compiler_id" = "CLANG"; then
    CURL_CFLAG_EXTRAS="$CURL_CFLAG_EXTRAS -pedantic-errors"
  fi
fi
AC_SUBST(CURL_CFLAG_EXTRAS)

CURL_CHECK_COMPILER_HALT_ON_ERROR
CURL_CHECK_COMPILER_ARRAY_SIZE_NEGATIVE
CURL_CHECK_COMPILER_PROTOTYPE_MISMATCH
CURL_CHECK_COMPILER_SYMBOL_HIDING




supports_unittests=yes
# cross-compilation of unit tests static library/programs fails when
# libcurl shared library is built. This might be due to a libtool or
# automake issue. In this case we disable unit tests.
if test "x$cross_compiling" != "xno" &&
   test "x$enable_shared" != "xno"; then
  supports_unittests=no
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
dnl Compilation based checks should not be done before this point.
dnl **********************************************************************

CURL_CHECK_WIN32_LARGEFILE
CURL_CHECK_WIN32_CRYPTO

CURL_DARWIN_CFLAGS
CURL_DARWIN_SYSTEMCONFIGURATION
CURL_SUPPORTS_BUILTIN_AVAILABLE

AM_CONDITIONAL([HAVE_WINDRES],
  [test "$curl_cv_native_windows" = "yes" && test -n "${RC}"])

if test "$curl_cv_native_windows" = "yes"; then
  AM_COND_IF([HAVE_WINDRES],,







<







593
594
595
596
597
598
599

600
601
602
603
604
605
606
dnl Compilation based checks should not be done before this point.
dnl **********************************************************************

CURL_CHECK_WIN32_LARGEFILE
CURL_CHECK_WIN32_CRYPTO

CURL_DARWIN_CFLAGS

CURL_SUPPORTS_BUILTIN_AVAILABLE

AM_CONDITIONAL([HAVE_WINDRES],
  [test "$curl_cv_native_windows" = "yes" && test -n "${RC}"])

if test "$curl_cv_native_windows" = "yes"; then
  AM_COND_IF([HAVE_WINDRES],,
795
796
797
798
799
800
801
802

803
804
805
806
807
808
809
          AC_MSG_NOTICE([Hyper support is experimental])
          curl_h1_msg="enabled (Hyper)"
          HYPER_ENABLED=1
          AC_DEFINE(USE_HYPER, 1, [if hyper is in use])
          AC_SUBST(USE_HYPER, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_HYPER"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_HYPER to CURL_LIBRARY_PATH]),

       )
      ],
      for d in `echo $DIR_HYPER | $SED -e 's/:/ /'`; do
        if test -f "$d/libhyper.a"; then
          AC_MSG_ERROR([hyper was found in $d but was probably built with wrong flags. See docs/HYPER.md.])
        fi
      done







|
>







794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
          AC_MSG_NOTICE([Hyper support is experimental])
          curl_h1_msg="enabled (Hyper)"
          HYPER_ENABLED=1
          AC_DEFINE(USE_HYPER, 1, [if hyper is in use])
          AC_SUBST(USE_HYPER, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_HYPER"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_HYPER to CURL_LIBRARY_PATH])
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE hyper"
       )
      ],
      for d in `echo $DIR_HYPER | $SED -e 's/:/ /'`; do
        if test -f "$d/libhyper.a"; then
          AC_MSG_ERROR([hyper was found in $d but was probably built with wrong flags. See docs/HYPER.md.])
        fi
      done
1377
1378
1379
1380
1381
1382
1383

1384
1385
1386
1387
1388
1389
1390
    AC_SUBST(HAVE_LIBZ)
    AC_DEFINE(HAVE_LIBZ, 1, [if zlib is available])
    LIBS="$ZLIB_LIBS $clean_LIBS"

    dnl replace 'HAVE_LIBZ' in the automake makefile.ams
    AMFIXLIB="1"
    AC_MSG_NOTICE([found both libz and libz.h header])

    curl_zlib_msg="enabled"
  fi
fi

dnl set variable for use in automakefile(s)
AM_CONDITIONAL(HAVE_LIBZ, test x"$AMFIXLIB" = x1)
AC_SUBST(ZLIB_LIBS)







>







1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
    AC_SUBST(HAVE_LIBZ)
    AC_DEFINE(HAVE_LIBZ, 1, [if zlib is available])
    LIBS="$ZLIB_LIBS $clean_LIBS"

    dnl replace 'HAVE_LIBZ' in the automake makefile.ams
    AMFIXLIB="1"
    AC_MSG_NOTICE([found both libz and libz.h header])
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE zlib"
    curl_zlib_msg="enabled"
  fi
fi

dnl set variable for use in automakefile(s)
AM_CONDITIONAL(HAVE_LIBZ, test x"$AMFIXLIB" = x1)
AC_SUBST(ZLIB_LIBS)
1465
1466
1467
1468
1469
1470
1471

1472
1473
1474
1475
1476
1477
1478

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_BROTLI"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_BROTLI to CURL_LIBRARY_PATH])
       fi
    fi

  else
    dnl no brotli, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi







>







1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_BROTLI"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_BROTLI to CURL_LIBRARY_PATH])
       fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libbrotlidec"
  else
    dnl no brotli, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi
1552
1553
1554
1555
1556
1557
1558

1559
1560
1561
1562
1563
1564
1565

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_ZSTD"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_ZSTD to CURL_LIBRARY_PATH])
       fi
    fi

  else
    dnl no zstd, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi







>







1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_ZSTD"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_ZSTD to CURL_LIBRARY_PATH])
       fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libzstd"
  else
    dnl no zstd, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
fi
2138
2139
2140
2141
2142
2143
2144

2145
2146
2147
2148
2149
2150
2151
  AC_CHECK_LIB(psl, psl_builtin,
    [
     AC_CHECK_HEADERS(libpsl.h,
        curl_psl_msg="enabled"
        LIBPSL_ENABLED=1
        AC_DEFINE(USE_LIBPSL, 1, [if libpsl is in use])
        AC_SUBST(USE_LIBPSL, [1])

     )
    ],
      dnl not found, revert back to clean variables
      LDFLAGS=$CLEANLDFLAGS
      CPPFLAGS=$CLEANCPPFLAGS
      LIBS=$CLEANLIBS
  )







>







2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
  AC_CHECK_LIB(psl, psl_builtin,
    [
     AC_CHECK_HEADERS(libpsl.h,
        curl_psl_msg="enabled"
        LIBPSL_ENABLED=1
        AC_DEFINE(USE_LIBPSL, 1, [if libpsl is in use])
        AC_SUBST(USE_LIBPSL, [1])
        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libpsl"
     )
    ],
      dnl not found, revert back to clean variables
      LDFLAGS=$CLEANLDFLAGS
      CPPFLAGS=$CLEANCPPFLAGS
      LIBS=$CLEANLIBS
  )
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
fi
AM_CONDITIONAL([USE_GSASL], [test "$curl_gsasl_msg" = "enabled"])

AC_ARG_WITH(libmetalink,,
  AC_MSG_ERROR([--with-libmetalink and --without-libmetalink no longer work!]))

dnl **********************************************************************
dnl Check for the presence of LIBSSH2 libraries and headers
dnl **********************************************************************

dnl Default to compiler & linker defaults for LIBSSH2 files & libraries.
OPT_LIBSSH2=off
AC_ARG_WITH(libssh2,dnl
AS_HELP_STRING([--with-libssh2=PATH],[Where to look for libssh2, PATH points to the libssh2 installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option])
AS_HELP_STRING([--with-libssh2], [enable libssh2]),
  OPT_LIBSSH2=$withval, OPT_LIBSSH2=no)









|


|







2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
fi
AM_CONDITIONAL([USE_GSASL], [test "$curl_gsasl_msg" = "enabled"])

AC_ARG_WITH(libmetalink,,
  AC_MSG_ERROR([--with-libmetalink and --without-libmetalink no longer work!]))

dnl **********************************************************************
dnl Check for the presence of libssh2 libraries and headers
dnl **********************************************************************

dnl Default to compiler & linker defaults for libssh2 files & libraries.
OPT_LIBSSH2=off
AC_ARG_WITH(libssh2,dnl
AS_HELP_STRING([--with-libssh2=PATH],[Where to look for libssh2, PATH points to the libssh2 installation; when possible, set the PKG_CONFIG_PATH environment variable instead of using this option])
AS_HELP_STRING([--with-libssh2], [enable libssh2]),
  OPT_LIBSSH2=$withval, OPT_LIBSSH2=no)


2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276

2277
2278
2279
2280
2281
2282
2283
  CPPFLAGS="$CPPFLAGS $CPP_SSH2"
  LIBS="$LIB_SSH2 $LIBS"

  dnl check for function added in libssh2 version 1.0
  AC_CHECK_LIB(ssh2, libssh2_session_block_directions)

  AC_CHECK_HEADER(libssh2.h,
    curl_ssh_msg="enabled (libSSH2)"
    LIBSSH2_ENABLED=1
    AC_DEFINE(USE_LIBSSH2, 1, [if libSSH2 is in use])
    AC_SUBST(USE_LIBSSH2, [1])
  )

  if test X"$OPT_LIBSSH2" != Xoff &&
     test "$LIBSSH2_ENABLED" != "1"; then
    AC_MSG_ERROR([libSSH2 libs and/or directories were not found where specified!])
  fi

  if test "$LIBSSH2_ENABLED" = "1"; then
    if test -n "$DIR_SSH2"; then
       dnl when the libssh2 shared libs were found in a path that the run-time
       dnl linker doesn't search through, we need to add it to CURL_LIBRARY_PATH
       dnl to prevent further configure tests to fail due to this

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH2"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_SSH2 to CURL_LIBRARY_PATH])
       fi
    fi

  else
    dnl no libssh2, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_LIBSSH" != Xno; then







|

|





|














>







2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
  CPPFLAGS="$CPPFLAGS $CPP_SSH2"
  LIBS="$LIB_SSH2 $LIBS"

  dnl check for function added in libssh2 version 1.0
  AC_CHECK_LIB(ssh2, libssh2_session_block_directions)

  AC_CHECK_HEADER(libssh2.h,
    curl_ssh_msg="enabled (libssh2)"
    LIBSSH2_ENABLED=1
    AC_DEFINE(USE_LIBSSH2, 1, [if libssh2 is in use])
    AC_SUBST(USE_LIBSSH2, [1])
  )

  if test X"$OPT_LIBSSH2" != Xoff &&
     test "$LIBSSH2_ENABLED" != "1"; then
    AC_MSG_ERROR([libssh2 libs and/or directories were not found where specified!])
  fi

  if test "$LIBSSH2_ENABLED" = "1"; then
    if test -n "$DIR_SSH2"; then
       dnl when the libssh2 shared libs were found in a path that the run-time
       dnl linker doesn't search through, we need to add it to CURL_LIBRARY_PATH
       dnl to prevent further configure tests to fail due to this

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH2"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_SSH2 to CURL_LIBRARY_PATH])
       fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libssh2"
  else
    dnl no libssh2, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_LIBSSH" != Xno; then
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349

2350
2351
2352
2353
2354
2355
2356
  LDFLAGS="$LDFLAGS $LD_SSH"
  CPPFLAGS="$CPPFLAGS $CPP_SSH"
  LIBS="$LIB_SSH $LIBS"

  AC_CHECK_LIB(ssh, ssh_new)

  AC_CHECK_HEADER(libssh/libssh.h,
    curl_ssh_msg="enabled (libSSH)"
    LIBSSH_ENABLED=1
    AC_DEFINE(USE_LIBSSH, 1, [if libSSH is in use])
    AC_SUBST(USE_LIBSSH, [1])
  )

  if test X"$OPT_LIBSSH" != Xoff &&
     test "$LIBSSH_ENABLED" != "1"; then
    AC_MSG_ERROR([libSSH libs and/or directories were not found where specified!])
  fi

  if test "$LIBSSH_ENABLED" = "1"; then
    if test -n "$DIR_SSH"; then
       dnl when the libssh shared libs were found in a path that the run-time
       dnl linker doesn't search through, we need to add it to CURL_LIBRARY_PATH
       dnl to prevent further configure tests to fail due to this

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_SSH to CURL_LIBRARY_PATH])
       fi
    fi

  else
    dnl no libssh, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_WOLFSSH" != Xno; then







|

|





|














>







2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
  LDFLAGS="$LDFLAGS $LD_SSH"
  CPPFLAGS="$CPPFLAGS $CPP_SSH"
  LIBS="$LIB_SSH $LIBS"

  AC_CHECK_LIB(ssh, ssh_new)

  AC_CHECK_HEADER(libssh/libssh.h,
    curl_ssh_msg="enabled (libssh)"
    LIBSSH_ENABLED=1
    AC_DEFINE(USE_LIBSSH, 1, [if libssh is in use])
    AC_SUBST(USE_LIBSSH, [1])
  )

  if test X"$OPT_LIBSSH" != Xoff &&
     test "$LIBSSH_ENABLED" != "1"; then
    AC_MSG_ERROR([libssh libs and/or directories were not found where specified!])
  fi

  if test "$LIBSSH_ENABLED" = "1"; then
    if test -n "$DIR_SSH"; then
       dnl when the libssh shared libs were found in a path that the run-time
       dnl linker doesn't search through, we need to add it to CURL_LIBRARY_PATH
       dnl to prevent further configure tests to fail due to this

       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_SSH"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $DIR_SSH to CURL_LIBRARY_PATH])
       fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libssh"
  else
    dnl no libssh, revert back to clean variables
    LDFLAGS=$CLEANLDFLAGS
    CPPFLAGS=$CLEANCPPFLAGS
    LIBS=$CLEANLIBS
  fi
elif test X"$OPT_WOLFSSH" != Xno; then
2437
2438
2439
2440
2441
2442
2443

2444
2445
2446
2447
2448
2449
2450
  AC_CHECK_LIB(rtmp, RTMP_Init,
    [
     AC_CHECK_HEADERS(librtmp/rtmp.h,
        curl_rtmp_msg="enabled (librtmp)"
        LIBRTMP_ENABLED=1
        AC_DEFINE(USE_LIBRTMP, 1, [if librtmp is in use])
        AC_SUBST(USE_LIBRTMP, [1])

     )
    ],
      dnl not found, revert back to clean variables
      LDFLAGS=$CLEANLDFLAGS
      CPPFLAGS=$CLEANCPPFLAGS
      LIBS=$CLEANLIBS
  )







>







2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
  AC_CHECK_LIB(rtmp, RTMP_Init,
    [
     AC_CHECK_HEADERS(librtmp/rtmp.h,
        curl_rtmp_msg="enabled (librtmp)"
        LIBRTMP_ENABLED=1
        AC_DEFINE(USE_LIBRTMP, 1, [if librtmp is in use])
        AC_SUBST(USE_LIBRTMP, [1])
        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE librtmp"
     )
    ],
      dnl not found, revert back to clean variables
      LDFLAGS=$CLEANLDFLAGS
      CPPFLAGS=$CLEANCPPFLAGS
      LIBS=$CLEANLIBS
  )
2720
2721
2722
2723
2724
2725
2726

2727
2728
2729
2730
2731
2732
2733
    AC_SUBST([IDN_ENABLED], [1])
    curl_idn_msg="enabled (libidn2)"
    if test -n "$IDN_DIR" -a "x$cross_compiling" != "xyes"; then
      CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$IDN_DIR"
      export CURL_LIBRARY_PATH
      AC_MSG_NOTICE([Added $IDN_DIR to CURL_LIBRARY_PATH])
    fi

  else
    AC_MSG_WARN([Cannot find libraries for IDN support: IDN disabled])
    CPPFLAGS="$clean_CPPFLAGS"
    LDFLAGS="$clean_LDFLAGS"
    LIBS="$clean_LIBS"
  fi
fi







>







2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
    AC_SUBST([IDN_ENABLED], [1])
    curl_idn_msg="enabled (libidn2)"
    if test -n "$IDN_DIR" -a "x$cross_compiling" != "xyes"; then
      CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$IDN_DIR"
      export CURL_LIBRARY_PATH
      AC_MSG_NOTICE([Added $IDN_DIR to CURL_LIBRARY_PATH])
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="libidn2 $LIBCURL_PC_REQUIRES_PRIVATE"
  else
    AC_MSG_WARN([Cannot find libraries for IDN support: IDN disabled])
    CPPFLAGS="$clean_CPPFLAGS"
    LDFLAGS="$clean_LDFLAGS"
    LIBS="$clean_LIBS"
  fi
fi
2810
2811
2812
2813
2814
2815
2816

2817
2818
2819
2820
2821
2822
2823
  AC_CHECK_LIB(nghttp2, nghttp2_session_get_stream_local_window_size,
    [
     AC_CHECK_HEADERS(nghttp2/nghttp2.h,
        curl_h2_msg="enabled (nghttp2)"
        NGHTTP2_ENABLED=1
        AC_DEFINE(USE_NGHTTP2, 1, [if nghttp2 is in use])
        AC_SUBST(USE_NGHTTP2, [1])

     )

     CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_H2"
     export CURL_LIBRARY_PATH
     AC_MSG_NOTICE([Added $DIR_H2 to CURL_LIBRARY_PATH])
    ],
      dnl not found, revert back to clean variables







>







2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
  AC_CHECK_LIB(nghttp2, nghttp2_session_get_stream_local_window_size,
    [
     AC_CHECK_HEADERS(nghttp2/nghttp2.h,
        curl_h2_msg="enabled (nghttp2)"
        NGHTTP2_ENABLED=1
        AC_DEFINE(USE_NGHTTP2, 1, [if nghttp2 is in use])
        AC_SUBST(USE_NGHTTP2, [1])
        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libnghttp2"
     )

     CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_H2"
     export CURL_LIBRARY_PATH
     AC_MSG_NOTICE([Added $DIR_H2 to CURL_LIBRARY_PATH])
    ],
      dnl not found, revert back to clean variables
2898
2899
2900
2901
2902
2903
2904

2905
2906
2907
2908
2909
2910
2911
       AC_CHECK_HEADERS(ngtcp2/ngtcp2.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2, 1, [if ngtcp2 is in use])
          AC_SUBST(USE_NGTCP2, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_TCP2"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_TCP2 to CURL_LIBRARY_PATH])

       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )







>







2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
       AC_CHECK_HEADERS(ngtcp2/ngtcp2.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2, 1, [if ngtcp2 is in use])
          AC_SUBST(USE_NGTCP2, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_TCP2"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_TCP2 to CURL_LIBRARY_PATH])
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2"
       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )
2954
2955
2956
2957
2958
2959
2960

2961
2962
2963
2964
2965
2966
2967
       AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2_CRYPTO_QUICTLS, 1, [if ngtcp2_crypto_quictls is in use])
          AC_SUBST(USE_NGTCP2_CRYPTO_QUICTLS, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_QUICTLS"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH])

       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )







>







2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
       AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2_CRYPTO_QUICTLS, 1, [if ngtcp2_crypto_quictls is in use])
          AC_SUBST(USE_NGTCP2_CRYPTO_QUICTLS, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_QUICTLS"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_QUICTLS to CURL_LIBRARY_PATH])
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2_crypto_quictls"
       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )
3009
3010
3011
3012
3013
3014
3015

3016
3017
3018
3019
3020
3021
3022
       AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2_CRYPTO_BORINGSSL, 1, [if ngtcp2_crypto_boringssl is in use])
          AC_SUBST(USE_NGTCP2_CRYPTO_BORINGSSL, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_BORINGSSL"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH])

       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )







>







3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
       AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2_CRYPTO_BORINGSSL, 1, [if ngtcp2_crypto_boringssl is in use])
          AC_SUBST(USE_NGTCP2_CRYPTO_BORINGSSL, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_BORINGSSL"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_BORINGSSL to CURL_LIBRARY_PATH])
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2_crypto_boringssl"
       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )
3064
3065
3066
3067
3068
3069
3070

3071
3072
3073
3074
3075
3076
3077
       AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2_CRYPTO_GNUTLS, 1, [if ngtcp2_crypto_gnutls is in use])
          AC_SUBST(USE_NGTCP2_CRYPTO_GNUTLS, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_GNUTLS"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH])

       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )







>







3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
       AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2_CRYPTO_GNUTLS, 1, [if ngtcp2_crypto_gnutls is in use])
          AC_SUBST(USE_NGTCP2_CRYPTO_GNUTLS, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_GNUTLS"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_GNUTLS to CURL_LIBRARY_PATH])
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2_crypto_gnutls"
       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )
3119
3120
3121
3122
3123
3124
3125

3126
3127
3128
3129
3130
3131
3132
       AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2_CRYPTO_WOLFSSL, 1, [if ngtcp2_crypto_wolfssl is in use])
          AC_SUBST(USE_NGTCP2_CRYPTO_WOLFSSL, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_WOLFSSL"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH])

       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )







>







3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
       AC_CHECK_HEADERS(ngtcp2/ngtcp2_crypto.h,
          NGTCP2_ENABLED=1
          AC_DEFINE(USE_NGTCP2_CRYPTO_WOLFSSL, 1, [if ngtcp2_crypto_wolfssl is in use])
          AC_SUBST(USE_NGTCP2_CRYPTO_WOLFSSL, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGTCP2_CRYPTO_WOLFSSL"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGTCP2_CRYPTO_WOLFSSL to CURL_LIBRARY_PATH])
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libngtcp2_crypto_wolfssl"
       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
curl_openssl_quic_msg="no      (--with-openssl-quic)"
if test "x$want_openssl_quic" = "xyes"; then

  if test "$NGTCP2_ENABLED" = 1; then
    AC_MSG_ERROR([--with-openssl-quic and --with-ngtcp2 are mutually exclusive])
  fi
  if test "$HAVE_OPENSSL_QUIC" != 1; then
    AC_MSG_ERROR([--with-openssl-quic requires quic support in OpenSSL])
  fi
  AC_DEFINE(USE_OPENSSL_QUIC, 1, [if openssl QUIC is in use])
  AC_SUBST(USE_OPENSSL_QUIC, [1])
fi

dnl **********************************************************************
dnl Check for nghttp3 (HTTP/3 with ngtcp2)







|







3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
curl_openssl_quic_msg="no      (--with-openssl-quic)"
if test "x$want_openssl_quic" = "xyes"; then

  if test "$NGTCP2_ENABLED" = 1; then
    AC_MSG_ERROR([--with-openssl-quic and --with-ngtcp2 are mutually exclusive])
  fi
  if test "$HAVE_OPENSSL_QUIC" != 1; then
    AC_MSG_ERROR([--with-openssl-quic requires quic support and OpenSSL >= 3.3.0])
  fi
  AC_DEFINE(USE_OPENSSL_QUIC, 1, [if openssl QUIC is in use])
  AC_SUBST(USE_OPENSSL_QUIC, [1])
fi

dnl **********************************************************************
dnl Check for nghttp3 (HTTP/3 with ngtcp2)
3211
3212
3213
3214
3215
3216
3217





3218
3219
3220
3221
3222
3223
3224
    want_nghttp3="yes"
    want_nghttp3_path="$withval/lib/pkgconfig"
    ;;
esac

curl_http3_msg="no      (--with-nghttp3)"
if test X"$want_nghttp3" != Xno; then






  dnl backup the pre-nghttp3 variables
  CLEANLDFLAGS="$LDFLAGS"
  CLEANCPPFLAGS="$CPPFLAGS"
  CLEANLIBS="$LIBS"

  CURL_CHECK_PKGCONFIG(libnghttp3, $want_nghttp3_path)







>
>
>
>
>







3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
    want_nghttp3="yes"
    want_nghttp3_path="$withval/lib/pkgconfig"
    ;;
esac

curl_http3_msg="no      (--with-nghttp3)"
if test X"$want_nghttp3" != Xno; then

  if test "x$USE_NGTCP2" != "x1" -a "x$USE_OPENSSL_QUIC" != "x1"; then
    # without ngtcp2 or openssl quic, nghttp3 is of no use for us
    AC_MSG_ERROR([nghttp3 enabled without a QUIC library; enable ngtcp2 or OpenSSL-QUIC])
  fi

  dnl backup the pre-nghttp3 variables
  CLEANLDFLAGS="$LDFLAGS"
  CLEANCPPFLAGS="$CPPFLAGS"
  CLEANLIBS="$LIBS"

  CURL_CHECK_PKGCONFIG(libnghttp3, $want_nghttp3_path)
3247
3248
3249
3250
3251
3252
3253

3254
3255
3256
3257
3258
3259
3260
      [
       AC_CHECK_HEADERS(nghttp3/nghttp3.h,
          AC_DEFINE(USE_NGHTTP3, 1, [if nghttp3 is in use])
          AC_SUBST(USE_NGHTTP3, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGHTTP3"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH])

       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )







>







3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
      [
       AC_CHECK_HEADERS(nghttp3/nghttp3.h,
          AC_DEFINE(USE_NGHTTP3, 1, [if nghttp3 is in use])
          AC_SUBST(USE_NGHTTP3, [1])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_NGHTTP3"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_NGHTTP3 to CURL_LIBRARY_PATH])
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libnghttp3"
       )
      ],
        dnl not found, revert back to clean variables
        LDFLAGS=$CLEANLDFLAGS
        CPPFLAGS=$CLEANCPPFLAGS
        LIBS=$CLEANLIBS
    )
3370
3371
3372
3373
3374
3375
3376
3377

3378
3379
3380
3381
3382
3383
3384
          curl_h3_msg="enabled (quiche)"
          QUICHE_ENABLED=1
          AC_DEFINE(USE_QUICHE, 1, [if quiche is in use])
          AC_SUBST(USE_QUICHE, [1])
          AC_CHECK_FUNCS([quiche_conn_set_qlog_fd])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_QUICHE"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_QUICHE to CURL_LIBRARY_PATH]),

          [],
          [
AC_INCLUDES_DEFAULT
#include <sys/socket.h>
          ]
       )
      ],







|
>







3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
          curl_h3_msg="enabled (quiche)"
          QUICHE_ENABLED=1
          AC_DEFINE(USE_QUICHE, 1, [if quiche is in use])
          AC_SUBST(USE_QUICHE, [1])
          AC_CHECK_FUNCS([quiche_conn_set_qlog_fd])
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_QUICHE"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $DIR_QUICHE to CURL_LIBRARY_PATH])
          LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE quiche",
          [],
          [
AC_INCLUDES_DEFAULT
#include <sys/socket.h>
          ]
       )
      ],
3465
3466
3467
3468
3469
3470
3471
3472

3473
3474
3475
3476
3477
3478
3479
    AC_CHECK_HEADERS(msh3.h,
        curl_h3_msg="enabled (msh3)"
        MSH3_ENABLED=1
        AC_DEFINE(USE_MSH3, 1, [if msh3 is in use])
        AC_SUBST(USE_MSH3, [1])
        CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_MSH3"
        export CURL_LIBRARY_PATH
        AC_MSG_NOTICE([Added $DIR_MSH3 to CURL_LIBRARY_PATH]),

        experimental="$experimental HTTP3"
     )
    ],
      dnl not found, revert back to clean variables
      LDFLAGS=$CLEANLDFLAGS
      CPPFLAGS=$CLEANCPPFLAGS
      LIBS=$CLEANLIBS







|
>







3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
    AC_CHECK_HEADERS(msh3.h,
        curl_h3_msg="enabled (msh3)"
        MSH3_ENABLED=1
        AC_DEFINE(USE_MSH3, 1, [if msh3 is in use])
        AC_SUBST(USE_MSH3, [1])
        CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$DIR_MSH3"
        export CURL_LIBRARY_PATH
        AC_MSG_NOTICE([Added $DIR_MSH3 to CURL_LIBRARY_PATH])
        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libmsh3"
        experimental="$experimental HTTP3"
     )
    ],
      dnl not found, revert back to clean variables
      LDFLAGS=$CLEANLDFLAGS
      CPPFLAGS=$CLEANCPPFLAGS
      LIBS=$CLEANLIBS
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
  default|no)
    dnl --without-fish-functions-dir option used
    ;;
  yes)
    dnl --with-fish-functions-dir option used without path
    CURL_CHECK_PKGCONFIG(fish)
    if test "$PKGCONFIG" != "no" ; then
      FISH_FUNCTIONS_DIR="$($PKGCONFIG --variable completionsdir fish)"
    else
      FISH_FUNCTIONS_DIR="$datarootdir/fish/vendor_completions.d"
    fi
    AC_SUBST(FISH_FUNCTIONS_DIR)
    ;;
  *)
    dnl --with-fish-functions-dir option used with path







|







3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
  default|no)
    dnl --without-fish-functions-dir option used
    ;;
  yes)
    dnl --with-fish-functions-dir option used without path
    CURL_CHECK_PKGCONFIG(fish)
    if test "$PKGCONFIG" != "no" ; then
      FISH_FUNCTIONS_DIR=`$PKGCONFIG --variable completionsdir fish`
    else
      FISH_FUNCTIONS_DIR="$datarootdir/fish/vendor_completions.d"
    fi
    AC_SUBST(FISH_FUNCTIONS_DIR)
    ;;
  *)
    dnl --with-fish-functions-dir option used with path
3571
3572
3573
3574
3575
3576
3577

3578
3579
3580
3581
3582
3583
3584
        socket.h \
        sys/resource.h \
        libgen.h \
        locale.h \
        stdbool.h \
        sys/filio.h \
        sys/wait.h \

        setjmp.h,
dnl to do if not found
[],
dnl to do if found
[],
dnl default includes
[







>







3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
        socket.h \
        sys/resource.h \
        libgen.h \
        locale.h \
        stdbool.h \
        sys/filio.h \
        sys/wait.h \
        sys/eventfd.h \
        setjmp.h,
dnl to do if not found
[],
dnl to do if found
[],
dnl default includes
[
3776
3777
3778
3779
3780
3781
3782

3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
AC_CHECK_DECLS([getpwuid_r], [], [AC_DEFINE(HAVE_DECL_GETPWUID_R_MISSING, 1, "Set if getpwuid_r() declaration is missing")],
        [[#include <pwd.h>
          #include <sys/types.h>]])

AC_CHECK_FUNCS([\
  _fseeki64 \
  arc4random \

  fnmatch \
  fseeko \
  geteuid \
  getpass_r \
  getppid \
  getpwuid \
  getpwuid_r \
  getrlimit \
  gettimeofday \
  if_nametoindex \
  mach_absolute_time \
  pipe \
  sched_yield \
  sendmsg \
  setlocale \
  setmode \
  setrlimit \
  snprintf \
  utime \
  utimes \
],[
],[
  func="$ac_func"
  eval skipcheck=\$skipcheck_$func
  if test "x$skipcheck" != "xyes"; then
    AC_MSG_CHECKING([deeper for $func])
    AC_LINK_IFELSE([
      AC_LANG_PROGRAM([[
      ]],[[
        $func ();
      ]])
    ],[
      AC_MSG_RESULT([yes])
      eval "ac_cv_func_$func=yes"
      AC_DEFINE_UNQUOTED(XC_SH_TR_CPP([HAVE_$func]), [1],
        [Define to 1 if you have the $func function.])
    ],[
      AC_MSG_RESULT([but still no])
    ])
  fi
])

dnl On Android, the only way to know if fseeko can be used is to see if it is
dnl declared or not (for this API level), as the symbol always exists in the
dnl lib.
AC_CHECK_DECL([fseeko],
              [AC_DEFINE([HAVE_DECL_FSEEKO], [1],







>




















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826




















3827
3828
3829
3830
3831
3832
3833
AC_CHECK_DECLS([getpwuid_r], [], [AC_DEFINE(HAVE_DECL_GETPWUID_R_MISSING, 1, "Set if getpwuid_r() declaration is missing")],
        [[#include <pwd.h>
          #include <sys/types.h>]])

AC_CHECK_FUNCS([\
  _fseeki64 \
  arc4random \
  eventfd \
  fnmatch \
  fseeko \
  geteuid \
  getpass_r \
  getppid \
  getpwuid \
  getpwuid_r \
  getrlimit \
  gettimeofday \
  if_nametoindex \
  mach_absolute_time \
  pipe \
  sched_yield \
  sendmsg \
  setlocale \
  setmode \
  setrlimit \
  snprintf \
  utime \
  utimes \




















])

dnl On Android, the only way to know if fseeko can be used is to see if it is
dnl declared or not (for this API level), as the symbol always exists in the
dnl lib.
AC_CHECK_DECL([fseeko],
              [AC_DEFINE([HAVE_DECL_FSEEKO], [1],
3866
3867
3868
3869
3870
3871
3872




3873
3874
3875
3876
3877
3878
3879
else
  build_libhostname=no
fi
AM_CONDITIONAL(BUILD_LIBHOSTNAME, test x$build_libhostname = xyes)

if test "x$want_ares" != xyes; then
  CURL_CHECK_OPTION_THREADED_RESOLVER




fi

dnl ************************************************************
dnl disable POSIX threads
dnl
AC_MSG_CHECKING([whether to use POSIX threads for threaded resolver])
AC_ARG_ENABLE(pthreads,







>
>
>
>







3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
else
  build_libhostname=no
fi
AM_CONDITIONAL(BUILD_LIBHOSTNAME, test x$build_libhostname = xyes)

if test "x$want_ares" != xyes; then
  CURL_CHECK_OPTION_THREADED_RESOLVER

  if test "$ipv6" = yes; then
    CURL_DARWIN_SYSTEMCONFIGURATION
  fi
fi

dnl ************************************************************
dnl disable POSIX threads
dnl
AC_MSG_CHECKING([whether to use POSIX threads for threaded resolver])
AC_ARG_ENABLE(pthreads,
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
fi

dnl detect pthreads
if test "$want_pthreads" != "no"; then
  AC_CHECK_HEADER(pthread.h,
    [ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>])
      save_CFLAGS="$CFLAGS"
      dnl When statically linking against boringssl, -lpthread is added to LIBS.
      dnl Make sure to that this does not pass the check below, we really want
      dnl -pthread in CFLAGS as recommended for GCC. This also ensures that
      dnl lib1541 and lib1565 tests are built with these options. Otherwise
      dnl they fail the build since tests/libtest/Makefile.am clears LIBS.
      save_LIBS="$LIBS"

      LIBS=







|







3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
fi

dnl detect pthreads
if test "$want_pthreads" != "no"; then
  AC_CHECK_HEADER(pthread.h,
    [ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>])
      save_CFLAGS="$CFLAGS"
      dnl When statically linking against BoringSSL, -lpthread is added to LIBS.
      dnl Make sure to that this does not pass the check below, we really want
      dnl -pthread in CFLAGS as recommended for GCC. This also ensures that
      dnl lib1541 and lib1565 tests are built with these options. Otherwise
      dnl they fail the build since tests/libtest/Makefile.am clears LIBS.
      save_LIBS="$LIBS"

      LIBS=
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589

  dnl check for OpenSSL
  if test "x$OPENSSL_ENABLED" = "x1"; then
    AC_CHECK_FUNCS(SSL_ech_set1_echconfig,
      ECH_SUPPORT="ECH support available via OpenSSL with SSL_ech_set1_echconfig"
      ECH_ENABLED=1)
  fi
  dnl check for boringssl equivalent
  if test "x$OPENSSL_ENABLED" = "x1"; then
    AC_CHECK_FUNCS(SSL_set1_ech_config_list,
      ECH_SUPPORT="ECH support available via boringssl with SSL_set1_ech_config_list"
      ECH_ENABLED=1)
  fi
  if test "x$WOLFSSL_ENABLED" = "x1"; then
    AC_CHECK_FUNCS(wolfSSL_CTX_GenerateEchConfig,
      ECH_SUPPORT="ECH support available via WolfSSL with wolfSSL_CTX_GenerateEchConfig"
      ECH_ENABLED=1)
  fi

  dnl now deal with whatever we found
  if test "x$ECH_ENABLED" = "x1"; then
    dnl force pre-requisites for ECH
    AC_DEFINE(USE_HTTPSRR, 1, [force HTTPS RR support for ECH])







|


|




|







4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597

  dnl check for OpenSSL
  if test "x$OPENSSL_ENABLED" = "x1"; then
    AC_CHECK_FUNCS(SSL_ech_set1_echconfig,
      ECH_SUPPORT="ECH support available via OpenSSL with SSL_ech_set1_echconfig"
      ECH_ENABLED=1)
  fi
  dnl check for BoringSSL equivalent
  if test "x$OPENSSL_ENABLED" = "x1"; then
    AC_CHECK_FUNCS(SSL_set1_ech_config_list,
      ECH_SUPPORT="ECH support available via BoringSSL with SSL_set1_ech_config_list"
      ECH_ENABLED=1)
  fi
  if test "x$WOLFSSL_ENABLED" = "x1"; then
    AC_CHECK_FUNCS(wolfSSL_CTX_GenerateEchConfig,
      ECH_SUPPORT="ECH support available via wolfSSL with wolfSSL_CTX_GenerateEchConfig"
      ECH_ENABLED=1)
  fi

  dnl now deal with whatever we found
  if test "x$ECH_ENABLED" = "x1"; then
    dnl force pre-requisites for ECH
    AC_DEFINE(USE_HTTPSRR, 1, [force HTTPS RR support for ECH])
4661
4662
4663
4664
4665
4666
4667


4668



4669

4670
4671

4672
4673

4674
4675
4676
4677
4678
4679
4680
ENABLE_SHARED="$enable_shared"
AC_SUBST(ENABLE_SHARED)

dnl to let curl-config output the static libraries correctly
ENABLE_STATIC="$enable_static"
AC_SUBST(ENABLE_STATIC)



dnl merge the pkg-config Libs.private field into Libs when static-only



if test "x$enable_shared" = "xno"; then

  LIBCURL_NO_SHARED=$LIBCURL_LIBS
else

  LIBCURL_NO_SHARED=
fi

AC_SUBST(LIBCURL_NO_SHARED)

rm $compilersh

dnl
dnl For keeping supported features and protocols also in pkg-config file
dnl since it is more cross-compile friendly than curl-config







>
>
|
>
>
>

>


>


>







4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
ENABLE_SHARED="$enable_shared"
AC_SUBST(ENABLE_SHARED)

dnl to let curl-config output the static libraries correctly
ENABLE_STATIC="$enable_static"
AC_SUBST(ENABLE_STATIC)

squeeze LIBCURL_PC_REQUIRES_PRIVATE
LIBCURL_PC_REQUIRES_PRIVATE=`echo $LIBCURL_PC_REQUIRES_PRIVATE | tr ' ' ','`

AC_SUBST(LIBCURL_PC_REQUIRES_PRIVATE)

dnl Merge pkg-config private fields into public ones when static-only
if test "x$enable_shared" = "xno"; then
  LIBCURL_PC_REQUIRES=$LIBCURL_PC_REQUIRES_PRIVATE
  LIBCURL_NO_SHARED=$LIBCURL_LIBS
else
  LIBCURL_PC_REQUIRES=
  LIBCURL_NO_SHARED=
fi
AC_SUBST(LIBCURL_PC_REQUIRES)
AC_SUBST(LIBCURL_NO_SHARED)

rm $compilersh

dnl
dnl For keeping supported features and protocols also in pkg-config file
dnl since it is more cross-compile friendly than curl-config
4799
4800
4801
4802
4803
4804
4805






4806
4807
4808
4809
4810
4811
4812
    fi
  else
    AC_MSG_RESULT([no])
  fi
else
  AC_MSG_RESULT([no])
fi







if test ${ac_cv_sizeof_curl_off_t} -gt 4; then
  if test ${ac_cv_sizeof_off_t} -gt 4 -o \
     "$curl_win32_file_api" = "win32_large_files"; then
    SUPPORT_FEATURES="$SUPPORT_FEATURES Largefile"
  fi
fi







>
>
>
>
>
>







4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
    fi
  else
    AC_MSG_RESULT([no])
  fi
else
  AC_MSG_RESULT([no])
fi

if test "x$OPENSSL_ENABLED" = "x1" -o -n "$SSL_ENABLED"; then
  if test "x$ECH_ENABLED" = "x1"; then
    SUPPORT_FEATURES="$SUPPORT_FEATURES ECH"
  fi
fi

if test ${ac_cv_sizeof_curl_off_t} -gt 4; then
  if test ${ac_cv_sizeof_off_t} -gt 4 -o \
     "$curl_win32_file_api" = "win32_large_files"; then
    SUPPORT_FEATURES="$SUPPORT_FEATURES Largefile"
  fi
fi
4826
4827
4828
4829
4830
4831
4832







4833
4834
4835
4836



4837

4838
4839
4840
4841
4842
4843
4844
      #endif
    ]])
  ],[
     SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"
  ],[
  ])
fi








dnl replace spaces with newlines
dnl sort the lines
dnl replace the newlines back to spaces



SUPPORT_FEATURES=`echo $SUPPORT_FEATURES | tr ' ' '\012' | sort | tr '\012' ' '`

AC_SUBST(SUPPORT_FEATURES)

dnl For supported protocols in pkg-config file
if test "x$CURL_DISABLE_HTTP" != "x1"; then
  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTP IPFS IPNS"
  if test "x$SSL_ENABLED" = "x1"; then
    SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTPS"







>
>
>
>
>
>
>




>
>
>
|
>







4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
      #endif
    ]])
  ],[
     SUPPORT_FEATURES="$SUPPORT_FEATURES threadsafe"
  ],[
  ])
fi

if test "x$want_debug" = "xyes"; then
  SUPPORT_FEATURES="$SUPPORT_FEATURES Debug"
fi
if test "x$want_curldebug" = "xyes"; then
  SUPPORT_FEATURES="$SUPPORT_FEATURES TrackMemory"
fi

dnl replace spaces with newlines
dnl sort the lines
dnl replace the newlines back to spaces
if sort -f </dev/null >/dev/null 2>&1; then
  SUPPORT_FEATURES=`echo $SUPPORT_FEATURES | tr ' ' '\012' | sort -f | tr '\012' ' '`
else
  SUPPORT_FEATURES=`echo $SUPPORT_FEATURES | tr ' ' '\012' | sort | tr '\012' ' '`
fi
AC_SUBST(SUPPORT_FEATURES)

dnl For supported protocols in pkg-config file
if test "x$CURL_DISABLE_HTTP" != "x1"; then
  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTP IPFS IPNS"
  if test "x$SSL_ENABLED" = "x1"; then
    SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS HTTPS"
4983
4984
4985
4986
4987
4988
4989


4990
4991
4992
4993
4994
4995

4996
4997
4998
4999
5000
5001
5002
           curl-config \
           libcurl.pc
])
AC_OUTPUT

CURL_GENERATE_CONFIGUREHELP_PM



AC_MSG_NOTICE([Configured to build curl/libcurl:

  Host setup:       ${host}
  Install prefix:   ${prefix}
  Compiler:         ${CC}
   CFLAGS:          ${CFLAGS}

   CPPFLAGS:        ${CPPFLAGS}
   LDFLAGS:         ${LDFLAGS}
   LIBS:            ${LIBS}

  curl version:     ${CURLVERSION}
  SSL:              ${curl_ssl_msg}
  SSH:              ${curl_ssh_msg}







>
>






>







5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
           curl-config \
           libcurl.pc
])
AC_OUTPUT

CURL_GENERATE_CONFIGUREHELP_PM

SUPPORT_PROTOCOLS_LOWER=`echo "$SUPPORT_PROTOCOLS" | tr A-Z a-z`

AC_MSG_NOTICE([Configured to build curl/libcurl:

  Host setup:       ${host}
  Install prefix:   ${prefix}
  Compiler:         ${CC}
   CFLAGS:          ${CFLAGS}
   CFLAGS extras:   ${CURL_CFLAG_EXTRAS}
   CPPFLAGS:        ${CPPFLAGS}
   LDFLAGS:         ${LDFLAGS}
   LIBS:            ${LIBS}

  curl version:     ${CURLVERSION}
  SSL:              ${curl_ssl_msg}
  SSH:              ${curl_ssh_msg}
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044

5045
5046
5047
5048
5049
5050

5051
  Headers API:      ${curl_headers_msg}
  HSTS:             ${curl_hsts_msg}
  HTTP1:            ${curl_h1_msg}
  HTTP2:            ${curl_h2_msg}
  HTTP3:            ${curl_h3_msg}
  ECH:              ${curl_ech_msg}
  WebSockets:       ${curl_ws_msg}
  Protocols:        ${SUPPORT_PROTOCOLS}
  Features:         ${SUPPORT_FEATURES}
])

non13=`echo "$TLSCHOICE" | grep -Ei 'bearssl|secure-transport|mbedtls'`;
if test -n "$non13"; then
 cat >&2 << _EOF
  WARNING: A selected TLS library ($TLSCHOICE) does not support TLS 1.3!
_EOF

fi

if test -n "$experimental"; then
 cat >&2 << _EOF
  WARNING: $experimental enabled but marked EXPERIMENTAL. Use with caution!
_EOF

fi







|



|

|
|
<
>



|
|
<
>

5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079

5080
5081
5082
5083
5084
5085

5086
5087
  Headers API:      ${curl_headers_msg}
  HSTS:             ${curl_hsts_msg}
  HTTP1:            ${curl_h1_msg}
  HTTP2:            ${curl_h2_msg}
  HTTP3:            ${curl_h3_msg}
  ECH:              ${curl_ech_msg}
  WebSockets:       ${curl_ws_msg}
  Protocols:        ${SUPPORT_PROTOCOLS_LOWER}
  Features:         ${SUPPORT_FEATURES}
])

non13=`echo "$TLSCHOICE" | $EGREP -io 'bearssl|secure-transport'`;
if test -n "$non13"; then
 for a in $non13; do
   AC_MSG_WARN([$a is enabled for TLS but it does not support TLS 1.3])

 done
fi

if test -n "$experimental"; then
 for a in $experimental; do
   AC_MSG_WARN([$a is enabled but marked EXPERIMENTAL. Use with caution!])

 done
fi
Changes to jni/curl/curl-config.in.
19
20
21
22
23
24
25


26
27
28
29
30
31
32
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################



prefix="@prefix@"
# Used in @libdir@
# shellcheck disable=SC2034
exec_prefix=@exec_prefix@
# shellcheck disable=SC2034
includedir=@includedir@
cppflag_curl_staticlib=@CPPFLAG_CURL_STATICLIB@







>
>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################

# shellcheck disable=SC2006

prefix="@prefix@"
# Used in @libdir@
# shellcheck disable=SC2034
exec_prefix=@exec_prefix@
# shellcheck disable=SC2034
includedir=@includedir@
cppflag_curl_staticlib=@CPPFLAG_CURL_STATICLIB@
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  --version)
    echo 'libcurl @CURLVERSION@'
    exit 0
    ;;

  --checkfor)
    checkfor=$2
    cmajor=$(echo "$checkfor" | cut -d. -f1)
    cminor=$(echo "$checkfor" | cut -d. -f2)
    # when extracting the patch part we strip off everything after a
    # dash as that's used for things like version 1.2.3-pre1
    cpatch=$(echo "$checkfor" | cut -d. -f3 | cut -d- -f1)

    vmajor=$(echo '@CURLVERSION@' | cut -d. -f1)
    vminor=$(echo '@CURLVERSION@' | cut -d. -f2)
    # when extracting the patch part we strip off everything after a
    # dash as that's used for things like version 1.2.3-pre1
    vpatch=$(echo '@CURLVERSION@' | cut -d. -f3 | cut -d- -f1)

    if test "$vmajor" -gt "$cmajor"; then
      exit 0
    fi
    if test "$vmajor" -eq "$cmajor"; then
      if test "$vminor" -gt "$cminor"; then
        exit 0







|
|


|

|
|


|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  --version)
    echo 'libcurl @CURLVERSION@'
    exit 0
    ;;

  --checkfor)
    checkfor=$2
    cmajor=`echo "$checkfor" | cut -d. -f1`
    cminor=`echo "$checkfor" | cut -d. -f2`
    # when extracting the patch part we strip off everything after a
    # dash as that's used for things like version 1.2.3-pre1
    cpatch=`echo "$checkfor" | cut -d. -f3 | cut -d- -f1`

    vmajor=`echo '@CURLVERSION@' | cut -d. -f1`
    vminor=`echo '@CURLVERSION@' | cut -d. -f2`
    # when extracting the patch part we strip off everything after a
    # dash as that's used for things like version 1.2.3-pre1
    vpatch=`echo '@CURLVERSION@' | cut -d. -f3 | cut -d- -f1`

    if test "$vmajor" -gt "$cmajor"; then
      exit 0
    fi
    if test "$vmajor" -eq "$cmajor"; then
      if test "$vminor" -gt "$cminor"; then
        exit 0
Changes to jni/curl/docs/BINDINGS.md.
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

[Harbour](https://github.com/vszakats/hb/tree/main/contrib/hbcurl) Written by Viktor Szakats

[Haskell](https://hackage.haskell.org/package/curl) Written by Galois, Inc

[Hollywood](https://www.hollywood-mal.com/download.html) hURL by Andreas Falkenhahn

[Java](https://github.com/pjlegato/curl-java)

[Julia](https://github.com/JuliaWeb/LibCURL.jl) Written by Amit Murthy

[Kapito](https://github.com/puzza007/katipo) is an Erlang HTTP library around libcurl.

[Lisp](https://common-lisp.net/project/cl-curl/) Written by Liam Healy








|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

[Harbour](https://github.com/vszakats/hb/tree/main/contrib/hbcurl) Written by Viktor Szakats

[Haskell](https://hackage.haskell.org/package/curl) Written by Galois, Inc

[Hollywood](https://www.hollywood-mal.com/download.html) hURL by Andreas Falkenhahn

[Java](https://github.com/covers1624/curl4j)

[Julia](https://github.com/JuliaWeb/LibCURL.jl) Written by Amit Murthy

[Kapito](https://github.com/puzza007/katipo) is an Erlang HTTP library around libcurl.

[Lisp](https://common-lisp.net/project/cl-curl/) Written by Liam Healy

Changes to jni/curl/docs/CIPHERS.md.
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

`TLS_AES_256_GCM_SHA384`
`TLS_CHACHA20_POLY1305_SHA256`
`TLS_AES_128_GCM_SHA256`
`TLS_AES_128_CCM_8_SHA256`
`TLS_AES_128_CCM_SHA256`

## WolfSSL

`RC4-SHA`,
`RC4-MD5`,
`DES-CBC3-SHA`,
`AES128-SHA`,
`AES256-SHA`,
`NULL-SHA`,







|







167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

`TLS_AES_256_GCM_SHA384`
`TLS_CHACHA20_POLY1305_SHA256`
`TLS_AES_128_GCM_SHA256`
`TLS_AES_128_CCM_8_SHA256`
`TLS_AES_128_CCM_SHA256`

## wolfSSL

`RC4-SHA`,
`RC4-MD5`,
`DES-CBC3-SHA`,
`AES128-SHA`,
`AES256-SHA`,
`NULL-SHA`,
Changes to jni/curl/docs/CLIENT-READERS.md.
119
120
121
122
123
124
125
126
127
128
129
130
131
132
2. `Curl_creader_will_rewind(data)`: tells if the reader chain rewinds at the start of the next request.
3. `Curl_creader_set_rewind(data, TRUE)`: marks the reader chain for rewinding at the start of the next request.
4. `Curl_client_start(data)`: tells the readers that a new request starts and they need to rewind if requested.


## Summary and Outlook

By adding the client reader interface, any protocol can control how/if it wants the curl transfer to send bytes for a request. The transfer loop becomes then blissfully ignorant of the specifics. 

The protocols on the other hand no longer have to care to package data most efficiently. At any time, should more data be needed, it can be read from the client. This is used when sending HTTP requests headers to add as much request body data to the initial sending as there is room for.

Future enhancements based on the client readers:
* `expect-100` handling: place that into a HTTP specific reader at `CURL_CR_PROTOCOL` and eliminate the checks in the generic transfer parts.
* `eos forwarding`: transfer should forward an `eos` flag to the connection filters. Filters like HTTP/2 and HTTP/3 can make use of that, terminating streams early. This would also eliminate length checks in stream handling.







|






119
120
121
122
123
124
125
126
127
128
129
130
131
132
2. `Curl_creader_will_rewind(data)`: tells if the reader chain rewinds at the start of the next request.
3. `Curl_creader_set_rewind(data, TRUE)`: marks the reader chain for rewinding at the start of the next request.
4. `Curl_client_start(data)`: tells the readers that a new request starts and they need to rewind if requested.


## Summary and Outlook

By adding the client reader interface, any protocol can control how/if it wants the curl transfer to send bytes for a request. The transfer loop becomes then blissfully ignorant of the specifics.

The protocols on the other hand no longer have to care to package data most efficiently. At any time, should more data be needed, it can be read from the client. This is used when sending HTTP requests headers to add as much request body data to the initial sending as there is room for.

Future enhancements based on the client readers:
* `expect-100` handling: place that into a HTTP specific reader at `CURL_CR_PROTOCOL` and eliminate the checks in the generic transfer parts.
* `eos forwarding`: transfer should forward an `eos` flag to the connection filters. Filters like HTTP/2 and HTTP/3 can make use of that, terminating streams early. This would also eliminate length checks in stream handling.
Changes to jni/curl/docs/CMakeLists.txt.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#add_subdirectory(examples)
if(BUILD_LIBCURL_DOCS)
  add_subdirectory(libcurl)
endif()
if(ENABLE_CURL_MANUAL AND BUILD_CURL_EXE)
  add_subdirectory(cmdline-opts)
endif()








|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################

if(BUILD_LIBCURL_DOCS)
  add_subdirectory(libcurl)
endif()
if(ENABLE_CURL_MANUAL AND BUILD_CURL_EXE)
  add_subdirectory(cmdline-opts)
endif()

Changes to jni/curl/docs/CODE_REVIEW.md.
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
data. Where it comes from and where it goes.

## Variable types differ

`size_t` is not a fixed size. `time_t` can be signed or unsigned and have
different sizes. Relying on variable sizes is a red flag.

Also remember that endianness and >= 32 bit accesses to unaligned addresses
are problematic areas.

## Integer overflows

Be careful about integer overflows. Some variable types can be either 32 bit
or 64 bit. Integer overflows must be detected and acted on *before* they
happen.

## Dangerous use of functions

Maybe use of `realloc()` should rather use the dynbuf functions?

Do not allow new code that grows buffers without using dynbuf.







|




|
|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
data. Where it comes from and where it goes.

## Variable types differ

`size_t` is not a fixed size. `time_t` can be signed or unsigned and have
different sizes. Relying on variable sizes is a red flag.

Also remember that endianness and >= 32-bit accesses to unaligned addresses
are problematic areas.

## Integer overflows

Be careful about integer overflows. Some variable types can be either 32-bit
or 64-bit. Integer overflows must be detected and acted on *before* they
happen.

## Dangerous use of functions

Maybe use of `realloc()` should rather use the dynbuf functions?

Do not allow new code that grows buffers without using dynbuf.
Changes to jni/curl/docs/CONNECTION-FILTERS.md.
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
                                 - ballerv4 --> TCP[151.101.1.91]:443
                                 - ballerv6 --> TCP[2a04:4e42:c00::347]:443
* v6 answers, connected
conn[curl.se] --> SETUP[TCP] --> HAPPY-EYEBALLS --> TCP[2a04:4e42:c00::347]:443
* transfer
```

The modular design of connection filters and that we can plug them into each other is used to control the parallel attempts. When a `TCP` filter does not connect (in time), it is torn down and another one is created for the next address. This keeps the `TCP` filter simple. 

The `HAPPY-EYEBALLS` on the other hand stays focused on its side of the problem. We can use it also to make other type of connection by just giving it another filter type to try to have happy eyeballing for QUIC:

```
* create connection for --http3-only https://curl.se
conn[curl.se] --> SETUP[QUIC] --> HAPPY-EYEBALLS --> NULL
* start connect







|







267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
                                 - ballerv4 --> TCP[151.101.1.91]:443
                                 - ballerv6 --> TCP[2a04:4e42:c00::347]:443
* v6 answers, connected
conn[curl.se] --> SETUP[TCP] --> HAPPY-EYEBALLS --> TCP[2a04:4e42:c00::347]:443
* transfer
```

The modular design of connection filters and that we can plug them into each other is used to control the parallel attempts. When a `TCP` filter does not connect (in time), it is torn down and another one is created for the next address. This keeps the `TCP` filter simple.

The `HAPPY-EYEBALLS` on the other hand stays focused on its side of the problem. We can use it also to make other type of connection by just giving it another filter type to try to have happy eyeballing for QUIC:

```
* create connection for --http3-only https://curl.se
conn[curl.se] --> SETUP[QUIC] --> HAPPY-EYEBALLS --> NULL
* start connect
Changes to jni/curl/docs/CONTRIBUTE.md.
312
313
314
315
316
317
318
319
320
321
322
323
There is a CI job called **REUSE compliance / check** that runs on every pull
request and commit to verify that the *REUSE state* of all files are still
fine.

This means that all files need to have their license and copyright information
clearly stated. Ideally by having the standard curl source code header, with
the SPDX-License-Identifier included. If the header does not work, you can use a
smaller header or add the information for a specific file to the `.reuse/dep5`
file.

You can manually verify the copyright and compliance status by running the
`./scripts/copyright.pl` script in the root of the git repository.







|



|
312
313
314
315
316
317
318
319
320
321
322
323
There is a CI job called **REUSE compliance / check** that runs on every pull
request and commit to verify that the *REUSE state* of all files are still
fine.

This means that all files need to have their license and copyright information
clearly stated. Ideally by having the standard curl source code header, with
the SPDX-License-Identifier included. If the header does not work, you can use a
smaller header or add the information for a specific file to the `REUSE.toml`
file.

You can manually verify the copyright and compliance status by running the
[REUSE helper tool](https://github.com/fsfe/reuse-tool): `reuse lint`
Changes to jni/curl/docs/CURLDOWN.md.
76
77
78
79
80
81
82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
    Protocol:
      - HTTP
    See-also:
      - CURLOPT_HEADEROPT (3)
      - CURLOPT_HTTPAUTH (3)
    TLS-backend:
      - [name]

    ---

All curldown files *must* have all the headers present and at least one
`See-also:` entry specified.

If the man page is for section 3 (library related). The `Protocol` list must
contain at least one protocol, which can be `*` if the option is virtually for
everything. If `*` is used, it must be the only listed protocol. Recognized
protocols are either URL schemes (in uppercase), `TLS` or `TCP`.

If the `Protocol` list contains `TLS`, then there must also be a `TLS-backend`
list, specifying `All` or a list of what TLS backends that work with this
option. The available TLS backends are:

- `BearSSL`
- `GnuTLS`
- `mbedTLS`
- `OpenSSL` (also covers BoringSSL, libressl, quictls, AWS-LC and AmiSSL)
- `rustls`
- `Schannel`
- `Secure Transport`
- `wolfSSL`
- `All`: all TLS backends

Following the header in the file, is the manual page using markdown-like







>

















|







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    Protocol:
      - HTTP
    See-also:
      - CURLOPT_HEADEROPT (3)
      - CURLOPT_HTTPAUTH (3)
    TLS-backend:
      - [name]
    Added-in: [version or "n/a"]
    ---

All curldown files *must* have all the headers present and at least one
`See-also:` entry specified.

If the man page is for section 3 (library related). The `Protocol` list must
contain at least one protocol, which can be `*` if the option is virtually for
everything. If `*` is used, it must be the only listed protocol. Recognized
protocols are either URL schemes (in uppercase), `TLS` or `TCP`.

If the `Protocol` list contains `TLS`, then there must also be a `TLS-backend`
list, specifying `All` or a list of what TLS backends that work with this
option. The available TLS backends are:

- `BearSSL`
- `GnuTLS`
- `mbedTLS`
- `OpenSSL` (also covers BoringSSL, LibreSSL, quictls, AWS-LC and AmiSSL)
- `rustls`
- `Schannel`
- `Secure Transport`
- `wolfSSL`
- `All`: all TLS backends

Following the header in the file, is the manual page using markdown-like
143
144
145
146
147
148
149








150
151
152
153
154
155
156
157
158
159
When generating the nroff output, the tooling removes superfluous newlines,
meaning they can be used freely in the source file to make the text more
readable.

To make sure curldown documents render correctly as markdown, all literal
occurrences of `<` or `>` need to be escaped by a leading backslash.









## symbols

All mentioned curl symbols that have their own man pages, like
`curl_easy_perform(3)` are automatically rendered using italics in the output
without having to enclose it with asterisks. This helps ensuring that they get
converted to links properly later in the HTML version on the website, as
converted with `roffit`. This makes the curldown text easier to read even when
mentioning many curl symbols.

This auto-linking works for patterns matching `(lib|)curl[^ ]*(3)`.







>
>
>
>
>
>
>
>
|









144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
When generating the nroff output, the tooling removes superfluous newlines,
meaning they can be used freely in the source file to make the text more
readable.

To make sure curldown documents render correctly as markdown, all literal
occurrences of `<` or `>` need to be escaped by a leading backslash.

## Generating contents

`# %PROTOCOLS%` - inserts a **PROTOCOLS** section based on the metadata
provided in the header.

`# %AVAILABILITY%` - inserts an **AVAILABILITY** section based on the metadata
provided in the header.

## Symbols

All mentioned curl symbols that have their own man pages, like
`curl_easy_perform(3)` are automatically rendered using italics in the output
without having to enclose it with asterisks. This helps ensuring that they get
converted to links properly later in the HTML version on the website, as
converted with `roffit`. This makes the curldown text easier to read even when
mentioning many curl symbols.

This auto-linking works for patterns matching `(lib|)curl[^ ]*(3)`.
Changes to jni/curl/docs/DEPRECATE.md.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


It requires that a curl build using the library should be able to negotiate
and use TLS 1.3, or else it is not good enough.

As of May 2024, the libraries that need to get fixed to remain supported after
May 2025 are: BearSSL and Secure Transport.

## space-separated `NOPROXY` patterns

When specifying patterns/domain names for curl that should *not* go through a
proxy, the curl tool features the `--noproxy` command line option and the
library supports the `NO_PROXY` environment variable and the `CURLOPT_NOPROXY`
libcurl option.

They all set the same list of patterns. This list is documented to be a set of
**comma-separated** names, but can also be provided separated with just
space. The ability to just use spaces for this has never been documented but
some users may still have come to rely on this.

Several other tools and utilities also parse the `NO_PROXY` environment
variable but do not consider a space to be a valid separator. Using spaces for
separator is probably less portable and might cause more friction than commas
do. Users should use commas for this for greater portability.

curl removes the support for space-separated names in July 2024.

## past removals

 - Pipelining
 - axTLS
 - PolarSSL
 - NPN
 - Support for systems without 64 bit data types
 - NSS
 - gskit
 - mingw v1
 - NTLM_WB








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|





|




>
19
20
21
22
23
24
25



















26
27
28
29
30
31
32
33
34
35
36
37

It requires that a curl build using the library should be able to negotiate
and use TLS 1.3, or else it is not good enough.

As of May 2024, the libraries that need to get fixed to remain supported after
May 2025 are: BearSSL and Secure Transport.




















## Past removals

 - Pipelining
 - axTLS
 - PolarSSL
 - NPN
 - Support for systems without 64-bit data types
 - NSS
 - gskit
 - mingw v1
 - NTLM_WB
 - space-separated `NOPROXY` patterns
Changes to jni/curl/docs/DISTROS.md.
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27
28

Lots of organizations distribute curl packages to end users. This is a
collection of pointers to where to learn more about curl on and with each
distro. Those marked *Rolling Release* typically run the latest version of curl
and are therefore less likely to have back-ported patches to older versions.

We discuss curl distro issues, patches and collaboration on the [curl-distros
mailing list](https://lists.haxx.se/listinfo/curl-distros).


## AlmaLinux

- curl package source and patches: curl package source and patches
- curl issues: https://bugs.almalinux.org/view_all_bug_page.php click Category and choose curl
- curl security: https://errata.almalinux.org/ search for curl

## Alpine Linux

- curl: https://pkgs.alpinelinux.org/package/edge/main/x86_64/curl
- curl issues: https://gitlab.alpinelinux.org/alpine/aports/-/issues







|
>



|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

Lots of organizations distribute curl packages to end users. This is a
collection of pointers to where to learn more about curl on and with each
distro. Those marked *Rolling Release* typically run the latest version of curl
and are therefore less likely to have back-ported patches to older versions.

We discuss curl distro issues, patches and collaboration on the [curl-distros
mailing list](https://lists.haxx.se/listinfo/curl-distros) ([list
archives](https://curl.se/mail/list.cgi?list=curl-distros)).

## AlmaLinux

- curl package source and patches: https://git.almalinux.org/rpms/curl/
- curl issues: https://bugs.almalinux.org/view_all_bug_page.php click Category and choose curl
- curl security: https://errata.almalinux.org/ search for curl

## Alpine Linux

- curl: https://pkgs.alpinelinux.org/package/edge/main/x86_64/curl
- curl issues: https://gitlab.alpinelinux.org/alpine/aports/-/issues
159
160
161
162
163
164
165








166
167
168
169
170
171
172
- curl issues: https://bugs.mageia.org/buglist.cgi?bug_status=NEW&bug_status=UNCONFIRMED&bug_status=NEEDINFO&bug_status=UPSTREAM&bug_status=ASSIGNED&component=RPM%20Packages&f1=cf_rpmpkg&list_id=176576&o1=casesubstring&product=Mageia&query_format=advanced&v1=curl
- curl patches: https://svnweb.mageia.org/packages/cauldron/curl/current/SOURCES/
- curl patches in stable distro releases: https://svnweb.mageia.org/packages/updates/<STABLE_VERSION>/curl/current/SOURCES/
- curl security: https://advisories.mageia.org/src_curl.html

## MSYS2









*Rolling Release*

- curl: https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-curl
- curl issues: https://github.com/msys2/MINGW-packages/issues
- curl patches: https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-curl (`*.patch`)

## Muldersoft







>
>
>
>
>
>
>
>







160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
- curl issues: https://bugs.mageia.org/buglist.cgi?bug_status=NEW&bug_status=UNCONFIRMED&bug_status=NEEDINFO&bug_status=UPSTREAM&bug_status=ASSIGNED&component=RPM%20Packages&f1=cf_rpmpkg&list_id=176576&o1=casesubstring&product=Mageia&query_format=advanced&v1=curl
- curl patches: https://svnweb.mageia.org/packages/cauldron/curl/current/SOURCES/
- curl patches in stable distro releases: https://svnweb.mageia.org/packages/updates/<STABLE_VERSION>/curl/current/SOURCES/
- curl security: https://advisories.mageia.org/src_curl.html

## MSYS2

*Rolling Release*

- curl: https://github.com/msys2/MSYS2-packages/tree/master/curl
- curl issues: https://github.com/msys2/MSYS2-packages/issues
- curl patches: https://github.com/msys2/MSYS2-packages/tree/master/curl (`*.patch`)

## MSYS2 (mingw-w64)

*Rolling Release*

- curl: https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-curl
- curl issues: https://github.com/msys2/MINGW-packages/issues
- curl patches: https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-curl (`*.patch`)

## Muldersoft
Changes to jni/curl/docs/ECH.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Building curl with HTTPS-RR and ECH support

We've added support for ECH to in this curl build. That can use HTTPS RRs
published in the DNS, if curl is using DoH, or else can accept the relevant
ECHConfigList values from the command line. That works with OpenSSL,
WolfSSL or boringssl as the TLS provider, depending on how you build curl.

This feature is EXPERIMENTAL. DO NOT USE IN PRODUCTION.

This should however provide enough of a proof-of-concept to prompt an informed
discussion about a good path forward for ECH support in curl, when using
OpenSSL, or other TLS libraries, as those add ECH support.

## OpenSSL Build

To build our ECH-enabled OpenSSL fork:

```bash
    cd $HOME/code








|
|
|
|




|
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# Building curl with HTTPS-RR and ECH support

We have added support for ECH to curl. It can use HTTPS RRs published in the
DNS if curl uses DoH, or else can accept the relevant ECHConfigList values
from the command line. This works with OpenSSL, wolfSSL or BoringSSL as the
TLS provider.

This feature is EXPERIMENTAL. DO NOT USE IN PRODUCTION.

This should however provide enough of a proof-of-concept to prompt an informed
discussion about a good path forward for ECH support in curl.


## OpenSSL Build

To build our ECH-enabled OpenSSL fork:

```bash
    cd $HOME/code
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
```bash
    cd $HOME/code
    git clone https://github.com/curl/curl
    cd curl
    autoreconf -fi
    LDFLAGS="-Wl,-rpath,$HOME/code/openssl-local-inst/lib/" ./configure --with-ssl=$HOME/code/openssl-local-inst --enable-ech --enable-httpsrr
    ...lots of output...
    WARNING: ech ECH HTTPSRR enabled but marked EXPERIMENTAL...
    make
    ...lots more output...
```

If you do not get that WARNING at the end of the ``configure`` command, then ECH
is not enabled, so go back some steps and re-do whatever needs re-doing:-) If you
want to debug curl then you should add ``--enable-debug`` to the ``configure``
command.

In a recent (2024-05-20) build on one machine, configure failed to find the
ECH-enabled SSL library, apparently due to the existence of
``$HOME/code/openssl-local-inst/lib/pkgconfig`` as a directory containing
various settings. Deleting that directory worked around the problem but may not
be the best solution.

## Using ECH and DoH

Curl supports using DoH for A/AAAA lookups so it was relatively easy to add
retrieval of HTTPS RRs in that situation. To use ECH and DoH together:

```bash







|




|
|
|
|




|
|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
```bash
    cd $HOME/code
    git clone https://github.com/curl/curl
    cd curl
    autoreconf -fi
    LDFLAGS="-Wl,-rpath,$HOME/code/openssl-local-inst/lib/" ./configure --with-ssl=$HOME/code/openssl-local-inst --enable-ech --enable-httpsrr
    ...lots of output...
    WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL...
    make
    ...lots more output...
```

If you do not get that WARNING at the end of the ``configure`` command, then
ECH is not enabled, so go back some steps and re-do whatever needs re-doing:-)
If you want to debug curl then you should add ``--enable-debug`` to the
``configure`` command.

In a recent (2024-05-20) build on one machine, configure failed to find the
ECH-enabled SSL library, apparently due to the existence of
``$HOME/code/openssl-local-inst/lib/pkgconfig`` as a directory containing
various settings. Deleting that directory worked around the problem but may
not be the best solution.

## Using ECH and DoH

Curl supports using DoH for A/AAAA lookups so it was relatively easy to add
retrieval of HTTPS RRs in that situation. To use ECH and DoH together:

```bash
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    ...
* ECH: retry_configs AQD+DQA8DAAgACBvYqJy+Hgk33wh/ZLBzKSPgwxeop7gvojQzfASq7zeZQAEAAEAAQANY292ZXIuZGVmby5pZQAA/g0APEMAIAAgXkT5r4cYs8z19q5rdittyIX8gfQ3ENW4wj1fVoiJZBoABAABAAEADWNvdmVyLmRlZm8uaWUAAP4NADw2ACAAINXSE9EdXzEQIJZA7vpwCIQsWqsFohZARXChgPsnfI1kAAQAAQABAA1jb3Zlci5kZWZvLmllAAD+DQA8cQAgACASeiD5F+UoSnVoHvA2l1EifUVMFtbVZ76xwDqmMPraHQAEAAEAAQANY292ZXIuZGVmby5pZQAA
* ECH: retry_configs for defo.ie from cover.defo.ie, 319
    ...
```

At that point, you could copy the base64 encoded value above and try again.
For now, this only works for the OpenSSL and boringssl builds.

## Default settings

Curl has various ways to configure default settings, e.g. in ``$HOME/.curlrc``,
so one can set the DoH URL and enable ECH that way:

```bash







|







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
    ...
* ECH: retry_configs AQD+DQA8DAAgACBvYqJy+Hgk33wh/ZLBzKSPgwxeop7gvojQzfASq7zeZQAEAAEAAQANY292ZXIuZGVmby5pZQAA/g0APEMAIAAgXkT5r4cYs8z19q5rdittyIX8gfQ3ENW4wj1fVoiJZBoABAABAAEADWNvdmVyLmRlZm8uaWUAAP4NADw2ACAAINXSE9EdXzEQIJZA7vpwCIQsWqsFohZARXChgPsnfI1kAAQAAQABAA1jb3Zlci5kZWZvLmllAAD+DQA8cQAgACASeiD5F+UoSnVoHvA2l1EifUVMFtbVZ76xwDqmMPraHQAEAAEAAQANY292ZXIuZGVmby5pZQAA
* ECH: retry_configs for defo.ie from cover.defo.ie, 319
    ...
```

At that point, you could copy the base64 encoded value above and try again.
For now, this only works for the OpenSSL and BoringSSL builds.

## Default settings

Curl has various ways to configure default settings, e.g. in ``$HOME/.curlrc``,
so one can set the DoH URL and enable ECH that way:

```bash
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
- ``USE_HTTPSRR`` is used for HTTPS RR retrieval code that could be generically
  used should non-ECH uses for HTTPS RRs be identified, e.g. use of ALPN values
or IP address hints.

- ``USE_ECH`` protects ECH specific code.

There are various obvious code blocks for handling the new command line
arguments which aren't described here, but should be fairly clear.

As shown in the ``configure`` usage above, there are ``configure.ac`` changes
that allow separately dis/enabling ``USE_HTTPSRR`` and ``USE_ECH``. If ``USE_ECH``
is enabled, then ``USE_HTTPSRR`` is forced. In both cases ``USE_DOH``
is required. (There may be some configuration conflicts available for the
determined:-)








|







211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
- ``USE_HTTPSRR`` is used for HTTPS RR retrieval code that could be generically
  used should non-ECH uses for HTTPS RRs be identified, e.g. use of ALPN values
or IP address hints.

- ``USE_ECH`` protects ECH specific code.

There are various obvious code blocks for handling the new command line
arguments which are not described here, but should be fairly clear.

As shown in the ``configure`` usage above, there are ``configure.ac`` changes
that allow separately dis/enabling ``USE_HTTPSRR`` and ``USE_ECH``. If ``USE_ECH``
is enabled, then ``USE_HTTPSRR`` is forced. In both cases ``USE_DOH``
is required. (There may be some configuration conflicts available for the
determined:-)

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
emerge would provide good answers there, but for now, it is not clear how best
curl might handle those values when present in the DNS.

- The SVCB/HTTPS RR specification supports a new "CNAME at apex" indirection
  ("aliasMode") - the current code takes no account of that at all. One could
envisage implementing the equivalent of following CNAMEs in such cases, but
it is not clear if that'd be a good plan. (As of now, chrome browsers do not seem
to have any support for that "aliasMode" and we've not checked Firefox for that
recently.)

- We have not investigated what related changes or additions might be needed
  for applications using libcurl, as opposed to use of curl as a command line
tool.

- We have not yet implemented tests as part of the usual curl test harness as
doing so would seem to require re-implementing an ECH-enabled server as part
of the curl test harness. For now, we have a ``./tests/ech_test.sh`` script
that attempts ECH with various test servers and with many combinations of the
allowed command line options. While that is a useful test and has find issues,
it is not comprehensive and we're not (as yet) sure what would be the right
level of coverage. When running that script you should not have a
``$HOME/.curlrc`` file that affects ECH or some of the negative tests could
produce spurious failures.

## Building with cmake

To build with cmake, assuming our ECH-enabled OpenSSL is as before:







|











|







265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
emerge would provide good answers there, but for now, it is not clear how best
curl might handle those values when present in the DNS.

- The SVCB/HTTPS RR specification supports a new "CNAME at apex" indirection
  ("aliasMode") - the current code takes no account of that at all. One could
envisage implementing the equivalent of following CNAMEs in such cases, but
it is not clear if that'd be a good plan. (As of now, chrome browsers do not seem
to have any support for that "aliasMode" and we have not checked Firefox for that
recently.)

- We have not investigated what related changes or additions might be needed
  for applications using libcurl, as opposed to use of curl as a command line
tool.

- We have not yet implemented tests as part of the usual curl test harness as
doing so would seem to require re-implementing an ECH-enabled server as part
of the curl test harness. For now, we have a ``./tests/ech_test.sh`` script
that attempts ECH with various test servers and with many combinations of the
allowed command line options. While that is a useful test and has find issues,
it is not comprehensive and we are not (as yet) sure what would be the right
level of coverage. When running that script you should not have a
``$HOME/.curlrc`` file that affects ECH or some of the negative tests could
produce spurious failures.

## Building with cmake

To build with cmake, assuming our ECH-enabled OpenSSL is as before:
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
    ...
    [100%] Built target curl
```

The binary produced by the cmake build does not need any ECH-specific
``LD_LIBRARY_PATH`` setting.

## boringssl build

BoringSSL is also supported by curl and also supports ECH, so to build
with that, instead of our ECH-enabled OpenSSL:

```bash
    cd $HOME/code
    git clone https://boringssl.googlesource.com/boringssl







|







302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
    ...
    [100%] Built target curl
```

The binary produced by the cmake build does not need any ECH-specific
``LD_LIBRARY_PATH`` setting.

## BoringSSL build

BoringSSL is also supported by curl and also supports ECH, so to build
with that, instead of our ECH-enabled OpenSSL:

```bash
    cd $HOME/code
    git clone https://boringssl.googlesource.com/boringssl
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
```bash
    cd $HOME/code
    git clone https://github.com/curl/curl
    cd curl
    autoreconf -fi
    LDFLAGS="-Wl,-rpath,$HOME/code/boringssl/inst/lib" ./configure --with-ssl=$HOME/code/boringssl/inst --enable-ech --enable-httpsrr
    ...lots of output...
    WARNING: ech ECH HTTPSRR enabled but marked EXPERIMENTAL. Use with caution!
    make
```

The boringssl APIs are fairly similar to those in our ECH-enabled OpenSSL
fork, so code changes are also in ``lib/vtls/openssl.c``, protected
via ``#ifdef OPENSSL_IS_BORINGSSL`` and are mostly obvious API variations.
 
The boringssl APIs however do not support the ``--ech pn:`` command line
variant as of now.

## WolfSSL build

WolfSSL also supports ECH and can be used by curl, so here's how:

```bash
    cd $HOME/code
    git clone https://github.com/wolfSSL/wolfssl
    cd wolfssl
    ./autogen.sh
    ./configure --prefix=$HOME/code/wolfssl/inst --enable-ech --enable-debug --enable-opensslextra
    make
    make install
```

The install prefix (``inst``) in the above causes WolfSSL to be installed there
and we seem to need that for the curl configure command to work out. The
``--enable-opensslextra`` turns out (after much faffing about;-) to be
important or else we get build problems with curl below.

```bash
    cd $HOME/code
    git clone https://github.com/curl/curl
    cd curl
    autoreconf -fi
    ./configure --with-wolfssl=$HOME/code/wolfssl/inst --enable-ech --enable-httpsrr
    make
```

There are some known issues with the ECH implementation in WolfSSL:

- The main issue is that the client currently handles HelloRetryRequest
  incorrectly.  [HRR issue](https://github.com/wolfSSL/wolfssl/issues/6802).)
  The HRR issue means that the client does not work for
  [this ECH test web site](https://tls-ech.dev) and any other similarly configured
  sites.
- There is also an issue related to so-called middlebox compatibility mode.
  [middlebox compatibility issue](https://github.com/wolfSSL/wolfssl/issues/6774) 

### Code changes to support WolfSSL

There are what seem like oddball differences:

- The DoH URL in``$HOME/.curlrc`` can use "1.1.1.1" for OpenSSL but has to be
  "one.one.one.one" for WolfSSL. The latter works for both, so OK, we'll change
  to that.
- There seems to be some difference in CA databases too - the WolfSSL version
  does not like ``defo.ie``, whereas the system and OpenSSL ones do. We can ignore
  that for our purposes via ``--insecure``/``-k`` but would need to fix for a
  real setup. (Browsers do like those certificates though.)

Then there are some functional code changes:

- tweak to ``configure.ac`` to check if WolfSSL has ECH or not
- added code to ``lib/vtls/wolfssl.c`` mirroring what's done in the
  OpenSSL equivalent above.
- WolfSSL does not support ``--ech false`` or the ``--ech pn:`` command line
  argument.

The lack of support for ``--ech false`` is because wolfSSL has decided to
always at least GREASE if built to support ECH. In other words, GREASE is
a compile time choice for wolfSSL, but a runtime choice for OpenSSL or
boringssl. (Both are reasonable.)

## Additional notes

### Supporting ECH without DoH

All of the above only applies if DoH is being used. There should be a use-case
for ECH when DoH is not used by curl - if a system stub resolver supports DoT
or DoH, then, considering only ECH and the network threat model, it would make
sense for curl to support ECH without curl itself using DoH. The author for
example uses a combination of stubby+unbound as the system resolver listening
on localhost:53, so would fit this use-case. That said, it is unclear if
this is a niche that is worth trying to address. (The author is just as happy to
let curl use DoH to talk to the same public recursive that stubby might use:-)

Assuming for the moment this is a use-case we'd like to support, then
if DoH is not being used by curl, it is not clear at this time how to provide
support for ECH. One option would seem to be to extend the ``c-ares`` library
to support HTTPS RRs, but in that case it is not now clear whether such changes
would be attractive to the ``c-ares`` maintainers, nor whether the "tag=value"
extensibility inherent in the HTTPS/SVCB specification is a good match for the
``c-ares`` approach of defining structures specific to decoded answers for each
supported RRtype. We're also not sure how many downstream curl deployments
actually make use of the ``c-ares`` library, which would affect the utility of
such changes. Another option might be to consider using some other generic DNS
library that does support HTTPS RRs, but it is unclear if such a library could
or would be used by all or almost all curl builds and downstream releases of
curl.

Our current conclusion is that doing the above is likely best left until we
have some experience with the "using DoH" approach, so we're going to punt on
this for now.

### Debugging

Just a note to self as remembering this is a nuisance:

```bash
LD_LIBRARY_PATH=$HOME/code/openssl:./lib/.libs gdb ./src/.libs/curl
```

### Localhost testing

It can be useful to be able to run against a localhost OpenSSL ``s_server``
for testing. We have published instructions for such 
[localhost tests](https://github.com/defo-project/ech-dev-utils/blob/main/howtos/localhost-tests.md)
in another repository. Once you have that set up, you can start a server
and then run curl against that:

```bash
    cd $HOME/code/ech-dev-utils
    ./scripts/echsvr.sh -d







|



|


|
|


|

|











|













|







|

|



|
|
<
|
|
|
|



|


|





|














|
|

|
|
|
|
|
|
|
|
|
|


|













|







326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387

388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
```bash
    cd $HOME/code
    git clone https://github.com/curl/curl
    cd curl
    autoreconf -fi
    LDFLAGS="-Wl,-rpath,$HOME/code/boringssl/inst/lib" ./configure --with-ssl=$HOME/code/boringssl/inst --enable-ech --enable-httpsrr
    ...lots of output...
    WARNING: ECH HTTPSRR enabled but marked EXPERIMENTAL. Use with caution!
    make
```

The BoringSSL APIs are fairly similar to those in our ECH-enabled OpenSSL
fork, so code changes are also in ``lib/vtls/openssl.c``, protected
via ``#ifdef OPENSSL_IS_BORINGSSL`` and are mostly obvious API variations.

The BoringSSL APIs however do not support the ``--ech pn:`` command line
variant as of now.

## wolfSSL build

wolfSSL also supports ECH and can be used by curl, so here's how:

```bash
    cd $HOME/code
    git clone https://github.com/wolfSSL/wolfssl
    cd wolfssl
    ./autogen.sh
    ./configure --prefix=$HOME/code/wolfssl/inst --enable-ech --enable-debug --enable-opensslextra
    make
    make install
```

The install prefix (``inst``) in the above causes wolfSSL to be installed there
and we seem to need that for the curl configure command to work out. The
``--enable-opensslextra`` turns out (after much faffing about;-) to be
important or else we get build problems with curl below.

```bash
    cd $HOME/code
    git clone https://github.com/curl/curl
    cd curl
    autoreconf -fi
    ./configure --with-wolfssl=$HOME/code/wolfssl/inst --enable-ech --enable-httpsrr
    make
```

There are some known issues with the ECH implementation in wolfSSL:

- The main issue is that the client currently handles HelloRetryRequest
  incorrectly.  [HRR issue](https://github.com/wolfSSL/wolfssl/issues/6802).)
  The HRR issue means that the client does not work for
  [this ECH test web site](https://tls-ech.dev) and any other similarly configured
  sites.
- There is also an issue related to so-called middlebox compatibility mode.
  [middlebox compatibility issue](https://github.com/wolfSSL/wolfssl/issues/6774)

### Code changes to support wolfSSL

There are what seem like oddball differences:

- The DoH URL in``$HOME/.curlrc`` can use `1.1.1.1` for OpenSSL but has to be
  `one.one.one.one` for wolfSSL. The latter works for both, so OK, we us that.

- There seems to be some difference in CA databases too - the wolfSSL version
  does not like ``defo.ie``, whereas the system and OpenSSL ones do. We can
  ignore that for our purposes via ``--insecure``/``-k`` but would need to fix
  for a real setup. (Browsers do like those certificates though.)

Then there are some functional code changes:

- tweak to ``configure.ac`` to check if wolfSSL has ECH or not
- added code to ``lib/vtls/wolfssl.c`` mirroring what's done in the
  OpenSSL equivalent above.
- wolfSSL does not support ``--ech false`` or the ``--ech pn:`` command line
  argument.

The lack of support for ``--ech false`` is because wolfSSL has decided to
always at least GREASE if built to support ECH. In other words, GREASE is
a compile time choice for wolfSSL, but a runtime choice for OpenSSL or
BoringSSL. (Both are reasonable.)

## Additional notes

### Supporting ECH without DoH

All of the above only applies if DoH is being used. There should be a use-case
for ECH when DoH is not used by curl - if a system stub resolver supports DoT
or DoH, then, considering only ECH and the network threat model, it would make
sense for curl to support ECH without curl itself using DoH. The author for
example uses a combination of stubby+unbound as the system resolver listening
on localhost:53, so would fit this use-case. That said, it is unclear if
this is a niche that is worth trying to address. (The author is just as happy to
let curl use DoH to talk to the same public recursive that stubby might use:-)

Assuming for the moment this is a use-case we would like to support, then if
DoH is not being used by curl, it is not clear at this time how to provide
support for ECH. One option would seem to be to extend the ``c-ares`` library
to support HTTPS RRs, but in that case it is not now clear whether such
changes would be attractive to the ``c-ares`` maintainers, nor whether the
"tag=value" extensibility inherent in the HTTPS/SVCB specification is a good
match for the ``c-ares`` approach of defining structures specific to decoded
answers for each supported RRtype. We are also not sure how many downstream
curl deployments actually make use of the ``c-ares`` library, which would
affect the utility of such changes. Another option might be to consider using
some other generic DNS library that does support HTTPS RRs, but it is unclear
if such a library could or would be used by all or almost all curl builds and
downstream releases of curl.

Our current conclusion is that doing the above is likely best left until we
have some experience with the "using DoH" approach, so we are going to punt on
this for now.

### Debugging

Just a note to self as remembering this is a nuisance:

```bash
LD_LIBRARY_PATH=$HOME/code/openssl:./lib/.libs gdb ./src/.libs/curl
```

### Localhost testing

It can be useful to be able to run against a localhost OpenSSL ``s_server``
for testing. We have published instructions for such
[localhost tests](https://github.com/defo-project/ech-dev-utils/blob/main/howtos/localhost-tests.md)
in another repository. Once you have that set up, you can start a server
and then run curl against that:

```bash
    cd $HOME/code/ech-dev-utils
    ./scripts/echsvr.sh -d
472
473
474
475
476
477
478
479
480

As of now we have not added support for using ``retry_config`` handling in the
application - for a command line tool, one can just use ``dig`` (or ``kdig``)
to get the HTTPS RR and pass the ECHConfigList from that on the command line,
if needed, or one can access the value from command line output in verbose more
and then re-use that in another invocation.

Both our OpenSSL fork and boringssl have APIs for both controlling GREASE and
accessing and logging ``retry_configs``, it seems WolfSSL has neither.







|
|
470
471
472
473
474
475
476
477
478

As of now we have not added support for using ``retry_config`` handling in the
application - for a command line tool, one can just use ``dig`` (or ``kdig``)
to get the HTTPS RR and pass the ECHConfigList from that on the command line,
if needed, or one can access the value from command line output in verbose more
and then re-use that in another invocation.

Both our OpenSSL fork and BoringSSL have APIs for both controlling GREASE and
accessing and logging ``retry_configs``, it seems wolfSSL has neither.
Changes to jni/curl/docs/FAQ.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  3.20 How to SFTP from my user's home directory?
  3.21 Protocol xxx not supported or disabled in libcurl
  3.22 curl -X gives me HTTP problems

 4. Running Problems
  4.2 Why do I get problems when I use & or % in the URL?
  4.3 How can I use {, }, [ or ] to specify multiple URLs?
  4.4 Why do I get downloaded data even though the web page does not exist?
  4.5 Why do I get return code XXX from an HTTP server?
   4.5.1 "400 Bad Request"
   4.5.2 "401 Unauthorized"
   4.5.3 "403 Forbidden"
   4.5.4 "404 Not Found"
   4.5.5 "405 Method Not Allowed"
   4.5.6 "301 Moved Permanently"
  4.6 Can you tell me what error code 142 means?
  4.7 How do I keep user names and passwords secret in curl command lines?
  4.8 I found a bug
  4.9 curl cannot authenticate to a server that requires NTLM?
  4.10 My HTTP request using HEAD, PUT or DELETE does not work
  4.11 Why do my HTTP range requests return the full document?
  4.12 Why do I get "certificate verify failed" ?
  4.13 Why is curl -R on Windows one hour off?
  4.14 Redirects work in browser but not with curl







|








|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  3.20 How to SFTP from my user's home directory?
  3.21 Protocol xxx not supported or disabled in libcurl
  3.22 curl -X gives me HTTP problems

 4. Running Problems
  4.2 Why do I get problems when I use & or % in the URL?
  4.3 How can I use {, }, [ or ] to specify multiple URLs?
  4.4 Why do I get downloaded data even though the webpage does not exist?
  4.5 Why do I get return code XXX from an HTTP server?
   4.5.1 "400 Bad Request"
   4.5.2 "401 Unauthorized"
   4.5.3 "403 Forbidden"
   4.5.4 "404 Not Found"
   4.5.5 "405 Method Not Allowed"
   4.5.6 "301 Moved Permanently"
  4.6 Can you tell me what error code 142 means?
  4.7 How do I keep usernames and passwords secret in curl command lines?
  4.8 I found a bug
  4.9 curl cannot authenticate to a server that requires NTLM?
  4.10 My HTTP request using HEAD, PUT or DELETE does not work
  4.11 Why do my HTTP range requests return the full document?
  4.12 Why do I get "certificate verify failed" ?
  4.13 Why is curl -R on Windows one hour off?
  4.14 Redirects work in browser but not with curl
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  5.2 How can I receive all data into a large memory chunk?
  5.3 How do I fetch multiple files with libcurl?
  5.4 Does libcurl do Winsock initialization on win32 systems?
  5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on win32 ?
  5.6 What about Keep-Alive or persistent connections?
  5.7 Link errors when building libcurl on Windows
  5.8 libcurl.so.X: open failed: No such file or directory
  5.9 How does libcurl resolve host names?
  5.10 How do I prevent libcurl from writing the response to stdout?
  5.11 How do I make libcurl not receive the whole HTTP response?
  5.12 Can I make libcurl fake or hide my real IP address?
  5.13 How do I stop an ongoing transfer?
  5.14 Using C++ non-static functions for callbacks?
  5.15 How do I get an FTP directory listing?
  5.16 I want a different time-out







|







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  5.2 How can I receive all data into a large memory chunk?
  5.3 How do I fetch multiple files with libcurl?
  5.4 Does libcurl do Winsock initialization on win32 systems?
  5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on win32 ?
  5.6 What about Keep-Alive or persistent connections?
  5.7 Link errors when building libcurl on Windows
  5.8 libcurl.so.X: open failed: No such file or directory
  5.9 How does libcurl resolve hostnames?
  5.10 How do I prevent libcurl from writing the response to stdout?
  5.11 How do I make libcurl not receive the whole HTTP response?
  5.12 Can I make libcurl fake or hide my real IP address?
  5.13 How do I stop an ongoing transfer?
  5.14 Using C++ non-static functions for callbacks?
  5.15 How do I get an FTP directory listing?
  5.16 I want a different time-out
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  2.2 Does curl work with other SSL libraries?

  curl has been written to use a generic SSL function layer internally, and
  that SSL functionality can then be provided by one out of many different SSL
  backends.

  curl can be built to use one of the following SSL alternatives: OpenSSL,
  libressl, BoringSSL, AWS-LC, GnuTLS, wolfSSL, mbedTLS, Secure Transport
  (native iOS/OS X), Schannel (native Windows), BearSSL or Rustls. They all
  have their pros and cons, and we try to maintain a comparison of them here:
  https://curl.se/docs/ssl-compared.html

  2.3 How do I upgrade curl.exe in Windows?

  The curl tool that is shipped as an integrated component of Windows 10 and







|







419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  2.2 Does curl work with other SSL libraries?

  curl has been written to use a generic SSL function layer internally, and
  that SSL functionality can then be provided by one out of many different SSL
  backends.

  curl can be built to use one of the following SSL alternatives: OpenSSL,
  LibreSSL, BoringSSL, AWS-LC, GnuTLS, wolfSSL, mbedTLS, Secure Transport
  (native iOS/OS X), Schannel (native Windows), BearSSL or Rustls. They all
  have their pros and cons, and we try to maintain a comparison of them here:
  https://curl.se/docs/ssl-compared.html

  2.3 How do I upgrade curl.exe in Windows?

  The curl tool that is shipped as an integrated component of Windows 10 and
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  adjust them to work in your environment.

  Remember that curl works and runs on more operating systems than most single
  individuals have ever tried.

  3.14 Does curl support JavaScript or PAC (automated proxy config)?

  Many web pages do magic stuff using embedded JavaScript. curl and libcurl
  have no built-in support for that, so it will be treated just like any other
  contents.

  .pac files are a Netscape invention and are sometimes used by organizations
  to allow them to differentiate which proxies to use. The .pac contents is
  just a JavaScript program that gets invoked by the browser and that returns
  the name of the proxy to connect to. Since curl does not support JavaScript,







|







620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  adjust them to work in your environment.

  Remember that curl works and runs on more operating systems than most single
  individuals have ever tried.

  3.14 Does curl support JavaScript or PAC (automated proxy config)?

  Many webpages do magic stuff using embedded JavaScript. curl and libcurl
  have no built-in support for that, so it will be treated just like any other
  contents.

  .pac files are a Netscape invention and are sometimes used by organizations
  to allow them to differentiate which proxies to use. The .pac contents is
  just a JavaScript program that gets invoked by the browser and that returns
  the name of the proxy to connect to. Since curl does not support JavaScript,
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  name and you want to address a specific one out of the set.

  Set a custom Host: header that identifies the server name you want to reach
  but use the target IP address in the URL:

    curl --header "Host: www.example.com" http://127.0.0.1/

  You can also opt to add faked host name entries to curl with the --resolve
  option. That has the added benefit that things like redirects will also work
  properly. The above operation would instead be done as:

    curl --resolve www.example.com:80:127.0.0.1 http://www.example.com/

  3.20 How to SFTP from my user's home directory?








|







718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  name and you want to address a specific one out of the set.

  Set a custom Host: header that identifies the server name you want to reach
  but use the target IP address in the URL:

    curl --header "Host: www.example.com" http://127.0.0.1/

  You can also opt to add faked hostname entries to curl with the --resolve
  option. That has the added benefit that things like redirects will also work
  properly. The above operation would instead be done as:

    curl --resolve www.example.com:80:127.0.0.1 http://www.example.com/

  3.20 How to SFTP from my user's home directory?

767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
  POST, -I will cause a HEAD and -T will make it a PUT.

  If for whatever reason you are not happy with these default choices that curl
  does for you, you can override those request methods by specifying -X
  [WHATEVER]. This way you can for example send a DELETE by doing "curl -X
  DELETE [URL]".

  It is thus pointless to do "curl -XGET [URL]" as GET would be used
  anyway. In the same vein it is pointless to do "curl -X POST -d data
  [URL]"... But you can make a fun and somewhat rare request that sends a
  request-body in a GET request with something like "curl -X GET -d data
  [URL]"

  Note that -X does not actually change curl's behavior as it only modifies the
  actual string sent in the request, but that may of course trigger a
  different set of events.

  Accordingly, by using -XPOST on a command line that for example would follow
  a 303 redirect, you will effectively prevent curl from behaving







|
|
|
|
<







767
768
769
770
771
772
773
774
775
776
777

778
779
780
781
782
783
784
  POST, -I will cause a HEAD and -T will make it a PUT.

  If for whatever reason you are not happy with these default choices that curl
  does for you, you can override those request methods by specifying -X
  [WHATEVER]. This way you can for example send a DELETE by doing "curl -X
  DELETE [URL]".

  It is thus pointless to do "curl -XGET [URL]" as GET would be used anyway.
  In the same vein it is pointless to do "curl -X POST -d data [URL]". You can
  make a fun and somewhat rare request that sends a request-body in a GET
  request with something like "curl -X GET -d data [URL]"


  Note that -X does not actually change curl's behavior as it only modifies the
  actual string sent in the request, but that may of course trigger a
  different set of events.

  Accordingly, by using -XPOST on a command line that for example would follow
  a 303 redirect, you will effectively prevent curl from behaving
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
    curl '{curl,www}.haxx.se'

  To be able to use those characters as actual parts of the URL (without using
  them for the curl URL "globbing" system), use the -g/--globoff option:

    curl -g 'www.example.com/weirdname[].html'

  4.4 Why do I get downloaded data even though the web page does not exist?

  curl asks remote servers for the page you specify. If the page does not exist
  at the server, the HTTP protocol defines how the server should respond and
  that means that headers and a "page" will be returned. That is simply how
  HTTP works.

  By using the --fail option you can tell curl explicitly to not get any data







|







817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
    curl '{curl,www}.haxx.se'

  To be able to use those characters as actual parts of the URL (without using
  them for the curl URL "globbing" system), use the -g/--globoff option:

    curl -g 'www.example.com/weirdname[].html'

  4.4 Why do I get downloaded data even though the webpage does not exist?

  curl asks remote servers for the page you specify. If the page does not exist
  at the server, the HTTP protocol defines how the server should respond and
  that means that headers and a "page" will be returned. That is simply how
  HTTP works.

  By using the --fail option you can tell curl explicitly to not get any data
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
  section called "EXIT CODES".

  Error codes that are larger than the highest documented error code means
  that curl has exited due to a crash. This is a serious error, and we
  appreciate a detailed bug report from you that describes how we could go
  ahead and repeat this.

  4.7 How do I keep user names and passwords secret in curl command lines?

  This problem has two sides:

  The first part is to avoid having clear-text passwords in the command line
  so that they do not appear in 'ps' outputs and similar. That is easily
  avoided by using the "-K" option to tell curl to read parameters from a file
  or stdin to which you can pass the secret info. curl itself will also







|







878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
  section called "EXIT CODES".

  Error codes that are larger than the highest documented error code means
  that curl has exited due to a crash. This is a serious error, and we
  appreciate a detailed bug report from you that describes how we could go
  ahead and repeat this.

  4.7 How do I keep usernames and passwords secret in curl command lines?

  This problem has two sides:

  The first part is to avoid having clear-text passwords in the command line
  so that they do not appear in 'ps' outputs and similar. That is easily
  avoided by using the "-K" option to tell curl to read parameters from a file
  or stdin to which you can pass the secret info. curl itself will also
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
  4.20 curl does not return error for HTTP non-200 responses

  Correct. Unless you use -f (--fail).

  When doing HTTP transfers, curl will perform exactly what you are asking it
  to do and if successful it will not return an error. You can use curl to
  test your web server's "file not found" page (that gets 404 back), you can
  use it to check your authentication protected web pages (that gets a 401
  back) and so on.

  The specific HTTP response code does not constitute a problem or error for
  curl. It simply sends and delivers HTTP as you asked and if that worked,
  everything is fine and dandy. The response code is generally providing more
  higher level error information that curl does not care about. The error was
  not in the HTTP transfer.







|







1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
  4.20 curl does not return error for HTTP non-200 responses

  Correct. Unless you use -f (--fail).

  When doing HTTP transfers, curl will perform exactly what you are asking it
  to do and if successful it will not return an error. You can use curl to
  test your web server's "file not found" page (that gets 404 back), you can
  use it to check your authentication protected webpages (that gets a 401
  back) and so on.

  The specific HTTP response code does not constitute a problem or error for
  curl. It simply sends and delivers HTTP as you asked and if that worked,
  everything is fine and dandy. The response code is generally providing more
  higher level error information that curl does not care about. The error was
  not in the HTTP transfer.
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
  file, even if that simply writes the data to the specified FILE *.
  Similarly, if you use CURLOPT_READDATA you must also specify
  CURLOPT_READFUNCTION.

  5.6 What about Keep-Alive or persistent connections?

  curl and libcurl have excellent support for persistent connections when
  transferring several files from the same server.  curl will attempt to reuse
  connections for all URLs specified on the same command line/config file, and
  libcurl will reuse connections for all transfers that are made using the
  same libcurl handle.

  When you use the easy interface the connection cache is kept within the easy
  handle. If you instead use the multi interface, the connection cache will be
  kept within the multi handle and will be shared among all the easy handles







|







1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
  file, even if that simply writes the data to the specified FILE *.
  Similarly, if you use CURLOPT_READDATA you must also specify
  CURLOPT_READFUNCTION.

  5.6 What about Keep-Alive or persistent connections?

  curl and libcurl have excellent support for persistent connections when
  transferring several files from the same server. curl will attempt to reuse
  connections for all URLs specified on the same command line/config file, and
  libcurl will reuse connections for all transfers that are made using the
  same libcurl handle.

  When you use the easy interface the connection cache is kept within the easy
  handle. If you instead use the multi interface, the connection cache will be
  kept within the multi handle and will be shared among all the easy handles
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
    should check for libs

  * Adjust the system's config to check for libs in the directory where you have
    put the library (like Linux's /etc/ld.so.conf)

  'man ld.so' and 'man ld' will tell you more details

  5.9 How does libcurl resolve host names?

  libcurl supports a large number of name resolve functions. One of them is
  picked at build-time and will be used unconditionally. Thus, if you want to
  change name resolver function you must rebuild libcurl and tell it to use a
  different function.

  - The non-IPv6 resolver that can use one of four different host name resolve
  calls (depending on what your system supports):

      A - gethostbyname()
      B - gethostbyname_r() with 3 arguments
      C - gethostbyname_r() with 5 arguments
      D - gethostbyname_r() with 6 arguments








|






|







1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
    should check for libs

  * Adjust the system's config to check for libs in the directory where you have
    put the library (like Linux's /etc/ld.so.conf)

  'man ld.so' and 'man ld' will tell you more details

  5.9 How does libcurl resolve hostnames?

  libcurl supports a large number of name resolve functions. One of them is
  picked at build-time and will be used unconditionally. Thus, if you want to
  change name resolver function you must rebuild libcurl and tell it to use a
  different function.

  - The non-IPv6 resolver that can use one of four different hostname resolve
  calls (depending on what your system supports):

      A - gethostbyname()
      B - gethostbyname_r() with 3 arguments
      C - gethostbyname_r() with 5 arguments
      D - gethostbyname_r() with 6 arguments

Changes to jni/curl/docs/FEATURES.md.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35
36
37
38
39
40


































41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

68
69
70

71


72
73
74
75
76
77
78
79
80
81

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112



113
114
115
116
117
118

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

## curl tool

 - config file support
 - multiple URLs in a single command line
 - range "globbing" support: [0-13], {one,two,three}
 - multiple file upload on a single command line
 - custom maximum transfer rate
 - redirect stderr
 - parallel transfers

## libcurl

 - URL RFC 3986 syntax
 - custom maximum download time
 - custom least download speed acceptable
 - custom output result after completion
 - guesses protocol from hostname unless specified
 - uses .netrc
 - progress bar with time statistics while downloading
 - "standard" proxy environment variables support
 - compiles on win32 (reported builds on 70+ operating systems)
 - selectable network interface for outgoing traffic
 - IPv6 support on Unix and Windows
 - happy eyeballs dual-stack connects
 - persistent connections
 - SOCKS 4 + 5 support, with or without local name resolving

 - supports username and password in proxy environment variables
 - operations through HTTP proxy "tunnel" (using CONNECT)
 - replaceable memory functions (malloc, free, realloc, etc)
 - asynchronous name resolving (6)
 - both a push and a pull style interface
 - international domain names (10)



































## HTTP

 - HTTP/0.9 responses are optionally accepted
 - HTTP/1.0
 - HTTP/1.1
 - HTTP/2, including multiplexing and server push (5)
 - GET
 - PUT
 - HEAD
 - POST
 - multipart formpost (RFC 1867-style)
 - authentication: Basic, Digest, NTLM (9) and Negotiate (SPNEGO) (3)
   to server and proxy
 - resume (both GET and PUT)
 - follow redirects
 - maximum amount of redirects to follow
 - custom HTTP request
 - cookie get/send fully parsed
 - reads/writes the Netscape cookie file format
 - custom headers (replace/remove internally generated headers)
 - custom user-agent string
 - custom referrer string
 - range
 - proxy authentication
 - time conditions
 - via HTTP proxy, HTTPS proxy or SOCKS proxy

 - retrieve file modification date
 - Content-Encoding support for deflate and gzip
 - "Transfer-Encoding: chunked" support in uploads

 - automatic data compression (11)



## HTTPS (1)

 - (all the HTTP features)
 - HTTP/3 experimental support
 - using client certificates
 - verify server certificate
 - via HTTP proxy, HTTPS proxy or SOCKS proxy
 - select desired encryption
 - select usage of a specific SSL version


## FTP

 - download
 - authentication
 - Kerberos 5 (12)
 - active/passive using PORT, EPRT, PASV or EPSV
 - single file size information (compare to HTTP HEAD)
 - 'type=' URL support
 - directory listing
 - directory listing names-only
 - upload
 - upload append
 - upload via http-proxy as HTTP PUT
 - download resume
 - upload resume
 - custom ftp commands (before and/or after the transfer)
 - simple "range" support
 - via HTTP proxy, HTTPS proxy or SOCKS proxy
 - all operations can be tunneled through proxy
 - customizable to retrieve file modification date
 - no directory depth limit

## FTPS (1)

 - implicit `ftps://` support that use SSL on both connections
 - explicit "AUTH TLS" and "AUTH SSL" usage to "upgrade" plain `ftp://`
   connection to use SSL for both or one of the connections

## SCP (8)




 - both password and public key auth

## SFTP (7)

 - both password and public key auth
 - with custom commands sent before/after the transfer


## TFTP

 - download
 - upload

## TELNET

 - connection negotiation
 - custom telnet options
 - stdin/stdout I/O

## LDAP (2)

 - full LDAP URL support

## DICT

 - extended DICT URL support








<







|


|

|
|


|


>



|

|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






|





|

|












>

|

>
|
>
>

|

<
|




|
>





|

















|





|

>
>
>


|



>












|







8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

## curl tool

 - config file support
 - multiple URLs in a single command line
 - range "globbing" support: [0-13], {one,two,three}
 - multiple file upload on a single command line

 - redirect stderr
 - parallel transfers

## libcurl

 - URL RFC 3986 syntax
 - custom maximum download time
 - custom lowest download speed acceptable
 - custom output result after completion
 - guesses protocol from hostname unless specified
 - supports .netrc
 - progress bar with time statistics while downloading
 - standard proxy environment variables support
 - have run on 101 operating systems and 28 CPU architectures
 - selectable network interface for outgoing traffic
 - IPv6 support on Unix and Windows
 - happy eyeballs dual-stack IPv4 + IPv6 connects
 - persistent connections
 - SOCKS 4 + 5 support, with or without local name resolving
 - *pre-proxy* support, for *proxy chaining*
 - supports username and password in proxy environment variables
 - operations through HTTP proxy "tunnel" (using CONNECT)
 - replaceable memory functions (malloc, free, realloc, etc)
 - asynchronous name resolving
 - both a push and a pull style interface
 - international domain names (IDN)
 - transfer late limiting
 - stable API and ABI
 - TCP keep alive
 - TCP Fast Open
 - DNS cache (that can be shared between transfers)
 - non-blocking single-threaded parallel transfers
 - unix domain sockets to server or proxy
 - DNS-over-HTTPS
 - uses non-blocking name resolves
 - selectable name resolver backend

## URL API

 - parses RFC 3986 URLs
 - generates URLs from individual components
 - manages "redirects"

## Header API

 - easy access to HTTP response headers, from all contexts
 - named headers
 - iterate over headers

## TLS

 - selectable TLS backend(s)
 - TLS False Start
 - TLS version control
 - TLS session resumption
 - key pinning
 - mutual authentication
 - Use dedicated CA cert bundle
 - Use OS-provided CA store
 - separate TLS options for HTTPS proxy

## HTTP

 - HTTP/0.9 responses are optionally accepted
 - HTTP/1.0
 - HTTP/1.1
 - HTTP/2, including multiplexing and server push
 - GET
 - PUT
 - HEAD
 - POST
 - multipart formpost (RFC 1867-style)
 - authentication: Basic, Digest, NTLM (9) and Negotiate (SPNEGO)
   to server and proxy
 - resume transfers
 - follow redirects
 - maximum amount of redirects to follow
 - custom HTTP request
 - cookie get/send fully parsed
 - reads/writes the Netscape cookie file format
 - custom headers (replace/remove internally generated headers)
 - custom user-agent string
 - custom referrer string
 - range
 - proxy authentication
 - time conditions
 - via HTTP proxy, HTTPS proxy or SOCKS proxy
 - HTTP/2 or HTTP/1.1 to HTTPS proxy
 - retrieve file modification date
 - Content-Encoding support for deflate, gzip, brotli and zstd
 - "Transfer-Encoding: chunked" support in uploads
 - HSTS
 - alt-svc
 - ETags
 - HTTP/1.1 trailers, both sending and getting

## HTTPS


 - HTTP/3
 - using client certificates
 - verify server certificate
 - via HTTP proxy, HTTPS proxy or SOCKS proxy
 - select desired encryption
 - select usage of a specific TLS version
 - ECH

## FTP

 - download
 - authentication
 - Kerberos 5
 - active/passive using PORT, EPRT, PASV or EPSV
 - single file size information (compare to HTTP HEAD)
 - 'type=' URL support
 - directory listing
 - directory listing names-only
 - upload
 - upload append
 - upload via http-proxy as HTTP PUT
 - download resume
 - upload resume
 - custom ftp commands (before and/or after the transfer)
 - simple "range" support
 - via HTTP proxy, HTTPS proxy or SOCKS proxy
 - all operations can be tunneled through proxy
 - customizable to retrieve file modification date
 - no directory depth limit

## FTPS

 - implicit `ftps://` support that use SSL on both connections
 - explicit "AUTH TLS" and "AUTH SSL" usage to "upgrade" plain `ftp://`
   connection to use SSL for both or one of the connections

## SSH (both SCP and SFTP)

 - selectable SSH backend
 - known hosts support
 - public key fingerprinting
 - both password and public key auth

## SFTP

 - both password and public key auth
 - with custom commands sent before/after the transfer
 - directory listing

## TFTP

 - download
 - upload

## TELNET

 - connection negotiation
 - custom telnet options
 - stdin/stdout I/O

## LDAP

 - full LDAP URL support

## DICT

 - extended DICT URL support

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
 - SMBv1 over TCP and SSL
 - download
 - upload
 - authentication with NTLMv1

## SMTP

 - authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9), Kerberos 5
   (4) and External.
 - send emails
 - mail from support
 - mail size support
 - mail auth support for trusted server-to-server relaying
 - multiple recipients
 - via http-proxy

## SMTPS (1)

 - implicit `smtps://` support
 - explicit "STARTTLS" usage to "upgrade" plain `smtp://` connections to use SSL
 - via http-proxy

## POP3

 - authentication: Clear Text, APOP and SASL
 - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9),
   Kerberos 5 (4) and External.
 - list emails
 - retrieve emails
 - enhanced command support for: CAPA, DELE, TOP, STAT, UIDL and NOOP via
   custom requests
 - via http-proxy

## POP3S (1)

 - implicit `pop3s://` support
 - explicit `STLS` usage to "upgrade" plain `pop3://` connections to use SSL
 - via http-proxy

## IMAP

 - authentication: Clear Text and SASL
 - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM (9),
   Kerberos 5 (4) and External.
 - list the folders of a mailbox
 - select a mailbox with support for verifying the `UIDVALIDITY`
 - fetch emails with support for specifying the UID and SECTION
 - upload emails via the append command
 - enhanced command support for: EXAMINE, CREATE, DELETE, RENAME, STATUS,
   STORE, COPY and UID via custom requests
 - via http-proxy

## IMAPS (1)

 - implicit `imaps://` support
 - explicit "STARTTLS" usage to "upgrade" plain `imap://` connections to use SSL
 - via http-proxy

## MQTT

 - Subscribe to and publish topics using URL scheme `mqtt://broker/topic`

## Footnotes

  1. requires a TLS library
  2. requires OpenLDAP or WinLDAP
  3. requires a GSS-API implementation (such as Heimdal or MIT Kerberos) or
     SSPI (native Windows)
  4. requires a GSS-API implementation, however, only Windows SSPI is
     currently supported
  5. requires nghttp2
  6. requires c-ares
  7. requires libssh2, libssh or wolfSSH
  8. requires libssh2 or libssh
  9. requires OpenSSL, GnuTLS, mbedTLS, Secure Transport or SSPI
     (native Windows)
  10. requires libidn2 or Windows
  11. requires libz, brotli and/or zstd
  12. requires a GSS-API implementation (such as Heimdal or MIT Kerberos)







|
|







|








|
|






|








|
|








|








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249


















 - SMBv1 over TCP and SSL
 - download
 - upload
 - authentication with NTLMv1

## SMTP

 - authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM, Kerberos 5 and
   External
 - send emails
 - mail from support
 - mail size support
 - mail auth support for trusted server-to-server relaying
 - multiple recipients
 - via http-proxy

## SMTPS

 - implicit `smtps://` support
 - explicit "STARTTLS" usage to "upgrade" plain `smtp://` connections to use SSL
 - via http-proxy

## POP3

 - authentication: Clear Text, APOP and SASL
 - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM,
   Kerberos 5 and External
 - list emails
 - retrieve emails
 - enhanced command support for: CAPA, DELE, TOP, STAT, UIDL and NOOP via
   custom requests
 - via http-proxy

## POP3S

 - implicit `pop3s://` support
 - explicit `STLS` usage to "upgrade" plain `pop3://` connections to use SSL
 - via http-proxy

## IMAP

 - authentication: Clear Text and SASL
 - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5, NTLM,
   Kerberos 5 and External
 - list the folders of a mailbox
 - select a mailbox with support for verifying the `UIDVALIDITY`
 - fetch emails with support for specifying the UID and SECTION
 - upload emails via the append command
 - enhanced command support for: EXAMINE, CREATE, DELETE, RENAME, STATUS,
   STORE, COPY and UID via custom requests
 - via http-proxy

## IMAPS

 - implicit `imaps://` support
 - explicit "STARTTLS" usage to "upgrade" plain `imap://` connections to use SSL
 - via http-proxy

## MQTT

 - Subscribe to and publish topics using URL scheme `mqtt://broker/topic`


















Changes to jni/curl/docs/HISTORY.md.
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
 Gopher support added (re-added actually, see January 2006)

2011
----

February: added support for the axTLS backend

April: added the cyassl backend (later renamed to WolfSSL)

2012
----

 July: Added support for Schannel (native Windows TLS backend) and Darwin SSL
 (Native Mac OS X and iOS TLS backend).








|







282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
 Gopher support added (re-added actually, see January 2006)

2011
----

February: added support for the axTLS backend

April: added the cyassl backend (later renamed to wolfSSL)

2012
----

 July: Added support for Schannel (native Windows TLS backend) and Darwin SSL
 (Native Mac OS X and iOS TLS backend).

Changes to jni/curl/docs/HTTP2.md.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

[HTTP/2 Spec](https://www.rfc-editor.org/rfc/rfc7540.txt)
[http2 explained](https://daniel.haxx.se/http2/)

Build prerequisites
-------------------
  - nghttp2
  - OpenSSL, libressl, BoringSSL, GnuTLS, mbedTLS, wolfSSL or Schannel
    with a new enough version.

[nghttp2](https://nghttp2.org/)
-------------------------------

libcurl uses this 3rd party library for the low level protocol handling
parts. The reason for this is that HTTP/2 is much more complex at that layer







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

[HTTP/2 Spec](https://www.rfc-editor.org/rfc/rfc7540.txt)
[http2 explained](https://daniel.haxx.se/http2/)

Build prerequisites
-------------------
  - nghttp2
  - OpenSSL, LibreSSL, BoringSSL, GnuTLS, mbedTLS, wolfSSL or Schannel
    with a new enough version.

[nghttp2](https://nghttp2.org/)
-------------------------------

libcurl uses this 3rd party library for the low level protocol handling
parts. The reason for this is that HTTP/2 is much more complex at that layer
Changes to jni/curl/docs/HTTP3.md.
178
179
180
181
182
183
184
185
186
187
188
189
190
191

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

# quiche version

quiche support is **EXPERIMENTAL**

Since the quiche build manages its dependencies, curl can be built against the latest version. You are *probably* able to build against their main branch, but in case of problems, we recommend their latest release tag.

## build

Build quiche and BoringSSL:

     % git clone --recursive -b 0.20.0 https://github.com/cloudflare/quiche
     % cd quiche
     % cargo build --package quiche --release --features ffi,pkg-config-meta,qlog

     % mkdir quiche/deps/boringssl/src/lib
     % ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) quiche/deps/boringssl/src/lib/

Build curl:

     % cd ..
     % git clone https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-openssl=$PWD/../quiche/quiche/deps/boringssl/src --with-quiche=$PWD/../quiche/target/release
     % make
     % make install

 If `make install` results in `Permission denied` error, you need to prepend
 it with `sudo`.

# OpenSSL version

QUIC support is **EXPERIMENTAL**

Build OpenSSL 3.2.0

     % cd ..
     % git clone -b openssl-3.2.0 https://github.com/openssl/openssl
     % cd openssl
     % ./config enable-tls1_3 --prefix=<somewhere> --libdir=<somewhere>/lib
     % make
     % make install

Build nghttp3

     % cd ..
     % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3
     % cd nghttp3
     % git submodule update --init
     % autoreconf -fi
     % ./configure --prefix=<somewhere2> --enable-lib-only
     % make
     % make install

Build curl:

     % cd ..
     % git clone https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % LDFLAGS="-Wl,-rpath,<somewhere>/lib" ./configure --with-openssl=<somewhere> --with-openssl-quic --with-nghttp3=<somewhere2> 
     % make
     % make install

You can build curl with cmake:

     % cd ..
     % git clone https://github.com/curl/curl







|



|


>




















|


|

|




















|







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

# quiche version

quiche support is **EXPERIMENTAL**

Since the quiche build manages its dependencies, curl can be built against the latest version. You are *probably* able to build against their main branch, but in case of problems, we recommend their latest release tag.

## Build

Build quiche and BoringSSL:

     % git clone --recursive -b 0.22.0 https://github.com/cloudflare/quiche
     % cd quiche
     % cargo build --package quiche --release --features ffi,pkg-config-meta,qlog
     % ln -s libquiche.so target/release/libquiche.so.0
     % mkdir quiche/deps/boringssl/src/lib
     % ln -vnf $(find target/release -name libcrypto.a -o -name libssl.a) quiche/deps/boringssl/src/lib/

Build curl:

     % cd ..
     % git clone https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % ./configure LDFLAGS="-Wl,-rpath,$PWD/../quiche/target/release" --with-openssl=$PWD/../quiche/quiche/deps/boringssl/src --with-quiche=$PWD/../quiche/target/release
     % make
     % make install

 If `make install` results in `Permission denied` error, you need to prepend
 it with `sudo`.

# OpenSSL version

QUIC support is **EXPERIMENTAL**

Build OpenSSL 3.3.1

     % cd ..
     % git clone -b openssl-3.3.1 https://github.com/openssl/openssl
     % cd openssl
     % ./config enable-tls1_3 --prefix=<somewhere> --libdir=lib
     % make
     % make install

Build nghttp3

     % cd ..
     % git clone -b v1.1.0 https://github.com/ngtcp2/nghttp3
     % cd nghttp3
     % git submodule update --init
     % autoreconf -fi
     % ./configure --prefix=<somewhere2> --enable-lib-only
     % make
     % make install

Build curl:

     % cd ..
     % git clone https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % LDFLAGS="-Wl,-rpath,<somewhere>/lib" ./configure --with-openssl=<somewhere> --with-openssl-quic --with-nghttp3=<somewhere2>
     % make
     % make install

You can build curl with cmake:

     % cd ..
     % git clone https://github.com/curl/curl
Changes to jni/curl/docs/HYPER.md.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Further development and tweaking of the Hyper backend support in curl happens
in the master branch using pull-requests, just like ordinary changes.

## Hyper version

The C API for Hyper is brand new and is still under development.

## build curl with hyper

Using Rust 1.64.0 or later, build hyper and enable its C API like this:

     % git clone https://github.com/hyperium/hyper
     % cd hyper
     % RUSTFLAGS="--cfg hyper_unstable_ffi" cargo rustc --features client,http1,http2,ffi --crate-type cdylib

Also, `--release` can be added for a release (optimized) build.

Build curl to use hyper's C API:

     % git clone https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % ./configure LDFLAGS="-Wl,-rpath,<hyper-dir>/target/debug -Wl,-rpath,<hyper-dir>/target/release" --with-openssl --with-hyper=<hyper-dir>
     % make

# using Hyper internally

Hyper is a low level HTTP transport library. curl itself provides all HTTP
headers and Hyper provides all received headers back to curl.

Therefore, most of the "header logic" in curl as in responding to and acting
on specific input and output headers are done the same way in curl code.








|

















|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Further development and tweaking of the Hyper backend support in curl happens
in the master branch using pull-requests, just like ordinary changes.

## Hyper version

The C API for Hyper is brand new and is still under development.

## Build curl with hyper

Using Rust 1.64.0 or later, build hyper and enable its C API like this:

     % git clone https://github.com/hyperium/hyper
     % cd hyper
     % RUSTFLAGS="--cfg hyper_unstable_ffi" cargo rustc --features client,http1,http2,ffi --crate-type cdylib

Also, `--release` can be added for a release (optimized) build.

Build curl to use hyper's C API:

     % git clone https://github.com/curl/curl
     % cd curl
     % autoreconf -fi
     % ./configure LDFLAGS="-Wl,-rpath,<hyper-dir>/target/debug -Wl,-rpath,<hyper-dir>/target/release" --with-openssl --with-hyper=<hyper-dir>
     % make

# Using Hyper internally

Hyper is a low level HTTP transport library. curl itself provides all HTTP
headers and Hyper provides all received headers back to curl.

Therefore, most of the "header logic" in curl as in responding to and acting
on specific input and output headers are done the same way in curl code.

Changes to jni/curl/docs/INSTALL-CMAKE.md.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# Current flaws in the curl CMake build

Missing features in the CMake build:

 - Builds libcurl without large file support
 - Does not support all SSL libraries (only OpenSSL, Schannel, Secure
   Transport, and mbedTLS, WolfSSL)
 - Does not allow different resolver backends (no c-ares build support)
 - No RTMP support built
 - Does not allow build curl and libcurl debug enabled
 - Does not allow a custom CA bundle path
 - Does not allow you to disable specific protocols from the build
 - Does not find or use krb4 or GSS
 - Rebuilds test files too eagerly, but still cannot run the tests







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# Current flaws in the curl CMake build

Missing features in the CMake build:

 - Builds libcurl without large file support
 - Does not support all SSL libraries (only OpenSSL, Schannel, Secure
   Transport, and mbedTLS, wolfSSL)
 - Does not allow different resolver backends (no c-ares build support)
 - No RTMP support built
 - Does not allow build curl and libcurl debug enabled
 - Does not allow a custom CA bundle path
 - Does not allow you to disable specific protocols from the build
 - Does not find or use krb4 or GSS
 - Rebuilds test files too eagerly, but still cannot run the tests
Changes to jni/curl/docs/INSTALL.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# how to install curl and libcurl

## Installing Binary Packages

Lots of people download binary distributions of curl and libcurl. This
document does not describe how to install curl or libcurl using such a binary
package. This document describes how to compile, build and install curl and
libcurl from source code.






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# How to install curl and libcurl

## Installing Binary Packages

Lots of people download binary distributions of curl and libcurl. This
document does not describe how to install curl or libcurl using such a binary
package. This document describes how to compile, build and install curl and
libcurl from source code.
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

These options are provided to select the TLS backend to use.

 - AmiSSL: `--with-amissl`
 - BearSSL: `--with-bearssl`
 - GnuTLS: `--with-gnutls`.
 - mbedTLS: `--with-mbedtls`
 - OpenSSL: `--with-openssl` (also for BoringSSL, AWS-LC, libressl, and quictls)
 - rustls: `--with-rustls`
 - Schannel: `--with-schannel`
 - Secure Transport: `--with-secure-transport`
 - wolfSSL: `--with-wolfssl`

You can build curl with *multiple* TLS backends at your choice, but some TLS
backends cannot be combined: if you build with an OpenSSL fork (or wolfSSL),
you cannot add another OpenSSL fork (or wolfSSL) simply because they have
conflicting identical symbol names.

When you build with multiple TLS backends, you can select the active one at
runtime when curl starts up.

## configure finding libs in wrong directory

When the configure script checks for third-party libraries, it adds those
directories to the `LDFLAGS` variable and then tries linking to see if it
works. When successful, the found directory is kept in the `LDFLAGS` variable
when the script continues to execute and do more tests and possibly check for
more libraries.








|













|







136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

These options are provided to select the TLS backend to use.

 - AmiSSL: `--with-amissl`
 - BearSSL: `--with-bearssl`
 - GnuTLS: `--with-gnutls`.
 - mbedTLS: `--with-mbedtls`
 - OpenSSL: `--with-openssl` (also for BoringSSL, AWS-LC, LibreSSL, and quictls)
 - rustls: `--with-rustls`
 - Schannel: `--with-schannel`
 - Secure Transport: `--with-secure-transport`
 - wolfSSL: `--with-wolfssl`

You can build curl with *multiple* TLS backends at your choice, but some TLS
backends cannot be combined: if you build with an OpenSSL fork (or wolfSSL),
you cannot add another OpenSSL fork (or wolfSSL) simply because they have
conflicting identical symbol names.

When you build with multiple TLS backends, you can select the active one at
runtime when curl starts up.

## Configure finding libs in wrong directory

When the configure script checks for third-party libraries, it adds those
directories to the `LDFLAGS` variable and then tries linking to see if it
works. When successful, the found directory is kept in the `LDFLAGS` variable
when the script continues to execute and do more tests and possibly check for
more libraries.

Changes to jni/curl/docs/INTERNALS.md.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 we use a few "build tools" and we make sure that we remain functional with
 these versions:

 - GNU Libtool  1.4.2
 - GNU Autoconf 2.59
 - GNU Automake 1.7
 - GNU M4       1.4
 - perl         5.6
 - roffit       0.5
 - cmake        3.7

Library Symbols
===============

 All symbols used internally in libcurl must use a `Curl_` prefix if they are







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 we use a few "build tools" and we make sure that we remain functional with
 these versions:

 - GNU Libtool  1.4.2
 - GNU Autoconf 2.59
 - GNU Automake 1.7
 - GNU M4       1.4
 - perl         5.8
 - roffit       0.5
 - cmake        3.7

Library Symbols
===============

 All symbols used internally in libcurl must use a `Curl_` prefix if they are
Changes to jni/curl/docs/KNOWN_BUGS.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

85
86

87
88
89
90
91
92
93
 1. HTTP
 1.2 hyper is slow
 1.5 Expect-100 meets 417

 2. TLS
 2.1 IMAPS connection fails with rustls error
 2.3 Unable to use PKCS12 certificate with Secure Transport
 2.4 Secure Transport will not import PKCS#12 client certificates without a password
 2.5 Client cert handling with Issuer DN differs between backends
 2.7 Client cert (MTLS) issues with Schannel
 2.11 Schannel TLS 1.2 handshake bug in old Windows versions
 2.13 CURLOPT_CERTINFO results in CURLE_OUT_OF_MEMORY with Schannel

 3. Email protocols
 3.1 IMAP SEARCH ALL truncated response
 3.2 No disconnect command
 3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses
 3.4 AUTH PLAIN for SMTP is not working on all servers
 3.5 APOP authentication fails on POP3
 3.6 POP3 issue when reading small chunks

 4. Command line



 5. Build and portability issues
 5.1 OS400 port requires deprecated IBM library
 5.2 curl-config --libs contains private details
 5.3 building for old macOS fails with gcc
 5.5 cannot handle Unicode arguments in non-Unicode builds on Windows
 5.6 cygwin: make install installs curl-config.1 twice
 5.9 Utilize Requires.private directives in libcurl.pc
 5.11 configure --with-gssapi with Heimdal is ignored on macOS
 5.12 flaky CI builds
 5.13 long paths are not fully supported on Windows
 5.14 Windows Unicode builds use homedir in current locale
 5.15 Unicode on Windows

 6. Authentication
 6.1 NTLM authentication and unicode
 6.2 MIT Kerberos for Windows build
 6.3 NTLM in system context uses wrong name
 6.5 NTLM does not support password with § character
 6.6 libcurl can fail to try alternatives with --proxy-any
 6.7 Do not clear digest for single realm
 6.9 SHA-256 digest not supported in Windows SSPI builds
 6.10 curl never completes Negotiate over HTTP
 6.11 Negotiate on Windows fails
 6.12 cannot use Secure Transport with Crypto Token Kit
 6.13 Negotiate against Hadoop HDFS

 7. FTP
 7.1 FTP upload fails if remembered dir is deleted
 7.2 Implicit FTPS upload timeout
 7.3 FTP with NOBODY and FAILONERROR
 7.4 FTP with ACCT
 7.5 FTPS upload, FileZilla, GnuTLS and close_notify
 7.11 FTPS upload data loss with TLS 1.3
 7.12 FTPS directory listing hangs on Windows with Schannel

 9. SFTP and SCP
 9.1 SFTP does not do CURLOPT_POSTQUOTE correct
 9.2 wolfssh: publickey auth does not work
 9.3 Remote recursive folder creation with SFTP
 9.4 libssh blocking and infinite loop problem
 9.5 cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!"

 10. SOCKS
 10.3 FTPS over SOCKS

 11. Internals
 11.1 gssapi library name + version is missing in curl_version_info()
 11.2 error buffer not set if connection to multiple addresses fails

 11.4 HTTP test server 'connection-monitor' problems
 11.5 Connection information when using TCP Fast Open


 12. LDAP
 12.1 OpenLDAP hangs after returning results
 12.2 LDAP on Windows does authentication wrong?
 12.3 LDAP on Windows does not work
 12.4 LDAPS requests to ActiveDirectory server hang








|














>
>







<




















|



<
<















>


>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
 1. HTTP
 1.2 hyper is slow
 1.5 Expect-100 meets 417

 2. TLS
 2.1 IMAPS connection fails with rustls error
 2.3 Unable to use PKCS12 certificate with Secure Transport
 2.4 Secure Transport does not import PKCS#12 client certificates without a password
 2.5 Client cert handling with Issuer DN differs between backends
 2.7 Client cert (MTLS) issues with Schannel
 2.11 Schannel TLS 1.2 handshake bug in old Windows versions
 2.13 CURLOPT_CERTINFO results in CURLE_OUT_OF_MEMORY with Schannel

 3. Email protocols
 3.1 IMAP SEARCH ALL truncated response
 3.2 No disconnect command
 3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses
 3.4 AUTH PLAIN for SMTP is not working on all servers
 3.5 APOP authentication fails on POP3
 3.6 POP3 issue when reading small chunks

 4. Command line
 4.1 -T /dev/stdin may upload with an incorrect content length
 4.2 -T - always uploads chunked

 5. Build and portability issues
 5.1 OS400 port requires deprecated IBM library
 5.2 curl-config --libs contains private details
 5.3 building for old macOS fails with gcc
 5.5 cannot handle Unicode arguments in non-Unicode builds on Windows
 5.6 cygwin: make install installs curl-config.1 twice

 5.11 configure --with-gssapi with Heimdal is ignored on macOS
 5.12 flaky CI builds
 5.13 long paths are not fully supported on Windows
 5.14 Windows Unicode builds use homedir in current locale
 5.15 Unicode on Windows

 6. Authentication
 6.1 NTLM authentication and unicode
 6.2 MIT Kerberos for Windows build
 6.3 NTLM in system context uses wrong name
 6.5 NTLM does not support password with § character
 6.6 libcurl can fail to try alternatives with --proxy-any
 6.7 Do not clear digest for single realm
 6.9 SHA-256 digest not supported in Windows SSPI builds
 6.10 curl never completes Negotiate over HTTP
 6.11 Negotiate on Windows fails
 6.12 cannot use Secure Transport with Crypto Token Kit
 6.13 Negotiate against Hadoop HDFS

 7. FTP
 7.1 FTP upload fails if remembered directory is deleted
 7.2 Implicit FTPS upload timeout
 7.3 FTP with NOBODY and FAILONERROR
 7.4 FTP with ACCT


 7.12 FTPS directory listing hangs on Windows with Schannel

 9. SFTP and SCP
 9.1 SFTP does not do CURLOPT_POSTQUOTE correct
 9.2 wolfssh: publickey auth does not work
 9.3 Remote recursive folder creation with SFTP
 9.4 libssh blocking and infinite loop problem
 9.5 cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!"

 10. SOCKS
 10.3 FTPS over SOCKS

 11. Internals
 11.1 gssapi library name + version is missing in curl_version_info()
 11.2 error buffer not set if connection to multiple addresses fails
 11.3 TFTP tests fail on OpenBSD
 11.4 HTTP test server 'connection-monitor' problems
 11.5 Connection information when using TCP Fast Open
 11.6 test cases sometimes timeout

 12. LDAP
 12.1 OpenLDAP hangs after returning results
 12.2 LDAP on Windows does authentication wrong?
 12.3 LDAP on Windows does not work
 12.4 LDAPS requests to ActiveDirectory server hang

101
102
103
104
105
106
107


108
109
110
111
112
113

114
115
116

117
118
119
120
121
122
123
 15.6 uses -lpthread instead of Threads::Threads
 15.7 generated .pc file contains strange entries
 15.11 ExternalProject_Add does not set CURL_CA_PATH
 15.13 CMake build with MIT Kerberos does not work

 16. aws-sigv4
 16.1 aws-sigv4 does not sign requests with * correctly


 16.6 aws-sigv4 does not behave well with AWS VPC Lattice

 17. HTTP/2
 17.1 HTTP/2 prior knowledge over proxy
 17.2 HTTP/2 frames while in the connection pool kill reuse
 17.3 ENHANCE_YOUR_CALM causes infinite retries


 18. HTTP/3
 18.1 connection migration does not work


 19. RTSP
 19.1 Some methods do not support response bodies

==============================================================================

1. HTTP







>
>






>



>







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
 15.6 uses -lpthread instead of Threads::Threads
 15.7 generated .pc file contains strange entries
 15.11 ExternalProject_Add does not set CURL_CA_PATH
 15.13 CMake build with MIT Kerberos does not work

 16. aws-sigv4
 16.1 aws-sigv4 does not sign requests with * correctly
 16.2 aws-sigv4 does not handle multipart/form-data correctly
 16.3 aws-sigv4 has problems with particular URLs
 16.6 aws-sigv4 does not behave well with AWS VPC Lattice

 17. HTTP/2
 17.1 HTTP/2 prior knowledge over proxy
 17.2 HTTP/2 frames while in the connection pool kill reuse
 17.3 ENHANCE_YOUR_CALM causes infinite retries
 17.4 HTTP/2 + TLS spends a lot of time in recv

 18. HTTP/3
 18.1 connection migration does not work
 18.2 quiche: QUIC connection is draining

 19. RTSP
 19.1 Some methods do not support response bodies

==============================================================================

1. HTTP
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

 https://github.com/curl/curl/issues/10457

2.3 Unable to use PKCS12 certificate with Secure Transport

 See https://github.com/curl/curl/issues/5403

2.4 Secure Transport will not import PKCS#12 client certificates without a password

 libcurl calls SecPKCS12Import with the PKCS#12 client certificate, but that
 function rejects certificates that do not have a password.
 https://github.com/curl/curl/issues/1308

2.5 Client cert handling with Issuer DN differs between backends








|







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

 https://github.com/curl/curl/issues/10457

2.3 Unable to use PKCS12 certificate with Secure Transport

 See https://github.com/curl/curl/issues/5403

2.4 Secure Transport does not import PKCS#12 client certificates without a password

 libcurl calls SecPKCS12Import with the PKCS#12 client certificate, but that
 function rejects certificates that do not have a password.
 https://github.com/curl/curl/issues/1308

2.5 Client cert handling with Issuer DN differs between backends

210
211
212
213
214
215
216



















217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

 CURL_DBG_SOCK_RMAX=4 ./runtests.pl -v 982

 See https://github.com/curl/curl/issues/12063

4. Command line




















5. Build and portability issues

5.1 OS400 port requires deprecated IBM library

 curl for OS400 requires QADRT to build, which provides ASCII wrappers for
 libc/POSIX functions in the ILE, but IBM no longer supports or even offers
 this library to download.

 See https://github.com/curl/curl/issues/5176

5.2 curl-config --libs contains private details

 "curl-config --libs" will include details set in LDFLAGS when configure is
 run that might be needed only for building libcurl. Further, curl-config
 --cflags suffers from the same effects with CFLAGS/CPPFLAGS.

5.3 building for old macOS fails with gcc

 Building curl for certain old macOS versions fails when gcc is used. We
 command using clang in those cases.

 See https://github.com/curl/curl/issues/11441

5.5 cannot handle Unicode arguments in non-Unicode builds on Windows

 If a URL or filename cannot be encoded using the user's current codepage then
 it can only be encoded properly in the Unicode character set. Windows uses
 UTF-16 encoding for Unicode and stores it in wide characters, however curl
 and libcurl are not equipped for that at the moment except when built with
 _UNICODE and UNICODE defined. And, except for Cygwin, Windows cannot use UTF-8
 as a locale.

  https://curl.se/bug/?i=345
  https://curl.se/bug/?i=731
  https://curl.se/bug/?i=3747

5.6 cygwin: make install installs curl-config.1 twice

 https://github.com/curl/curl/issues/8839

5.9 Utilize Requires.private directives in libcurl.pc

 https://github.com/curl/curl/issues/864

5.11 configure --with-gssapi with Heimdal is ignored on macOS

 ... unless you also pass --with-gssapi-libs

 https://github.com/curl/curl/issues/3841

5.12 flaky CI builds







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












|
|
|














|
|









<
<
<
<







215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280




281
282
283
284
285
286
287

 CURL_DBG_SOCK_RMAX=4 ./runtests.pl -v 982

 See https://github.com/curl/curl/issues/12063

4. Command line

4.1 -T /dev/stdin may upload with an incorrect content length

 -T stats the path to figure out its size in bytes to use it as Content-Length
 if it is a regular file.

 The problem with that is that, on BSDs and some other UNIXes (not Linux),
 open(path) may not give you a file descriptor with a 0 offset from the start
 of the file.

 See https://github.com/curl/curl/issues/12177

4.2 -T - always uploads chunked

 When the `<` shell operator is used. curl should realise that stdin is a
 regular file in this case, and that it can do a non-chunked upload, like it
 would do if you used -T file.

 See https://github.com/curl/curl/issues/12171

5. Build and portability issues

5.1 OS400 port requires deprecated IBM library

 curl for OS400 requires QADRT to build, which provides ASCII wrappers for
 libc/POSIX functions in the ILE, but IBM no longer supports or even offers
 this library to download.

 See https://github.com/curl/curl/issues/5176

5.2 curl-config --libs contains private details

 "curl-config --libs" include details set in LDFLAGS when configure is run
 that might be needed only for building libcurl. Further, curl-config --cflags
 suffers from the same effects with CFLAGS/CPPFLAGS.

5.3 building for old macOS fails with gcc

 Building curl for certain old macOS versions fails when gcc is used. We
 command using clang in those cases.

 See https://github.com/curl/curl/issues/11441

5.5 cannot handle Unicode arguments in non-Unicode builds on Windows

 If a URL or filename cannot be encoded using the user's current codepage then
 it can only be encoded properly in the Unicode character set. Windows uses
 UTF-16 encoding for Unicode and stores it in wide characters, however curl
 and libcurl are not equipped for that at the moment except when built with
 _UNICODE and UNICODE defined. Except for Cygwin, Windows cannot use UTF-8 as
 a locale.

  https://curl.se/bug/?i=345
  https://curl.se/bug/?i=731
  https://curl.se/bug/?i=3747

5.6 cygwin: make install installs curl-config.1 twice

 https://github.com/curl/curl/issues/8839





5.11 configure --with-gssapi with Heimdal is ignored on macOS

 ... unless you also pass --with-gssapi-libs

 https://github.com/curl/curl/issues/3841

5.12 flaky CI builds
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349

 https://github.com/curl/curl/issues/12231

6. Authentication

6.1 NTLM authentication and unicode

 NTLM authentication involving unicode user name or password only works
 properly if built with UNICODE defined together with the Schannel
 backend. The original problem was mentioned in:
 https://curl.se/mail/lib-2009-10/0024.html
 https://curl.se/bug/view.cgi?id=896

 The Schannel version verified to work as mentioned in
 https://curl.se/mail/lib-2012-07/0073.html

6.2 MIT Kerberos for Windows build

 libcurl fails to build with MIT Kerberos for Windows (KfW) due to KfW's
 library header files exporting symbols/macros that should be kept private to
 the KfW library. See ticket #5601 at https://krbdev.mit.edu/rt/

6.3 NTLM in system context uses wrong name

 NTLM authentication using SSPI (on Windows) when (lib)curl is running in
 "system context" will make it use wrong(?) user name - at least when compared
 to what winhttp does. See https://curl.se/bug/view.cgi?id=535

6.5 NTLM does not support password with § character

 https://github.com/curl/curl/issues/2120

6.6 libcurl can fail to try alternatives with --proxy-any

 When connecting via a proxy using --proxy-any, a failure to establish an
 authentication will cause libcurl to abort trying other options if the
 failed method has a higher preference than the alternatives. As an example,
 --proxy-any against a proxy which advertise Negotiate and NTLM, but which
 fails to set up Kerberos authentication will not proceed to try authentication
 using NTLM.

 https://github.com/curl/curl/issues/876

6.7 Do not clear digest for single realm

 https://github.com/curl/curl/issues/3267








|

















|
|








|
|

|
|







323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369

 https://github.com/curl/curl/issues/12231

6. Authentication

6.1 NTLM authentication and unicode

 NTLM authentication involving unicode username or password only works
 properly if built with UNICODE defined together with the Schannel
 backend. The original problem was mentioned in:
 https://curl.se/mail/lib-2009-10/0024.html
 https://curl.se/bug/view.cgi?id=896

 The Schannel version verified to work as mentioned in
 https://curl.se/mail/lib-2012-07/0073.html

6.2 MIT Kerberos for Windows build

 libcurl fails to build with MIT Kerberos for Windows (KfW) due to KfW's
 library header files exporting symbols/macros that should be kept private to
 the KfW library. See ticket #5601 at https://krbdev.mit.edu/rt/

6.3 NTLM in system context uses wrong name

 NTLM authentication using SSPI (on Windows) when (lib)curl is running in
 "system context" makes it use wrong(?) username - at least when compared to
 what winhttp does. See https://curl.se/bug/view.cgi?id=535

6.5 NTLM does not support password with § character

 https://github.com/curl/curl/issues/2120

6.6 libcurl can fail to try alternatives with --proxy-any

 When connecting via a proxy using --proxy-any, a failure to establish an
 authentication causes libcurl to abort trying other options if the failed
 method has a higher preference than the alternatives. As an example,
 --proxy-any against a proxy which advertise Negotiate and NTLM, but which
 fails to set up Kerberos authentication does not proceed to try
 authentication using NTLM.

 https://github.com/curl/curl/issues/876

6.7 Do not clear digest for single realm

 https://github.com/curl/curl/issues/3267

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

6.13 Negotiate authentication against Hadoop HDFS

 https://github.com/curl/curl/issues/8264

7. FTP

7.1 FTP upload fails if remembered dir is deleted

 curl's FTP code assumes that the directory it entered in a previous transfer
 still exists when it comes back to do a second transfer, and does not respond
 well if it was indeed deleted in the mean time.

 https://github.com/curl/curl/issues/12181

7.2 Implicit FTPS upload timeout

 https://github.com/curl/curl/issues/11720

7.3 FTP with NOBODY and FAILONERROR

 It seems sensible to be able to use CURLOPT_NOBODY and CURLOPT_FAILONERROR
 with FTP to detect if a file exists or not, but it is not working:
 https://curl.se/mail/lib-2008-07/0295.html

7.4 FTP with ACCT

 When doing an operation over FTP that requires the ACCT command (but not when
 logging in), the operation will fail since libcurl does not detect this and
 thus fails to issue the correct command:
 https://curl.se/bug/view.cgi?id=635

7.5 FTPS upload, FileZilla, GnuTLS and close_notify

 An issue where curl does not send the TLS alert close_notify, which triggers
 the wrath of GnuTLS in FileZilla server, and a FTP reply 426 ECONNABORTED.

 https://github.com/curl/curl/issues/11383

7.11 FTPS upload data loss with TLS 1.3

 During FTPS upload curl does not attempt to read TLS handshake messages sent
 after the initial handshake. OpenSSL servers running TLS 1.3 may send such a
 message. When curl closes the upload connection if unread data has been
 received (such as a TLS handshake message) then the TCP protocol sends an
 RST to the server, which may cause the server to discard or truncate the
 upload if it has not read all sent data yet, and then return an error to curl
 on the control channel connection.

 Since 7.78.0 this is mostly fixed. curl will do a single read before closing
 TLS connections (which causes the TLS library to read handshake messages),
 however there is still possibility of an RST if more messages need to be read
 or a message arrives after the read but before close (network race condition).

 https://github.com/curl/curl/issues/6149

7.12 FTPS server compatibility on Windows with Schannel

 FTPS is not widely used with the Schannel TLS backend and so there may be more
 bugs compared to other TLS backends such as OpenSSL. In the past users have
 reported hanging and failed connections. It's very likely some changes to curl
 since then fixed the issues. None of the reported issues can be reproduced any
 longer.

 If you encounter an issue connecting to your server via FTPS with the latest
 curl and Schannel then please search for open issues or file a new issue.

9. SFTP and SCP

9.1 SFTP does not do CURLOPT_POSTQUOTE correct







|




















|
<
|

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


|
|
|
|
|







398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

427
428
























429
430
431
432
433
434
435
436
437
438
439
440
441
442

6.13 Negotiate authentication against Hadoop HDFS

 https://github.com/curl/curl/issues/8264

7. FTP

7.1 FTP upload fails if remembered directory is deleted

 curl's FTP code assumes that the directory it entered in a previous transfer
 still exists when it comes back to do a second transfer, and does not respond
 well if it was indeed deleted in the mean time.

 https://github.com/curl/curl/issues/12181

7.2 Implicit FTPS upload timeout

 https://github.com/curl/curl/issues/11720

7.3 FTP with NOBODY and FAILONERROR

 It seems sensible to be able to use CURLOPT_NOBODY and CURLOPT_FAILONERROR
 with FTP to detect if a file exists or not, but it is not working:
 https://curl.se/mail/lib-2008-07/0295.html

7.4 FTP with ACCT

 When doing an operation over FTP that requires the ACCT command (but not when
 logging in), the operation fails since libcurl does not detect this and thus

 fails to issue the correct command: https://curl.se/bug/view.cgi?id=635

























7.12 FTPS server compatibility on Windows with Schannel

 FTPS is not widely used with the Schannel TLS backend and so there may be
 more bugs compared to other TLS backends such as OpenSSL. In the past users
 have reported hanging and failed connections. It is likely some changes to
 curl since then fixed the issues. None of the reported issues can be
 reproduced any longer.

 If you encounter an issue connecting to your server via FTPS with the latest
 curl and Schannel then please search for open issues or file a new issue.

9. SFTP and SCP

9.1 SFTP does not do CURLOPT_POSTQUOTE correct
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482

 See https://github.com/curl/curl/issues/5204

9.4 libssh blocking and infinite loop problem

 In the SSH_SFTP_INIT state for libssh, the ssh session working mode is set to
 blocking mode. If the network is suddenly disconnected during sftp
 transmission, curl will be stuck, even if curl is configured with a timeout.

 https://github.com/curl/curl/issues/8632

9.5 cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!"

 Running SCP and SFTP tests on cygwin makes this warning message appear.








|







463
464
465
466
467
468
469
470
471
472
473
474
475
476
477

 See https://github.com/curl/curl/issues/5204

9.4 libssh blocking and infinite loop problem

 In the SSH_SFTP_INIT state for libssh, the ssh session working mode is set to
 blocking mode. If the network is suddenly disconnected during sftp
 transmission, curl is stuck, even if curl is configured with a timeout.

 https://github.com/curl/curl/issues/8632

9.5 cygwin: "WARNING: UNPROTECTED PRIVATE KEY FILE!"

 Running SCP and SFTP tests on cygwin makes this warning message appear.

496
497
498
499
500
501
502
503
504
505
506







507
508
509
510
511
512
513
514
515
516
517
518
519
520
521






522
523
524
525
526
527
528
 The struct needs to be expanded and code added to store this info.

 See https://github.com/curl/curl/issues/13492

11.2 error buffer not set if connection to multiple addresses fails

 If you ask libcurl to resolve a hostname like example.com to IPv6 addresses
 only. But you only have IPv4 connectivity. libcurl will correctly fail with
 CURLE_COULDNT_CONNECT. But the error buffer set by CURLOPT_ERRORBUFFER
 remains empty. Issue: https://github.com/curl/curl/issues/544








11.4 HTTP test server 'connection-monitor' problems

 The 'connection-monitor' feature of the sws HTTP test server does not work
 properly if some tests are run in unexpected order. Like 1509 and then 1525.

 See https://github.com/curl/curl/issues/868

11.5 Connection information when using TCP Fast Open

 CURLINFO_LOCAL_PORT (and possibly a few other) fails when TCP Fast Open is
 enabled.

 See https://github.com/curl/curl/issues/1332 and
 https://github.com/curl/curl/issues/4296







12. LDAP

12.1 OpenLDAP hangs after returning results

 By configuration defaults, OpenLDAP automatically chase referrals on
 secondary socket descriptors. The OpenLDAP backend is asynchronous and thus
 should monitor all socket descriptors involved. Currently, these secondary







|
|


>
>
>
>
>
>
>















>
>
>
>
>
>







491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
 The struct needs to be expanded and code added to store this info.

 See https://github.com/curl/curl/issues/13492

11.2 error buffer not set if connection to multiple addresses fails

 If you ask libcurl to resolve a hostname like example.com to IPv6 addresses
 when you only have IPv4 connectivity. libcurl fails with
 CURLE_COULDNT_CONNECT, but the error buffer set by CURLOPT_ERRORBUFFER
 remains empty. Issue: https://github.com/curl/curl/issues/544

11.3 TFTP tests fail on OpenBSD

 When adding an OpenBSD job with tests to GHA, some tests consistently fail
 to run.

 See https://github.com/curl/curl/issues/13623

11.4 HTTP test server 'connection-monitor' problems

 The 'connection-monitor' feature of the sws HTTP test server does not work
 properly if some tests are run in unexpected order. Like 1509 and then 1525.

 See https://github.com/curl/curl/issues/868

11.5 Connection information when using TCP Fast Open

 CURLINFO_LOCAL_PORT (and possibly a few other) fails when TCP Fast Open is
 enabled.

 See https://github.com/curl/curl/issues/1332 and
 https://github.com/curl/curl/issues/4296

11.6 test cases sometimes timeout

 Occasionally, one of the tests timeouts. Inexplicably.

 See https://github.com/curl/curl/issues/13350

12. LDAP

12.1 OpenLDAP hangs after returning results

 By configuration defaults, OpenLDAP automatically chase referrals on
 secondary socket descriptors. The OpenLDAP backend is asynchronous and thus
 should monitor all socket descriptors involved. Currently, these secondary
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
 https://github.com/curl/curl/issues/9580

13. TCP/IP

13.2 Trying local ports fails on Windows

 This makes '--local-port [range]' to not work since curl cannot properly
 detect if a port is already in use, so it will try the first port, use that and
 then subsequently fail anyway if that was actually in use.

 https://github.com/curl/curl/issues/8112

15. CMake

15.1 cmake outputs: no version information available








|
|







564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
 https://github.com/curl/curl/issues/9580

13. TCP/IP

13.2 Trying local ports fails on Windows

 This makes '--local-port [range]' to not work since curl cannot properly
 detect if a port is already in use, so it tries the first port, uses that and
 then subsequently fails anyway if that was actually in use.

 https://github.com/curl/curl/issues/8112

15. CMake

15.1 cmake outputs: no version information available

609
610
611
612
613
614
615








616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643










644
645
646
647
648
649






650
651
652
653
654
655
656
657
658
 https://github.com/curl/curl/issues/6904

16. aws-sigv4

16.1 aws-sigv4 does not sign requests with * correctly

 https://github.com/curl/curl/issues/7559









16.6 aws-sigv4 does not behave well with AWS VPC Lattice

 https://github.com/curl/curl/issues/11007

17. HTTP/2

17.1 HTTP/2 prior knowledge over proxy

 https://github.com/curl/curl/issues/12641

17.2 HTTP/2 frames while in the connection pool kill reuse

 If the server sends HTTP/2 frames (like for example an HTTP/2 PING frame) to
 curl while the connection is held in curl's connection pool, the socket will
 be found readable when considered for reuse and that makes curl think it is
 dead and then it will be closed and a new connection gets created instead.

 This is *best* fixed by adding monitoring to connections while they are kept
 in the pool so that pings can be responded to appropriately.

17.3 ENHANCE_YOUR_CALM causes infinite retries

 Infinite retries with 2 parallel requests on one connection receiving GOAWAY
 with ENHANCE_YOUR_CALM error code.

 See https://github.com/curl/curl/issues/5119











18. HTTP/3

18.1 connection migration does not work

 https://github.com/curl/curl/issues/7695







19. RTSP

19.1 Some methods do not support response bodies

 The RTSP implementation is written to assume that a number of RTSP methods
 will always get responses without bodies, even though there seems to be no
 indication in the RFC that this is always the case.

 https://github.com/curl/curl/issues/12414







>
>
>
>
>
>
>
>














|
|
|











>
>
>
>
>
>
>
>
>
>






>
>
>
>
>
>





|



617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
 https://github.com/curl/curl/issues/6904

16. aws-sigv4

16.1 aws-sigv4 does not sign requests with * correctly

 https://github.com/curl/curl/issues/7559

16.2 aws-sigv4 does not handle multipart/form-data correctly

 https://github.com/curl/curl/issues/13351

16.3 aws-sigv4 has problems with particular URLs

 https://github.com/curl/curl/issues/13058

16.6 aws-sigv4 does not behave well with AWS VPC Lattice

 https://github.com/curl/curl/issues/11007

17. HTTP/2

17.1 HTTP/2 prior knowledge over proxy

 https://github.com/curl/curl/issues/12641

17.2 HTTP/2 frames while in the connection pool kill reuse

 If the server sends HTTP/2 frames (like for example an HTTP/2 PING frame) to
 curl while the connection is held in curl's connection pool, the socket is
 found readable when considered for reuse and that makes curl think it is dead
 and then it is closed and a new connection gets created instead.

 This is *best* fixed by adding monitoring to connections while they are kept
 in the pool so that pings can be responded to appropriately.

17.3 ENHANCE_YOUR_CALM causes infinite retries

 Infinite retries with 2 parallel requests on one connection receiving GOAWAY
 with ENHANCE_YOUR_CALM error code.

 See https://github.com/curl/curl/issues/5119

17.4 HTTP/2 + TLS spends a lot of time in recv

 It has been observered that by making the speed limit less accurate we could
 improve this performance. (by reverting
 https://github.com/curl/curl/commit/db5c9f4f9e0779b49624752b135281a0717b277b)
 Can we find a golden middle ground?

 See https://curl.se/mail/lib-2024-05/0026.html and
 https://github.com/curl/curl/issues/13416

18. HTTP/3

18.1 connection migration does not work

 https://github.com/curl/curl/issues/7695

18.2 quiche: QUIC connection is draining

 The transfer ends with error "QUIC connection is draining".

 https://github.com/curl/curl/issues/12037

19. RTSP

19.1 Some methods do not support response bodies

 The RTSP implementation is written to assume that a number of RTSP methods
 always get responses without bodies, even though there seems to be no
 indication in the RFC that this is always the case.

 https://github.com/curl/curl/issues/12414
Changes to jni/curl/docs/MANUAL.md.
305
306
307
308
309
310
311
312

313
314
315
316
317
318
319

Post a simple `name` and `phone` guestbook.

    curl -d "name=Rafael%20Sagula&phone=3320780" http://www.example.com/guest.cgi

Or automatically [URL encode the data](https://everything.curl.dev/http/post/url-encode).

    curl --data-urlencode "name=Rafael Sagula&phone=3320780" http://www.example.com/guest.cgi


How to post a form with curl, lesson #1:

Dig out all the `<input>` tags in the form that you want to fill in.

If there is a normal post, you use `-d` to post. `-d` takes a full post
string, which is in the format







|
>







305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

Post a simple `name` and `phone` guestbook.

    curl -d "name=Rafael%20Sagula&phone=3320780" http://www.example.com/guest.cgi

Or automatically [URL encode the data](https://everything.curl.dev/http/post/url-encode).

    curl --data-urlencode "name=Rafael Sagula&phone=3320780"
      http://www.example.com/guest.cgi

How to post a form with curl, lesson #1:

Dig out all the `<input>` tags in the form that you want to fill in.

If there is a normal post, you use `-d` to post. `-d` takes a full post
string, which is in the format
339
340
341
342
343
344
345
346

347
348
349
350
351
352
353
</form>
```

We want to enter user `foobar` with password `12345`.

To post to this, you would enter a curl command line like:

    curl -d "user=foobar&pass=12345&id=blablabla&ding=submit" http://example.com/post.cgi


While `-d` uses the application/x-www-form-urlencoded mime-type, generally
understood by CGI's and similar, curl also supports the more capable
multipart/form-data type. This latter type supports things like file upload.

`-F` accepts parameters like `-F "name=contents"`. If you want the contents to
be read from a file, use `@filename` as contents. When specifying a file, you







|
>







340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
</form>
```

We want to enter user `foobar` with password `12345`.

To post to this, you would enter a curl command line like:

    curl -d "user=foobar&pass=12345&id=blablabla&ding=submit"
      http://example.com/post.cgi

While `-d` uses the application/x-www-form-urlencoded mime-type, generally
understood by CGI's and similar, curl also supports the more capable
multipart/form-data type. This latter type supports things like file upload.

`-F` accepts parameters like `-F "name=contents"`. If you want the contents to
be read from a file, use `@filename` as contents. When specifying a file, you
Changes to jni/curl/docs/Makefile.am.
24
25
26
27
28
29
30

31
32
33
34
35
36
37

AUTOMAKE_OPTIONS = foreign no-dependencies

if BUILD_DOCS
# if we disable man page building, ignore these
MK_CA_DOCS = mk-ca-bundle.1
CURLCONF_DOCS = curl-config.1

endif

CURLPAGES = curl-config.md mk-ca-bundle.md

SUBDIRS = . cmdline-opts libcurl
DIST_SUBDIRS = $(SUBDIRS) examples








>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

AUTOMAKE_OPTIONS = foreign no-dependencies

if BUILD_DOCS
# if we disable man page building, ignore these
MK_CA_DOCS = mk-ca-bundle.1
CURLCONF_DOCS = curl-config.1
man_MANS = curl-config.1
endif

CURLPAGES = curl-config.md mk-ca-bundle.md

SUBDIRS = . cmdline-opts libcurl
DIST_SUBDIRS = $(SUBDIRS) examples

Changes to jni/curl/docs/Makefile.in.
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







129
130
131
132
133
134
135

136
137
138
139
140
141
142
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
171
172
173
174
175
176
177































178
179
180
181
182
183
184
	installdirs-recursive pdf-recursive ps-recursive \
	tags-recursive uninstall-recursive
am__can_run_installinfo = \
  case $$AM_UPDATE_INFO_DIR in \
    n|no|NO) false;; \
    *) (install-info --version) >/dev/null 2>&1;; \
  esac































RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
  distclean-recursive maintainer-clean-recursive
am__recursive_targets = \
  $(RECURSIVE_TARGETS) \
  $(RECURSIVE_CLEAN_TARGETS) \
  $(am__extra_recursive_targets)
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
	installdirs-recursive pdf-recursive ps-recursive \
	tags-recursive uninstall-recursive
am__can_run_installinfo = \
  case $$AM_UPDATE_INFO_DIR in \
    n|no|NO) false;; \
    *) (install-info --version) >/dev/null 2>&1;; \
  esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
    *) f=$$p;; \
  esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
  for p in $$list; do echo "$$p $$p"; done | \
  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
    if (++n[$$2] == $(am__install_max)) \
      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
    END { for (dir in files) print dir, files[dir] }'
am__base_list = \
  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
  test -z "$$files" \
    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
         $(am__cd) "$$dir" && rm -f $$files; }; \
  }
man1dir = $(mandir)/man1
am__installdirs = "$(DESTDIR)$(man1dir)"
NROFF = nroff
MANS = $(man_MANS)
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
  distclean-recursive maintainer-clean-recursive
am__recursive_targets = \
  $(RECURSIVE_TARGETS) \
  $(RECURSIVE_CLEAN_TARGETS) \
  $(am__extra_recursive_targets)
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
312
313
314
315
316
317
318


319
320
321
322
323
324
325
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
452
453
454
455
456
457
458

459
460
461
462
463
464
465
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign no-dependencies

# if we disable man page building, ignore these
@BUILD_DOCS_TRUE@MK_CA_DOCS = mk-ca-bundle.1
@BUILD_DOCS_TRUE@CURLCONF_DOCS = curl-config.1

CURLPAGES = curl-config.md mk-ca-bundle.md
SUBDIRS = . cmdline-opts libcurl
DIST_SUBDIRS = $(SUBDIRS) examples
@BUILD_DOCS_TRUE@CLEANFILES = mk-ca-bundle.1 curl-config.1
EXTRA_DIST = \
 $(CURLPAGES)                                   \
 ALTSVC.md                                      \







>







484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign no-dependencies

# if we disable man page building, ignore these
@BUILD_DOCS_TRUE@MK_CA_DOCS = mk-ca-bundle.1
@BUILD_DOCS_TRUE@CURLCONF_DOCS = curl-config.1
@BUILD_DOCS_TRUE@man_MANS = curl-config.1
CURLPAGES = curl-config.md mk-ca-bundle.md
SUBDIRS = . cmdline-opts libcurl
DIST_SUBDIRS = $(SUBDIRS) examples
@BUILD_DOCS_TRUE@CLEANFILES = mk-ca-bundle.1 curl-config.1
EXTRA_DIST = \
 $(CURLPAGES)                                   \
 ALTSVC.md                                      \
565
566
567
568
569
570
571











































572
573
574
575
576
577
578
$(am__aclocal_m4_deps):

mostlyclean-libtool:
	-rm -f *.lo

clean-libtool:
	-rm -rf .libs _libs












































# This directory's subdirectories are mostly independent; you can cd
# into them and run 'make' without going through this Makefile.
# To change the values of 'make' variables: instead of editing Makefiles,
# (1) if the variable is set in 'config.status', edit 'config.status'
#     (which will cause the Makefiles to be regenerated when you run 'make');
# (2) otherwise, pass the desired values on the 'make' command line.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
$(am__aclocal_m4_deps):

mostlyclean-libtool:
	-rm -f *.lo

clean-libtool:
	-rm -rf .libs _libs
install-man1: $(man_MANS)
	@$(NORMAL_INSTALL)
	@list1=''; \
	list2='$(man_MANS)'; \
	test -n "$(man1dir)" \
	  && test -n "`echo $$list1$$list2`" \
	  || exit 0; \
	echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
	$(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
	{ for i in $$list1; do echo "$$i"; done;  \
	if test -n "$$list2"; then \
	  for i in $$list2; do echo "$$i"; done \
	    | sed -n '/\.1[a-z]*$$/p'; \
	fi; \
	} | while read p; do \
	  if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
	  echo "$$d$$p"; echo "$$p"; \
	done | \
	sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
	sed 'N;N;s,\n, ,g' | { \
	list=; while read file base inst; do \
	  if test "$$base" = "$$inst"; then list="$$list $$file"; else \
	    echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
	    $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
	  fi; \
	done; \
	for i in $$list; do echo "$$i"; done | $(am__base_list) | \
	while read files; do \
	  test -z "$$files" || { \
	    echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
	    $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
	done; }

uninstall-man1:
	@$(NORMAL_UNINSTALL)
	@list=''; test -n "$(man1dir)" || exit 0; \
	files=`{ for i in $$list; do echo "$$i"; done; \
	l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
	  sed -n '/\.1[a-z]*$$/p'; \
	} | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
	      -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
	dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)

# This directory's subdirectories are mostly independent; you can cd
# into them and run 'make' without going through this Makefile.
# To change the values of 'make' variables: instead of editing Makefiles,
# (1) if the variable is set in 'config.status', edit 'config.status'
#     (which will cause the Makefiles to be regenerated when you run 'make');
# (2) otherwise, pass the desired values on the 'make' command line.
724
725
726
727
728
729
730
731
732
733



734
735
736
737
738
739
740
		am__skip_mode_fix=: \
	        distdir) \
	      || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-recursive
all-am: Makefile
installdirs: installdirs-recursive
installdirs-am:



install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive

install-am: all-am
	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am







|


>
>
>







800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
		am__skip_mode_fix=: \
	        distdir) \
	      || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-recursive
all-am: Makefile $(MANS)
installdirs: installdirs-recursive
installdirs-am:
	for dir in "$(DESTDIR)$(man1dir)"; do \
	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
	done
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive

install-am: all-am
	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806

html-am:

info: info-recursive

info-am:

install-data-am:

install-dvi: install-dvi-recursive

install-dvi-am:

install-exec-am:

install-html: install-html-recursive

install-html-am:

install-info: install-info-recursive

install-info-am:

install-man:

install-pdf: install-pdf-recursive

install-pdf-am:

install-ps: install-ps-recursive








|















|







855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885

html-am:

info: info-recursive

info-am:

install-data-am: install-man

install-dvi: install-dvi-recursive

install-dvi-am:

install-exec-am:

install-html: install-html-recursive

install-html-am:

install-info: install-info-recursive

install-info-am:

install-man: install-man1

install-pdf: install-pdf-recursive

install-pdf-am:

install-ps: install-ps-recursive

820
821
822
823
824
825
826
827


828
829
830
831
832
833
834
835
836
837
838
839
840
841
842

843
844
845
846
847
848
849

pdf-am:

ps: ps-recursive

ps-am:

uninstall-am:



.MAKE: $(am__recursive_targets) install-am install-strip

.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
	check-am clean clean-generic clean-libtool cscopelist-am ctags \
	ctags-am distclean distclean-generic distclean-libtool \
	distclean-tags distdir dvi dvi-am html html-am info info-am \
	install install-am install-data install-data-am install-dvi \
	install-dvi-am install-exec install-exec-am install-html \
	install-html-am install-info install-info-am install-man \
	install-pdf install-pdf-am install-ps install-ps-am \
	install-strip installcheck installcheck-am installdirs \
	installdirs-am maintainer-clean maintainer-clean-generic \
	mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
	ps ps-am tags tags-am uninstall uninstall-am


.PRECIOUS: Makefile


all: $(MK_CA_DOCS) $(CURLCONF_DOCS)

.md.1:







|
>
>










|
|
|
|
|
>







899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931

pdf-am:

ps: ps-recursive

ps-am:

uninstall-am: uninstall-man

uninstall-man: uninstall-man1

.MAKE: $(am__recursive_targets) install-am install-strip

.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
	check-am clean clean-generic clean-libtool cscopelist-am ctags \
	ctags-am distclean distclean-generic distclean-libtool \
	distclean-tags distdir dvi dvi-am html html-am info info-am \
	install install-am install-data install-data-am install-dvi \
	install-dvi-am install-exec install-exec-am install-html \
	install-html-am install-info install-info-am install-man \
	install-man1 install-pdf install-pdf-am install-ps \
	install-ps-am install-strip installcheck installcheck-am \
	installdirs installdirs-am maintainer-clean \
	maintainer-clean-generic mostlyclean mostlyclean-generic \
	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
	uninstall-am uninstall-man uninstall-man1

.PRECIOUS: Makefile


all: $(MK_CA_DOCS) $(CURLCONF_DOCS)

.md.1:
Changes to jni/curl/docs/RELEASE-PROCEDURE.md.
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

Coming dates
------------

Based on the description above, here are some planned release dates (at the
time of this writing):

- May 22, 2024
- July 17, 2024
- September 11, 2024
- November 6, 2024
- January 8, 2025
- March 5, 2025
- April 30, 2025
- June 25, 2025







<
|






107
108
109
110
111
112
113

114
115
116
117
118
119
120

Coming dates
------------

Based on the description above, here are some planned release dates (at the
time of this writing):


- July 24, 2024
- September 11, 2024
- November 6, 2024
- January 8, 2025
- March 5, 2025
- April 30, 2025
- June 25, 2025
Changes to jni/curl/docs/RELEASE-TOOLS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Release tools used for curl 8.8.0

The following tools and their Debian package version numbers were used to
produce this release tarball.

- autoconf: 2.71-3
- automake: 1:1.16.5-1.3
- libtool: 2.4.7-5
- make: 4.3-4.1
- perl: 5.36.0-7+deb12u1
- git: 1:2.39.2-1.1

# Reproduce the tarball

- Clone the repo and checkout the tag: curl-8_8_0
- Install the same set of tools + versions as listed above

## Do a standard build

- autoreconf -fi
- ./configure [...]
- make

## Generate the tarball with the same timestamp

- export SOURCE_DATE_EPOCH=1716357300
- ./maketgz [version]

|






|






|










|


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Release tools used for curl 8.9.0

The following tools and their Debian package version numbers were used to
produce this release tarball.

- autoconf: 2.71-3
- automake: 1:1.16.5-1.3
- libtool: 2.4.7-7~deb12u1
- make: 4.3-4.1
- perl: 5.36.0-7+deb12u1
- git: 1:2.39.2-1.1

# Reproduce the tarball

- Clone the repo and checkout the tag: curl-8_9_0
- Install the same set of tools + versions as listed above

## Do a standard build

- autoreconf -fi
- ./configure [...]
- make

## Generate the tarball with the same timestamp

- export SOURCE_DATE_EPOCH=1721802095
- ./maketgz [version]

Changes to jni/curl/docs/ROADMAP.md.
10
11
12
13
14
15
16
17
serve as a guideline for others for information, feedback and possible
participation.

## WebSocket

Agree that it is a good enough API and remove the EXPERIMENTAL label.

## 







|
10
11
12
13
14
15
16
17
serve as a guideline for others for information, feedback and possible
participation.

## WebSocket

Agree that it is a good enough API and remove the EXPERIMENTAL label.

##
Changes to jni/curl/docs/SSLCERTS.md.
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    environment variable `CURL_CA_BUNDLE` to the path of your choice.

    If you are using the curl command line tool on Windows, curl searches for
    a CA cert file named "curl-ca-bundle.crt" in these directories and in this
    order:
      1. application's directory
      2. current working directory
      3. Windows System directory (e.g. C:\windows\system32)
      4. Windows Directory (e.g. C:\windows)
      5. all directories along %PATH%

 5. Get another CA cert bundle. One option is to extract the one a recent
    Firefox browser uses by running 'make ca-bundle' in the curl build tree
    root, or possibly download a version that was generated this way for you:
    [CA Extract](https://curl.se/docs/caextract.html)








|
|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    environment variable `CURL_CA_BUNDLE` to the path of your choice.

    If you are using the curl command line tool on Windows, curl searches for
    a CA cert file named "curl-ca-bundle.crt" in these directories and in this
    order:
      1. application's directory
      2. current working directory
      3. Windows System directory (e.g. C:\Windows\System32)
      4. Windows Directory (e.g. C:\Windows)
      5. all directories along %PATH%

 5. Get another CA cert bundle. One option is to extract the one a recent
    Firefox browser uses by running 'make ca-bundle' in the curl build tree
    root, or possibly download a version that was generated this way for you:
    [CA Extract](https://curl.se/docs/caextract.html)

Changes to jni/curl/docs/THANKS.
64
65
66
67
68
69
70

71
72
73
74
75
76
77
Alejandro Alvarez Ayllon
Alejandro Colomar
Alejandro R. Sedeño
Aleksandar Milivojevic
Aleksander Mazur
Aleksandr Krotov
Aleksey Tulinov

Ales Mlakar
Ales Novak
Alessandro Ghedini
Alessandro Vesely
Alex aka WindEagle
Alex Baines
Alex Bligh







>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Alejandro Alvarez Ayllon
Alejandro Colomar
Alejandro R. Sedeño
Aleksandar Milivojevic
Aleksander Mazur
Aleksandr Krotov
Aleksey Tulinov
alervd on github
Ales Mlakar
Ales Novak
Alessandro Ghedini
Alessandro Vesely
Alex aka WindEagle
Alex Baines
Alex Bligh
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

112
113
114
115
116
117
118
Alex Mayorga
Alex McLellan
Alex Neblett
Alex Nichols
Alex Potapenko
Alex Rousskov
Alex Samorukov

Alex Suykov
Alex Vinnik
Alex Xu
Alexander Bartel
Alexander Beedie
Alexander Chuykov
Alexander Dyagilev
Alexander Elgert
Alexander Jaeger
Alexander Kanavin
Alexander Klauer
Alexander Kourakos
Alexander Krasnostavsky
Alexander Lazic
Alexander Pepper
Alexander Peslyak

Alexander Sinditskiy
Alexander Traud
Alexander V. Tikhonov
Alexander Zhuravlev
Alexandre Bury
Alexandre Ferrieux
Alexandre Pion







>
















>







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
Alex Mayorga
Alex McLellan
Alex Neblett
Alex Nichols
Alex Potapenko
Alex Rousskov
Alex Samorukov
Alex Snast
Alex Suykov
Alex Vinnik
Alex Xu
Alexander Bartel
Alexander Beedie
Alexander Chuykov
Alexander Dyagilev
Alexander Elgert
Alexander Jaeger
Alexander Kanavin
Alexander Klauer
Alexander Kourakos
Alexander Krasnostavsky
Alexander Lazic
Alexander Pepper
Alexander Peslyak
Alexander Shtuchkin
Alexander Sinditskiy
Alexander Traud
Alexander V. Tikhonov
Alexander Zhuravlev
Alexandre Bury
Alexandre Ferrieux
Alexandre Pion
205
206
207
208
209
210
211


212
213
214
215
216
217
218
Andrey Labunets
Andrii Moiseiev
Andrius Merkys
Andrés García
Andy Alt
Andy Cedilnik
Andy Fiddaman


Andy Serpa
Andy Stamp
Andy Tsouladze
Angus Mackay
anio on github
annalee
anon00000000 on github







>
>







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
Andrey Labunets
Andrii Moiseiev
Andrius Merkys
Andrés García
Andy Alt
Andy Cedilnik
Andy Fiddaman
Andy Pan
Andy Reitz
Andy Serpa
Andy Stamp
Andy Tsouladze
Angus Mackay
anio on github
annalee
anon00000000 on github
266
267
268
269
270
271
272

273
274
275
276
277
278
279
Ashwin Metpalli
Ask Bjørn Hansen
Askar Safin
AtariDreams on github
Ates Goral
atjg on github
Augustus Saunders

Austin Green
av223119 on github
Avery Fay
awesomekosm on github
awesomenode on github
Axel Chong
Axel Morawietz







>







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
Ashwin Metpalli
Ask Bjørn Hansen
Askar Safin
AtariDreams on github
Ates Goral
atjg on github
Augustus Saunders
Aurélien Pierre
Austin Green
av223119 on github
Avery Fay
awesomekosm on github
awesomenode on github
Axel Chong
Axel Morawietz
336
337
338
339
340
341
342

343
344
345
346
347
348
349
Bernhard Reutner-Fischer
Bernhard Walle
Bert Huijben
Bertrand Demiddelaer
Bertrand Simonnet
beslick5 on github
Bevan Weiss

Bill Doyle
Bill Egert
Bill Hoffman
Bill Middlecamp
Bill Nagel
Bill Pyne
billionai on github







>







342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
Bernhard Reutner-Fischer
Bernhard Walle
Bert Huijben
Bertrand Demiddelaer
Bertrand Simonnet
beslick5 on github
Bevan Weiss
Bhanu Prakash
Bill Doyle
Bill Egert
Bill Hoffman
Bill Middlecamp
Bill Nagel
Bill Pyne
billionai on github
400
401
402
403
404
405
406

407
408
409
410
411
412
413
Brian Clemens
Brian Dessent
Brian E. Gallew
Brian Green
Brian Inglis
Brian J. Murrell
Brian Lund

Brian Nixon
Brian Prodoehl
Brian R Duffy
Brian Ulm
Brock Noland
Bru Rom
Bruce Mitchener







>







407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
Brian Clemens
Brian Dessent
Brian E. Gallew
Brian Green
Brian Inglis
Brian J. Murrell
Brian Lund
brian m. carlson
Brian Nixon
Brian Prodoehl
Brian R Duffy
Brian Ulm
Brock Noland
Bru Rom
Bruce Mitchener
493
494
495
496
497
498
499

500
501
502
503
504
505
506
Chris Talbot
Chris Webb
Chris Young
Christian Fillion
Christian Grothoff
Christian Heimes
Christian Hesse

Christian Hägele
Christian Krause
Christian Kurz
Christian Robottom Reis
Christian Schmitz
Christian Stewart
Christian Vogt







>







501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
Chris Talbot
Chris Webb
Chris Young
Christian Fillion
Christian Grothoff
Christian Heimes
Christian Hesse
Christian Heusel
Christian Hägele
Christian Krause
Christian Kurz
Christian Robottom Reis
Christian Schmitz
Christian Stewart
Christian Vogt
530
531
532
533
534
535
536

537
538
539
540
541
542
543
clbr on github
Clemens Gruber
Cliff Crosland
Clifford Wolf
Clint Clayton
Cloudogu Siebels
Clément Notin

cmfrolick on github
codesniffer13 on github
Cody Jones
Cody Mack
COFFEETALES on github
coinhubs on github
Colby Ranger







>







539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
clbr on github
Clemens Gruber
Cliff Crosland
Clifford Wolf
Clint Clayton
Cloudogu Siebels
Clément Notin
CMD
cmfrolick on github
codesniffer13 on github
Cody Jones
Cody Mack
COFFEETALES on github
coinhubs on github
Colby Ranger
710
711
712
713
714
715
716

717
718
719
720
721
722
723
Denis Chaplygin
Denis Feklushkin
Denis Goleshchikhin
Denis Laxalde
Denis Ollier
Dennis Clarke
Dennis Felsing

Derek Higgins
Derzsi Dániel
Desmond O. Chang
destman on github
Detlef Schmier
Dexter Gerig
dfdity on github







>







720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
Denis Chaplygin
Denis Feklushkin
Denis Goleshchikhin
Denis Laxalde
Denis Ollier
Dennis Clarke
Dennis Felsing
dependabot[bot]
Derek Higgins
Derzsi Dániel
Desmond O. Chang
destman on github
Detlef Schmier
Dexter Gerig
dfdity on github
764
765
766
767
768
769
770

771
772
773
774
775
776

777
778
779
780

781
782
783
784
785
786
787
Dmitry Mikhirev
Dmitry Popov
Dmitry Rechkin
Dmitry S. Baikov
Dmitry Tretyakov
Dmitry Wagin
dnivras on github

Dolbneff A.V
Domen Kožar
Domenico Andreoli
Dominick Meglio
Dominik Hölzl
Dominik Klemba

Dominik Thalhammer
Dominique Leuenberger
Don J Olmstead
Dongliang Mu

Doron Behar
Doug Kaufman
Doug Porter
Douglas Creager
Douglas E. Wegscheid
Douglas Kilpatrick
Douglas Mencken







>






>




>







775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
Dmitry Mikhirev
Dmitry Popov
Dmitry Rechkin
Dmitry S. Baikov
Dmitry Tretyakov
Dmitry Wagin
dnivras on github
dogma
Dolbneff A.V
Domen Kožar
Domenico Andreoli
Dominick Meglio
Dominik Hölzl
Dominik Klemba
Dominik Piątkowski
Dominik Thalhammer
Dominique Leuenberger
Don J Olmstead
Dongliang Mu
Dorian Craps
Doron Behar
Doug Kaufman
Doug Porter
Douglas Creager
Douglas E. Wegscheid
Douglas Kilpatrick
Douglas Mencken
834
835
836
837
838
839
840

841
842
843
844
845
846
847
Eldar Zaitov
elelel on github
elephoenix on github
Eli Schwartz
Elia Tufarolo
Elliot Killick
Elliot Saba

Ellis Pritchard
Elmira A Semenova
Elms
Eloy Degen
elsamuko on github
emanruse on github
Emanuele Bovisio







>







848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
Eldar Zaitov
elelel on github
elephoenix on github
Eli Schwartz
Elia Tufarolo
Elliot Killick
Elliot Saba
Elliott Balsley
Ellis Pritchard
Elmira A Semenova
Elms
Eloy Degen
elsamuko on github
emanruse on github
Emanuele Bovisio
1067
1068
1069
1070
1071
1072
1073

1074
1075
1076
1077
1078
1079
1080
Gregory Panakkal
Gregory Szorc
Griffin Downs
Grigory Entin
Grisha Levit
Guenole Bescon
Guido Berhoerster

Guillaume Algis
Guillaume Arluison
guitared on github
Gunamoi Software
Gunter Knauf
guoxinvmware on github
Gustaf Hui







>







1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
Gregory Panakkal
Gregory Szorc
Griffin Downs
Grigory Entin
Grisha Levit
Guenole Bescon
Guido Berhoerster
Guilherme Puida
Guillaume Algis
Guillaume Arluison
guitared on github
Gunamoi Software
Gunter Knauf
guoxinvmware on github
Gustaf Hui
1232
1233
1234
1235
1236
1237
1238

1239
1240
1241
1242
1243
1244
1245
Jaime Fullaondo
jakirkham on github
Jakob Hirsch
Jakub Bochenski
Jakub Jelen
Jakub Wilk
Jakub Zakrzewski

James Atwill
James Brown
James Bursa
James Cheng
James Clancy
James Cone
James Dury







>







1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
Jaime Fullaondo
jakirkham on github
Jakob Hirsch
Jakub Bochenski
Jakub Jelen
Jakub Wilk
Jakub Zakrzewski
James Abbatiello
James Atwill
James Brown
James Bursa
James Cheng
James Clancy
James Cone
James Dury
1289
1290
1291
1292
1293
1294
1295

1296
1297
1298
1299
1300
1301
1302
Javier Barroso
Javier Blazquez
Javier G. Sogo
Javier Navarro
Javier Sixto
Jay Austin
Jay Dommaschk

Jay Wu
Jayesh A Shah
Jaz Fresh
JazJas on github
jbgoog on github
Jean Fabrice
Jean Gressmann







>







1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
Javier Barroso
Javier Blazquez
Javier G. Sogo
Javier Navarro
Javier Sixto
Jay Austin
Jay Dommaschk
Jay Guerette
Jay Wu
Jayesh A Shah
Jaz Fresh
JazJas on github
jbgoog on github
Jean Fabrice
Jean Gressmann
1350
1351
1352
1353
1354
1355
1356

1357
1358
1359
1360
1361
1362
1363
Jesper Jensen
Jess Lowe
Jesse Chisholm
Jesse Noller
Jesse Tan
jethrogb on github
jhoyla on github

Jiawen Geng
Jie He
Jiehong on github
Jilayne Lovejoy
Jim Beveridge
Jim Drash
Jim Freeman







>







1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
Jesper Jensen
Jess Lowe
Jesse Chisholm
Jesse Noller
Jesse Tan
jethrogb on github
jhoyla on github
Jiang Wenjian
Jiawen Geng
Jie He
Jiehong on github
Jilayne Lovejoy
Jim Beveridge
Jim Drash
Jim Freeman
1456
1457
1458
1459
1460
1461
1462

1463
1464
1465
1466
1467
1468
1469
Jonas Minnberg
Jonas Schnelli
Jonas Vautherin
Jonatan Lander
Jonatan Vela
Jonathan Cardoso Machado
Jonathan Hseu

Jonathan Moerman
Jonathan Nieder
Jonathan Perkin
Jonathan Watt
Jonathan Wernberg
Jongki Suwandi
jonny112 on github







>







1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
Jonas Minnberg
Jonas Schnelli
Jonas Vautherin
Jonatan Lander
Jonatan Vela
Jonathan Cardoso Machado
Jonathan Hseu
Jonathan Matthews
Jonathan Moerman
Jonathan Nieder
Jonathan Perkin
Jonathan Watt
Jonathan Wernberg
Jongki Suwandi
jonny112 on github
1553
1554
1555
1556
1557
1558
1559

1560
1561
1562
1563
1564
1565
1566
1567
1568

1569
1570
1571
1572
1573
1574
1575
Kang-Jin Lee
Kantanat Wannapaka
Kareem
Kari Pahula
Karl Chen
Karl Moerder
Karol Pietrzak

Kartatz on Github
Karthikdasari0423
Karthikdasari0423 on github
Kartik Mahajan
Kaspar Brand
Katie Wang
Katsuhiko YOSHIDA
Kazuho Oku
kchow-FTNT on github

Kees Cook
Kees Dekker
Keitagit-kun on github
Keith MacDonald
Keith McGuigan
Keith Mok
Kelly Kaoudis







>









>







1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
Kang-Jin Lee
Kantanat Wannapaka
Kareem
Kari Pahula
Karl Chen
Karl Moerder
Karol Pietrzak
kartatz
Kartatz on Github
Karthikdasari0423
Karthikdasari0423 on github
Kartik Mahajan
Kaspar Brand
Katie Wang
Katsuhiko YOSHIDA
Kazuho Oku
kchow-FTNT on github
Keerthi Timmaraju
Kees Cook
Kees Dekker
Keitagit-kun on github
Keith MacDonald
Keith McGuigan
Keith Mok
Kelly Kaoudis
1671
1672
1673
1674
1675
1676
1677

1678
1679
1680
1681
1682
1683
1684
Laurie Clark-Michalek
Lawrence Gripper
Lawrence Matthews
Lawrence Wagerfield
Leah Neukirchen
Lealem Amedie
Leandro Coutinho

LeeRiva
Legoff Vincent
Lehel Bernadt
Leif W
Leigh Purdie
Leith Bade
Len Krause







>







1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
Laurie Clark-Michalek
Lawrence Gripper
Lawrence Matthews
Lawrence Wagerfield
Leah Neukirchen
Lealem Amedie
Leandro Coutinho
Lee Li
LeeRiva
Legoff Vincent
Lehel Bernadt
Leif W
Leigh Purdie
Leith Bade
Len Krause
1744
1745
1746
1747
1748
1749
1750

1751
1752
1753
1754
1755
1756
1757
Lukas Tribus
Lukasz Czekierda
lukaszgn on github
Luke Amery
Luke Call
Luke Dashjr
Luke Granger-Brown

Lukáš Zaoral
luminixinc on github
Luo Jinghua
Luong Dinh Dung
Luz Paz
Luật Nguyễn
lwthiker on github







>







1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
Lukas Tribus
Lukasz Czekierda
lukaszgn on github
Luke Amery
Luke Call
Luke Dashjr
Luke Granger-Brown
Luke Hamburg
Lukáš Zaoral
luminixinc on github
Luo Jinghua
Luong Dinh Dung
Luz Paz
Luật Nguyễn
lwthiker on github
1861
1862
1863
1864
1865
1866
1867

1868
1869
1870
1871
1872
1873
1874
1875
1876

1877
1878
1879
1880
1881
1882
1883
Martin Halle
Martin Hedenfalk
Martin Howarth
Martin Jansen
Martin Kammerhofer
Martin Kepplinger
Martin Lemke

Martin Schmatz
Martin Skinner
Martin Staael
Martin Storsjö
Martin Strunz
Martin V
Martin Vejnár
Martin Waleczek
Martin Ågren

Marty Kuhrt
Maruko
Masaya Suzuki
masbug on github
Massimiliano Fantuzzi
Massimiliano Ziccardi
Massimo Callegari







>









>







1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
Martin Halle
Martin Hedenfalk
Martin Howarth
Martin Jansen
Martin Kammerhofer
Martin Kepplinger
Martin Lemke
Martin Peck
Martin Schmatz
Martin Skinner
Martin Staael
Martin Storsjö
Martin Strunz
Martin V
Martin Vejnár
Martin Waleczek
Martin Ågren
martinevsky
Marty Kuhrt
Maruko
Masaya Suzuki
masbug on github
Massimiliano Fantuzzi
Massimiliano Ziccardi
Massimo Callegari
1911
1912
1913
1914
1915
1916
1917

1918
1919
1920
1921
1922
1923
1924
Matthew Hall
Matthew Kerwin
Matthew Thompson
Matthew Whitehead
Matthias Bolte
Matthias Gatto
Matthias Naegler

Mattias Fornander
Matus Uzak
Maurice Barnum
Mauricio Scheffer
Mauro Iorio
Mauro Rappa
Maurício Meneghini Fauth







>







1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
Matthew Hall
Matthew Kerwin
Matthew Thompson
Matthew Whitehead
Matthias Bolte
Matthias Gatto
Matthias Naegler
Matthieu Baerts
Mattias Fornander
Matus Uzak
Maurice Barnum
Mauricio Scheffer
Mauro Iorio
Mauro Rappa
Maurício Meneghini Fauth
2047
2048
2049
2050
2051
2052
2053

2054
2055
2056
2057
2058
2059
2060
Mohammadreza Hendiani
Mohammed Naser
Mohun Biswas
momala454 on github
Momoka Yamamoto
MonkeybreadSoftware on github
moohoorama on github

Morten Minde Neergaard
Mostyn Bramley-Moore
Moti Avrahami
MrdUkk on github
MrSorcus on github
Muhammad Herdiansyah
Muhammad Hussein Ammari







>







2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
Mohammadreza Hendiani
Mohammed Naser
Mohun Biswas
momala454 on github
Momoka Yamamoto
MonkeybreadSoftware on github
moohoorama on github
Morgan Willcock
Morten Minde Neergaard
Mostyn Bramley-Moore
Moti Avrahami
MrdUkk on github
MrSorcus on github
Muhammad Herdiansyah
Muhammad Hussein Ammari
2171
2172
2173
2174
2175
2176
2177

2178
2179
2180
2181
2182
2183
2184
Oliver Graute
Oliver Kuckertz
Oliver Roberts
Oliver Schindler
Oliver Urbann
oliverpool on github
Olivier Berger

Olivier Brunel
Omar Ramadan
omau on github
Ondřej Koláček
opensignature on github
opensslonzos-github on github
Ophir Lojkine







>







2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
Oliver Graute
Oliver Kuckertz
Oliver Roberts
Oliver Schindler
Oliver Urbann
oliverpool on github
Olivier Berger
Olivier Bonaventure
Olivier Brunel
Omar Ramadan
omau on github
Ondřej Koláček
opensignature on github
opensslonzos-github on github
Ophir Lojkine
2424
2425
2426
2427
2428
2429
2430

2431
2432
2433
2434
2435
2436
2437
Renaud Allard
Renaud Chaillat
Renaud Duhaut
Renaud Guillard
Renaud Lehoux
Rene Bernhardt
Rene Rebe

renovate[bot]
Reuven Wachtfogel
RevaliQaQ on github
Reza Arbab
Rianov Viacheslav
riastradh on github
Ricardo Cadime







>







2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
Renaud Allard
Renaud Chaillat
Renaud Duhaut
Renaud Guillard
Renaud Lehoux
Rene Bernhardt
Rene Rebe
renovate[bot]
renovate[bot]
Reuven Wachtfogel
RevaliQaQ on github
Reza Arbab
Rianov Viacheslav
riastradh on github
Ricardo Cadime
2611
2612
2613
2614
2615
2616
2617

2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636

2637
2638
2639
2640
2641
2642
2643
Sara Golemon
Saran Neti
Sascha Swiercy
Sascha Zengler
Satadru Pramanik
Satana de Sant'Ana
Saul good

Saurav Babu
sayrer on github
SBKarr on github
Scarlett McAllister
Scott Bailey
Scott Barrett
Scott Cantor
Scott Davis
Scott McCreary
Scott Mutter
Scott Talbert
sd0 on hackerone
Sean Boudreau
Sean Burford
Sean MacLennan
Sean McArthur
Sean Miller
Sean Molenaar
Sebastiaan van Erk

Sebastian Haglund
Sebastian Mundry
Sebastian Neubauer
Sebastian Pohlschmidt
Sebastian Rasmussen
Sebastian Sterk
selmelc on hackerone







>



















>







2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
Sara Golemon
Saran Neti
Sascha Swiercy
Sascha Zengler
Satadru Pramanik
Satana de Sant'Ana
Saul good
saurabhsingh-dev on github
Saurav Babu
sayrer on github
SBKarr on github
Scarlett McAllister
Scott Bailey
Scott Barrett
Scott Cantor
Scott Davis
Scott McCreary
Scott Mutter
Scott Talbert
sd0 on hackerone
Sean Boudreau
Sean Burford
Sean MacLennan
Sean McArthur
Sean Miller
Sean Molenaar
Sebastiaan van Erk
Sebastian Andersson
Sebastian Haglund
Sebastian Mundry
Sebastian Neubauer
Sebastian Pohlschmidt
Sebastian Rasmussen
Sebastian Sterk
selmelc on hackerone
2659
2660
2661
2662
2663
2664
2665

2666
2667
2668
2669
2670
2671
2672
Sergio Barresi
Sergio Borghese
Sergio Durigan Junior
Sergio Mijatovic
Sergio-IME on github
sergio-nsk on github
Serj Kalichev

SerusDev on github
Seshubabu Pasam
Seth Mos
Sevan Janiyan
sfan5 on github
Sgharat on github
Sh Diao







>







2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
Sergio Barresi
Sergio Borghese
Sergio Durigan Junior
Sergio Mijatovic
Sergio-IME on github
sergio-nsk on github
Serj Kalichev
Sertonix
SerusDev on github
Seshubabu Pasam
Seth Mos
Sevan Janiyan
sfan5 on github
Sgharat on github
Sh Diao
2942
2943
2944
2945
2946
2947
2948

2949
2950
2951
2952
2953
2954
2955
Tomasz Lacki
Tommie Gannert
tommink[at]post.pl
Tommy Chiang
Tommy Odom
Tommy Petty
Tommy Tam

Ton Voon
Toni Moreno
Tony Kelman
tonystz on Github
Toon Claes
Toon Verwaest
Tor Arntsen







>







2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
Tomasz Lacki
Tommie Gannert
tommink[at]post.pl
Tommy Chiang
Tommy Odom
Tommy Petty
Tommy Tam
tomy2105 on github
Ton Voon
Toni Moreno
Tony Kelman
tonystz on Github
Toon Claes
Toon Verwaest
Tor Arntsen
3036
3037
3038
3039
3040
3041
3042

3043
3044
3045
3046
3047
3048
3049
Vojtech Janota
Vojtech Minarik
Vojtěch Král
Volker Schmid
Vsevolod Novikov
vshmuk on hackerone
vulnerabilityspotter on hackerone

vvb2060
vvb2060 on github
Vyron Tsingaras
Vítor Galvão
W. Mark Kubacki
w0x42 on hackerone
Waldek Kozba







>







3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
Vojtech Janota
Vojtech Minarik
Vojtěch Král
Volker Schmid
Vsevolod Novikov
vshmuk on hackerone
vulnerabilityspotter on hackerone
vuonganh1993 on github
vvb2060
vvb2060 on github
Vyron Tsingaras
Vítor Galvão
W. Mark Kubacki
w0x42 on hackerone
Waldek Kozba
3131
3132
3133
3134
3135
3136
3137

3138
3139
3140
3141
3142
3143
3144
Yuriy Sosov
yushicheng7788 on github
Yusuke Nakamura
Yves Arrouye
Yves Lejeune
YX Hao
z2-2z on github

z2_ on hackerone
Zachary Seguin
Zdenek Pavlas
Zekun Ni
zelinchen on github
zengwei
zengwei2000







>







3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
Yuriy Sosov
yushicheng7788 on github
Yusuke Nakamura
Yves Arrouye
Yves Lejeune
YX Hao
z2-2z on github
z2_
z2_ on hackerone
Zachary Seguin
Zdenek Pavlas
Zekun Ni
zelinchen on github
zengwei
zengwei2000
3169
3170
3171
3172
3173
3174
3175

3176
3177

Коваленко Анатолий Викторович
Никита Дорохин
ウさん
不确定
加藤郁之
南宫雪珊
左潇峰

梦终无痕
積丹尼 Dan Jacobson








>


>
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
Коваленко Анатолий Викторович
Никита Дорохин
ウさん
不确定
加藤郁之
南宫雪珊
左潇峰
李四
梦终无痕
積丹尼 Dan Jacobson
罗朝辉
Changes to jni/curl/docs/TODO.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

31
32
33
34
35
36
37

 All bugs documented in the KNOWN_BUGS document are subject for fixing.

 1. libcurl
 1.1 TFO support on Windows
 1.2 Consult %APPDATA% also for .netrc
 1.3 struct lifreq
 1.4 Better and more sharing
 1.5 get rid of PATH_MAX
 1.8 CURLOPT_RESOLVE for any port number
 1.9 Cache negative name resolves
 1.10 auto-detect proxy
 1.11 minimize dependencies with dynamically loaded modules
 1.12 updated DNS server while running
 1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION

 1.15 Monitor connections in the connection pool
 1.16 Try to URL encode given URL
 1.17 Add support for IRIs
 1.18 try next proxy if one does not work
 1.19 provide timing info for each redirect
 1.20 SRV and URI DNS records
 1.21 netrc caching and sharing







|







>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

 All bugs documented in the KNOWN_BUGS document are subject for fixing.

 1. libcurl
 1.1 TFO support on Windows
 1.2 Consult %APPDATA% also for .netrc
 1.3 struct lifreq
 1.4 alt-svc sharing
 1.5 get rid of PATH_MAX
 1.8 CURLOPT_RESOLVE for any port number
 1.9 Cache negative name resolves
 1.10 auto-detect proxy
 1.11 minimize dependencies with dynamically loaded modules
 1.12 updated DNS server while running
 1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION
 1.14 connect to multiple IPs in parallel
 1.15 Monitor connections in the connection pool
 1.16 Try to URL encode given URL
 1.17 Add support for IRIs
 1.18 try next proxy if one does not work
 1.19 provide timing info for each redirect
 1.20 SRV and URI DNS records
 1.21 netrc caching and sharing
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
 3. Documentation
 3.1 Improve documentation about fork safety
 3.2 Provide cmake config-file

 4. FTP
 4.1 HOST
 4.2 Alter passive/active on failure and retry
 4.3 Earlier bad letter detection
 4.4 Support CURLOPT_PREQUOTE for dir listings too
 4.5 ASCII support
 4.6 GSSAPI via Windows SSPI
 4.7 STAT for LIST without data connection
 4.8 Passive transfer could try other IP addresses

 5. HTTP
 5.1 Provide the error body from a CONNECT response







<
|







59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
 3. Documentation
 3.1 Improve documentation about fork safety
 3.2 Provide cmake config-file

 4. FTP
 4.1 HOST
 4.2 Alter passive/active on failure and retry

 4.4 Support CURLOPT_PREQUOTE for directories listings
 4.5 ASCII support
 4.6 GSSAPI via Windows SSPI
 4.7 STAT for LIST without data connection
 4.8 Passive transfer could try other IP addresses

 5. HTTP
 5.1 Provide the error body from a CONNECT response
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
 11. SMB
 11.1 File listing support
 11.2 Honor file timestamps
 11.3 Use NTLMv2
 11.4 Create remote directories

 12. FILE
 12.1 Directory listing for FILE:

 13. TLS
 13.1 TLS-PSK with OpenSSL
 13.2 Provide mutex locking API
 13.3 Defeat TLS fingerprinting
 13.4 Cache/share OpenSSL contexts
 13.5 Export session ids
 13.6 Provide callback for cert verification
 13.7 Less memory massaging with Schannel
 13.8 Support DANE
 13.9 TLS record padding
 13.10 Support Authority Information Access certificate extension (AIA)
 13.11 Some TLS options are not offered for HTTPS proxies
 13.12 Reduce CA certificate bundle reparsing
 13.13 Make sure we forbid TLS 1.3 post-handshake authentication
 13.14 Support the clienthello extension
 13.15 Select signature algorithms

 14. GnuTLS
 14.2 check connection

 15. Schannel
 15.1 Extend support for client certificate authentication
 15.2 Extend support for the --ciphers option
 15.4 Add option to allow abrupt server closure

 16. SASL







|



|

<







<



|
|
<







104
105
106
107
108
109
110
111
112
113
114
115
116

117
118
119
120
121
122
123

124
125
126
127
128

129
130
131
132
133
134
135
 11. SMB
 11.1 File listing support
 11.2 Honor file timestamps
 11.3 Use NTLMv2
 11.4 Create remote directories

 12. FILE
 12.1 Directory listing on non-POSIX

 13. TLS
 13.1 TLS-PSK with OpenSSL
 13.2 TLS channel binding
 13.3 Defeat TLS fingerprinting

 13.5 Export session ids
 13.6 Provide callback for cert verification
 13.7 Less memory massaging with Schannel
 13.8 Support DANE
 13.9 TLS record padding
 13.10 Support Authority Information Access certificate extension (AIA)
 13.11 Some TLS options are not offered for HTTPS proxies

 13.13 Make sure we forbid TLS 1.3 post-handshake authentication
 13.14 Support the clienthello extension
 13.15 Select signature algorithms
 13.16 Share the CA cache
 13.17 Add missing features to TLS backends


 15. Schannel
 15.1 Extend support for client certificate authentication
 15.2 Extend support for the --ciphers option
 15.4 Add option to allow abrupt server closure

 16. SASL
146
147
148
149
150
151
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

197
198
199
200
201
202
203
204
205
206
 17.4 Support CURLOPT_PREQUOTE
 17.5 SSH over HTTPS proxy with more backends
 17.6 SFTP with SCP://

 18. Command line tool
 18.1 sync
 18.2 glob posts

 18.4 --proxycommand
 18.5 UTF-8 filenames in Content-Disposition
 18.6 Option to make -Z merge lined based outputs on stdout
 18.8 Consider convenience options for JSON and XML?
 18.9 Choose the name of file in braces for complex URLs
 18.10 improve how curl works in a windows console window
 18.11 Windows: set attribute 'archive' for completed downloads
 18.12 keep running, read instructions from pipe/socket
 18.13 Ratelimit or wait between serial requests
 18.14 --dry-run
 18.15 --retry should resume
 18.16 send only part of --data
 18.17 consider file name from the redirected URL with -O ?
 18.18 retry on network is unreachable
 18.19 expand ~/ in config files
 18.20 host name sections in config files
 18.21 retry on the redirected-to URL
 18.23 Set the modification date on an uploaded file
 18.24 Use multiple parallel transfers for a single download
 18.25 Prevent terminal injection when writing to terminal
 18.26 Custom progress meter update interval
 18.27 -J and -O with %-encoded file names
 18.28 -J with -C -
 18.29 --retry and transfer timeouts

 19. Build
 19.2 Enable PIE and RELRO by default
 19.3 Do not use GNU libtool on OpenBSD
 19.4 Package curl for Windows in a signed installer
 19.5 make configure use --cache-file more and better
 19.6 build curl with Windows Unicode support

 20. Test suite
 20.1 SSL tunnel
 20.2 nicer lacking perl message
 20.3 more protocols supported
 20.4 more platforms supported
 20.5 Add support for concurrent connections
 20.6 Use the RFC 6265 test suite
 20.7 Support LD_PRELOAD on macOS
 20.8 Run web-platform-tests URL tests

 21. MQTT
 21.1 Support rate-limiting


 22. TFTP
 22.1 TFTP doesn't convert LF to CRLF for mode=netascii

==============================================================================

1. libcurl

1.1 TFO support on Windows








>



|




|



|


|





|















<

<




>


|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

188

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
 17.4 Support CURLOPT_PREQUOTE
 17.5 SSH over HTTPS proxy with more backends
 17.6 SFTP with SCP://

 18. Command line tool
 18.1 sync
 18.2 glob posts
 18.3 -h option
 18.4 --proxycommand
 18.5 UTF-8 filenames in Content-Disposition
 18.6 Option to make -Z merge lined based outputs on stdout
 18.7 specify which response codes that make -f/--fail return error
 18.9 Choose the name of file in braces for complex URLs
 18.10 improve how curl works in a windows console window
 18.11 Windows: set attribute 'archive' for completed downloads
 18.12 keep running, read instructions from pipe/socket
 18.13 Acknowledge Ratelimit headers
 18.14 --dry-run
 18.15 --retry should resume
 18.16 send only part of --data
 18.17 consider filename from the redirected URL with -O ?
 18.18 retry on network is unreachable
 18.19 expand ~/ in config files
 18.20 hostname sections in config files
 18.21 retry on the redirected-to URL
 18.23 Set the modification date on an uploaded file
 18.24 Use multiple parallel transfers for a single download
 18.25 Prevent terminal injection when writing to terminal
 18.26 Custom progress meter update interval
 18.27 -J and -O with %-encoded filenames
 18.28 -J with -C -
 18.29 --retry and transfer timeouts

 19. Build
 19.2 Enable PIE and RELRO by default
 19.3 Do not use GNU libtool on OpenBSD
 19.4 Package curl for Windows in a signed installer
 19.5 make configure use --cache-file more and better
 19.6 build curl with Windows Unicode support

 20. Test suite
 20.1 SSL tunnel
 20.2 nicer lacking perl message
 20.3 more protocols supported
 20.4 more platforms supported

 20.6 Use the RFC 6265 test suite

 20.8 Run web-platform-tests URL tests

 21. MQTT
 21.1 Support rate-limiting
 21.2 Support MQTTS

 22. TFTP
 22.1 TFTP does not convert LF to CRLF for mode=netascii

==============================================================================

1. libcurl

1.1 TFO support on Windows

221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

1.3 struct lifreq

 Use 'struct lifreq' and SIOCGLIFADDR instead of 'struct ifreq' and
 SIOCGIFADDR on newer Solaris versions as they claim the latter is obsolete.
 To support IPv6 interface addresses for network interfaces properly.

1.4 Better and more sharing

 The share interface could benefit from allowing the alt-svc cache to be
 possible to share between easy handles.

 See https://github.com/curl/curl/issues/4476

 The share interface offers CURL_LOCK_DATA_CONNECT to have multiple easy







|







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

1.3 struct lifreq

 Use 'struct lifreq' and SIOCGLIFADDR instead of 'struct ifreq' and
 SIOCGIFADDR on newer Solaris versions as they claim the latter is obsolete.
 To support IPv6 interface addresses for network interfaces properly.

1.4 alt-svc sharing

 The share interface could benefit from allowing the alt-svc cache to be
 possible to share between easy handles.

 See https://github.com/curl/curl/issues/4476

 The share interface offers CURL_LOCK_DATA_CONNECT to have multiple easy
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
 there we need libssh2 to properly tell us when we pass in a too small buffer
 and its current API (as of libssh2 1.2.7) does not.

1.8 CURLOPT_RESOLVE for any port number

 This option allows applications to set a replacement IP address for a given
 host + port pair. Consider making support for providing a replacement address
 for the host name on all port numbers.

 See https://github.com/curl/curl/issues/1264

1.9 Cache negative name resolves

 A name resolve that has failed is likely to fail when made again within a
 short period of time. Currently we only cache positive responses.







|







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
 there we need libssh2 to properly tell us when we pass in a too small buffer
 and its current API (as of libssh2 1.2.7) does not.

1.8 CURLOPT_RESOLVE for any port number

 This option allows applications to set a replacement IP address for a given
 host + port pair. Consider making support for providing a replacement address
 for the hostname on all port numbers.

 See https://github.com/curl/curl/issues/1264

1.9 Cache negative name resolves

 A name resolve that has failed is likely to fail when made again within a
 short period of time. Currently we only cache positive responses.
291
292
293
294
295
296
297
298
299
300
301
302

303
304
305











306
307
308
309
310
311
312
 failures to mitigate against this. Firefox works like that. Note that Windows
 does not have res_init() or an alternative.

 https://github.com/curl/curl/issues/2251

1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION

 curl will create most sockets via the CURLOPT_OPENSOCKETFUNCTION callback and
 close them with the CURLOPT_CLOSESOCKETFUNCTION callback. However, c-ares
 does not use those functions and instead opens and closes the sockets
 itself. This means that when curl passes the c-ares socket to the
 CURLMOPT_SOCKETFUNCTION it is not owned by the application like other sockets.


 See https://github.com/curl/curl/issues/2734












1.15 Monitor connections in the connection pool

 libcurl's connection cache or pool holds a number of open connections for the
 purpose of possible subsequent connection reuse. It may contain a few up to a
 significant amount of connections. Currently, libcurl leaves all connections
 as they are and first when a connection is iterated over for matching or
 reuse purpose it is verified that it is still alive.







|

|
|
|
>



>
>
>
>
>
>
>
>
>
>
>







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
 failures to mitigate against this. Firefox works like that. Note that Windows
 does not have res_init() or an alternative.

 https://github.com/curl/curl/issues/2251

1.13 c-ares and CURLOPT_OPENSOCKETFUNCTION

 curl creates most sockets via the CURLOPT_OPENSOCKETFUNCTION callback and
 close them with the CURLOPT_CLOSESOCKETFUNCTION callback. However, c-ares
 does not use those functions and instead opens and closes the sockets itself.
 This means that when curl passes the c-ares socket to the
 CURLMOPT_SOCKETFUNCTION it is not owned by the application like other
 sockets.

 See https://github.com/curl/curl/issues/2734

1.14 connect to multiple IPs in parallel

 curl currently implements the happy eyeball algorithm for connecting to the
 IPv4 and IPv6 alternatives for a host in parallel, sticking with the
 connection that "wins". We could implement a similar algorithm per individual
 IP family as well when there are multiple available addresses: start with the
 first address, then start a second attempt N milliseconds after and then a
 third another N milliseconds later. That way there would be less waiting when
 the first IP has problems. It also improves the connection timeout value
 handling for multiple address situations.

1.15 Monitor connections in the connection pool

 libcurl's connection cache or pool holds a number of open connections for the
 purpose of possible subsequent connection reuse. It may contain a few up to a
 significant amount of connections. Currently, libcurl leaves all connections
 as they are and first when a connection is iterated over for matching or
 reuse purpose it is verified that it is still alive.
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
 everything in a non-blocking manner and signals when something is done. A
 remove or add would then only ask for the action to get started and then
 multi_perform() etc still be called until the add/remove is completed.

2.4 Split connect and authentication process

 The multi interface treats the authentication process as part of the connect
 phase. As such any failures during authentication will not trigger the relevant
 QUIT or LOGOFF for protocols such as IMAP, POP3 and SMTP.

2.5 Edge-triggered sockets should work

 The multi_socket API should work with edge-triggered socket events. One of
 the internal actions that need to be improved for this to work perfectly is
 the 'maxloops' handling in transfer.c:readwrite_data().








|
|







490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
 everything in a non-blocking manner and signals when something is done. A
 remove or add would then only ask for the action to get started and then
 multi_perform() etc still be called until the add/remove is completed.

2.4 Split connect and authentication process

 The multi interface treats the authentication process as part of the connect
 phase. As such any failures during authentication does not trigger the
 relevant QUIT or LOGOFF for protocols such as IMAP, POP3 and SMTP.

2.5 Edge-triggered sockets should work

 The multi_socket API should work with edge-triggered socket events. One of
 the internal actions that need to be improved for this to work perfectly is
 the 'maxloops' handling in transfer.c:readwrite_data().

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
 to write cmake scripts to find and use libcurl easier. See
 https://github.com/curl/curl/issues/885

4. FTP

4.1 HOST

 HOST is a command for a client to tell which host name to use, to offer FTP
 servers named-based virtual hosting:

 https://datatracker.ietf.org/doc/html/rfc7151

4.2 Alter passive/active on failure and retry

 When trying to connect passively to a server which only supports active
 connections, libcurl returns CURLE_FTP_WEIRD_PASV_REPLY and closes the
 connection. There could be a way to fallback to an active connection (and
 vice versa). https://curl.se/bug/feature.cgi?id=1754793

4.3 Earlier bad letter detection

 Make the detection of (bad) %0d and %0a codes in FTP URL parts earlier in the
 process to avoid doing a resolve and connect in vain.

4.4 Support CURLOPT_PREQUOTE for dir listings too

 The lack of support is mostly an oversight and requires the FTP state machine
 to get updated to get fixed.

 https://github.com/curl/curl/issues/8602

4.5 ASCII support







|











<
<
<
<
<
|







541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559





560
561
562
563
564
565
566
567
 to write cmake scripts to find and use libcurl easier. See
 https://github.com/curl/curl/issues/885

4. FTP

4.1 HOST

 HOST is a command for a client to tell which hostname to use, to offer FTP
 servers named-based virtual hosting:

 https://datatracker.ietf.org/doc/html/rfc7151

4.2 Alter passive/active on failure and retry

 When trying to connect passively to a server which only supports active
 connections, libcurl returns CURLE_FTP_WEIRD_PASV_REPLY and closes the
 connection. There could be a way to fallback to an active connection (and
 vice versa). https://curl.se/bug/feature.cgi?id=1754793






4.4 Support CURLOPT_PREQUOTE for directions listings

 The lack of support is mostly an oversight and requires the FTP state machine
 to get updated to get fixed.

 https://github.com/curl/curl/issues/8602

4.5 ASCII support
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607

 See https://github.com/curl/curl/issues/1508

5. HTTP

5.1 Provide the error body from a CONNECT response

 When curl receives a body response from a CONNECT request to a proxy, it will
 always just read and ignore it. It would make some users happy if curl
 instead optionally would be able to make that responsible available. Via a new
 callback? Through some other means?

 See https://github.com/curl/curl/issues/9513

5.2 Obey Retry-After in redirects

 The Retry-After is said to dicate "the minimum time that the user agent is
 asked to wait before issuing the redirected request" and libcurl does not







|
|
|
|







594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611

 See https://github.com/curl/curl/issues/1508

5. HTTP

5.1 Provide the error body from a CONNECT response

 When curl receives a body response from a CONNECT request to a proxy, it
 always just reads and ignores it. It would make some users happy if curl
 instead optionally would be able to make that responsible available. Via a
 new callback? Through some other means?

 See https://github.com/curl/curl/issues/9513

5.2 Obey Retry-After in redirects

 The Retry-After is said to dicate "the minimum time that the user agent is
 asked to wait before issuing the redirected request" and libcurl does not
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
 sorts the headers based on that number. We could then have internally created
 headers use a default value so only headers that need to be moved have to be
 specified.

5.4 Allow SAN names in HTTP/2 server push

 curl only allows HTTP/2 push promise if the provided :authority header value
 exactly matches the host name given in the URL. It could be extended to allow
 any name that would match the Subject Alternative Names in the server's TLS
 certificate.

 See https://github.com/curl/curl/pull/3581

5.5 auth= in URLs








|







624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
 sorts the headers based on that number. We could then have internally created
 headers use a default value so only headers that need to be moved have to be
 specified.

5.4 Allow SAN names in HTTP/2 server push

 curl only allows HTTP/2 push promise if the provided :authority header value
 exactly matches the hostname given in the URL. It could be extended to allow
 any name that would match the Subject Alternative Names in the server's TLS
 certificate.

 See https://github.com/curl/curl/pull/3581

5.5 auth= in URLs

665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
 Reading input (to send to the remote server) on stdin is a crappy solution
 for library purposes. We need to invent a good way for the application to be
 able to provide the data to send.

6.2 ditch telnet-specific select

 Move the telnet support's network select() loop go away and merge the code
 into the main transfer loop. Until this is done, the multi interface will not
 work for telnet.

6.3 feature negotiation debug data

 Add telnet feature negotiation data to the debug callback as header data.

6.4 exit immediately upon connection if stdin is /dev/null







|







669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
 Reading input (to send to the remote server) on stdin is a crappy solution
 for library purposes. We need to invent a good way for the application to be
 able to provide the data to send.

6.2 ditch telnet-specific select

 Move the telnet support's network select() loop go away and merge the code
 into the main transfer loop. Until this is done, the multi interface does not
 work for telnet.

6.3 feature negotiation debug data

 Add telnet feature negotiation data to the debug callback as header data.

6.4 exit immediately upon connection if stdin is /dev/null
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797






798


799



800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831

 Support for creating remote directories when uploading a file to a directory
 that does not exist on the server, just like --ftp-create-dirs.


12. FILE

12.1 Directory listing for FILE:

 Add support for listing the contents of a directory accessed with FILE. The
 output should probably be the same as/similar to FTP.


13. TLS

13.1 TLS-PSK with OpenSSL

 Transport Layer Security pre-shared key ciphersuites (TLS-PSK) is a set of
 cryptographic protocols that provide secure communication based on pre-shared
 keys (PSKs). These pre-shared keys are symmetric keys shared in advance among
 the communicating parties.

 https://github.com/curl/curl/issues/5081

13.2 Provide mutex locking API

 Provide a libcurl API for setting mutex callbacks in the underlying SSL






 library, so that the same application code can use mutex-locking


 independently of OpenSSL or GnutTLS being used.




13.3 Defeat TLS fingerprinting

 By changing the order of TLS extensions provided in the TLS handshake, it is
 sometimes possible to circumvent TLS fingerprinting by servers. The TLS
 extension order is of course not the only way to fingerprint a client.

 See https://github.com/curl/curl/issues/8119

13.4 Cache/share OpenSSL contexts

 "Look at SSL cafile - quick traces look to me like these are done on every
 request as well, when they should only be necessary once per SSL context (or
 once per handle)". The major improvement we can rather easily do is to make
 sure we do not create and kill a new SSL "context" for every request, but
 instead make one for every connection and reuse that SSL context in the same
 style connections are reused. It will make us use slightly more memory but it
 will libcurl do less creations and deletions of SSL contexts.

 Technically, the "caching" is probably best implemented by getting added to
 the share interface so that easy handles who want to and can reuse the
 context specify that by sharing with the right properties set.

 https://github.com/curl/curl/issues/1110

13.5 Export session ids

 Add an interface to libcurl that enables "session IDs" to get
 exported/imported. Cris Bailiff said: "OpenSSL has functions which can
 serialise the current SSL state to a buffer of your choice, and recover/reset
 the state from such a buffer at a later date - this is used by mod_ssl for
 apache to implement and SSL session ID cache".







|

|
|
|












|

|
>
>
>
>
>
>
|
>
>
|
>
>
>









<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
















824
825
826
827
828
829
830

 Support for creating remote directories when uploading a file to a directory
 that does not exist on the server, just like --ftp-create-dirs.


12. FILE

12.1 Directory listing on non-POSIX

 Listing the contents of a directory accessed with FILE only works on
 platforms with opendir. Support could be added for more systems, like
 Windows.

13. TLS

13.1 TLS-PSK with OpenSSL

 Transport Layer Security pre-shared key ciphersuites (TLS-PSK) is a set of
 cryptographic protocols that provide secure communication based on pre-shared
 keys (PSKs). These pre-shared keys are symmetric keys shared in advance among
 the communicating parties.

 https://github.com/curl/curl/issues/5081

13.2 TLS channel binding

 TLS 1.2 and 1.3 provide the ability to extract some secret data from the TLS
 connection and use it in the client request (usually in some sort of
 authentication) to ensure that the data sent is bound to the specific TLS
 connection and cannot be successfully intercepted by a proxy. This
 functionality can be used in a standard authentication mechanism such as
 GSS-API or SCRAM, or in custom approaches like custom HTTP Authentication
 headers.

 For TLS 1.2, the binding type is usually tls-unique, and for TLS 1.3 it is
 tls-exporter.

 https://datatracker.ietf.org/doc/html/rfc5929
 https://datatracker.ietf.org/doc/html/rfc9266
 https://github.com/curl/curl/issues/9226

13.3 Defeat TLS fingerprinting

 By changing the order of TLS extensions provided in the TLS handshake, it is
 sometimes possible to circumvent TLS fingerprinting by servers. The TLS
 extension order is of course not the only way to fingerprint a client.

 See https://github.com/curl/curl/issues/8119

















13.5 Export session ids

 Add an interface to libcurl that enables "session IDs" to get
 exported/imported. Cris Bailiff said: "OpenSSL has functions which can
 serialise the current SSL state to a buffer of your choice, and recover/reset
 the state from such a buffer at a later date - this is used by mod_ssl for
 apache to implement and SSL session ID cache".
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
 provided for the server and not for HTTPS proxies. --proxy-tls-max,
 --proxy-tlsv1.3, --proxy-curves and a few more.
 For more Documentation on this see:
 https://curl.se/libcurl/c/tls-options.html

 https://github.com/curl/curl/issues/12286

13.12 Reduce CA certificate bundle reparsing

 When using the OpenSSL backend, curl will load and reparse the CA bundle at
 the creation of the "SSL context" when it sets up a connection to do a TLS
 handshake. A more effective way would be to somehow cache the CA bundle to
 avoid it having to be repeatedly reloaded and reparsed.

 See https://github.com/curl/curl/issues/9379

13.13 Make sure we forbid TLS 1.3 post-handshake authentication

 RFC 8740 explains how using HTTP/2 must forbid the use of TLS 1.3
 post-handshake authentication. We should make sure to live up to that.

 See https://github.com/curl/curl/issues/5396








<
<
<
<
<
<
<
<
<







882
883
884
885
886
887
888









889
890
891
892
893
894
895
 provided for the server and not for HTTPS proxies. --proxy-tls-max,
 --proxy-tlsv1.3, --proxy-curves and a few more.
 For more Documentation on this see:
 https://curl.se/libcurl/c/tls-options.html

 https://github.com/curl/curl/issues/12286










13.13 Make sure we forbid TLS 1.3 post-handshake authentication

 RFC 8740 explains how using HTTP/2 must forbid the use of TLS 1.3
 post-handshake authentication. We should make sure to live up to that.

 See https://github.com/curl/curl/issues/5396

917
918
919
920
921
922
923
924
925
926



927

928
929



930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959

 Consider adding an option or a way for users to select TLS signature
 algorithm. The signature algorithms set by a client are used directly in the
 supported signature algorithm in the client hello message.

 https://github.com/curl/curl/issues/12982

14. GnuTLS

14.2 check connection





 Add a way to check if the connection seems to be alive, to correspond to the
 SSL_peak() way we use with OpenSSL.




15. Schannel

15.1 Extend support for client certificate authentication

 The existing support for the -E/--cert and --key options could be
 extended by supplying a custom certificate and key in PEM format, see:
 - Getting a Certificate for Schannel
   https://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx

15.2 Extend support for the --ciphers option

 The existing support for the --ciphers option could be extended
 by mapping the OpenSSL/GnuTLS cipher suites to the Schannel APIs, see
 - Specifying Schannel Ciphers and Cipher Strengths
   https://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx

15.4 Add option to allow abrupt server closure

 libcurl w/schannel will error without a known termination point from the
 server (such as length of transfer, or SSL "close notify" alert) to prevent
 against a truncation attack. Really old servers may neglect to send any
 termination point. An option could be added to ignore such abrupt closures.

 https://github.com/curl/curl/issues/4427

16. SASL

16.1 Other authentication mechanisms








|

|
>
>
>

>
|
<
>
>
>



















|
|
|
|







907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922

923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955

 Consider adding an option or a way for users to select TLS signature
 algorithm. The signature algorithms set by a client are used directly in the
 supported signature algorithm in the client hello message.

 https://github.com/curl/curl/issues/12982

13.16 Share the CA cache

 For TLS backends that supports CA caching, it makes sense to allow the share
 object to be used to store the CA cache as well via the share API. Would
 allow multiple easy handles to reuse the CA cache and save themselves from a
 lot of extra processing overhead.

13.17 Add missing features to TLS backends


 The feature matrix at https://curl.se/libcurl/c/tls-options.html shows which
 features are supported by which TLS backends, and thus also where there are
 feature gaps.

15. Schannel

15.1 Extend support for client certificate authentication

 The existing support for the -E/--cert and --key options could be
 extended by supplying a custom certificate and key in PEM format, see:
 - Getting a Certificate for Schannel
   https://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx

15.2 Extend support for the --ciphers option

 The existing support for the --ciphers option could be extended
 by mapping the OpenSSL/GnuTLS cipher suites to the Schannel APIs, see
 - Specifying Schannel Ciphers and Cipher Strengths
   https://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx

15.4 Add option to allow abrupt server closure

 libcurl w/schannel errors without a known termination point from the server
 (such as length of transfer, or SSL "close notify" alert) to prevent against
 a truncation attack. Really old servers may neglect to send any termination
 point. An option could be added to ignore such abrupt closures.

 https://github.com/curl/curl/issues/4427

16. SASL

16.1 Other authentication mechanisms

971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
17. SSH protocols

17.1 Multiplexing

 SSH is a perfectly fine multiplexed protocols which would allow libcurl to do
 multiple parallel transfers from the same host using the same connection,
 much in the same spirit as HTTP/2 does. libcurl however does not take
 advantage of that ability but will instead always create a new connection for
 new transfers even if an existing connection already exists to the host.

 To fix this, libcurl would have to detect an existing connection and "attach"
 the new transfer to the existing one.

17.2 Handle growing SFTP files

 The SFTP code in libcurl checks the file size *before* a transfer starts and
 then proceeds to transfer exactly that amount of data. If the remote file
 grows while the transfer is in progress libcurl will not notice and will not
 adapt. The OpenSSH SFTP command line tool does and libcurl could also just
 attempt to download more to see if there is more to get...

 https://github.com/curl/curl/issues/4344

17.3 Read keys from ~/.ssh/id_ecdsa, id_ed25519








|









|







967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
17. SSH protocols

17.1 Multiplexing

 SSH is a perfectly fine multiplexed protocols which would allow libcurl to do
 multiple parallel transfers from the same host using the same connection,
 much in the same spirit as HTTP/2 does. libcurl however does not take
 advantage of that ability but does instead always create a new connection for
 new transfers even if an existing connection already exists to the host.

 To fix this, libcurl would have to detect an existing connection and "attach"
 the new transfer to the existing one.

17.2 Handle growing SFTP files

 The SFTP code in libcurl checks the file size *before* a transfer starts and
 then proceeds to transfer exactly that amount of data. If the remote file
 grows while the transfer is in progress libcurl does not notice and does not
 adapt. The OpenSSH SFTP command line tool does and libcurl could also just
 attempt to download more to see if there is more to get...

 https://github.com/curl/curl/issues/4344

17.3 Read keys from ~/.ssh/id_ecdsa, id_ed25519

1029
1030
1031
1032
1033
1034
1035






1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
 should also be used to set the mod date on the downloaded file.

18.2 glob posts

 Globbing support for -d and -F, as in 'curl -d "name=foo[0-9]" URL'.
 This is easily scripted though.







18.4 --proxycommand

 Allow the user to make curl run a command and use its stdio to make requests
 and not do any network connection by itself. Example:

   curl --proxycommand 'ssh pi@raspberrypi.local -W 10.1.1.75 80' \
        http://some/otherwise/unavailable/service.php

 See https://github.com/curl/curl/issues/4941

18.5 UTF-8 filenames in Content-Disposition

 RFC 6266 documents how UTF-8 names can be passed to a client in the
 Content-Disposition header, and curl does not support this.

 https://github.com/curl/curl/issues/1888

18.6 Option to make -Z merge lined based outputs on stdout

 When a user requests multiple lined based files using -Z and sends them to
 stdout, curl will not "merge" and send complete lines fine but may send
 partial lines from several sources.

 https://github.com/curl/curl/issues/5175

18.8 Consider convenience options for JSON and XML?

 Could we add `--xml` or `--json` to add headers needed to call rest API:

 `--xml` adds -H 'Content-Type: application/xml' -H "Accept: application/xml" and
 `--json` adds -H 'Content-Type: application/json' -H "Accept: application/json"

 Setting Content-Type when doing a GET or any other method without a body
 would be a bit strange I think - so maybe only add CT for requests with body?
 Maybe plain `--xml` and ` --json` are a bit too brief and generic. Maybe
 `--http-json` etc?

 See https://github.com/curl/curl/issues/5203

18.9 Choose the name of file in braces for complex URLs

 When using braces to download a list of URLs and you use complicated names
 in the list of alternatives, it could be handy to allow curl to use other
 names when saving.








>
>
>
>
>
>




















|




<
|
<

<
<
|
<
<
<
<
|
<







1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062

1063

1064


1065




1066

1067
1068
1069
1070
1071
1072
1073
 should also be used to set the mod date on the downloaded file.

18.2 glob posts

 Globbing support for -d and -F, as in 'curl -d "name=foo[0-9]" URL'.
 This is easily scripted though.

18.3 -h option

 Support "curl -h --insecure" etc to output the manpage section for the
 --insecure command line option in the terminal. Should be possible to work
 with either long or short versions of command line options.

18.4 --proxycommand

 Allow the user to make curl run a command and use its stdio to make requests
 and not do any network connection by itself. Example:

   curl --proxycommand 'ssh pi@raspberrypi.local -W 10.1.1.75 80' \
        http://some/otherwise/unavailable/service.php

 See https://github.com/curl/curl/issues/4941

18.5 UTF-8 filenames in Content-Disposition

 RFC 6266 documents how UTF-8 names can be passed to a client in the
 Content-Disposition header, and curl does not support this.

 https://github.com/curl/curl/issues/1888

18.6 Option to make -Z merge lined based outputs on stdout

 When a user requests multiple lined based files using -Z and sends them to
 stdout, curl does not "merge" and send complete lines fine but may send
 partial lines from several sources.

 https://github.com/curl/curl/issues/5175


18.7 specify which response codes that make -f/--fail return error




 Allows a user to better specify exacly which error code(s) that are fine




 and which are errors for their specific uses cases


18.9 Choose the name of file in braces for complex URLs

 When using braces to download a list of URLs and you use complicated names
 in the list of alternatives, it could be handy to allow curl to use other
 names when saving.

1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124

18.11 Windows: set attribute 'archive' for completed downloads

 The archive bit (FILE_ATTRIBUTE_ARCHIVE, 0x20) separates files that shall be
 backed up from those that are either not ready or have not changed.

 Downloads in progress are neither ready to be backed up, nor should they be
 opened by a different process. Only after a download has been completed it's
 sensible to include it in any integer snapshot or backup of the system.

 See https://github.com/curl/curl/issues/3354

18.12 keep running, read instructions from pipe/socket

 Provide an option that makes curl not exit after the last URL (or even work
 without a given URL), and then make it read instructions passed on a pipe or
 over a socket to make further instructions so that a second subsequent curl
 invoke can talk to the still running instance and ask for transfers to get
 done, and thus maintain its connection pool, DNS cache and more.

18.13 Ratelimit or wait between serial requests

 Consider a command line option that can make curl do multiple serial requests
 slow, potentially with a (random) wait between transfers. There is also a
 proposed set of standard HTTP headers to let servers let the client adapt to
 its rate limits:
 https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/

 See https://github.com/curl/curl/issues/5406

18.14 --dry-run

 A command line option that makes curl show exactly what it would do and send







|












|


<
<
|







1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107


1108
1109
1110
1111
1112
1113
1114
1115

18.11 Windows: set attribute 'archive' for completed downloads

 The archive bit (FILE_ATTRIBUTE_ARCHIVE, 0x20) separates files that shall be
 backed up from those that are either not ready or have not changed.

 Downloads in progress are neither ready to be backed up, nor should they be
 opened by a different process. Only after a download has been completed it is
 sensible to include it in any integer snapshot or backup of the system.

 See https://github.com/curl/curl/issues/3354

18.12 keep running, read instructions from pipe/socket

 Provide an option that makes curl not exit after the last URL (or even work
 without a given URL), and then make it read instructions passed on a pipe or
 over a socket to make further instructions so that a second subsequent curl
 invoke can talk to the still running instance and ask for transfers to get
 done, and thus maintain its connection pool, DNS cache and more.

18.13 Acknowledge Ratelimit headers

 Consider a command line option that can make curl do multiple serial requests


 while acknowledging server specified rate limits:
 https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/

 See https://github.com/curl/curl/issues/5406

18.14 --dry-run

 A command line option that makes curl show exactly what it would do and send
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
 When the user only wants to send a small piece of the data provided with
 --data or --data-binary, like when that data is a huge file, consider a way
 to specify that curl should only send a piece of that. One suggested syntax
 would be: "--data-binary @largefile.zip!1073741823-2147483647".

 See https://github.com/curl/curl/issues/1200

18.17 consider file name from the redirected URL with -O ?

 When a user gives a URL and uses -O, and curl follows a redirect to a new
 URL, the file name is not extracted and used from the newly redirected-to URL
 even if the new URL may have a much more sensible file name.

 This is clearly documented and helps for security since there is no surprise
 to users which file name that might get overwritten. But maybe a new option
 could allow for this or maybe -J should imply such a treatment as well as -J
 already allows for the server to decide what file name to use so it already
 provides the "may overwrite any file" risk.

 This is extra tricky if the original URL has no file name part at all since
 then the current code path will error out with an error message, and we cannot
 *know* already at that point if curl will be redirected to a URL that has a
 file name...

 See https://github.com/curl/curl/issues/1241

18.18 retry on network is unreachable

 The --retry option retries transfers on "transient failures". We later added
 --retry-connrefused to also retry for "connection refused" errors.







|


|
|


|

|


|
|
|
|







1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
 When the user only wants to send a small piece of the data provided with
 --data or --data-binary, like when that data is a huge file, consider a way
 to specify that curl should only send a piece of that. One suggested syntax
 would be: "--data-binary @largefile.zip!1073741823-2147483647".

 See https://github.com/curl/curl/issues/1200

18.17 consider filename from the redirected URL with -O ?

 When a user gives a URL and uses -O, and curl follows a redirect to a new
 URL, the filename is not extracted and used from the newly redirected-to URL
 even if the new URL may have a much more sensible filename.

 This is clearly documented and helps for security since there is no surprise
 to users which filename that might get overwritten, but maybe a new option
 could allow for this or maybe -J should imply such a treatment as well as -J
 already allows for the server to decide what filename to use so it already
 provides the "may overwrite any file" risk.

 This is extra tricky if the original URL has no filename part at all since
 then the current code path does error out with an error message, and we
 cannot *know* already at that point if curl is redirected to a URL that has a
 filename...

 See https://github.com/curl/curl/issues/1241

18.18 retry on network is unreachable

 The --retry option retries transfers on "transient failures". We later added
 --retry-connrefused to also retry for "connection refused" errors.
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194

18.19 expand ~/ in config files

 For example .curlrc could benefit from being able to do this.

 See https://github.com/curl/curl/issues/2317

18.20 host name sections in config files

 config files would be more powerful if they could set different
 configurations depending on used URLs, host name or possibly origin. Then a
 default .curlrc could a specific user-agent only when doing requests against
 a certain site.

18.21 retry on the redirected-to URL

 When curl is told to --retry a failed transfer and follows redirects, it
 might get an HTTP 429 response from the redirected-to URL and not the







|


|







1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185

18.19 expand ~/ in config files

 For example .curlrc could benefit from being able to do this.

 See https://github.com/curl/curl/issues/2317

18.20 hostname sections in config files

 config files would be more powerful if they could set different
 configurations depending on used URLs, hostname or possibly origin. Then a
 default .curlrc could a specific user-agent only when doing requests against
 a certain site.

18.21 retry on the redirected-to URL

 When curl is told to --retry a failed transfer and follows redirects, it
 might get an HTTP 429 response from the redirected-to URL and not the
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296

1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
 - First start getting the full file as transfer A
 - If after N seconds have passed and the transfer is expected to continue for
   M seconds or more, add a new transfer (B) that asks for the second half of
   A's content (and stop A at the middle).
 - If splitting up the work improves the transfer rate, it could then be done
   again. Then again, etc up to a limit.

 This way, if transfer B fails (because Range: is not supported) it will let
 transfer A remain the single one. N and M could be set to some sensible
 defaults.

 See https://github.com/curl/curl/issues/5774

18.25 Prevent terminal injection when writing to terminal

 curl could offer an option to make escape sequence either non-functional or
 avoid cursor moves or similar to reduce the risk of a user getting tricked by
 clever tricks.

 See https://github.com/curl/curl/issues/6150

18.26 Custom progress meter update interval

 Users who are for example doing large downloads in CI or remote setups might
 want the occasional progress meter update to see that the transfer is
 progressing and has not stuck, but they may not appreciate the
 many-times-a-second frequency curl can end up doing it with now.

18.27 -J and -O with %-encoded file names

 -J/--remote-header-name does not decode %-encoded file names. RFC 6266 details
 how it should be done. The can of worm is basically that we have no charset
 handling in curl and ascii >=128 is a challenge for us. Not to mention that
 decoding also means that we need to check for nastiness that is attempted,
 like "../" sequences and the like. Probably everything to the left of any
 embedded slashes should be cut off.
 https://curl.se/bug/view.cgi?id=1294

 -O also does not decode %-encoded names, and while it has even less
 information about the charset involved the process is similar to the -J case.

 Note that we will not add decoding to -O without the user asking for it with
 some other means as well, since -O has always been documented to use the name
 exactly as specified in the URL.

18.28 -J with -C -

 When using -J (with -O), automatically resumed downloading together with "-C
 -" fails. Without -J the same command line works. This happens because the
 resume logic is worked out before the target file name (and thus its
 pre-transfer size) has been figured out. This can be improved.

 https://curl.se/bug/view.cgi?id=1169

18.29 --retry and transfer timeouts

 If using --retry and the transfer timeouts (possibly due to using -m or
 -y/-Y) the next attempt does not resume the transfer properly from what was
 downloaded in the previous attempt but will truncate and restart at the
 original position where it was at before the previous failed attempt. See
 https://curl.se/mail/lib-2008-01/0080.html and Mandriva bug report
 https://qa.mandriva.com/show_bug.cgi?id=22565


19. Build

19.2 Enable PIE and RELRO by default

 Especially when having programs that execute curl via the command line, PIE
 renders the exploitation of memory corruption vulnerabilities a lot more
 difficult. This can be attributed to the additional information leaks being
 required to conduct a successful attack. RELRO, on the other hand, masks
 different binary sections like the GOT as read-only and thus kills a handful
 of techniques that come in handy when attackers are able to arbitrarily
 overwrite memory. A few tests showed that enabling these features had close
 to no impact, neither on the performance nor on the general functionality of
 curl.

19.3 Do not use GNU libtool on OpenBSD

 When compiling curl on OpenBSD with "--enable-debug" it will give linking
 errors when you use GNU libtool. This can be fixed by using the libtool
 provided by OpenBSD itself. However for this the user always needs to invoke
 make with "LIBTOOL=/usr/bin/libtool". It would be nice if the script could
 have some magic to detect if this system is an OpenBSD host and then use the
 OpenBSD libtool instead.

 See https://github.com/curl/curl/issues/5862

19.4 Package curl for Windows in a signed installer

 See https://github.com/curl/curl/issues/5424








|




















|

|










|
|
|





|








|
|



















>
|
|
|
|
|
|







1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
 - First start getting the full file as transfer A
 - If after N seconds have passed and the transfer is expected to continue for
   M seconds or more, add a new transfer (B) that asks for the second half of
   A's content (and stop A at the middle).
 - If splitting up the work improves the transfer rate, it could then be done
   again. Then again, etc up to a limit.

 This way, if transfer B fails (because Range: is not supported) it lets
 transfer A remain the single one. N and M could be set to some sensible
 defaults.

 See https://github.com/curl/curl/issues/5774

18.25 Prevent terminal injection when writing to terminal

 curl could offer an option to make escape sequence either non-functional or
 avoid cursor moves or similar to reduce the risk of a user getting tricked by
 clever tricks.

 See https://github.com/curl/curl/issues/6150

18.26 Custom progress meter update interval

 Users who are for example doing large downloads in CI or remote setups might
 want the occasional progress meter update to see that the transfer is
 progressing and has not stuck, but they may not appreciate the
 many-times-a-second frequency curl can end up doing it with now.

18.27 -J and -O with %-encoded filenames

 -J/--remote-header-name does not decode %-encoded filenames. RFC 6266 details
 how it should be done. The can of worm is basically that we have no charset
 handling in curl and ascii >=128 is a challenge for us. Not to mention that
 decoding also means that we need to check for nastiness that is attempted,
 like "../" sequences and the like. Probably everything to the left of any
 embedded slashes should be cut off.
 https://curl.se/bug/view.cgi?id=1294

 -O also does not decode %-encoded names, and while it has even less
 information about the charset involved the process is similar to the -J case.

 Note that we do not decode -O without the user asking for it with some other
 means, since -O has always been documented to use the name exactly as
 specified in the URL.

18.28 -J with -C -

 When using -J (with -O), automatically resumed downloading together with "-C
 -" fails. Without -J the same command line works. This happens because the
 resume logic is worked out before the target filename (and thus its
 pre-transfer size) has been figured out. This can be improved.

 https://curl.se/bug/view.cgi?id=1169

18.29 --retry and transfer timeouts

 If using --retry and the transfer timeouts (possibly due to using -m or
 -y/-Y) the next attempt does not resume the transfer properly from what was
 downloaded in the previous attempt but truncates and restarts at the original
 position where it was at before the previous failed attempt. See
 https://curl.se/mail/lib-2008-01/0080.html and Mandriva bug report
 https://qa.mandriva.com/show_bug.cgi?id=22565


19. Build

19.2 Enable PIE and RELRO by default

 Especially when having programs that execute curl via the command line, PIE
 renders the exploitation of memory corruption vulnerabilities a lot more
 difficult. This can be attributed to the additional information leaks being
 required to conduct a successful attack. RELRO, on the other hand, masks
 different binary sections like the GOT as read-only and thus kills a handful
 of techniques that come in handy when attackers are able to arbitrarily
 overwrite memory. A few tests showed that enabling these features had close
 to no impact, neither on the performance nor on the general functionality of
 curl.

19.3 Do not use GNU libtool on OpenBSD

 When compiling curl on OpenBSD with "--enable-debug" it gives linking errors
 when you use GNU libtool. This can be fixed by using the libtool provided by
 OpenBSD itself. However for this the user always needs to invoke make with
 "LIBTOOL=/usr/bin/libtool". It would be nice if the script could have some
 magic to detect if this system is an OpenBSD host and then use the OpenBSD
 libtool instead.

 See https://github.com/curl/curl/issues/5862

19.4 Package curl for Windows in a signed installer

 See https://github.com/curl/curl/issues/5424

1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391


1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
 or http operations (for which we have test servers).

20.4 more platforms supported

 Make the test suite work on more platforms. OpenBSD and Mac OS. Remove
 fork()s and it should become even more portable.

20.5 Add support for concurrent connections

 Tests 836, 882 and 938 were designed to verify that separate connections are
 not used when using different login credentials in protocols that should not
 reuse a connection under such circumstances.

 Unfortunately, ftpserver.pl does not appear to support multiple concurrent
 connections. The read while() loop seems to loop until it receives a
 disconnect from the client, where it then enters the waiting for connections
 loop. When the client opens a second connection to the server, the first
 connection has not been dropped (unless it has been forced - which we
 should not do in these tests) and thus the wait for connections loop is never
 entered to receive the second connection.

20.6 Use the RFC 6265 test suite

 A test suite made for HTTP cookies (RFC 6265) by Adam Barth is available at
 https://github.com/abarth/http-state/tree/master/tests

 It'd be really awesome if someone would write a script/setup that would run
 curl with that test suite and detect deviances. Ideally, that would even be
 incorporated into our regular test suite.

20.7 Support LD_PRELOAD on macOS

 LD_RELOAD does not work on macOS, but there are tests which require it to run
 properly. Look into making the preload support in runtests.pl portable such
 that it uses DYLD_INSERT_LIBRARIES on macOS.

20.8 Run web-platform-tests URL tests

 Run web-platform-tests URL tests and compare results with browsers on wpt.fyi

 It would help us find issues to fix and help us document where our parser
 differs from the WHATWG URL spec parsers.

 See https://github.com/curl/curl/issues/4477

21. MQTT

21.1 Support rate-limiting

 The rate-limiting logic is done in the PERFORMING state in multi.c but MQTT
 is not (yet) implemented to use that.



22. TFTP

22.1 TFTP doesn't convert LF to CRLF for mode=netascii

 RFC 3617 defines that an TFTP transfer can be done using "netascii"
 mode. curl does not support extracting that mode from the URL nor does it treat
 such transfers specifically. It should probably do LF to CRLF translations
 for them.

 See https://github.com/curl/curl/issues/12655







<
<
<
<
<
<
<
<
<
<
<
<
<
<





|
|


<
<
<
<
<
<
















>
>


|







1332
1333
1334
1335
1336
1337
1338














1339
1340
1341
1342
1343
1344
1345
1346
1347






1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
 or http operations (for which we have test servers).

20.4 more platforms supported

 Make the test suite work on more platforms. OpenBSD and Mac OS. Remove
 fork()s and it should become even more portable.















20.6 Use the RFC 6265 test suite

 A test suite made for HTTP cookies (RFC 6265) by Adam Barth is available at
 https://github.com/abarth/http-state/tree/master/tests

 It would be good if someone would write a script/setup that would run curl
 with that test suite and detect deviances. Ideally, that would even be
 incorporated into our regular test suite.







20.8 Run web-platform-tests URL tests

 Run web-platform-tests URL tests and compare results with browsers on wpt.fyi

 It would help us find issues to fix and help us document where our parser
 differs from the WHATWG URL spec parsers.

 See https://github.com/curl/curl/issues/4477

21. MQTT

21.1 Support rate-limiting

 The rate-limiting logic is done in the PERFORMING state in multi.c but MQTT
 is not (yet) implemented to use that.

21.2 Support MQTTS

22. TFTP

22.1 TFTP does not convert LF to CRLF for mode=netascii

 RFC 3617 defines that an TFTP transfer can be done using "netascii"
 mode. curl does not support extracting that mode from the URL nor does it treat
 such transfers specifically. It should probably do LF to CRLF translations
 for them.

 See https://github.com/curl/curl/issues/12655
Changes to jni/curl/docs/TheArtOfHttpScripting.md.
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
 which one your curl was built to use (if any!). To get a page from an HTTPS
 server, simply run curl like:

    curl https://secure.example.com

## Certificates

 In the HTTPS world, you use certificates to validate that you are the one
 you claim to be, as an addition to normal passwords. Curl supports client-
 side certificates. All certificates are locked with a pass phrase, which you
 need to enter before the certificate can be used by curl. The pass phrase
 can be specified on the command line or if not, entered interactively when
 curl queries for it. Use a certificate with curl on an HTTPS server like:

    curl --cert mycert.pem https://secure.example.com

 curl also tries to verify that the server is who it claims to be, by
 verifying the server's certificate against a locally stored CA cert bundle.
 Failing the verification causes curl to deny the connection. You must then
 use [`--insecure`](https://curl.se/docs/manpage.html#-k) (`-k`) in case you







|
|
|
|
|
|







574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
 which one your curl was built to use (if any!). To get a page from an HTTPS
 server, simply run curl like:

    curl https://secure.example.com

## Certificates

 In the HTTPS world, you use certificates to validate that you are the one you
 claim to be, as an addition to normal passwords. Curl supports client- side
 certificates. All certificates are locked with a passphrase, which you need
 to enter before the certificate can be used by curl. The passphrase can be
 specified on the command line or if not, entered interactively when curl
 queries for it. Use a certificate with curl on an HTTPS server like:

    curl --cert mycert.pem https://secure.example.com

 curl also tries to verify that the server is who it claims to be, by
 verifying the server's certificate against a locally stored CA cert bundle.
 Failing the verification causes curl to deny the connection. You must then
 use [`--insecure`](https://curl.se/docs/manpage.html#-k) (`-k`) in case you
Changes to jni/curl/docs/URL-SYNTAX.md.
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
curl recognizes a URL syntax that we call "RFC 3986 plus". It is grounded on
the well established RFC 3986 to make sure previously written command lines
and curl using scripts remain working.

curl's URL parser allows a few deviations from the spec in order to
inter-operate better with URLs that appear in the wild.

### spaces

A URL provided to curl cannot contain spaces. They need to be provided URL
encoded to be accepted in a URL by curl.

An exception to this rule: `Location:` response headers that indicate to a
client where a resource has been redirected to, sometimes contain spaces. This
is a violation of RFC 3986 but is fine in the WHATWG spec. curl handles these
by re-encoding them to `%20`.

### non-ASCII

Byte values in a provided URL that are outside of the printable ASCII range
are percent-encoded by curl.

### multiple slashes

An absolute URL always starts with a "scheme" followed by a colon. For all the
schemes curl supports, the colon must be followed by two slashes according to
RFC 3986 but not according to the WHATWG spec - which allows one to infinity
amount.

curl allows one, two or three slashes after the colon to still be considered a







|









|




|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
curl recognizes a URL syntax that we call "RFC 3986 plus". It is grounded on
the well established RFC 3986 to make sure previously written command lines
and curl using scripts remain working.

curl's URL parser allows a few deviations from the spec in order to
inter-operate better with URLs that appear in the wild.

### Spaces

A URL provided to curl cannot contain spaces. They need to be provided URL
encoded to be accepted in a URL by curl.

An exception to this rule: `Location:` response headers that indicate to a
client where a resource has been redirected to, sometimes contain spaces. This
is a violation of RFC 3986 but is fine in the WHATWG spec. curl handles these
by re-encoding them to `%20`.

### Non-ASCII

Byte values in a provided URL that are outside of the printable ASCII range
are percent-encoded by curl.

### Multiple slashes

An absolute URL always starts with a "scheme" followed by a colon. For all the
schemes curl supports, the colon must be followed by two slashes according to
RFC 3986 but not according to the WHATWG spec - which allows one to infinity
amount.

curl allows one, two or three slashes after the colon to still be considered a
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
 - `dict.` means DICT
 - `ldap.` means LDAP
 - `imap.` means IMAP
 - `smtp.` means SMTP
 - `pop3.` means POP3
 - all other means HTTP

### globbing letters

The curl command line tool supports "globbing" of URLs. It means that you can
create ranges and lists using `[N-M]` and `{one,two,three}` sequences. The
letters used for this (`[]{}`) are reserved in RFC 3986 and can therefore not
legitimately be part of such a URL.

They are however not reserved or special in the WHATWG specification, so







|







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
 - `dict.` means DICT
 - `ldap.` means LDAP
 - `imap.` means IMAP
 - `smtp.` means SMTP
 - `pop3.` means POP3
 - all other means HTTP

### Globbing letters

The curl command line tool supports "globbing" of URLs. It means that you can
create ranges and lists using `[N-M]` and `{one,two,three}` sequences. The
letters used for this (`[]{}`) are reserved in RFC 3986 and can therefore not
legitimately be part of such a URL.

They are however not reserved or special in the WHATWG specification, so
Changes to jni/curl/docs/VULN-DISCLOSURE-POLICY.md.
294
295
296
297
298
299
300
















Content that is transferred from a server and gets displayed in a terminal by
curl may contain escape sequences or use other tricks to fool the user. This
is curl working as designed and is not a curl security problem. Escape
sequences, moving cursor, changing color etc, is also frequently used for
good. To reduce the risk of getting fooled, save files and browse them after
download using a display method that minimizes risks.






















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315

Content that is transferred from a server and gets displayed in a terminal by
curl may contain escape sequences or use other tricks to fool the user. This
is curl working as designed and is not a curl security problem. Escape
sequences, moving cursor, changing color etc, is also frequently used for
good. To reduce the risk of getting fooled, save files and browse them after
download using a display method that minimizes risks.

## NULL dereferences and crashes

If a malicious server can trigger a NULL dereference in curl or otherwise
cause curl to crash (and nothing worse), chances are big that we do not
consider that a security problem.

Malicious servers can already cause considerable harm and denial of service
like scenarios without having to trigger such code paths. For example by
stalling, being terribly slow or by delivering enormous amounts of data.
Additionally, applications are expected to handle "normal" crashes without
that being the end of the world.

There need to be more and special circumstances to treat such problems as
security issues.
Changes to jni/curl/docs/cmdline-opts/MANPAGE.md.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    Example:
      - (an example command line, without "curl" and can use `$URL`)
      - (another example)
    Experimental: yes (if so)
    Help: (short text for the --help output for this option)
    Long: (long form name, without dashes)
    Magic: (description of "magic" options)
    Multi: single/append/boolean/mutex/custom (if used more than once)
    Mutexed: (space separated list of options this overrides, no dashes)
    Protocols: (space separated list for which protocols this option works)
    Requires: (space separated list of features this requires, no dashes)
    Scope: global (if the option is global)
    See-also:
      - (a related option, no dashes)
      - (another related option, no dashes)







|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    Example:
      - (an example command line, without "curl" and can use `$URL`)
      - (another example)
    Experimental: yes (if so)
    Help: (short text for the --help output for this option)
    Long: (long form name, without dashes)
    Magic: (description of "magic" options)
    Multi: single/append/boolean/mutex/custom/per-URL (if used more than once)
    Mutexed: (space separated list of options this overrides, no dashes)
    Protocols: (space separated list for which protocols this option works)
    Requires: (space separated list of features this requires, no dashes)
    Scope: global (if the option is global)
    See-also:
      - (a related option, no dashes)
      - (another related option, no dashes)
Changes to jni/curl/docs/cmdline-opts/Makefile.am.
50
51
52
53
54
55
56
57
58
59
60
$(MANPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN)
	$(GEN)(rm -f $(MANPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) mainpage $(DPAGES) > manpage.tmp.$$$$ && mv manpage.tmp.$$$$ $(MANPAGE))

$(ASCIIPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN)
	$(GEN)(rm -f $(ASCIIPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) ascii $(DPAGES) > asciipage.tmp.$$$$ && mv asciipage.tmp.$$$$ $(ASCIIPAGE))

listhelp:
	$(MANAGEN) listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c

listcats:
	@$(MANAGEN) listcats $(DPAGES)







|



50
51
52
53
54
55
56
57
58
59
60
$(MANPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN)
	$(GEN)(rm -f $(MANPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) mainpage $(DPAGES) > manpage.tmp.$$$$ && mv manpage.tmp.$$$$ $(MANPAGE))

$(ASCIIPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN)
	$(GEN)(rm -f $(ASCIIPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) ascii $(DPAGES) > asciipage.tmp.$$$$ && mv asciipage.tmp.$$$$ $(ASCIIPAGE))

listhelp:
	$(MANAGEN) -d $(srcdir) listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c

listcats:
	@$(MANAGEN) listcats $(DPAGES)
Changes to jni/curl/docs/cmdline-opts/Makefile.in.
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







154
155
156
157
158
159
160

161
162
163
164
165
166
167
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
311
312
313
314
315
316
317


318
319
320
321
322
323
324
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
562
563
564
565
566
567
568

569
570
571
572
573

574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

594
595
596
597
598
599
600
  http2.md \
  http3.md \
  http3-only.md \
  ignore-content-length.md \
  include.md \
  insecure.md \
  interface.md \

  ipfs-gateway.md \
  ipv4.md \
  ipv6.md \
  json.md \
  junk-session-cookies.md \

  keepalive-time.md \
  key-type.md \
  key.md \
  krb.md \
  libcurl.md \
  limit-rate.md \
  list-only.md \
  local-port.md \
  location-trusted.md \
  location.md \
  login-options.md \
  mail-auth.md \
  mail-from.md \
  mail-rcpt-allowfails.md \
  mail-rcpt.md \
  manual.md \
  max-filesize.md \
  max-redirs.md \
  max-time.md \
  metalink.md \

  negotiate.md \
  netrc-file.md \
  netrc-optional.md \
  netrc.md \
  next.md \
  no-alpn.md \
  no-buffer.md \







>





>




















>







563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
  http2.md \
  http3.md \
  http3-only.md \
  ignore-content-length.md \
  include.md \
  insecure.md \
  interface.md \
  ip-tos.md \
  ipfs-gateway.md \
  ipv4.md \
  ipv6.md \
  json.md \
  junk-session-cookies.md \
  keepalive-cnt.md \
  keepalive-time.md \
  key-type.md \
  key.md \
  krb.md \
  libcurl.md \
  limit-rate.md \
  list-only.md \
  local-port.md \
  location-trusted.md \
  location.md \
  login-options.md \
  mail-auth.md \
  mail-from.md \
  mail-rcpt-allowfails.md \
  mail-rcpt.md \
  manual.md \
  max-filesize.md \
  max-redirs.md \
  max-time.md \
  metalink.md \
  mptcp.md \
  negotiate.md \
  netrc-file.md \
  netrc-optional.md \
  netrc.md \
  next.md \
  no-alpn.md \
  no-buffer.md \
728
729
730
731
732
733
734

735
736
737
738
739
740
741
  url-query.md \
  use-ascii.md \
  user-agent.md \
  user.md \
  variable.md \
  verbose.md \
  version.md \

  write-out.md \
  xattr.md

EXTRA_DIST = $(DPAGES) MANPAGE.md $(SUPPORT) CMakeLists.txt mainpage.idx
GEN = $(GN_$(V))
GN_0 = @echo "  GENERATE" $@;
GN_1 = 







>







732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
  url-query.md \
  use-ascii.md \
  user-agent.md \
  user.md \
  variable.md \
  verbose.md \
  version.md \
  vlan-priority.md \
  write-out.md \
  xattr.md

EXTRA_DIST = $(DPAGES) MANPAGE.md $(SUPPORT) CMakeLists.txt mainpage.idx
GEN = $(GN_$(V))
GN_0 = @echo "  GENERATE" $@;
GN_1 = 
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
$(MANPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN)
	$(GEN)(rm -f $(MANPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) mainpage $(DPAGES) > manpage.tmp.$$$$ && mv manpage.tmp.$$$$ $(MANPAGE))

$(ASCIIPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN)
	$(GEN)(rm -f $(ASCIIPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) ascii $(DPAGES) > asciipage.tmp.$$$$ && mv asciipage.tmp.$$$$ $(ASCIIPAGE))

listhelp:
	$(MANAGEN) listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c

listcats:
	@$(MANAGEN) listcats $(DPAGES)

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:







|







999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
$(MANPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN)
	$(GEN)(rm -f $(MANPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) mainpage $(DPAGES) > manpage.tmp.$$$$ && mv manpage.tmp.$$$$ $(MANPAGE))

$(ASCIIPAGE): $(DPAGES) $(SUPPORT) mainpage.idx Makefile.inc $(MANAGEN)
	$(GEN)(rm -f $(ASCIIPAGE) && @PERL@ $(MANAGEN) -d $(srcdir) -I $(INCDIR) ascii $(DPAGES) > asciipage.tmp.$$$$ && mv asciipage.tmp.$$$$ $(ASCIIPAGE))

listhelp:
	$(MANAGEN) -d $(srcdir) listhelp $(DPAGES) > $(top_builddir)/src/tool_listhelp.c

listcats:
	@$(MANAGEN) listcats $(DPAGES)

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
Changes to jni/curl/docs/cmdline-opts/Makefile.inc.
132
133
134
135
136
137
138

139
140
141
142
143

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
  http2.md \
  http3.md \
  http3-only.md \
  ignore-content-length.md \
  include.md \
  insecure.md \
  interface.md \

  ipfs-gateway.md \
  ipv4.md \
  ipv6.md \
  json.md \
  junk-session-cookies.md \

  keepalive-time.md \
  key-type.md \
  key.md \
  krb.md \
  libcurl.md \
  limit-rate.md \
  list-only.md \
  local-port.md \
  location-trusted.md \
  location.md \
  login-options.md \
  mail-auth.md \
  mail-from.md \
  mail-rcpt-allowfails.md \
  mail-rcpt.md \
  manual.md \
  max-filesize.md \
  max-redirs.md \
  max-time.md \
  metalink.md \

  negotiate.md \
  netrc-file.md \
  netrc-optional.md \
  netrc.md \
  next.md \
  no-alpn.md \
  no-buffer.md \







>





>




















>







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  http2.md \
  http3.md \
  http3-only.md \
  ignore-content-length.md \
  include.md \
  insecure.md \
  interface.md \
  ip-tos.md \
  ipfs-gateway.md \
  ipv4.md \
  ipv6.md \
  json.md \
  junk-session-cookies.md \
  keepalive-cnt.md \
  keepalive-time.md \
  key-type.md \
  key.md \
  krb.md \
  libcurl.md \
  limit-rate.md \
  list-only.md \
  local-port.md \
  location-trusted.md \
  location.md \
  login-options.md \
  mail-auth.md \
  mail-from.md \
  mail-rcpt-allowfails.md \
  mail-rcpt.md \
  manual.md \
  max-filesize.md \
  max-redirs.md \
  max-time.md \
  metalink.md \
  mptcp.md \
  negotiate.md \
  netrc-file.md \
  netrc-optional.md \
  netrc.md \
  next.md \
  no-alpn.md \
  no-buffer.md \
298
299
300
301
302
303
304

305
306
  url-query.md \
  use-ascii.md \
  user-agent.md \
  user.md \
  variable.md \
  verbose.md \
  version.md \

  write-out.md \
  xattr.md







>


301
302
303
304
305
306
307
308
309
310
  url-query.md \
  use-ascii.md \
  user-agent.md \
  user.md \
  variable.md \
  verbose.md \
  version.md \
  vlan-priority.md \
  write-out.md \
  xattr.md
Changes to jni/curl/docs/cmdline-opts/_PROTOCOLS.md.
45
46
47
48
49
50
51


Uploading contents to an SMTP server means sending an email. With or without
TLS.
## TELNET
Fetching a telnet URL starts an interactive session where it sends what it
reads on stdin and outputs what the server sends it.
## TFTP
curl can do TFTP downloads and uploads.









>
>
45
46
47
48
49
50
51
52
53
Uploading contents to an SMTP server means sending an email. With or without
TLS.
## TELNET
Fetching a telnet URL starts an interactive session where it sends what it
reads on stdin and outputs what the server sends it.
## TFTP
curl can do TFTP downloads and uploads.
## WS(S)
WebSocket done over HTTP/1. WSS implies that it works over HTTPS.
Changes to jni/curl/docs/cmdline-opts/connect-timeout.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: connect-timeout
Arg: <seconds>
Help: Maximum time allowed to connect
Category: connection
Added: 7.7
Multi: single
See-also:
  - max-time
Example:
  - --connect-timeout 20 $URL
  - --connect-timeout 3.14 $URL






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: connect-timeout
Arg: <seconds>
Help: Maximum time allowed to connect
Category: connection timeout
Added: 7.7
Multi: single
See-also:
  - max-time
Example:
  - --connect-timeout 20 $URL
  - --connect-timeout 3.14 $URL
Changes to jni/curl/docs/cmdline-opts/connect-to.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: connect-to
Arg: <HOST1:PORT1:HOST2:PORT2>
Help: Connect to host
Added: 7.49.0
Category: connection
Multi: append
See-also:
  - resolve
  - header
Example:
  - --connect-to example.com:443:example.net:8443 $URL
---





|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: connect-to
Arg: <HOST1:PORT1:HOST2:PORT2>
Help: Connect to host2 instead of host1
Added: 7.49.0
Category: connection dns
Multi: append
See-also:
  - resolve
  - header
Example:
  - --connect-to example.com:443:example.net:8443 $URL
---
24
25
26
27
28
29
30










`HOST1` and `PORT1` may be empty strings, meaning any host or any port number.
`HOST2` and `PORT2` may also be empty strings, meaning use the request's
original hostname and port number.

A hostname specified to this option is compared as a string, so it needs to
match the name used in request URL. It can be either numerical such as
`127.0.0.1` or the full host name such as `example.org`.

















>
>
>
>
>
>
>
>
>
>
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
`HOST1` and `PORT1` may be empty strings, meaning any host or any port number.
`HOST2` and `PORT2` may also be empty strings, meaning use the request's
original hostname and port number.

A hostname specified to this option is compared as a string, so it needs to
match the name used in request URL. It can be either numerical such as
`127.0.0.1` or the full host name such as `example.org`.

Example: redirect connects from the example.com hostname to 127.0.0.1
independently of port number:

    curl --connect-to example.com::127.0.0.1: https://example.com/

Example: redirect connects from all hostnames to 127.0.0.1 independently of
port number:

    curl --connect-to ::127.0.0.1: http://example.com/
Changes to jni/curl/docs/cmdline-opts/cookie-jar.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: c
Long: cookie-jar
Arg: <filename>
Protocols: HTTP
Help: Save cookies to <filename> after operation
Category: http
Added: 7.9
Multi: single
See-also:
  - cookie

Example:
  - -c store-here.txt $URL
  - -c store-here.txt -b read-these $URL
---

# `--cookie-jar`














>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: c
Long: cookie-jar
Arg: <filename>
Protocols: HTTP
Help: Save cookies to <filename> after operation
Category: http
Added: 7.9
Multi: single
See-also:
  - cookie
  - junk-session-cookies
Example:
  - -c store-here.txt $URL
  - -c store-here.txt -b read-these $URL
---

# `--cookie-jar`

Changes to jni/curl/docs/cmdline-opts/create-dirs.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: create-dirs
Help: Create necessary local directory hierarchy
Category: curl
Added: 7.10.3
Multi: boolean
See-also:
  - ftp-create-dirs
  - output-dir
Example:
  - --create-dirs --output local/dir/file $URL





|







1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: create-dirs
Help: Create necessary local directory hierarchy
Category: output
Added: 7.10.3
Multi: boolean
See-also:
  - ftp-create-dirs
  - output-dir
Example:
  - --create-dirs --output local/dir/file $URL
Changes to jni/curl/docs/cmdline-opts/crlf.md.
13
14
15
16
17
18
19
20
21
  - --crlf -T file ftp://example.com/
---

# `--crlf`

Convert line feeds to carriage return plus line feeds in upload. Useful for
**MVS (OS/390)**.

(SMTP added in 7.40.0)







<
<
13
14
15
16
17
18
19


  - --crlf -T file ftp://example.com/
---

# `--crlf`

Convert line feeds to carriage return plus line feeds in upload. Useful for
**MVS (OS/390)**.


Changes to jni/curl/docs/cmdline-opts/disable.md.
14
15
16
17
18
19
20
21
22
23
---

# `--disable`

If used as the **first** parameter on the command line, the *curlrc* config
file is not read or used. See the --config for details on the default config
file search path.

Prior to 7.50.0 curl supported the short option name *q* but not the long
option name *disable*.







<
<
<
14
15
16
17
18
19
20



---

# `--disable`

If used as the **first** parameter on the command line, the *curlrc* config
file is not read or used. See the --config for details on the default config
file search path.



Changes to jni/curl/docs/cmdline-opts/doh-insecure.md.
1
2
3
4
5
6
7
8
9
10


11
12
13
14
15
16








17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: doh-insecure
Help: Allow insecure DoH server connections
Added: 7.76.0
Category: dns tls
Multi: boolean
See-also:
  - doh-url


Example:
  - --doh-insecure --doh-url https://doh.example $URL
---

# `--doh-insecure`









Same as --insecure but used for DoH (DNS-over-HTTPS).










>
>






>
>
>
>
>
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: doh-insecure
Help: Allow insecure DoH server connections
Added: 7.76.0
Category: dns tls
Multi: boolean
See-also:
  - doh-url
  - insecure
  - proxy-insecure
Example:
  - --doh-insecure --doh-url https://doh.example $URL
---

# `--doh-insecure`

By default, every connection curl makes to a DoH server is verified to be
secure before the transfer takes place. This option tells curl to skip the
verification step and proceed without checking.

**WARNING**: using this option makes the DoH transfer and name resolution
insecure.

This option is equivalent to --insecure and --proxy-insecure but used for DoH
(DNS-over-HTTPS) only.
Changes to jni/curl/docs/cmdline-opts/dump-header.md.
9
10
11
12
13
14
15

16
17
18
19
20
21

22
23
24
25
26
27
Category: http ftp
Added: 5.7
Multi: single
See-also:
  - output
Example:
  - --dump-header store.txt $URL

---

# `--dump-header`

Write the received protocol headers to the specified file. If no headers are
received, the use of this option creates an empty file.


When used in FTP, the FTP server response lines are considered being "headers"
and thus are saved there.

Having multiple transfers in one set of operations (i.e. the URLs in one
--next clause), appends them to the same file, separated by a blank line.







>





|
>






9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Category: http ftp
Added: 5.7
Multi: single
See-also:
  - output
Example:
  - --dump-header store.txt $URL
  - --dump-header - $URL -o save
---

# `--dump-header`

Write the received protocol headers to the specified file. If no headers are
received, the use of this option creates an empty file. Specify `-` as file
name (a single minus) to have it written to stdout.

When used in FTP, the FTP server response lines are considered being "headers"
and thus are saved there.

Having multiple transfers in one set of operations (i.e. the URLs in one
--next clause), appends them to the same file, separated by a blank line.
Changes to jni/curl/docs/cmdline-opts/ech.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ech
Arg: <config>
Help: Configure Encrypted Client Hello (ECH) for use with the TLS session
Added: 8.8.0
Category: tls ECH
Protocols: HTTPS
Multi: single
See-also:
  - doh-url
Example:
  - --ech true $URL
---





|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ech
Arg: <config>
Help: Configure ECH
Added: 8.8.0
Category: tls
Protocols: HTTPS
Multi: single
See-also:
  - doh-url
Example:
  - --ech true $URL
---
Changes to jni/curl/docs/cmdline-opts/egd-file.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: egd-file
Arg: <file>
Help: EGD socket path for random data
Protocols: TLS
Category: tls
Added: 7.7
Multi: single
See-also:
  - random-file
Example:
  - --egd-file /random/here $URL
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: egd-file
Arg: <file>
Help: EGD socket path for random data
Protocols: TLS
Category: deprecated
Added: 7.7
Multi: single
See-also:
  - random-file
Example:
  - --egd-file /random/here $URL
---
Changes to jni/curl/docs/cmdline-opts/expect100-timeout.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: expect100-timeout
Arg: <seconds>
Help: How long to wait for 100-continue
Protocols: HTTP
Added: 7.47.0
Category: http
Multi: single
See-also:
  - connect-timeout
Example:
  - --expect100-timeout 2.5 -T file $URL
---









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: expect100-timeout
Arg: <seconds>
Help: How long to wait for 100-continue
Protocols: HTTP
Added: 7.47.0
Category: http timeout
Multi: single
See-also:
  - connect-timeout
Example:
  - --expect100-timeout 2.5 -T file $URL
---

Changes to jni/curl/docs/cmdline-opts/fail-early.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: fail-early
Help: Fail on first transfer error
Added: 7.52.0
Category: curl
Multi: boolean
Scope: global
See-also:
  - fail
  - fail-with-body
Example:
  - --fail-early $URL https://two.example






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: fail-early
Help: Fail on first transfer error
Added: 7.52.0
Category: curl global
Multi: boolean
Scope: global
See-also:
  - fail
  - fail-with-body
Example:
  - --fail-early $URL https://two.example
Changes to jni/curl/docs/cmdline-opts/fail.md.
14
15
16
17
18
19
20
21

22
23
24
25





26
27
28
29
  - fail-early
Example:
  - --fail $URL
---

# `--fail`

Fail fast with no output at all on server errors. This is useful to enable

scripts and users to better deal with failed attempts. In normal cases when an
HTTP server fails to deliver a document, it returns an HTML document stating
so (which often also describes why and more). This command line option
prevents curl from outputting that and return error 22.






This method is not fail-safe and there are occasions where non-successful
response codes slip through, especially when authentication is involved
(response codes 401 and 407).







|
>
|
|
|
|
>
>
>
>
>




14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  - fail-early
Example:
  - --fail $URL
---

# `--fail`

Fail with error code 22 and with no response body output at all for HTTP
transfers returning HTTP response codes at 400 or greater.

In normal cases when an HTTP server fails to deliver a document, it returns a
body of text stating so (which often also describes why and more) and a 4xx
HTTP response code. This command line option prevents curl from outputting
that data and instead returns error 22 early. By default, curl does not
consider HTTP response codes to indicate failure.

To get both the error code and also save the content, use --fail-with-body
instead.

This method is not fail-safe and there are occasions where non-successful
response codes slip through, especially when authentication is involved
(response codes 401 and 407).
Changes to jni/curl/docs/cmdline-opts/form-escape.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: form-escape
Help: Escape form fields using backslash
Protocols: HTTP
Added: 7.81.0
Category: http upload
Multi: single
See-also:
  - form
Example:
  - --form-escape -F 'field\name=curl' -F 'file=@load"this' $URL
---






|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: form-escape
Help: Escape form fields using backslash
Protocols: HTTP imap smtp
Added: 7.81.0
Category: http upload post
Multi: single
See-also:
  - form
Example:
  - --form-escape -F 'field\name=curl' -F 'file=@load"this' $URL
---

Changes to jni/curl/docs/cmdline-opts/form-string.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: form-string
Help: Specify multipart MIME data
Protocols: HTTP SMTP IMAP
Arg: <name=string>
Category: http upload
Added: 7.13.2
Multi: append
See-also:
  - form
Example:
  - --form-string "name=data" $URL
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: form-string
Help: Specify multipart MIME data
Protocols: HTTP SMTP IMAP
Arg: <name=string>
Category: http upload post smtp imap
Added: 7.13.2
Multi: append
See-also:
  - form
Example:
  - --form-string "name=data" $URL
---
Changes to jni/curl/docs/cmdline-opts/form.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: form
Short: F
Arg: <name=content>
Help: Specify multipart MIME data
Protocols: HTTP SMTP IMAP
Mutexed: data head upload-file
Category: http upload
Added: 5.0
Multi: append
See-also:
  - data
  - form-string
  - form-escape
Example:









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: form
Short: F
Arg: <name=content>
Help: Specify multipart MIME data
Protocols: HTTP SMTP IMAP
Mutexed: data head upload-file
Category: http upload post imap smtp
Added: 5.0
Multi: append
See-also:
  - data
  - form-string
  - form-escape
Example:
Changes to jni/curl/docs/cmdline-opts/ftp-create-dirs.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ftp-create-dirs
Protocols: FTP SFTP
Help: Create the remote dirs if not present
Category: ftp sftp curl
Added: 7.10.7
Multi: boolean
See-also:
  - create-dirs
Example:
  - --ftp-create-dirs -T file ftp://example.com/remote/path/file
---






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ftp-create-dirs
Protocols: FTP SFTP
Help: Create the remote dirs if not present
Category: ftp sftp
Added: 7.10.7
Multi: boolean
See-also:
  - create-dirs
Example:
  - --ftp-create-dirs -T file ftp://example.com/remote/path/file
---
Changes to jni/curl/docs/cmdline-opts/get.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: get
Short: G
Help: Put the post data in the URL and use GET
Protocols: HTTP
Category: http upload
Added: 7.8.1
Multi: boolean
See-also:
  - data
  - request
Example:
  - --get $URL
  - --get -d "tool=curl" -d "age=old" $URL
  - --get -I -d "tool=curl" $URL
---

# `--get`

When used, this option makes all data specified with --data, --data-binary
or --data-urlencode to be used in an HTTP GET request instead of the POST
request that otherwise would be used. The data is appended to the URL
with a '?' separator.

If used in combination with --head, the POST data is instead appended to the
URL with a HEAD request.







|













|
|
|
|



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: get
Short: G
Help: Put the post data in the URL and use GET
Protocols: HTTP
Category: http
Added: 7.8.1
Multi: boolean
See-also:
  - data
  - request
Example:
  - --get $URL
  - --get -d "tool=curl" -d "age=old" $URL
  - --get -I -d "tool=curl" $URL
---

# `--get`

When used, this option makes all data specified with --data, --data-binary or
--data-urlencode to be used in an HTTP GET request instead of the POST request
that otherwise would be used. curl appends the provided data to the URL as a
query string.

If used in combination with --head, the POST data is instead appended to the
URL with a HEAD request.
Changes to jni/curl/docs/cmdline-opts/happy-eyeballs-timeout-ms.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: happy-eyeballs-timeout-ms
Arg: <ms>
Help: Time for IPv6 before IPv4
Added: 7.59.0
Category: connection
Multi: single
See-also:
  - max-time
  - connect-timeout
Example:
  - --happy-eyeballs-timeout-ms 500 $URL
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: happy-eyeballs-timeout-ms
Arg: <ms>
Help: Time for IPv6 before IPv4
Added: 7.59.0
Category: connection timeout
Multi: single
See-also:
  - max-time
  - connect-timeout
Example:
  - --happy-eyeballs-timeout-ms 500 $URL
---
Changes to jni/curl/docs/cmdline-opts/header.md.
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
end-of-line marker, you should thus **not** add that as a part of the header
content: do not add newlines or carriage returns, they only mess things up for
you. curl passes on the verbatim string you give it without any filter or
other safe guards. That includes white space and control characters.

This option can take an argument in @filename style, which then adds a header
for each line in the input file. Using @- makes curl read the header file from
stdin. Added in 7.55.0.

Please note that most anti-spam utilities check the presence and value of
several MIME mail headers: these are `From:`, `To:`, `Date:` and `Subject:`
among others and should be added with this option.

You need --proxy-header to send custom headers intended for an HTTP
proxy. Added in 7.37.0.

Passing on a "Transfer-Encoding: chunked" header when doing an HTTP request
with a request body, makes curl send the data using chunked encoding.

**WARNING**: headers set with this option are set in all HTTP requests - even
after redirects are followed, like when told with --location. This can lead to
the header being sent to other hosts than the original host, so sensitive







|





|
|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
end-of-line marker, you should thus **not** add that as a part of the header
content: do not add newlines or carriage returns, they only mess things up for
you. curl passes on the verbatim string you give it without any filter or
other safe guards. That includes white space and control characters.

This option can take an argument in @filename style, which then adds a header
for each line in the input file. Using @- makes curl read the header file from
stdin. (Added in 7.55.0)

Please note that most anti-spam utilities check the presence and value of
several MIME mail headers: these are `From:`, `To:`, `Date:` and `Subject:`
among others and should be added with this option.

You need --proxy-header to send custom headers intended for an HTTP proxy.
(Added in 7.37.0)

Passing on a "Transfer-Encoding: chunked" header when doing an HTTP request
with a request body, makes curl send the data using chunked encoding.

**WARNING**: headers set with this option are set in all HTTP requests - even
after redirects are followed, like when told with --location. This can lead to
the header being sent to other hosts than the original host, so sensitive
Changes to jni/curl/docs/cmdline-opts/hostpubmd5.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: hostpubmd5
Arg: <md5>
Help: Acceptable MD5 hash of host public key
Protocols: SFTP SCP
Added: 7.17.1
Category: sftp scp
Multi: single
See-also:
  - hostpubsha256
Example:
  - --hostpubmd5 e5c1c49020640a5ab0f2034854c321a8 sftp://example.com/
---









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: hostpubmd5
Arg: <md5>
Help: Acceptable MD5 hash of host public key
Protocols: SFTP SCP
Added: 7.17.1
Category: sftp scp ssh
Multi: single
See-also:
  - hostpubsha256
Example:
  - --hostpubmd5 e5c1c49020640a5ab0f2034854c321a8 sftp://example.com/
---

Changes to jni/curl/docs/cmdline-opts/hostpubsha256.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: hostpubsha256
Arg: <sha256>
Help: Acceptable SHA256 hash of host public key
Protocols: SFTP SCP
Added: 7.80.0
Category: sftp scp
Multi: single
See-also:
  - hostpubmd5
Example:
  - --hostpubsha256 NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ= sftp://example.com/
---









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: hostpubsha256
Arg: <sha256>
Help: Acceptable SHA256 hash of host public key
Protocols: SFTP SCP
Added: 7.80.0
Category: sftp scp ssh
Multi: single
See-also:
  - hostpubmd5
Example:
  - --hostpubsha256 NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ= sftp://example.com/
---

Changes to jni/curl/docs/cmdline-opts/include.md.
17
18
19
20
21
22
23
24
25
26
# `--include`

Include response headers in the output. HTTP response headers can include
things like server name, cookies, date of the document, HTTP version and
more... With non-HTTP protocols, the "headers" are other server communication.

To view the request headers, consider the --verbose option.

Prior to 7.75.0 curl did not print the headers if --fail was used in
combination with this option and there was error reported by server.







<
<
<
17
18
19
20
21
22
23



# `--include`

Include response headers in the output. HTTP response headers can include
things like server name, cookies, date of the document, HTTP version and
more... With non-HTTP protocols, the "headers" are other server communication.

To view the request headers, consider the --verbose option.



Changes to jni/curl/docs/cmdline-opts/insecure.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: insecure
Short: k
Help: Allow insecure server connections
Protocols: TLS SFTP SCP
Category: tls sftp scp
Added: 7.10
Multi: boolean
See-also:
  - proxy-insecure
  - cacert
  - capath
Example:







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: insecure
Short: k
Help: Allow insecure server connections
Protocols: TLS SFTP SCP
Category: tls sftp scp ssh
Added: 7.10
Multi: boolean
See-also:
  - proxy-insecure
  - cacert
  - capath
Example:
Changes to jni/curl/docs/cmdline-opts/interface.md.
1
2
3
4
5
6
7
8
9
10
11
12
13


14
15
16
17
18
19

20

21


22

23

24

25

















---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: interface
Arg: <name>
Help: Use network INTERFACE (or address)
Category: connection
Added: 7.3
Multi: single
See-also:
  - dns-interface
Example:
  - --interface eth0 $URL


---

# `--interface`

Perform an operation using a specified interface. You can enter interface
name, IP address or hostname. An example could look like:



    curl --interface eth0:1 https://www.example.com/




On Linux it can be used to specify a **VRF**, but the binary needs to either

have **CAP_NET_RAW** or to be run as root. More information about Linux

**VRF**: https://www.kernel.org/doc/Documentation/networking/vrf.txt






















|







>
>




|
|
>

>
|
>
>

>
|
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: interface
Arg: <name>
Help: Use network interface
Category: connection
Added: 7.3
Multi: single
See-also:
  - dns-interface
Example:
  - --interface eth0 $URL
  - --interface "host!10.0.0.1" $URL
  - --interface "if!enp3s0" $URL
---

# `--interface`

Perform the operation using a specified interface. You can enter interface
name, IP address or hostname. If you prefer to be specific, you can use the
following special syntax:

## if!<name>

Interface name. If the provided name does not match an existing interface,
curl returns with error 45.

## host!<name>

IP address or hostname.

## ifhost!<interface>!<host>

Interface name and IP address or hostname. This syntax requires libcurl 8.9.0
or later.

If the provided name does not match an existing interface, curl returns with
error 45.

##

curl does not support using network interface names for this option on
Windows.

That name resolve operation if a hostname is provided does **not** use
DNS-over-HTTPS even if --doh-url is set.

On Linux this option can be used to specify a **VRF** (Virtual Routing and
Forwarding) device, but the binary then needs to either have the
**CAP_NET_RAW** capability set or to be run as root.
Added jni/curl/docs/cmdline-opts/ip-tos.md.






















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ip-tos
Arg: <string>
Help: Set IP Type of Service or Traffic Class
Added: 8.9.0
Category: connection
Protocols: All
Multi: single
See-also:
  - tcp-nodelay
  - vlan-priority
Example:
  - --ip-tos CS5 $URL
---

# `--ip-tos`

Set Type of Service (TOS) for IPv4 or Traffic Class for IPv6.

The values allowed for \<string\> can be a numeric value between 1 and 255
or one of the following:

CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, AF11, AF12, AF13, AF21, AF22, AF23,
AF31, AF32, AF33, AF41, AF42, AF43, EF, VOICE-ADMIT, ECT1, ECT0, CE, LE,
LOWCOST, LOWDELAY, THROUGHPUT, RELIABILITY, MINCOST
Changes to jni/curl/docs/cmdline-opts/ipfs-gateway.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Mark Gaiser, <markg85@gmail.com>
SPDX-License-Identifier: curl
Long: ipfs-gateway
Arg: <URL>
Help: Gateway for IPFS
Protocols: IPFS
Added: 8.4.0
Category: ipfs
Multi: single
See-also:
  - help
  - manual
Example:
  - --ipfs-gateway $URL ipfs://
---








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Mark Gaiser, <markg85@gmail.com>
SPDX-License-Identifier: curl
Long: ipfs-gateway
Arg: <URL>
Help: Gateway for IPFS
Protocols: IPFS
Added: 8.4.0
Category: curl
Multi: single
See-also:
  - help
  - manual
Example:
  - --ipfs-gateway $URL ipfs://
---
Added jni/curl/docs/cmdline-opts/keepalive-cnt.md.






















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Long: keepalive-cnt
Arg: <integer>
Help: Maximum number of keepalive probes
Added: 8.9.0
Category: connection
Multi: single
See-also:
  - keepalive-time
  - no-keepalive
Example:
  - --keepalive-cnt 3 $URL
---

# `--keepalive-cnt`

Set the maximum number of keepalive probes TCP should send but get no response
before dropping the connection. This option is usually used in conjunction
with --keepalive-time.

This option is supported on Linux, *BSD/macOS, Windows \>=10.0.16299, Solaris
11.4, and recent AIX, HP-UX and more. This option has no effect if
--no-keepalive is used.

If unspecified, the option defaults to 9.
Changes to jni/curl/docs/cmdline-opts/keepalive-time.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
24


25
26
27
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: keepalive-time
Arg: <seconds>
Help: Interval time for keepalive probes
Added: 7.18.0
Category: connection
Multi: single
See-also:
  - no-keepalive

  - max-time
Example:
  - --keepalive-time 20 $URL
---

# `--keepalive-time`

Set the time a connection needs to remain idle before sending keepalive probes
and the time between individual keepalive probes. It is currently effective on
operating systems offering the `TCP_KEEPIDLE` and `TCP_KEEPINTVL` socket
options (meaning Linux, recent AIX, HP-UX and more). Keepalive is used by the
TCP stack to detect broken networks on idle connections. The number of missed
keepalive probes before declaring the connection down is OS dependent and is


commonly 9 or 10. This option has no effect if --no-keepalive is used.

If unspecified, the option defaults to 60 seconds.







|



>










|
|
|
>
>
|


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: keepalive-time
Arg: <seconds>
Help: Interval time for keepalive probes
Added: 7.18.0
Category: connection timeout
Multi: single
See-also:
  - no-keepalive
  - keepalive-cnt
  - max-time
Example:
  - --keepalive-time 20 $URL
---

# `--keepalive-time`

Set the time a connection needs to remain idle before sending keepalive probes
and the time between individual keepalive probes. It is currently effective on
operating systems offering the `TCP_KEEPIDLE` and `TCP_KEEPINTVL` socket
options (meaning Linux, *BSD/macOS, Windows, Solaris, and recent AIX, HP-UX and more).
Keepalive is used by the TCP stack to detect broken networks on idle connections.
The number of missed keepalive probes before declaring the connection down is OS
dependent and is commonly 8 (*BSD/macOS/AIX), 9 (Linux/AIX) or 5/10 (Windows), and
this number can be changed by specifying the curl option `keepalive-cnt`.
Note that this option has no effect if --no-keepalive is used.

If unspecified, the option defaults to 60 seconds.
Changes to jni/curl/docs/cmdline-opts/libcurl.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: libcurl
Arg: <file>
Help: Generate libcurl code for this command line
Added: 7.16.1
Category: curl
Multi: single
Scope: global
See-also:
  - verbose
Example:
  - --libcurl client.c $URL
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: libcurl
Arg: <file>
Help: Generate libcurl code for this command line
Added: 7.16.1
Category: curl global
Multi: single
Scope: global
See-also:
  - verbose
Example:
  - --libcurl client.c $URL
---
Changes to jni/curl/docs/cmdline-opts/location-trusted.md.
1
2
3
4
5
6
7
8
9
10
11
12
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: location-trusted
Help: Like --location, but send auth to other hosts
Protocols: HTTP
Category: http auth
Added: 7.10.4
Multi: boolean
See-also:
  - user
Example:




|







1
2
3
4
5
6
7
8
9
10
11
12
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: location-trusted
Help: As --location, but send auth to other hosts
Protocols: HTTP
Category: http auth
Added: 7.10.4
Multi: boolean
See-also:
  - user
Example:
Changes to jni/curl/docs/cmdline-opts/login-options.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: login-options
Arg: <options>
Protocols: IMAP LDAP POP3 SMTP
Help: Server login options
Added: 7.34.0
Category: imap pop3 smtp auth
Multi: single
See-also:
  - user
Example:
  - --login-options 'AUTH=*' imap://example.com
---









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: login-options
Arg: <options>
Protocols: IMAP LDAP POP3 SMTP
Help: Server login options
Added: 7.34.0
Category: imap pop3 smtp auth ldap
Multi: single
See-also:
  - user
Example:
  - --login-options 'AUTH=*' imap://example.com
---

Changes to jni/curl/docs/cmdline-opts/mail-auth.md.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Added: 7.25.0
Category: smtp
Multi: single
See-also:
  - mail-rcpt
  - mail-from
Example:
  - --mail-auth user@example.come -T mail smtp://example.com/
---

# `--mail-auth`

Specify a single address. This is used to specify the authentication address
(identity) of a submitted message that is being relayed to another server.







|






8
9
10
11
12
13
14
15
16
17
18
19
20
21
Added: 7.25.0
Category: smtp
Multi: single
See-also:
  - mail-rcpt
  - mail-from
Example:
  - --mail-auth user@example.com -T mail smtp://example.com/
---

# `--mail-auth`

Specify a single address. This is used to specify the authentication address
(identity) of a submitted message that is being relayed to another server.
Changes to jni/curl/docs/cmdline-opts/max-time.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: max-time
Short: m
Arg: <seconds>
Help: Maximum time allowed for transfer
Category: connection
Added: 4.0
Multi: single
See-also:
  - connect-timeout
  - retry-max-time
Example:
  - --max-time 10 $URL







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: max-time
Short: m
Arg: <seconds>
Help: Maximum time allowed for transfer
Category: connection timeout
Added: 4.0
Multi: single
See-also:
  - connect-timeout
  - retry-max-time
Example:
  - --max-time 10 $URL
Changes to jni/curl/docs/cmdline-opts/metalink.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: metalink
Help: Process given URLs as metalink XML file
Added: 7.27.0
Category: misc
Multi: single
See-also:
  - parallel
Example:
  - --metalink file $URL
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: metalink
Help: Process given URLs as metalink XML file
Added: 7.27.0
Category: deprecated
Multi: single
See-also:
  - parallel
Example:
  - --metalink file $URL
---

Added jni/curl/docs/cmdline-opts/mptcp.md.






























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
---
c: Copyright (C) Dorian Craps, <dorian.craps@student.vinci.be>
SPDX-License-Identifier: curl
Long: mptcp
Added: 8.9.0
Help: Enable Multipath TCP
Category: connection
Multi: boolean
See-also:
  - tcp-fastopen
Example:
  - --mptcp $URL
---

# `--mptcp`

Enables the use of Multipath TCP (MPTCP) for connections. MPTCP is an extension
to the standard TCP that allows multiple TCP streams over different network
paths between the same source and destination. This can enhance bandwidth and
improve reliability by using multiple paths simultaneously.

MPTCP is beneficial in networks where multiple paths exist between clients and
servers, such as mobile networks where a device may switch between WiFi and
cellular data or in wired networks with multiple Internet Service Providers.

This option is currently only supported on Linux starting from kernel 5.6. Only
TCP connections are modified, hence this option does not effect HTTP/3 (QUIC)
or UDP connections.

The server curl connects to must also support MPTCP. If not, the connection
seamlessly falls back to TCP.
Changes to jni/curl/docs/cmdline-opts/netrc-file.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: netrc-file
Help: Specify FILE for netrc
Arg: <filename>
Added: 7.21.5
Mutexed: netrc
Category: curl
Multi: single
See-also:
  - netrc
  - user
  - config
Example:
  - --netrc-file netrc $URL








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: netrc-file
Help: Specify FILE for netrc
Arg: <filename>
Added: 7.21.5
Mutexed: netrc
Category: auth
Multi: single
See-also:
  - netrc
  - user
  - config
Example:
  - --netrc-file netrc $URL
Changes to jni/curl/docs/cmdline-opts/netrc-optional.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: netrc-optional
Help: Use either .netrc or URL
Mutexed: netrc
Category: curl
Added: 7.9.8
Multi: boolean
See-also:
  - netrc-file
Example:
  - --netrc-optional $URL
---






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: netrc-optional
Help: Use either .netrc or URL
Mutexed: netrc
Category: auth
Added: 7.9.8
Multi: boolean
See-also:
  - netrc-file
Example:
  - --netrc-optional $URL
---
Changes to jni/curl/docs/cmdline-opts/netrc.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: netrc
Short: n
Help: Must read .netrc for username and password
Category: curl
Added: 4.6
Mutexed: netrc-file netrc-optional
Multi: boolean
See-also:
  - netrc-file
  - config
  - user






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: netrc
Short: n
Help: Must read .netrc for username and password
Category: auth
Added: 4.6
Mutexed: netrc-file netrc-optional
Multi: boolean
See-also:
  - netrc-file
  - config
  - user
Changes to jni/curl/docs/cmdline-opts/next.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: :
Long: next
Tags:
Protocols:
Added: 7.36.0
Magic: divider
Help: Make next URL use its separate set of options
Category: curl
Multi: append
See-also:
  - parallel
  - config
Example:
  - $URL --next -d postthis www2.example.com









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: :
Long: next
Tags:
Protocols:
Added: 7.36.0
Magic: divider
Help: Make next URL use separate options
Category: curl
Multi: append
See-also:
  - parallel
  - config
Example:
  - $URL --next -d postthis www2.example.com
Changes to jni/curl/docs/cmdline-opts/no-buffer.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: no-buffer
Short: N
Help: Disable buffering of the output stream
Category: curl
Added: 6.5
Multi: boolean
See-also:
  - progress-bar
Example:
  - --no-buffer $URL
---






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: no-buffer
Short: N
Help: Disable buffering of the output stream
Category: output
Added: 6.5
Multi: boolean
See-also:
  - progress-bar
Example:
  - --no-buffer $URL
---
Changes to jni/curl/docs/cmdline-opts/no-clobber.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: no-clobber
Help: Do not overwrite files that already exist
Category: curl output
Added: 7.83.0
Multi: boolean
See-also:
  - output
  - remote-name
Example:
  - --no-clobber --output local/dir/file $URL





|







1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: no-clobber
Help: Do not overwrite files that already exist
Category: output
Added: 7.83.0
Multi: boolean
See-also:
  - output
  - remote-name
Example:
  - --no-clobber --output local/dir/file $URL
Changes to jni/curl/docs/cmdline-opts/no-keepalive.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: no-keepalive
Help: Disable TCP keepalive on the connection
Category: connection
Added: 7.18.0
Multi: boolean
See-also:
  - keepalive-time

Example:
  - --no-keepalive $URL
---

# `--no-keepalive`

Disables the use of keepalive messages on the TCP connection. curl otherwise










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: no-keepalive
Help: Disable TCP keepalive on the connection
Category: connection
Added: 7.18.0
Multi: boolean
See-also:
  - keepalive-time
  - keepalive-cnt
Example:
  - --no-keepalive $URL
---

# `--no-keepalive`

Disables the use of keepalive messages on the TCP connection. curl otherwise
Changes to jni/curl/docs/cmdline-opts/no-npn.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: no-npn
Tags: Versions HTTP/2
Protocols: HTTPS
Added: 7.36.0
Mutexed:
Requires: TLS
Help: Disable the NPN TLS extension
Category: tls http
Multi: boolean
See-also:
  - no-alpn
  - http2
Example:
  - --no-npn $URL
---










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: no-npn
Tags: Versions HTTP/2
Protocols: HTTPS
Added: 7.36.0
Mutexed:
Requires: TLS
Help: Disable the NPN TLS extension
Category: deprecated
Multi: boolean
See-also:
  - no-alpn
  - http2
Example:
  - --no-npn $URL
---
Changes to jni/curl/docs/cmdline-opts/ntlm-wb.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ntlm-wb
Help: HTTP NTLM authentication with winbind
Protocols: HTTP
Category: auth http
Added: 7.22.0
Multi: mutex
See-also:
  - ntlm
  - proxy-ntlm
Example:
  - --ntlm-wb -u user:password $URL






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ntlm-wb
Help: HTTP NTLM authentication with winbind
Protocols: HTTP
Category: deprecated
Added: 7.22.0
Multi: mutex
See-also:
  - ntlm
  - proxy-ntlm
Example:
  - --ntlm-wb -u user:password $URL
Changes to jni/curl/docs/cmdline-opts/oauth2-bearer.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: oauth2-bearer
Help: OAuth 2 Bearer Token
Arg: <token>
Protocols: IMAP LDAP POP3 SMTP HTTP
Category: auth
Added: 7.33.0
Multi: single
See-also:
  - basic
  - ntlm
  - digest
Example:







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: oauth2-bearer
Help: OAuth 2 Bearer Token
Arg: <token>
Protocols: IMAP LDAP POP3 SMTP HTTP
Category: auth imap pop3 smtp ldap
Added: 7.33.0
Multi: single
See-also:
  - basic
  - ntlm
  - digest
Example:
Changes to jni/curl/docs/cmdline-opts/output-dir.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: output-dir
Arg: <dir>
Help: Directory to save files in
Added: 7.73.0
Category: curl
Multi: single
See-also:
  - remote-name
  - remote-header-name
Example:
  - --output-dir "tmp" -O $URL
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: output-dir
Arg: <dir>
Help: Directory to save files in
Added: 7.73.0
Category: output
Multi: single
See-also:
  - remote-name
  - remote-header-name
Example:
  - --output-dir "tmp" -O $URL
---
Changes to jni/curl/docs/cmdline-opts/output.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: output
Arg: <file>
Short: o
Help: Write to file instead of stdout
Category: important curl
Added: 4.0
Multi: append
See-also:
  - remote-name
  - remote-name-all
  - remote-header-name
Example:
  - -o file $URL
  - "http://{one,two}.example.com" -o "file_#1.txt"







|

|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: output
Arg: <file>
Short: o
Help: Write to file instead of stdout
Category: important output
Added: 4.0
Multi: per-URL
See-also:
  - remote-name
  - remote-name-all
  - remote-header-name
Example:
  - -o file $URL
  - "http://{one,two}.example.com" -o "file_#1.txt"
Changes to jni/curl/docs/cmdline-opts/parallel-immediate.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21



22
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: parallel-immediate
Help: Do not wait for multiplexing (with --parallel)
Added: 7.68.0
Category: connection curl
Multi: boolean
Scope: global
See-also:
  - parallel
  - parallel-max
Example:
  - --parallel-immediate -Z $URL -o file1 $URL -o file2
---

# `--parallel-immediate`

When doing parallel transfers, this option instructs curl that it should
rather prefer opening up more connections in parallel at once rather than
waiting to see if new transfers can be added as multiplexed streams on another



connection.




|

|











|
|
|
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: parallel-immediate
Help: Do not wait for multiplexing
Added: 7.68.0
Category: connection curl global
Multi: boolean
Scope: global
See-also:
  - parallel
  - parallel-max
Example:
  - --parallel-immediate -Z $URL -o file1 $URL -o file2
---

# `--parallel-immediate`

When doing parallel transfers, this option instructs curl to prefer opening up
more connections in parallel at once rather than waiting to see if new
transfers can be added as multiplexed streams on another connection.

By default, without this option set, curl prefers to wait a little and
multiplex new transfers over existing connections. It keeps the number of
connections low at the expense of risking a slightly slower transfer startup.
Changes to jni/curl/docs/cmdline-opts/parallel-max.md.
1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: parallel-max
Arg: <num>
Help: Maximum concurrency for parallel transfers
Added: 7.66.0
Category: connection curl
Multi: single

See-also:
  - parallel
Example:
  - --parallel-max 100 -Z $URL ftp://example.com/
---

# `--parallel-max`

When asked to do parallel transfers, using --parallel, this option controls
the maximum amount of transfers to do simultaneously.

This option is global and does not need to be specified for each use of
--next.

The default is 50.







|

>











<
<
<
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21



22
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: parallel-max
Arg: <num>
Help: Maximum concurrency for parallel transfers
Added: 7.66.0
Category: connection curl global
Multi: single
Scope: global
See-also:
  - parallel
Example:
  - --parallel-max 100 -Z $URL ftp://example.com/
---

# `--parallel-max`

When asked to do parallel transfers, using --parallel, this option controls
the maximum amount of transfers to do simultaneously.




The default is 50. 300 is the largest supported value.
Changes to jni/curl/docs/cmdline-opts/parallel.md.
1
2
3
4
5
6
7
8
9
10
11
12
13


14
15
16
17
18
19
20



21






---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: Z
Long: parallel
Help: Perform transfers in parallel
Added: 7.66.0
Category: connection curl
Multi: boolean
Scope: global
See-also:
  - next
  - verbose


Example:
  - --parallel $URL -o file1 $URL -o file2
---

# `--parallel`

Makes curl perform its transfers in parallel as compared to the regular serial



manner.













|





>
>






|
>
>
>
|
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: Z
Long: parallel
Help: Perform transfers in parallel
Added: 7.66.0
Category: connection curl global
Multi: boolean
Scope: global
See-also:
  - next
  - verbose
  - parallel-max
  - parallel-immediate
Example:
  - --parallel $URL -o file1 $URL -o file2
---

# `--parallel`

Makes curl perform all transfers in parallel as compared to the regular serial
manner. Parallel transfer means that curl runs up to N concurrent transfers
simultaneously and if there are more than N transfers to handle, it starts new
ones when earlier transfers finish.

With parallel transfers, the progress meter output is different than when
doing serial transfers, as it then displays the transfer status for multiple
transfers in a single line.

The maximum amount of concurrent transfers is set with --parallel-max and it
defaults to 50.
Changes to jni/curl/docs/cmdline-opts/pass.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: pass
Arg: <phrase>
Help: Pass phrase for the private key
Protocols: SSH TLS
Category: ssh tls auth
Added: 7.9.3
Multi: single
See-also:
  - key
  - user





|







1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: pass
Arg: <phrase>
Help: Passphrase for the private key
Protocols: SSH TLS
Category: ssh tls auth
Added: 7.9.3
Multi: single
See-also:
  - key
  - user
Changes to jni/curl/docs/cmdline-opts/pinnedpubkey.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: pinnedpubkey
Arg: <hashes>
Help: FILE/HASHES Public key to verify peer against
Protocols: TLS
Category: tls
Added: 7.39.0
Multi: single
See-also:
  - hostpubsha256
Example:





|







1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: pinnedpubkey
Arg: <hashes>
Help: Public key to verify peer against
Protocols: TLS
Category: tls
Added: 7.39.0
Multi: single
See-also:
  - hostpubsha256
Example:
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44

This option is independent of option --insecure. If you use both options
together then the peer is still verified by public key.

PEM/DER support:

OpenSSL and GnuTLS (added in 7.39.0), wolfSSL (added in 7.43.0), mbedTLS
(added in 7.47.0), Secure Transport macOS 10.7+/iOS 10+ (7.54.1), Schannel
(7.58.1)

sha256 support:

OpenSSL, GnuTLS and wolfSSL (added in 7.44.0), mbedTLS (added in 7.47.0),
Secure Transport macOS 10.7+/iOS 10+ (7.54.1), Schannel (7.58.1)


Other SSL backends not supported.







|
|




|
>


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

This option is independent of option --insecure. If you use both options
together then the peer is still verified by public key.

PEM/DER support:

OpenSSL and GnuTLS (added in 7.39.0), wolfSSL (added in 7.43.0), mbedTLS
(added in 7.47.0), Secure Transport macOS 10.7+/iOS 10+ (added in 7.54.1),
Schannel (added in 7.58.1)

sha256 support:

OpenSSL, GnuTLS and wolfSSL (added in 7.44.0), mbedTLS (added in 7.47.0),
Secure Transport macOS 10.7+/iOS 10+ (added in 7.54.1), Schannel
(added in 7.58.1)

Other SSL backends not supported.
Changes to jni/curl/docs/cmdline-opts/progress-bar.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: #
Long: progress-bar
Help: Display transfer progress as a bar
Category: verbose
Added: 5.10
Multi: boolean
Scope: global
See-also:
  - styled-output
Example:
  - -# -O $URL






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: #
Long: progress-bar
Help: Display transfer progress as a bar
Category: verbose global
Added: 5.10
Multi: boolean
Scope: global
See-also:
  - styled-output
Example:
  - -# -O $URL
Changes to jni/curl/docs/cmdline-opts/proto-redir.md.
18
19
20
21
22
23
24
25
26
27
Limit what protocols to allow on redirects. Protocols denied by --proto are
not overridden by this option. See --proto for how protocols are represented.

Example, allow only HTTP and HTTPS on redirect:

    curl --proto-redir -all,http,https http://example.com

By default curl only allows HTTP, HTTPS, FTP and FTPS on redirects (added in
7.65.2). Specifying *all* or *+all* enables all protocols on redirects, which
is not good for security.







|
|
|
18
19
20
21
22
23
24
25
26
27
Limit what protocols to allow on redirects. Protocols denied by --proto are
not overridden by this option. See --proto for how protocols are represented.

Example, allow only HTTP and HTTPS on redirect:

    curl --proto-redir -all,http,https http://example.com

By default curl only allows HTTP, HTTPS, FTP and FTPS on redirects
(added in 7.65.2). Specifying *all* or *+all* enables all protocols on
redirects, which is not good for security.
Changes to jni/curl/docs/cmdline-opts/proxy-ca-native.md.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Added: 8.2.0
Multi: boolean
See-also:
  - cacert
  - capath
  - insecure
Example:
  - --ca-native $URL
---

# `--proxy-ca-native`

Use the CA store from the native operating system to verify the HTTPS proxy.
By default, curl uses a CA store provided in a single file or directory, but
when using this option it interfaces the operating system's own vault.







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Added: 8.2.0
Multi: boolean
See-also:
  - cacert
  - capath
  - insecure
Example:
  - --proxy-ca-native $URL
---

# `--proxy-ca-native`

Use the CA store from the native operating system to verify the HTTPS proxy.
By default, curl uses a CA store provided in a single file or directory, but
when using this option it interfaces the operating system's own vault.
Changes to jni/curl/docs/cmdline-opts/proxy-cacert.md.
14
15
16
17
18
19
20






21
  - proxy
Example:
  - --proxy-cacert CA-file.txt -x https://proxy $URL
---

# `--proxy-cacert`







Same as --cacert but used in HTTPS proxy context.







>
>
>
>
>
>
|
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  - proxy
Example:
  - --proxy-cacert CA-file.txt -x https://proxy $URL
---

# `--proxy-cacert`

Use the specified certificate file to verify the HTTPS proxy. The file may
contain multiple CA certificates. The certificate(s) must be in PEM format.

This allows you to use a different trust for the proxy compared to the remote
server connected to via the proxy.

Equivalent to --cacert but used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-cert-type.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17







18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-cert-type
Arg: <type>
Added: 7.52.0
Help: Client certificate type for HTTPS proxy
Category: proxy tls
Multi: single
See-also:
  - proxy-cert

Example:
  - --proxy-cert-type PEM --proxy-cert file -x https://proxy $URL
---

# `--proxy-cert-type`








Same as --cert-type but used in HTTPS proxy context.











>






>
>
>
>
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-cert-type
Arg: <type>
Added: 7.52.0
Help: Client certificate type for HTTPS proxy
Category: proxy tls
Multi: single
See-also:
  - proxy-cert
  - proxy-key
Example:
  - --proxy-cert-type PEM --proxy-cert file -x https://proxy $URL
---

# `--proxy-cert-type`

Set type of the provided client certificate when using HTTPS proxy. PEM, DER,
ENG and P12 are recognized types.

The default type depends on the TLS backend and is usually PEM, however for
Secure Transport and Schannel it is P12. If --proxy-cert is a pkcs11: URI then
ENG is the default type.

Equivalent to --cert-type but used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-cert.md.
1
2
3
4
5
6
7
8
9
10


11
12
13
14
15
16
17






18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-cert
Arg: <cert[:passwd]>
Help: Set client certificate for proxy
Added: 7.52.0
Category: proxy tls
Multi: single
See-also:


  - proxy-cert-type
Example:
  - --proxy-cert file -x https://proxy $URL
---

# `--proxy-cert`







Same as --cert but used in HTTPS proxy context.










>
>







>
>
>
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-cert
Arg: <cert[:passwd]>
Help: Set client certificate for proxy
Added: 7.52.0
Category: proxy tls
Multi: single
See-also:
  - proxy
  - proxy-key
  - proxy-cert-type
Example:
  - --proxy-cert file -x https://proxy $URL
---

# `--proxy-cert`

Use the specified client certificate file when communicating with an HTTPS
proxy. The certificate must be in PKCS#12 format if using Secure Transport, or
PEM format if using any other engine. If the optional password is not
specified, it is queried for on the terminal. Use --proxy-key to provide the
private key.

This option is the equivalent to --cert but used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-crlfile.md.
12
13
14
15
16
17
18




19
  - proxy
Example:
  - --proxy-crlfile rejects.txt -x https://proxy $URL
---

# `--proxy-crlfile`





Same as --crlfile but used in HTTPS proxy context.







>
>
>
>
|
12
13
14
15
16
17
18
19
20
21
22
23
  - proxy
Example:
  - --proxy-crlfile rejects.txt -x https://proxy $URL
---

# `--proxy-crlfile`

Provide filename for a PEM formatted file with a Certificate Revocation List
that specifies peer certificates that are considered revoked when
communicating with an HTTPS proxy.

Equivalent to --crlfile but only used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-key-type.md.
12
13
14
15
16
17
18



19
  - proxy
Example:
  - --proxy-key-type DER --proxy-key here -x https://proxy $URL
---

# `--proxy-key-type`




Same as --key-type but used in HTTPS proxy context.







>
>
>
|
12
13
14
15
16
17
18
19
20
21
22
  - proxy
Example:
  - --proxy-key-type DER --proxy-key here -x https://proxy $URL
---

# `--proxy-key-type`

Specify the private key file type your --proxy-key provided private key uses.
DER, PEM, and ENG are supported. If not specified, PEM is assumed.

Equivalent to --key-type but used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-key.md.
12
13
14
15
16
17
18


19
  - proxy
Example:
  - --proxy-key here -x https://proxy $URL
---

# `--proxy-key`



Same as --key but used in HTTPS proxy context.







>
>
|
12
13
14
15
16
17
18
19
20
21
  - proxy
Example:
  - --proxy-key here -x https://proxy $URL
---

# `--proxy-key`

Specify the filename for your private key when using client certificates with
your HTTPS proxy. This option is the equivalent to --key but used in HTTPS
proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-negotiate.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-negotiate
Help: HTTP Negotiate (SPNEGO) auth with the proxy
Added: 7.17.1
Category: proxy auth
Multi: mutex
See-also:
  - proxy-anyauth
  - proxy-basic

Example:
  - --proxy-negotiate --proxy-user user:passwd -x proxy $URL
---

# `--proxy-negotiate`

Use HTTP Negotiate (SPNEGO) authentication when communicating with the given











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-negotiate
Help: HTTP Negotiate (SPNEGO) auth with the proxy
Added: 7.17.1
Category: proxy auth
Multi: mutex
See-also:
  - proxy-anyauth
  - proxy-basic
  - proxy-service-name
Example:
  - --proxy-negotiate --proxy-user user:passwd -x proxy $URL
---

# `--proxy-negotiate`

Use HTTP Negotiate (SPNEGO) authentication when communicating with the given
Changes to jni/curl/docs/cmdline-opts/proxy-ntlm.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-ntlm
Help: NTLM authentication with the proxy
Category: proxy auth
Added: 7.10.7
Multi: mutex
See-also:
  - proxy-negotiate
  - proxy-anyauth

Example:
  - --proxy-ntlm --proxy-user user:passwd -x http://proxy $URL
---

# `--proxy-ntlm`

Use HTTP NTLM authentication when communicating with the given proxy. Use











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-ntlm
Help: NTLM authentication with the proxy
Category: proxy auth
Added: 7.10.7
Multi: mutex
See-also:
  - proxy-negotiate
  - proxy-anyauth
  - proxy-user
Example:
  - --proxy-ntlm --proxy-user user:passwd -x http://proxy $URL
---

# `--proxy-ntlm`

Use HTTP NTLM authentication when communicating with the given proxy. Use
Changes to jni/curl/docs/cmdline-opts/proxy-pass.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-pass
Arg: <phrase>
Help: Pass phrase for the private key for HTTPS proxy
Added: 7.52.0
Category: proxy tls auth
Multi: single
See-also:
  - proxy
  - proxy-key
Example:
  - --proxy-pass secret --proxy-key here -x https://proxy $URL
---

# `--proxy-pass`



Same as --pass but used in HTTPS proxy context.





|












>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-pass
Arg: <phrase>
Help: Passphrase for private key for HTTPS proxy
Added: 7.52.0
Category: proxy tls auth
Multi: single
See-also:
  - proxy
  - proxy-key
Example:
  - --proxy-pass secret --proxy-key here -x https://proxy $URL
---

# `--proxy-pass`

Passphrase for the private key for HTTPS proxy client certificate.

Equivalent to --pass but used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-service-name.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-service-name
Arg: <name>
Help: SPNEGO proxy service name
Added: 7.43.0
Category: proxy tls
Multi: single
See-also:
  - service-name
  - proxy

Example:
  - --proxy-service-name "shrubbery" -x proxy $URL
---

# `--proxy-service-name`

Set the service name for proxy negotiation.












>






|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-service-name
Arg: <name>
Help: SPNEGO proxy service name
Added: 7.43.0
Category: proxy tls
Multi: single
See-also:
  - service-name
  - proxy
  - proxy-negotiate
Example:
  - --proxy-service-name "shrubbery" -x proxy $URL
---

# `--proxy-service-name`

Set the service name for SPNEGO when doing proxy authentication.
Changes to jni/curl/docs/cmdline-opts/proxy-ssl-allow-beast.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17











18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-ssl-allow-beast
Help: Allow security flaw for interop for HTTPS proxy
Added: 7.52.0
Category: proxy tls
Multi: boolean
See-also:
  - ssl-allow-beast
  - proxy
Example:
  - --proxy-ssl-allow-beast -x https://proxy $URL
---

# `--proxy-ssl-allow-beast`












Same as --ssl-allow-beast but used in HTTPS proxy context.




|












>
>
>
>
>
>
>
>
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-ssl-allow-beast
Help: Allow this security flaw for HTTPS proxy
Added: 7.52.0
Category: proxy tls
Multi: boolean
See-also:
  - ssl-allow-beast
  - proxy
Example:
  - --proxy-ssl-allow-beast -x https://proxy $URL
---

# `--proxy-ssl-allow-beast`

Do not work around a security flaw in the TLS1.0 protocol known as BEAST when
communicating to an HTTPS proxy. If this option is not used, the TLS layer may
use workarounds known to cause interoperability problems with some older
server implementations.

This option only changes how curl does TLS 1.0 with an HTTPS proxy and has no
effect on later TLS versions.

**WARNING**: this option loosens the TLS security, and by using this flag you
ask for exactly that.

Equivalent to --ssl-allow-beast but used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-tlsauthtype.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18




19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-tlsauthtype
Arg: <type>
Help: TLS authentication type for HTTPS proxy
Added: 7.52.0
Category: proxy tls auth
Multi: single
See-also:
  - proxy
  - proxy-tlsuser

Example:
  - --proxy-tlsauthtype SRP -x https://proxy $URL
---

# `--proxy-tlsauthtype`





Same as --tlsauthtype but used in HTTPS proxy context.












>






>
>
>
>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proxy-tlsauthtype
Arg: <type>
Help: TLS authentication type for HTTPS proxy
Added: 7.52.0
Category: proxy tls auth
Multi: single
See-also:
  - proxy
  - proxy-tlsuser
  - proxy-tlspassword
Example:
  - --proxy-tlsauthtype SRP -x https://proxy $URL
---

# `--proxy-tlsauthtype`

Set TLS authentication type with HTTPS proxy. The only supported option is
`SRP`, for TLS-SRP (RFC 5054). This option works only if the underlying
libcurl is built with TLS-SRP support.

Equivalent to --tlsauthtype but used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-tlspassword.md.
12
13
14
15
16
17
18






19
  - proxy-tlsuser
Example:
  - --proxy-tlspassword passwd -x https://proxy $URL
---

# `--proxy-tlspassword`







Same as --tlspassword but used in HTTPS proxy context.







>
>
>
>
>
>
|
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - proxy-tlsuser
Example:
  - --proxy-tlspassword passwd -x https://proxy $URL
---

# `--proxy-tlspassword`

Set password to use with the TLS authentication method specified with
--proxy-tlsauthtype when using HTTPS proxy. Requires that --proxy-tlsuser is
set.

This option does not work with TLS 1.3.

Equivalent to --tlspassword but used in HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/proxy-tlsuser.md.
12
13
14
15
16
17
18



19

  - proxy-tlspassword
Example:
  - --proxy-tlsuser smith -x https://proxy $URL
---

# `--proxy-tlsuser`




Same as --tlsuser but used in HTTPS proxy context.








>
>
>
|
>
12
13
14
15
16
17
18
19
20
21
22
23
  - proxy-tlspassword
Example:
  - --proxy-tlsuser smith -x https://proxy $URL
---

# `--proxy-tlsuser`

Set username for use for HTTPS proxy with the TLS authentication method
specified with --proxy-tlsauthtype. Requires that --proxy-tlspassword also is
set.

This option does not work with TLS 1.3.
Changes to jni/curl/docs/cmdline-opts/proxy-tlsv1.md.
10
11
12
13
14
15
16



17
  - proxy
Example:
  - --proxy-tlsv1 -x https://proxy $URL
---

# `--proxy-tlsv1`




Same as --tlsv1 but used in HTTPS proxy context.







>
>
>
|
10
11
12
13
14
15
16
17
18
19
20
  - proxy
Example:
  - --proxy-tlsv1 -x https://proxy $URL
---

# `--proxy-tlsv1`

Use at least TLS version 1.x when negotiating with an HTTPS proxy. That means
TLS version 1.0 or higher

Equivalent to --tlsv1 but for an HTTPS proxy context.
Changes to jni/curl/docs/cmdline-opts/pubkey.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: pubkey
Arg: <key>
Protocols: SFTP SCP
Help: SSH Public key filename
Category: sftp scp auth
Added: 7.16.2
Multi: single
See-also:
  - pass
Example:
  - --pubkey file.pub sftp://example.com/
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: pubkey
Arg: <key>
Protocols: SFTP SCP
Help: SSH Public key filename
Category: sftp scp ssh auth
Added: 7.16.2
Multi: single
See-also:
  - pass
Example:
  - --pubkey file.pub sftp://example.com/
---
Changes to jni/curl/docs/cmdline-opts/random-file.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: random-file
Arg: <file>
Help: File for reading random data from
Category: misc
Added: 7.7
Multi: single
See-also:
  - egd-file
Example:
  - --random-file rubbish $URL
---






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: random-file
Arg: <file>
Help: File for reading random data from
Category: deprecated
Added: 7.7
Multi: single
See-also:
  - egd-file
Example:
  - --random-file rubbish $URL
---
Changes to jni/curl/docs/cmdline-opts/rate.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: rate
Arg: <max request rate>
Help: Request rate for serial transfers
Category: connection
Added: 7.84.0
Multi: single
Scope: global
See-also:
  - limit-rate
  - retry-delay
Example:






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: rate
Arg: <max request rate>
Help: Request rate for serial transfers
Category: connection global
Added: 7.84.0
Multi: single
Scope: global
See-also:
  - limit-rate
  - retry-delay
Example:
Changes to jni/curl/docs/cmdline-opts/remote-name.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: remote-name
Short: O
Help: Write output to file named as remote file
Category: important output
Added: 4.0
Multi: append
See-also:
  - remote-name-all
  - output-dir
  - remote-header-name
Example:
  - -O https://example.com/filename

---

# `--remote-name`

Write output to a local file named like the remote file we get. (Only the file
part of the remote file is used, the path is cut off.)









|






>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: remote-name
Short: O
Help: Write output to file named as remote file
Category: important output
Added: 4.0
Multi: per-URL
See-also:
  - remote-name-all
  - output-dir
  - remote-header-name
Example:
  - -O https://example.com/filename
  - -O https://example.com/filename -O https://example.com/file2
---

# `--remote-name`

Write output to a local file named like the remote file we get. (Only the file
part of the remote file is used, the path is cut off.)

Changes to jni/curl/docs/cmdline-opts/remove-on-error.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: remove-on-error
Help: Remove output file on errors
Category: curl
Added: 7.83.0
Multi: boolean
See-also:
  - fail
Example:
  - --remove-on-error -o output $URL
---





|







1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: remove-on-error
Help: Remove output file on errors
Category: output
Added: 7.83.0
Multi: boolean
See-also:
  - fail
Example:
  - --remove-on-error -o output $URL
---
Changes to jni/curl/docs/cmdline-opts/request.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: request
Short: X
Arg: <method>
Help: Specify request method to use
Category: connection
Added: 6.0
Multi: single
See-also:
  - request-target
Example:
  - -X "DELETE" $URL
  - -X NLST ftp://example.com/
---

# `--request`

Change the method to use when starting the transfer.

curl passes on the verbatim string you give it its the request without any
filter or other safe guards. That includes white space and control characters.

## HTTP
Specifies a custom request method to use when communicating with the HTTP
server. The specified request method is used instead of the method otherwise
used (which defaults to *GET*). Read the HTTP 1.1 specification for details
and explanations. Common additional HTTP requests include *PUT* and *DELETE*,







|













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: request
Short: X
Arg: <method>
Help: Specify request method to use
Category: connection pop3 ftp imap smtp
Added: 6.0
Multi: single
See-also:
  - request-target
Example:
  - -X "DELETE" $URL
  - -X NLST ftp://example.com/
---

# `--request`

Change the method to use when starting the transfer.

curl passes on the verbatim string you give it in the request without any
filter or other safe guards. That includes white space and control characters.

## HTTP
Specifies a custom request method to use when communicating with the HTTP
server. The specified request method is used instead of the method otherwise
used (which defaults to *GET*). Read the HTTP 1.1 specification for details
and explanations. Common additional HTTP requests include *PUT* and *DELETE*,
Changes to jni/curl/docs/cmdline-opts/resolve.md.
33
34
35
36
37
38
39
40
41
42
43
44
45
46

By prefixing the host with a '+' you can make the entry time out after curl's
default timeout (1 minute). Note that this only makes sense for long running
parallel transfers with a lot of files. In such cases, if this option is used
curl tries to resolve the host as it normally would once the timeout has
expired.

Support for providing the IP address within [brackets] was added in 7.57.0.

Support for providing multiple IP addresses per entry was added in 7.59.0.

Support for resolving with wildcard was added in 7.64.0.

Support for the '+' prefix was added in 7.75.0.







|
|
<




33
34
35
36
37
38
39
40
41

42
43
44
45

By prefixing the host with a '+' you can make the entry time out after curl's
default timeout (1 minute). Note that this only makes sense for long running
parallel transfers with a lot of files. In such cases, if this option is used
curl tries to resolve the host as it normally would once the timeout has
expired.

To redirect connects from a specific hostname or any hostname, independently
of port number, consider the --connect-to option.


Support for resolving with wildcard was added in 7.64.0.

Support for the '+' prefix was added in 7.75.0.
Changes to jni/curl/docs/cmdline-opts/retry-delay.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: retry-delay
Arg: <seconds>
Help: Wait time between retries
Added: 7.12.3
Category: curl
Multi: single
See-also:
  - retry
Example:
  - --retry-delay 5 --retry 7 $URL
---








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: retry-delay
Arg: <seconds>
Help: Wait time between retries
Added: 7.12.3
Category: curl timeout
Multi: single
See-also:
  - retry
Example:
  - --retry-delay 5 --retry 7 $URL
---

Changes to jni/curl/docs/cmdline-opts/retry-max-time.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: retry-max-time
Arg: <seconds>
Help: Retry only within this period
Added: 7.12.3
Category: curl
Multi: single
See-also:
  - retry
Example:
  - --retry-max-time 30 --retry 10 $URL
---








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: retry-max-time
Arg: <seconds>
Help: Retry only within this period
Added: 7.12.3
Category: curl timeout
Multi: single
See-also:
  - retry
Example:
  - --retry-max-time 30 --retry 10 $URL
---

Changes to jni/curl/docs/cmdline-opts/service-name.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: service-name
Help: SPNEGO service name
Arg: <name>
Added: 7.43.0
Category: misc
Multi: single
See-also:
  - negotiate
  - proxy-service-name
Example:
  - --service-name sockd/server $URL
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: service-name
Help: SPNEGO service name
Arg: <name>
Added: 7.43.0
Category: auth
Multi: single
See-also:
  - negotiate
  - proxy-service-name
Example:
  - --service-name sockd/server $URL
---
Changes to jni/curl/docs/cmdline-opts/show-error.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: show-error
Short: S
Help: Show error even when -s is used
Category: curl
Added: 5.9
Multi: boolean
Scope: global
See-also:
  - no-progress-meter
Example:
  - --show-error --silent $URL






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: show-error
Short: S
Help: Show error even when -s is used
Category: curl global
Added: 5.9
Multi: boolean
Scope: global
See-also:
  - no-progress-meter
Example:
  - --show-error --silent $URL
Changes to jni/curl/docs/cmdline-opts/socks5.md.
29
30
31
32
33
34
35
36
using a socks5:// protocol prefix. (Added in 7.21.7)

--preproxy can be used to specify a SOCKS proxy at the same time --proxy is
used with an HTTP/HTTPS proxy (added in 7.52.0). In such a case, curl first
connects to the SOCKS proxy and then connects (through SOCKS) to the HTTP or
HTTPS proxy.

This option (as well as --socks4) does not work with IPV6, FTPS or LDAP.







|
29
30
31
32
33
34
35
36
using a socks5:// protocol prefix. (Added in 7.21.7)

--preproxy can be used to specify a SOCKS proxy at the same time --proxy is
used with an HTTP/HTTPS proxy (added in 7.52.0). In such a case, curl first
connects to the SOCKS proxy and then connects (through SOCKS) to the HTTP or
HTTPS proxy.

This option does not work with FTPS or LDAP.
Changes to jni/curl/docs/cmdline-opts/speed-time.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: speed-time
Short: y
Arg: <seconds>
Help: Trigger 'speed-limit' abort after this time
Category: connection
Added: 4.7
Multi: single
See-also:
  - speed-limit
  - limit-rate
Example:
  - --speed-limit 300 --speed-time 10 $URL







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: speed-time
Short: y
Arg: <seconds>
Help: Trigger 'speed-limit' abort after this time
Category: connection timeout
Added: 4.7
Multi: single
See-also:
  - speed-limit
  - limit-rate
Example:
  - --speed-limit 300 --speed-time 10 $URL
Changes to jni/curl/docs/cmdline-opts/ssl-allow-beast.md.
12
13
14
15
16
17
18
19
20
21
22



23
24
  - insecure
Example:
  - --ssl-allow-beast $URL
---

# `--ssl-allow-beast`

Do not work around a security flaw in the SSL3 and TLS1.0 protocols known as
BEAST. If this option is not used, the SSL layer may use workarounds known to
cause interoperability problems with some older SSL implementations.




**WARNING**: this option loosens the SSL security, and by using this flag you
ask for exactly that.







|
|
|

>
>
>
|

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  - insecure
Example:
  - --ssl-allow-beast $URL
---

# `--ssl-allow-beast`

Do not work around a security flaw in the TLS1.0 protocol known as BEAST. If
this option is not used, the TLS layer may use workarounds known to cause
interoperability problems with some older server implementations.

This option only changes how curl does TLS 1.0 and has no effect on later TLS
versions.

**WARNING**: this option loosens the TLS security, and by using this flag you
ask for exactly that.
Changes to jni/curl/docs/cmdline-opts/ssl-reqd.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ssl-reqd
Help: Require SSL/TLS
Protocols: FTP IMAP POP3 SMTP LDAP
Added: 7.20.0
Category: tls
Multi: boolean
See-also:
  - ssl
  - insecure
Example:
  - --ssl-reqd ftp://example.com
---







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ssl-reqd
Help: Require SSL/TLS
Protocols: FTP IMAP POP3 SMTP LDAP
Added: 7.20.0
Category: tls imap pop3 smtp ldap
Multi: boolean
See-also:
  - ssl
  - insecure
Example:
  - --ssl-reqd ftp://example.com
---
Changes to jni/curl/docs/cmdline-opts/ssl.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ssl
Help: Try enabling TLS
Protocols: FTP IMAP POP3 SMTP LDAP
Added: 7.20.0
Category: tls
Multi: boolean
See-also:
  - ssl-reqd
  - insecure
  - ciphers
Example:
  - --ssl pop3://example.com/







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: ssl
Help: Try enabling TLS
Protocols: FTP IMAP POP3 SMTP LDAP
Added: 7.20.0
Category: tls imap pop3 smtp ldap
Multi: boolean
See-also:
  - ssl-reqd
  - insecure
  - ciphers
Example:
  - --ssl pop3://example.com/
Changes to jni/curl/docs/cmdline-opts/sslv2.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: 2
Long: sslv2
Tags: Versions
Protocols: SSL
Added: 5.9
Mutexed: sslv3 tlsv1 tlsv1.1 tlsv1.2
Requires: TLS
Help: SSLv2
Category: tls
Multi: mutex
See-also:
  - http1.1
  - http2
Example:
  - --sslv2 $URL
---











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: 2
Long: sslv2
Tags: Versions
Protocols: SSL
Added: 5.9
Mutexed: sslv3 tlsv1 tlsv1.1 tlsv1.2
Requires: TLS
Help: SSLv2
Category: deprecated
Multi: mutex
See-also:
  - http1.1
  - http2
Example:
  - --sslv2 $URL
---
Changes to jni/curl/docs/cmdline-opts/sslv3.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: 3
Long: sslv3
Tags: Versions
Protocols: SSL
Added: 5.9
Mutexed: sslv2 tlsv1 tlsv1.1 tlsv1.2
Requires: TLS
Help: SSLv3
Category: tls
Multi: mutex
See-also:
  - http1.1
  - http2
Example:
  - --sslv3 $URL
---











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: 3
Long: sslv3
Tags: Versions
Protocols: SSL
Added: 5.9
Mutexed: sslv2 tlsv1 tlsv1.1 tlsv1.2
Requires: TLS
Help: SSLv3
Category: deprecated
Multi: mutex
See-also:
  - http1.1
  - http2
Example:
  - --sslv3 $URL
---
Changes to jni/curl/docs/cmdline-opts/stderr.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: stderr
Arg: <file>
Help: Where to redirect stderr
Category: verbose
Added: 6.2
Multi: single
Scope: global
See-also:
  - verbose
  - silent
Example:






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: stderr
Arg: <file>
Help: Where to redirect stderr
Category: verbose global
Added: 6.2
Multi: single
Scope: global
See-also:
  - verbose
  - silent
Example:
Changes to jni/curl/docs/cmdline-opts/styled-output.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: styled-output
Help: Enable styled output for HTTP headers
Added: 7.61.0
Category: verbose
Multi: boolean
Scope: global
See-also:
  - head
  - verbose
Example:
  - --styled-output -I $URL






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: styled-output
Help: Enable styled output for HTTP headers
Added: 7.61.0
Category: verbose global
Multi: boolean
Scope: global
See-also:
  - head
  - verbose
Example:
  - --styled-output -I $URL
Changes to jni/curl/docs/cmdline-opts/tlspassword.md.
12
13
14
15
16
17
18
19
20
21
22
  - tlsuser
Example:
  - --tlspassword pwd --tlsuser user $URL
---

# `--tlspassword`

Set password for use with the TLS authentication method specified with
--tlsauthtype. Requires that --tlsuser also be set.

This option does not work with TLS 1.3.







|
|


12
13
14
15
16
17
18
19
20
21
22
  - tlsuser
Example:
  - --tlspassword pwd --tlsuser user $URL
---

# `--tlspassword`

Set password to use with the TLS authentication method specified with
--tlsauthtype. Requires that --tlsuser is set.

This option does not work with TLS 1.3.
Changes to jni/curl/docs/cmdline-opts/trace-ascii.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-ascii
Arg: <file>
Help: Like --trace, but without hex output
Mutexed: trace verbose
Category: verbose
Added: 7.9.7
Multi: single
Scope: global
See-also:
  - verbose
  - trace
Example:
  - --trace-ascii log.txt $URL
---

# `--trace-ascii`

Save a full trace dump of all incoming and outgoing data, including
descriptive information, in the given output file. Use `-` as filename to have
the output sent to stdout.

This is similar to --trace, but leaves out the hex part and only shows the
ASCII part of the dump. It makes smaller output that might be easier to read
for untrained humans.

Note that verbose output of curl activities and network traffic might contain
sensitive data, including usernames, credentials or secret data content. Be
aware and be careful when sharing trace logs with others.







|














|








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-ascii
Arg: <file>
Help: Like --trace, but without hex output
Mutexed: trace verbose
Category: verbose global
Added: 7.9.7
Multi: single
Scope: global
See-also:
  - verbose
  - trace
Example:
  - --trace-ascii log.txt $URL
---

# `--trace-ascii`

Save a full trace dump of all incoming and outgoing data, including
descriptive information, in the given output file. Use `-` as filename to have
the output sent to stdout. Use `%` as filename to send the output to stderr.

This is similar to --trace, but leaves out the hex part and only shows the
ASCII part of the dump. It makes smaller output that might be easier to read
for untrained humans.

Note that verbose output of curl activities and network traffic might contain
sensitive data, including usernames, credentials or secret data content. Be
aware and be careful when sharing trace logs with others.
Changes to jni/curl/docs/cmdline-opts/trace-config.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-config
Arg: <string>
Help: Details to log in trace/verbose output
Category: verbose
Added: 8.3.0
Multi: append
Scope: global
See-also:
  - verbose
  - trace
Example:






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-config
Arg: <string>
Help: Details to log in trace/verbose output
Category: verbose global
Added: 8.3.0
Multi: append
Scope: global
See-also:
  - verbose
  - trace
Example:
Changes to jni/curl/docs/cmdline-opts/trace-ids.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-ids
Help: Transfer + connection ids in verbose output
Added: 8.2.0
Category: verbose
Multi: boolean
Scope: global
See-also:
  - trace
  - verbose
Example:
  - --trace-ids --trace-ascii output $URL






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-ids
Help: Transfer + connection ids in verbose output
Added: 8.2.0
Category: verbose global
Multi: boolean
Scope: global
See-also:
  - trace
  - verbose
Example:
  - --trace-ids --trace-ascii output $URL
Changes to jni/curl/docs/cmdline-opts/trace-time.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-time
Help: Add time stamps to trace/verbose output
Added: 7.14.0
Category: verbose
Multi: boolean
Scope: global
See-also:
  - trace
  - verbose
Example:
  - --trace-time --trace-ascii output $URL






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace-time
Help: Add time stamps to trace/verbose output
Added: 7.14.0
Category: verbose global
Multi: boolean
Scope: global
See-also:
  - trace
  - verbose
Example:
  - --trace-time --trace-ascii output $URL
Changes to jni/curl/docs/cmdline-opts/trace.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace
Arg: <file>
Help: Write a debug trace to FILE
Mutexed: verbose trace-ascii
Category: verbose
Added: 7.9.7
Multi: single
Scope: global
See-also:
  - trace-ascii
  - trace-config
  - trace-ids
  - trace-time
Example:
  - --trace log.txt $URL
---

# `--trace`

Save a full trace dump of all incoming and outgoing data, including
descriptive information, in the given output file. Use "-" as filename to have
the output sent to stdout. Use "%" as filename to have the output sent to
stderr.

Note that verbose output of curl activities and network traffic might contain
sensitive data, including usernames, credentials or secret data content. Be
aware and be careful when sharing trace logs with others.







|















|
|





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: trace
Arg: <file>
Help: Write a debug trace to FILE
Mutexed: verbose trace-ascii
Category: verbose global
Added: 7.9.7
Multi: single
Scope: global
See-also:
  - trace-ascii
  - trace-config
  - trace-ids
  - trace-time
Example:
  - --trace log.txt $URL
---

# `--trace`

Save a full trace dump of all incoming and outgoing data, including
descriptive information, in the given output file. Use `-` as filename to have
the output sent to stdout. Use `%` as filename to have the output sent to
stderr.

Note that verbose output of curl activities and network traffic might contain
sensitive data, including usernames, credentials or secret data content. Be
aware and be careful when sharing trace logs with others.
Changes to jni/curl/docs/cmdline-opts/upload-file.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: upload-file
Short: T
Arg: <file>
Help: Transfer local FILE to destination
Category: important upload
Added: 4.0
Multi: append
See-also:
  - get
  - head
  - request
  - data
Example:
  - -T file $URL
  - -T "img[1-1000].png" ftp://ftp.example.com/
  - --upload-file "{file1,file2}" $URL

---

# `--upload-file`

Upload the specified local file to the remote URL.

If there is no file part in the specified URL, curl appends the local file









|









>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: upload-file
Short: T
Arg: <file>
Help: Transfer local FILE to destination
Category: important upload
Added: 4.0
Multi: per-URL
See-also:
  - get
  - head
  - request
  - data
Example:
  - -T file $URL
  - -T "img[1-1000].png" ftp://ftp.example.com/
  - --upload-file "{file1,file2}" $URL
  - -T file -T file2 $URL $URL
---

# `--upload-file`

Upload the specified local file to the remote URL.

If there is no file part in the specified URL, curl appends the local file
Changes to jni/curl/docs/cmdline-opts/url.md.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

Specify a URL to fetch.

If the given URL is missing a scheme name (such as `http://` or `ftp://` etc)
then curl makes a guess based on the host. If the outermost subdomain name
matches DICT, FTP, IMAP, LDAP, POP3 or SMTP then that protocol is used,
otherwise HTTP is used. Guessing can be avoided by providing a full URL
including the scheme, or disabled by setting a default protocol (added in
7.45.0), see --proto-default for details.

To control where this URL is written, use the --output or the --remote-name
options.

**WARNING**: On Windows, particular `file://` accesses can be converted to
network accesses by the operating system. Beware!







|
|






18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

Specify a URL to fetch.

If the given URL is missing a scheme name (such as `http://` or `ftp://` etc)
then curl makes a guess based on the host. If the outermost subdomain name
matches DICT, FTP, IMAP, LDAP, POP3 or SMTP then that protocol is used,
otherwise HTTP is used. Guessing can be avoided by providing a full URL
including the scheme, or disabled by setting a default protocol, see
--proto-default for details.

To control where this URL is written, use the --output or the --remote-name
options.

**WARNING**: On Windows, particular `file://` accesses can be converted to
network accesses by the operating system. Beware!
Changes to jni/curl/docs/cmdline-opts/use-ascii.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: B
Long: use-ascii
Help: Use ASCII/text transfer
Protocols: FTP LDAP
Category: misc
Added: 5.0
Multi: boolean
See-also:
  - crlf
  - data-ascii
Example:
  - -B ftp://example.com/README







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: B
Long: use-ascii
Help: Use ASCII/text transfer
Protocols: FTP LDAP
Category: ftp output ldap
Added: 5.0
Multi: boolean
See-also:
  - crlf
  - data-ascii
Example:
  - -B ftp://example.com/README
Changes to jni/curl/docs/cmdline-opts/variable.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: variable
Arg: <[%]name=text/@file>
Help: Set variable
Category: curl
Added: 8.3.0
Multi: append
See-also:
  - config
Example:
  - --variable name=smith $URL
---

# `--variable`

Set a variable with `name=content` or `name@file` (where `file` can be stdin
if set to a single dash (`-`)). The name is a case sensitive identifier that
must consist of no other letters than a-z, A-Z, 0-9 or underscore. The












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: variable
Arg: <[%]name=text/@file>
Help: Set variable
Category: curl
Added: 8.3.0
Multi: append
See-also:
  - config
Example:
  - --variable name=smith --expand-url "$URL/{{name}}"
---

# `--variable`

Set a variable with `name=content` or `name@file` (where `file` can be stdin
if set to a single dash (`-`)). The name is a case sensitive identifier that
must consist of no other letters than a-z, A-Z, 0-9 or underscore. The
Changes to jni/curl/docs/cmdline-opts/verbose.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: v
Long: verbose
Mutexed: trace trace-ascii
Help: Make the operation more talkative
Category: important verbose
Added: 4.0
Multi: boolean
Scope: global
See-also:
  - include
  - silent
  - trace







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: v
Long: verbose
Mutexed: trace trace-ascii
Help: Make the operation more talkative
Category: important verbose global
Added: 4.0
Multi: boolean
Scope: global
See-also:
  - include
  - silent
  - trace
Added jni/curl/docs/cmdline-opts/vlan-priority.md.














































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: vlan-priority
Arg: <priority>
Help: Set VLAN priority
Added: 8.9.0
Category: connection
Protocols: All
Multi: single
See-also:
  - ip-tos
Example:
  - --vlan-priority 4 $URL
---

# `--vlan-priority`

Set VLAN priority as defined in IEEE 802.1Q.

This field is set on Ethernet level, and only works within a local network.

The valid range for \<priority\> is 0 to 7.
Changes to jni/curl/docs/cmdline-opts/write-out.md.
59
60
61
62
63
64
65





66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

The variables available are:

## `certs`
Output the certificate chain with details. Supported only by the OpenSSL,
GnuTLS, Schannel and Secure Transport backends. (Added in 7.88.0)






## `content_type`
The Content-Type of the requested document, if there was any.

## `errormsg`
The error message. (Added in 7.75.0)

## `exitcode`
The numerical exit code of the transfer. (Added in 7.75.0)

## `filename_effective`
The ultimate filename that curl writes out to. This is only meaningful if curl
is told to write to a file with the --remote-name or --output option. It is
most useful in combination with the --remote-header-name option. (Added in
7.26.0)

## `ftp_entry_path`
The initial path curl ended up in when logging on to the remote FTP
server. (Added in 7.15.4)

## `header_json`
A JSON object with all HTTP response headers from the recent transfer. Values







>
>
>
>
>












|
|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

The variables available are:

## `certs`
Output the certificate chain with details. Supported only by the OpenSSL,
GnuTLS, Schannel and Secure Transport backends. (Added in 7.88.0)

## `conn_id`
The connection identifier last used by the transfer. The connection id is
unique number among all connections using the same connection cache.
(Added in 8.2.0)

## `content_type`
The Content-Type of the requested document, if there was any.

## `errormsg`
The error message. (Added in 7.75.0)

## `exitcode`
The numerical exit code of the transfer. (Added in 7.75.0)

## `filename_effective`
The ultimate filename that curl writes out to. This is only meaningful if curl
is told to write to a file with the --remote-name or --output option. It is
most useful in combination with the --remote-header-name option.
(Added in 7.26.0)

## `ftp_entry_path`
The initial path curl ended up in when logging on to the remote FTP
server. (Added in 7.15.4)

## `header_json`
A JSON object with all HTTP response headers from the recent transfer. Values
125
126
127
128
129
130
131




132
133
134
135
136
137
138

## `num_headers`
The number of response headers in the most recent request (restarted at each
redirect). Note that the status line IS NOT a header. (Added in 7.73.0)

## `num_redirects`
Number of redirects that were followed in the request. (Added in 7.12.3)





## `onerror`
The rest of the output is only shown if the transfer returned a non-zero error.
(Added in 7.75.0)

## `proxy_ssl_verify_result`
The result of the HTTPS proxy's SSL peer certificate verification that was







>
>
>
>







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

## `num_headers`
The number of response headers in the most recent request (restarted at each
redirect). Note that the status line IS NOT a header. (Added in 7.73.0)

## `num_redirects`
Number of redirects that were followed in the request. (Added in 7.12.3)

## `num_retries`
Number of retries actually performed when `--retry` has been used.
(Added in 8.9.0)

## `onerror`
The rest of the output is only shown if the transfer returned a non-zero error.
(Added in 7.75.0)

## `proxy_ssl_verify_result`
The result of the HTTPS proxy's SSL peer certificate verification that was
301
302
303
304
305
306
307






## `urlnum`
The URL index number of this transfer, 0-indexed. Unglobbed URLs share the
same index number as the origin globbed URL. (Added in 7.75.0)

## `url_effective`
The URL that was fetched last. This is most meaningful if you have told curl
to follow location: headers.













>
>
>
>
>
>
310
311
312
313
314
315
316
317
318
319
320
321
322
## `urlnum`
The URL index number of this transfer, 0-indexed. Unglobbed URLs share the
same index number as the origin globbed URL. (Added in 7.75.0)

## `url_effective`
The URL that was fetched last. This is most meaningful if you have told curl
to follow location: headers.

## `xfer_id`
The numerical identifier of the last transfer done. -1 if no transfer has been
started yet for the handle. The transfer id is unique among all transfers
performed using the same connection cache.
(Added in 8.2.0)
Changes to jni/curl/docs/cmdline-opts/xattr.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: xattr
Help: Store metadata in extended file attributes
Category: misc
Added: 7.21.3
Multi: boolean
See-also:
  - remote-time
  - write-out
  - verbose
Example:





|







1
2
3
4
5
6
7
8
9
10
11
12
13
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: xattr
Help: Store metadata in extended file attributes
Category: output
Added: 7.21.3
Multi: boolean
See-also:
  - remote-time
  - write-out
  - verbose
Example:
Changes to jni/curl/docs/curl-config.md.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl-config
Section: 1
Source: curl-config
See-also:
  - curl (1)

---

# NAME

curl-config - Get information about a libcurl installation

# SYNOPSIS








>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl-config
Section: 1
Source: curl-config
See-also:
  - curl (1)
Added-in: 7.7.2
---

# NAME

curl-config - Get information about a libcurl installation

# SYNOPSIS
Changes to jni/curl/docs/examples/10-at-a-time.c.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 *
 ***************************************************************************/
/* <DESC>
 * Download many files in parallel, in the same thread.
 * </DESC>
 */

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
#  include <unistd.h>
#endif
#include <curl/curl.h>

static const char *urls[] = {
  "https://www.microsoft.com",
  "https://opensource.org",
  "https://www.google.com",
  "https://www.yahoo.com",







<


<
<
<







22
23
24
25
26
27
28

29
30



31
32
33
34
35
36
37
 *
 ***************************************************************************/
/* <DESC>
 * Download many files in parallel, in the same thread.
 * </DESC>
 */


#include <stdlib.h>
#include <string.h>



#include <curl/curl.h>

static const char *urls[] = {
  "https://www.microsoft.com",
  "https://opensource.org",
  "https://www.google.com",
  "https://www.yahoo.com",
123
124
125
126
127
128
129

130
131
132
133
134
135
136
137
      transfers++)
    add_transfer(cm, transfers, &left);

  do {
    int still_alive = 1;
    curl_multi_perform(cm, &still_alive);


    while((msg = curl_multi_info_read(cm, &msgs_left))) {
      if(msg->msg == CURLMSG_DONE) {
        char *url;
        CURL *e = msg->easy_handle;
        curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url);
        fprintf(stderr, "R: %d - %s <%s>\n",
                msg->data.result, curl_easy_strerror(msg->data.result), url);
        curl_multi_remove_handle(cm, e);







>
|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
      transfers++)
    add_transfer(cm, transfers, &left);

  do {
    int still_alive = 1;
    curl_multi_perform(cm, &still_alive);

    /* !checksrc! disable EQUALSNULL 1 */
    while((msg = curl_multi_info_read(cm, &msgs_left)) != NULL) {
      if(msg->msg == CURLMSG_DONE) {
        char *url;
        CURL *e = msg->easy_handle;
        curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &url);
        fprintf(stderr, "R: %d - %s <%s>\n",
                msg->data.result, curl_easy_strerror(msg->data.result), url);
        curl_multi_remove_handle(cm, e);
Changes to jni/curl/docs/examples/Makefile.example.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
CC = gcc

# Compiler flags, -g for debug, -c to make an object file
CFLAGS = -c -g

# This should point to a directory that holds libcurl, if it is not
# in the system's standard lib dir
# We also set a -L to include the directory where we have the openssl
# libraries
LDFLAGS = -L/home/dast/lib -L/usr/local/ssl/lib

# We need -lcurl for the curl stuff
# We need -lsocket and -lnsl when on Solaris
# We need -lssl and -lcrypto when using libcurl with SSL support
# We need -lpthread for the pthread example







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
CC = gcc

# Compiler flags, -g for debug, -c to make an object file
CFLAGS = -c -g

# This should point to a directory that holds libcurl, if it is not
# in the system's standard lib dir
# We also set a -L to include the directory where we have the OpenSSL
# libraries
LDFLAGS = -L/home/dast/lib -L/usr/local/ssl/lib

# We need -lcurl for the curl stuff
# We need -lsocket and -lnsl when on Solaris
# We need -lssl and -lcrypto when using libcurl with SSL support
# We need -lpthread for the pthread example
Changes to jni/curl/docs/examples/Makefile.in.
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







196
197
198
199
200
201
202

203
204
205
206
207
208
209
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
1235
1236
1237
1238
1239
1240
1241


1242
1243
1244
1245
1246
1247
1248
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@







>
>







1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
Changes to jni/curl/docs/examples/cookie_interface.c.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 * Import and export cookies with COOKIELIST.
 * </DESC>
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

#include <curl/curl.h>

static void
print_cookies(CURL *curl)
{







<







25
26
27
28
29
30
31

32
33
34
35
36
37
38
 * Import and export cookies with COOKIELIST.
 * </DESC>
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <time.h>

#include <curl/curl.h>

static void
print_cookies(CURL *curl)
{
Changes to jni/curl/docs/examples/externalsocket.c.
21
22
23
24
25
26
27






28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
/* <DESC>
 * Pass in a custom socket for libcurl to use.
 * </DESC>
 */






#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <curl/curl.h>

#ifdef _WIN32
#include <winsock2.h>
#define close closesocket
#else
#include <sys/types.h>        /*  socket types              */
#include <sys/socket.h>       /*  socket definitions        */
#include <netinet/in.h>
#include <arpa/inet.h>        /*  inet (3) functions         */
#include <unistd.h>           /*  misc. Unix functions      */
#endif

#include <errno.h>

/* The IP address and port number to connect to */
#define IPADDR "127.0.0.1"







>
>
>
>
>
>






<





|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
48
49
50
51
52
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
/* <DESC>
 * Pass in a custom socket for libcurl to use.
 * </DESC>
 */
#ifdef _WIN32
#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS  /* for inet_addr() */
#endif
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <curl/curl.h>

#ifdef _WIN32

#define close closesocket
#else
#include <sys/types.h>        /*  socket types              */
#include <sys/socket.h>       /*  socket definitions        */
#include <netinet/in.h>
#include <arpa/inet.h>        /*  inet (3) functions        */
#include <unistd.h>           /*  misc. Unix functions      */
#endif

#include <errno.h>

/* The IP address and port number to connect to */
#define IPADDR "127.0.0.1"
Changes to jni/curl/docs/examples/http2-download.c.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>

/* curl stuff */
#include <curl/curl.h>
#include <curl/mprintf.h>

#ifndef CURLPIPE_MULTIPLEX
/* This little trick makes sure that we do not enable pipelining for libcurls
   old enough to not have this symbol. It is _not_ defined to zero in a recent







<
<
<
<







26
27
28
29
30
31
32




33
34
35
36
37
38
39
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>





/* curl stuff */
#include <curl/curl.h>
#include <curl/mprintf.h>

#ifndef CURLPIPE_MULTIPLEX
/* This little trick makes sure that we do not enable pipelining for libcurls
   old enough to not have this symbol. It is _not_ defined to zero in a recent
Changes to jni/curl/docs/examples/http2-pushinmemory.c.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 * HTTP/2 server push. Receive all data in memory.
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>

/* curl stuff */
#include <curl/curl.h>

struct Memory {
  char *memory;
  size_t size;
};







<
<
<
<







25
26
27
28
29
30
31




32
33
34
35
36
37
38
 * HTTP/2 server push. Receive all data in memory.
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>





/* curl stuff */
#include <curl/curl.h>

struct Memory {
  char *memory;
  size_t size;
};
Changes to jni/curl/docs/examples/http2-serverpush.c.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 * HTTP/2 server push
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>

/* curl stuff */
#include <curl/curl.h>

#ifndef CURLPIPE_MULTIPLEX
#error "too old libcurl, cannot do HTTP/2 server push!"
#endif








<
<
<
<







25
26
27
28
29
30
31




32
33
34
35
36
37
38
 * HTTP/2 server push
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>





/* curl stuff */
#include <curl/curl.h>

#ifndef CURLPIPE_MULTIPLEX
#error "too old libcurl, cannot do HTTP/2 server push!"
#endif

Changes to jni/curl/docs/examples/http2-upload.c.
29
30
31
32
33
34
35

36
37

38
39
40
41
42
43
44
45
46
47
48
49
50




















51
52
53
54
55
56
57
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>

/* somewhat unix-specific */

#include <sys/time.h>
#include <unistd.h>


/* curl stuff */
#include <curl/curl.h>
#include <curl/mprintf.h>

#ifndef CURLPIPE_MULTIPLEX
/* This little trick makes sure that we do not enable pipelining for libcurls
   old enough to not have this symbol. It is _not_ defined to zero in a recent
   libcurl header. */
#define CURLPIPE_MULTIPLEX 0
#endif

#define NUM_HANDLES 1000





















struct input {
  FILE *in;
  size_t bytes_read; /* count up */
  CURL *hnd;
  int num;
};







>


>













>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>

/* somewhat unix-specific */
#ifndef _MSC_VER
#include <sys/time.h>
#include <unistd.h>
#endif

/* curl stuff */
#include <curl/curl.h>
#include <curl/mprintf.h>

#ifndef CURLPIPE_MULTIPLEX
/* This little trick makes sure that we do not enable pipelining for libcurls
   old enough to not have this symbol. It is _not_ defined to zero in a recent
   libcurl header. */
#define CURLPIPE_MULTIPLEX 0
#endif

#define NUM_HANDLES 1000

#ifdef _MSC_VER
#define gettimeofday(a, b) my_gettimeofday((a), (b))
int my_gettimeofday(struct timeval *tp, void *tzp)
{
  (void)tzp;
  if(tp) {
    /* Offset between 1601-01-01 and 1970-01-01 in 100 nanosec units */
    #define _WIN32_FT_OFFSET (116444736000000000)
    union {
      CURL_TYPEOF_CURL_OFF_T ns100; /* time since 1 Jan 1601 in 100ns units */
      FILETIME ft;
    } _now;
    GetSystemTimeAsFileTime(&_now.ft);
    tp->tv_usec = (long)((_now.ns100 / 10) % 1000000);
    tp->tv_sec = (long)((_now.ns100 - _WIN32_FT_OFFSET) / 10000000);
  }
  return 0;
}
#endif

struct input {
  FILE *in;
  size_t bytes_read; /* count up */
  CURL *hnd;
  int num;
};
Changes to jni/curl/docs/examples/keepalive.c.
40
41
42
43
44
45
46



47
48
49
50
51
52
53

    /* keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);




    curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }








>
>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

    /* keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

    /* maximum number of keep-alive probes: 3 */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);

    curl_easy_setopt(curl, CURLOPT_URL, "https://curl.se/");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }

Changes to jni/curl/docs/examples/multi-app.c.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 * transfers in parallel.
 * </DESC>
 */

#include <stdio.h>
#include <string.h>

/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>

/* curl stuff */
#include <curl/curl.h>

/*
 * Download an HTTP file and upload an FTP file simultaneously.
 */








<
<
<
<







26
27
28
29
30
31
32




33
34
35
36
37
38
39
 * transfers in parallel.
 * </DESC>
 */

#include <stdio.h>
#include <string.h>





/* curl stuff */
#include <curl/curl.h>

/*
 * Download an HTTP file and upload an FTP file simultaneously.
 */

80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
      /* wait for activity, timeout or "nothing" */
      mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);

    if(mc)
      break;
  }
  /* See how the transfers went */

  while((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
    if(msg->msg == CURLMSG_DONE) {
      int idx;

      /* Find out which handle this message is about */
      for(idx = 0; idx<HANDLECOUNT; idx++) {
        int found = (msg->easy_handle == handles[idx]);
        if(found)







>
|







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
      /* wait for activity, timeout or "nothing" */
      mc = curl_multi_poll(multi_handle, NULL, 0, 1000, NULL);

    if(mc)
      break;
  }
  /* See how the transfers went */
  /* !checksrc! disable EQUALSNULL 1 */
  while((msg = curl_multi_info_read(multi_handle, &msgs_left)) != NULL) {
    if(msg->msg == CURLMSG_DONE) {
      int idx;

      /* Find out which handle this message is about */
      for(idx = 0; idx<HANDLECOUNT; idx++) {
        int found = (msg->easy_handle == handles[idx]);
        if(found)
Changes to jni/curl/docs/examples/multi-debugcallback.c.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 * multi interface and debug callback
 * </DESC>
 */

#include <stdio.h>
#include <string.h>

/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>

/* curl stuff */
#include <curl/curl.h>

#define TRUE 1

static void dump(const char *text, FILE *stream, unsigned char *ptr,
                 size_t size, char nohex)







<
<
<
<







25
26
27
28
29
30
31




32
33
34
35
36
37
38
 * multi interface and debug callback
 * </DESC>
 */

#include <stdio.h>
#include <string.h>





/* curl stuff */
#include <curl/curl.h>

#define TRUE 1

static void dump(const char *text, FILE *stream, unsigned char *ptr,
                 size_t size, char nohex)
Changes to jni/curl/docs/examples/multi-double.c.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* <DESC>
 * multi interface code doing two parallel HTTP transfers
 * </DESC>
 */
#include <stdio.h>
#include <string.h>

/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>

/* curl stuff */
#include <curl/curl.h>

/*
 * Simply download two HTTP files!
 */
int main(void)







<
<
<
<







24
25
26
27
28
29
30




31
32
33
34
35
36
37
/* <DESC>
 * multi interface code doing two parallel HTTP transfers
 * </DESC>
 */
#include <stdio.h>
#include <string.h>





/* curl stuff */
#include <curl/curl.h>

/*
 * Simply download two HTTP files!
 */
int main(void)
Changes to jni/curl/docs/examples/multi-formadd.c.
29
30
31
32
33
34
35
36
37
38





39
40
41
42
43
44
45
/*
 * Warning: this example uses the deprecated form api. See "multi-post.c"
 *          for a similar example using the mime api.
 */

#include <stdio.h>
#include <string.h>
#include <sys/time.h>

#include <curl/curl.h>






int main(void)
{
  CURL *curl;

  CURLM *multi_handle;
  int still_running = 0;







<


>
>
>
>
>







29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
 * Warning: this example uses the deprecated form api. See "multi-post.c"
 *          for a similar example using the mime api.
 */

#include <stdio.h>
#include <string.h>


#include <curl/curl.h>

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

int main(void)
{
  CURL *curl;

  CURLM *multi_handle;
  int still_running = 0;
109
110
111
112
113
114
115




    curl_formfree(formpost);

    /* free slist */
    curl_slist_free_all(headerlist);
  }
  return 0;
}











>
>
>
>
113
114
115
116
117
118
119
120
121
122
123
    curl_formfree(formpost);

    /* free slist */
    curl_slist_free_all(headerlist);
  }
  return 0;
}

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
Changes to jni/curl/docs/examples/multi-legacy.c.
27
28
29
30
31
32
33

34
35

36
37
38
39
40
41
42
 * </DESC>
 */

#include <stdio.h>
#include <string.h>

/* somewhat unix-specific */

#include <sys/time.h>
#include <unistd.h>


/* curl stuff */
#include <curl/curl.h>

/*
 * Download an HTTP file and upload an FTP file simultaneously.
 */







>


>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 * </DESC>
 */

#include <stdio.h>
#include <string.h>

/* somewhat unix-specific */
#ifndef _WIN32
#include <sys/time.h>
#include <unistd.h>
#endif

/* curl stuff */
#include <curl/curl.h>

/*
 * Download an HTTP file and upload an FTP file simultaneously.
 */
143
144
145
146
147
148
149

150
151
152
153
154
155
156
157
    default: /* action */
      curl_multi_perform(multi_handle, &still_running);
      break;
    }
  }

  /* See how the transfers went */

  while((msg = curl_multi_info_read(multi_handle, &msgs_left))) {
    if(msg->msg == CURLMSG_DONE) {
      int idx;

      /* Find out which handle this message is about */
      for(idx = 0; idx<HANDLECOUNT; idx++) {
        int found = (msg->easy_handle == handles[idx]);
        if(found)







>
|







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    default: /* action */
      curl_multi_perform(multi_handle, &still_running);
      break;
    }
  }

  /* See how the transfers went */
  /* !checksrc! disable EQUALSNULL 1 */
  while((msg = curl_multi_info_read(multi_handle, &msgs_left)) != NULL) {
    if(msg->msg == CURLMSG_DONE) {
      int idx;

      /* Find out which handle this message is about */
      for(idx = 0; idx<HANDLECOUNT; idx++) {
        int found = (msg->easy_handle == handles[idx]);
        if(found)
Changes to jni/curl/docs/examples/multi-post.c.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/* <DESC>
 * using the multi interface to do a multipart formpost without blocking
 * </DESC>
 */

#include <stdio.h>
#include <string.h>
#include <sys/time.h>

#include <curl/curl.h>

int main(void)
{
  CURL *curl;








<







24
25
26
27
28
29
30

31
32
33
34
35
36
37
/* <DESC>
 * using the multi interface to do a multipart formpost without blocking
 * </DESC>
 */

#include <stdio.h>
#include <string.h>


#include <curl/curl.h>

int main(void)
{
  CURL *curl;

Changes to jni/curl/docs/examples/multi-single.c.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 * using the multi interface to do a single download
 * </DESC>
 */

#include <stdio.h>
#include <string.h>

/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>

/* curl stuff */
#include <curl/curl.h>

/*
 * Simply download an HTTP file.
 */
int main(void)







<
<
<
<







25
26
27
28
29
30
31




32
33
34
35
36
37
38
 * using the multi interface to do a single download
 * </DESC>
 */

#include <stdio.h>
#include <string.h>





/* curl stuff */
#include <curl/curl.h>

/*
 * Simply download an HTTP file.
 */
int main(void)
Changes to jni/curl/docs/examples/persistent.c.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 ***************************************************************************/
/* <DESC>
 * reusing handles to do HTTP persistent connections
 * </DESC>
 */
#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>

int main(void)
{
  CURL *curl;
  CURLcode res;








|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 ***************************************************************************/
/* <DESC>
 * reusing handles to do HTTP persistent connections
 * </DESC>
 */
#include <stdio.h>

#include <curl/curl.h>

int main(void)
{
  CURL *curl;
  CURLcode res;

Changes to jni/curl/docs/examples/postit2-formadd.c.
42
43
44
45
46
47
48





49
50
51
52
53
54
55
 * </form>
 */

#include <stdio.h>
#include <string.h>

#include <curl/curl.h>






int main(int argc, char *argv[])
{
  CURL *curl;
  CURLcode res;

  struct curl_httppost *formpost = NULL;







>
>
>
>
>







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 * </form>
 */

#include <stdio.h>
#include <string.h>

#include <curl/curl.h>

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif

int main(int argc, char *argv[])
{
  CURL *curl;
  CURLcode res;

  struct curl_httppost *formpost = NULL;
106
107
108
109
110
111
112




    /* then cleanup the formpost chain */
    curl_formfree(formpost);
    /* free slist */
    curl_slist_free_all(headerlist);
  }
  return 0;
}











>
>
>
>
111
112
113
114
115
116
117
118
119
120
121
    /* then cleanup the formpost chain */
    curl_formfree(formpost);
    /* free slist */
    curl_slist_free_all(headerlist);
  }
  return 0;
}

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
Changes to jni/curl/docs/examples/sepheaders.c.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 ***************************************************************************/
/* <DESC>
 * Simple HTTP GET that stores the headers in a separate file
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <curl/curl.h>

static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
  size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
  return written;







<







23
24
25
26
27
28
29

30
31
32
33
34
35
36
 ***************************************************************************/
/* <DESC>
 * Simple HTTP GET that stores the headers in a separate file
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>


#include <curl/curl.h>

static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
  size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
  return written;
Changes to jni/curl/docs/examples/threaded-ssl.c.
23
24
25
26
27
28
29
30
31
32
33
34
35


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
 ***************************************************************************/
/* <DESC>
 * Show the required mutex callback setups for GnuTLS and OpenSSL when using
 * libcurl multi-threaded.
 * </DESC>
 */
/* A multi-threaded example that uses pthreads and fetches 4 remote files at
 * once over HTTPS. The lock callbacks and stuff assume OpenSSL <1.1 or GnuTLS
 * (libgcrypt) so far.
 *
 * OpenSSL docs for this:
 *   https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_num_locks.html
 * gcrypt docs for this:


 *   https://gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
 */

#define USE_OPENSSL /* or USE_GNUTLS accordingly */

#include <stdio.h>
#include <pthread.h>
#include <curl/curl.h>

#define NUMT 4

/* we have this global to let the callback get easy access to it */
static pthread_mutex_t *lockarray;

#ifdef USE_OPENSSL
#include <openssl/crypto.h>
static void lock_callback(int mode, int type, char *file, int line)
{
  (void)file;
  (void)line;
  if(mode & CRYPTO_LOCK) {
    pthread_mutex_lock(&(lockarray[type]));
  }
  else {
    pthread_mutex_unlock(&(lockarray[type]));
  }
}

static unsigned long thread_id(void)
{
  unsigned long ret;

  ret = (unsigned long)pthread_self();
  return ret;
}

static void init_locks(void)
{
  int i;

  lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
                                                sizeof(pthread_mutex_t));
  for(i = 0; i<CRYPTO_num_locks(); i++) {
    pthread_mutex_init(&(lockarray[i]), NULL);
  }

  CRYPTO_set_id_callback((unsigned long (*)())thread_id);
  CRYPTO_set_locking_callback((void (*)())lock_callback);
}

static void kill_locks(void)
{
  int i;

  CRYPTO_set_locking_callback(NULL);
  for(i = 0; i<CRYPTO_num_locks(); i++)
    pthread_mutex_destroy(&(lockarray[i]));

  OPENSSL_free(lockarray);
}
#endif

#ifdef USE_GNUTLS
#include <gcrypt.h>
#include <errno.h>

GCRY_THREAD_OPTION_PTHREAD_IMPL;

void init_locks(void)
{
  gcry_control(GCRYCTL_SET_THREAD_CBS);
}

#define kill_locks()
#endif

/* List of URLs to fetch.*/
const char * const urls[]= {
  "https://www.example.com/",
  "https://www2.example.com/",
  "https://www3.example.com/",
  "https://www4.example.com/",
};







|
<

|
<
|
>
>
|










<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







23
24
25
26
27
28
29
30

31
32

33
34
35
36
37
38
39
40
41
42
43
44
45
46

































































47
48
49
50
51
52
53
 ***************************************************************************/
/* <DESC>
 * Show the required mutex callback setups for GnuTLS and OpenSSL when using
 * libcurl multi-threaded.
 * </DESC>
 */
/* A multi-threaded example that uses pthreads and fetches 4 remote files at
 * once over HTTPS.

 *
 * Recent versions of OpenSSL and GnuTLS are thread safe by design, assuming

 * support for the underlying OS threading API is built-in. Older revisions
 * of this example demonstrated locking callbacks for the SSL library, which
 * are no longer necessary. An older revision with callbacks can be found at
 * https://github.com/curl/curl/blob/curl-7_88_1/docs/examples/threaded-ssl.c
 */

#define USE_OPENSSL /* or USE_GNUTLS accordingly */

#include <stdio.h>
#include <pthread.h>
#include <curl/curl.h>

#define NUMT 4


































































/* List of URLs to fetch.*/
const char * const urls[]= {
  "https://www.example.com/",
  "https://www2.example.com/",
  "https://www3.example.com/",
  "https://www4.example.com/",
};
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  int i;
  (void)argc; /* we do not use any arguments in this example */
  (void)argv;

  /* Must initialize libcurl before any threads are started */
  curl_global_init(CURL_GLOBAL_ALL);

  init_locks();

  for(i = 0; i< NUMT; i++) {
    int error = pthread_create(&tid[i],
                               NULL, /* default attributes please */
                               pull_one_url,
                               (void *)urls[i]);
    if(0 != error)
      fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
    else
      fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
  }

  /* now wait for all threads to terminate */
  for(i = 0; i< NUMT; i++) {
    pthread_join(tid[i], NULL);
    fprintf(stderr, "Thread %d terminated\n", i);
  }

  kill_locks();

  return 0;
}







<
<

















<
<


74
75
76
77
78
79
80


81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97


98
99
  int i;
  (void)argc; /* we do not use any arguments in this example */
  (void)argv;

  /* Must initialize libcurl before any threads are started */
  curl_global_init(CURL_GLOBAL_ALL);



  for(i = 0; i< NUMT; i++) {
    int error = pthread_create(&tid[i],
                               NULL, /* default attributes please */
                               pull_one_url,
                               (void *)urls[i]);
    if(0 != error)
      fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
    else
      fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
  }

  /* now wait for all threads to terminate */
  for(i = 0; i< NUMT; i++) {
    pthread_join(tid[i], NULL);
    fprintf(stderr, "Thread %d terminated\n", i);
  }



  return 0;
}
Changes to jni/curl/docs/examples/url2file.c.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 ***************************************************************************/
/* <DESC>
 * Download a given URL into a local file named page.out.
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <curl/curl.h>

static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
  size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
  return written;







<







23
24
25
26
27
28
29

30
31
32
33
34
35
36
 ***************************************************************************/
/* <DESC>
 * Download a given URL into a local file named page.out.
 * </DESC>
 */
#include <stdio.h>
#include <stdlib.h>


#include <curl/curl.h>

static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
  size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);
  return written;
Changes to jni/curl/docs/examples/usercertinmem.c.
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

  /* tell SSL to use the RSA key from memory */
  ret = SSL_CTX_use_RSAPrivateKey((SSL_CTX*)sslctx, rsa);
  if(ret != 1) {
    printf("Use Key failed\n");
  }

  /* free resources that have been allocated by openssl functions */
  if(bio)
    BIO_free(bio);

  if(kbio)
    BIO_free(kbio);

  if(rsa)







|







153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

  /* tell SSL to use the RSA key from memory */
  ret = SSL_CTX_use_RSAPrivateKey((SSL_CTX*)sslctx, rsa);
  if(ret != 1) {
    printf("Use Key failed\n");
  }

  /* free resources that have been allocated by OpenSSL functions */
  if(bio)
    BIO_free(bio);

  if(kbio)
    BIO_free(kbio);

  if(rsa)
Changes to jni/curl/docs/examples/websocket.c.
23
24
25
26
27
28
29




30


31
32
33
34
35
36
37
 ***************************************************************************/
/* <DESC>
 * WebSocket using CONNECT_ONLY
 * </DESC>
 */
#include <stdio.h>
#include <string.h>




#include <unistd.h>


#include <curl/curl.h>

static int ping(CURL *curl, const char *send_payload)
{
  size_t sent;
  CURLcode result =
    curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0,







>
>
>
>

>
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 ***************************************************************************/
/* <DESC>
 * WebSocket using CONNECT_ONLY
 * </DESC>
 */
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#define sleep(s) Sleep((DWORD)(s))
#else
#include <unistd.h>
#endif

#include <curl/curl.h>

static int ping(CURL *curl, const char *send_payload)
{
  size_t sent;
  CURLcode result =
    curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0,
Changes to jni/curl/docs/examples/xmlstream.c.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 * gcc -Wall -I/usr/local/include xmlstream.c -lcurl -lexpat -o xmlstream
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <expat.h>
#include <curl/curl.h>

struct MemoryStruct {
  char *memory;
  size_t size;







<







32
33
34
35
36
37
38

39
40
41
42
43
44
45
 * gcc -Wall -I/usr/local/include xmlstream.c -lcurl -lexpat -o xmlstream
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include <expat.h>
#include <curl/curl.h>

struct MemoryStruct {
  char *memory;
  size_t size;
Changes to jni/curl/docs/libcurl/Makefile.in.
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







156
157
158
159
160
161
162

163
164
165
166
167
168
169
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
373
374
375
376
377
378
379


380
381
382
383
384
385
386
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
Changes to jni/curl/docs/libcurl/curl_easy_cleanup.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
  - curl_easy_duphandle (3)
  - curl_easy_init (3)
  - curl_easy_reset (3)
  - curl_multi_cleanup (3)
  - curl_multi_remove_handle (3)
Protocol:
  - All

---

# NAME

curl_easy_cleanup - End a libcurl easy handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

void curl_easy_cleanup(CURL *handle);







>




|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  - curl_easy_duphandle (3)
  - curl_easy_init (3)
  - curl_easy_reset (3)
  - curl_multi_cleanup (3)
  - curl_multi_remove_handle (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_easy_cleanup - free an easy handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

void curl_easy_cleanup(CURL *handle);
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
To close an easy handle that has been used with the multi interface, make sure
to first call curl_multi_remove_handle(3) to remove it from the multi handle
before it is closed.

Passing in a NULL pointer in *handle* makes this function return immediately
with no action.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res)
      printf("error: %s\n", curl_easy_strerror(res));
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.1

# RETURN VALUE

None







>
>

















|
<
<




49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75


76
77
78
79
To close an easy handle that has been used with the multi interface, make sure
to first call curl_multi_remove_handle(3) to remove it from the multi handle
before it is closed.

Passing in a NULL pointer in *handle* makes this function return immediately
with no action.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res)
      printf("error: %s\n", curl_easy_strerror(res));
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

None
Changes to jni/curl/docs/libcurl/curl_easy_duphandle.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_duphandle
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_init (3)
  - curl_easy_reset (3)
  - curl_global_init (3)
Protocol:
  - All

---

# NAME

curl_easy_duphandle - Clone a libcurl session handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURL *curl_easy_duphandle(CURL *handle);













>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_duphandle
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_init (3)
  - curl_easy_reset (3)
  - curl_global_init (3)
Protocol:
  - All
Added-in: 7.9
---

# NAME

curl_easy_duphandle - clone an easy handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURL *curl_easy_duphandle(CURL *handle);
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

If the source handle has HSTS or alt-svc enabled, the duplicate gets data read
data from the main filename to populate the cache.

In multi-threaded programs, this function must be called in a synchronous way,
the input handle may not be in use when cloned.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    CURL *nother;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    nother = curl_easy_duphandle(curl);
    res = curl_easy_perform(nother);
    curl_easy_cleanup(nother);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.9

# RETURN VALUE

If this function returns NULL, something went wrong and no valid handle was
returned.







>
>


















|
<
<





43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
75

If the source handle has HSTS or alt-svc enabled, the duplicate gets data read
data from the main filename to populate the cache.

In multi-threaded programs, this function must be called in a synchronous way,
the input handle may not be in use when cloned.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    CURL *nother;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    nother = curl_easy_duphandle(curl);
    res = curl_easy_perform(nother);
    curl_easy_cleanup(nother);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

If this function returns NULL, something went wrong and no valid handle was
returned.
Changes to jni/curl/docs/libcurl/curl_easy_escape.md.
1
2
3
4
5
6
7
8
9

10
11

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53













54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72



73

74
75
76
77
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_escape
Section: 3
Source: libcurl
See-also:
  - curl_easy_unescape (3)
  - curl_free (3)

Protocol:
  - All

---

# NAME

curl_easy_escape - URL encodes the given string

# SYNOPSIS

~~~c
#include <curl/curl.h>

char *curl_easy_escape(CURL *curl, const char *string, int length);
~~~

# DESCRIPTION

This function converts the given input *string* to a URL encoded string
and returns that as a new allocated string. All input characters that are not
a-z, A-Z, 0-9, '-', '.', '_' or '~' are converted to their "URL escaped"
version (**%NN** where **NN** is a two-digit hexadecimal number).

If *length* is set to 0 (zero), curl_easy_escape(3) uses strlen() on
the input *string* to find out the size. This function does not accept
input strings longer than **CURL_MAX_INPUT_LENGTH** (8 MB).

Since 7.82.0, the **curl** parameter is ignored. Prior to that there was
per-handle character conversion support for some old operating systems such as
TPF, but it was otherwise ignored.

You must curl_free(3) the returned string when you are done with it.

# ENCODING

libcurl is typically not aware of, nor does it care about, character
encodings. curl_easy_escape(3) encodes the data byte-by-byte into the
URL encoded version without knowledge or care for what particular character
encoding the application or the receiving server may assume that the data
uses.

The caller of curl_easy_escape(3) must make sure that the data passed in
to the function is encoded correctly.














# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    char *output = curl_easy_escape(curl, "data to convert", 15);
    if(output) {
      printf("Encoded: %s\n", output);
      curl_free(output);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY




Added in 7.15.4 and replaces the old curl_escape(3) function.


# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed.








|
>


>




|











|
|
|
|

|
|
|
<
<
<
<














>
>
>
>
>
>
>
>
>
>
>
>
>

















|

>
>
>
|
>




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37




38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_escape
Section: 3
Source: libcurl
See-also:
  - curl_easy_unescape (3)
  - curl_url_set (3)
  - curl_url_get (3)
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

curl_easy_escape - URL encode a string

# SYNOPSIS

~~~c
#include <curl/curl.h>

char *curl_easy_escape(CURL *curl, const char *string, int length);
~~~

# DESCRIPTION

This function converts the given input *string* to a URL encoded string and
returns that as a new allocated string. All input characters that are not a-z,
A-Z, 0-9, '-', '.', '_' or '~' are converted to their "URL escaped" version
(**%NN** where **NN** is a two-digit hexadecimal number).

If *length* is set to 0 (zero), curl_easy_escape(3) uses strlen() on the input
*string* to find out the size. This function does not accept input strings
longer than **CURL_MAX_INPUT_LENGTH** (8 MB).





You must curl_free(3) the returned string when you are done with it.

# ENCODING

libcurl is typically not aware of, nor does it care about, character
encodings. curl_easy_escape(3) encodes the data byte-by-byte into the
URL encoded version without knowledge or care for what particular character
encoding the application or the receiving server may assume that the data
uses.

The caller of curl_easy_escape(3) must make sure that the data passed in
to the function is encoded correctly.

# URLs

URLs are by definition *URL encoded*. To create a proper URL from a set of
components that may not be URL encoded already, you cannot just URL encode the
entire URL string with curl_easy_escape(3), because it then also converts
colons, slashes and other symbols that you probably want untouched.

To create a proper URL from strings that are not already URL encoded, we
recommend using libcurl's URL API: set the pieces with curl_url_set(3) and get
the final correct URL with curl_url_get(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    char *output = curl_easy_escape(curl, "data to convert", 15);
    if(output) {
      printf("Encoded: %s\n", output);
      curl_free(output);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Since 7.82.0, the **curl** parameter is ignored. Prior to that there was
per-handle character conversion support for some old operating systems such as
TPF, but it was otherwise ignored.

# %AVAILABILITY%

# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed.
Changes to jni/curl/docs/libcurl/curl_easy_getinfo.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_getinfo
Section: 3
Source: libcurl
See-also:
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

curl_easy_getinfo - extract information from a curl handle

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_getinfo
Section: 3
Source: libcurl
See-also:
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

curl_easy_getinfo - extract information from a curl handle

# SYNOPSIS
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

254








255
256


257
258

259





260


261
262
263
264





265
266


267
268

269
270
271


272
273

274
275
276








277
278
279
280
281


















282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319


320
321
322


323

324


325
326
327
328
329



330
331
332
333
334

335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370

371
372


373
374
375
376
377
378
379
380









381
382



















































383








384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
man page of the *info* option. The data is stored accordingly and can be
relied upon only if this function returns CURLE_OK. Use this function after a
performed transfer if you want to get transfer related data.

You should not free the memory returned by this function unless it is
explicitly mentioned below.

# AVAILABLE INFORMATION

The following information can be extracted:

## CURLINFO_EFFECTIVE_METHOD

Last used HTTP method. See CURLINFO_EFFECTIVE_METHOD(3)

## CURLINFO_EFFECTIVE_URL

Last used URL. See CURLINFO_EFFECTIVE_URL(3)

## CURLINFO_RESPONSE_CODE

Last received response code. See CURLINFO_RESPONSE_CODE(3)

## CURLINFO_REFERER

Referrer header. See CURLINFO_REFERER(3)

## CURLINFO_HTTP_CONNECTCODE

Last proxy CONNECT response code. See CURLINFO_HTTP_CONNECTCODE(3)

## CURLINFO_HTTP_VERSION

The http version used in the connection. See CURLINFO_HTTP_VERSION(3)

## CURLINFO_FILETIME

Remote time of the retrieved document. See CURLINFO_FILETIME(3)

## CURLINFO_FILETIME_T

Remote time of the retrieved document. See CURLINFO_FILETIME_T(3)

## CURLINFO_TOTAL_TIME

Total time of previous transfer. See CURLINFO_TOTAL_TIME(3)

## CURLINFO_TOTAL_TIME_T

Total time of previous transfer. See CURLINFO_TOTAL_TIME_T(3)

## CURLINFO_NAMELOOKUP_TIME

Time from start until name resolving completed. See
CURLINFO_NAMELOOKUP_TIME(3)

## CURLINFO_NAMELOOKUP_TIME_T

Time from start until name resolving completed. See
CURLINFO_NAMELOOKUP_TIME_T(3)

## CURLINFO_CONNECT_TIME

Time from start until remote host or proxy completed.
See CURLINFO_CONNECT_TIME(3)

## CURLINFO_CONNECT_TIME_T

Time from start until remote host or proxy completed.
See CURLINFO_CONNECT_TIME_T(3)

## CURLINFO_APPCONNECT_TIME

Time from start until SSL/SSH handshake completed.
See CURLINFO_APPCONNECT_TIME(3)

## CURLINFO_APPCONNECT_TIME_T

Time from start until SSL/SSH handshake completed.
See CURLINFO_APPCONNECT_TIME_T(3)

## CURLINFO_PRETRANSFER_TIME

Time from start until just before the transfer begins.
See CURLINFO_PRETRANSFER_TIME(3)

## CURLINFO_PRETRANSFER_TIME_T

Time from start until just before the transfer begins.
See CURLINFO_PRETRANSFER_TIME_T(3)

## CURLINFO_QUEUE_TIME_T

Time during which this transfer was held in a waiting queue.
See CURLINFO_QUEUE_TIME_T(3)

## CURLINFO_USED_PROXY

Whether the proxy was used (Added in 8.7.0). See CURLINFO_USED_PROXY(3)

## CURLINFO_STARTTRANSFER_TIME

Time from start until just when the first byte is received.
See CURLINFO_STARTTRANSFER_TIME(3)

## CURLINFO_STARTTRANSFER_TIME_T

Time from start until just when the first byte is received.
See CURLINFO_STARTTRANSFER_TIME_T(3)

## CURLINFO_REDIRECT_TIME

Time taken for all redirect steps before the final transfer.
See CURLINFO_REDIRECT_TIME(3)

## CURLINFO_REDIRECT_TIME_T

Time taken for all redirect steps before the final transfer.
See CURLINFO_REDIRECT_TIME_T(3)

## CURLINFO_REDIRECT_COUNT

Total number of redirects that were followed.
See CURLINFO_REDIRECT_COUNT(3)

## CURLINFO_REDIRECT_URL

URL a redirect would take you to, had you enabled redirects.
See CURLINFO_REDIRECT_URL(3)

## CURLINFO_SIZE_UPLOAD

(Deprecated) Number of bytes uploaded.
See CURLINFO_SIZE_UPLOAD(3)

## CURLINFO_SIZE_UPLOAD_T

Number of bytes uploaded.
See CURLINFO_SIZE_UPLOAD_T(3)

## CURLINFO_SIZE_DOWNLOAD

(Deprecated) Number of bytes downloaded.
See CURLINFO_SIZE_DOWNLOAD(3)

## CURLINFO_SIZE_DOWNLOAD_T

Number of bytes downloaded.
See CURLINFO_SIZE_DOWNLOAD_T(3)

## CURLINFO_SPEED_DOWNLOAD

(Deprecated) Average download speed.
See CURLINFO_SPEED_DOWNLOAD(3)

## CURLINFO_SPEED_DOWNLOAD_T

Average download speed.
See CURLINFO_SPEED_DOWNLOAD_T(3)

## CURLINFO_SPEED_UPLOAD

(Deprecated) Average upload speed.
See CURLINFO_SPEED_UPLOAD(3)

## CURLINFO_SPEED_UPLOAD_T

Average upload speed.
See CURLINFO_SPEED_UPLOAD_T(3)

## CURLINFO_HEADER_SIZE

Number of bytes of all headers received.
See CURLINFO_HEADER_SIZE(3)

## CURLINFO_REQUEST_SIZE

Number of bytes sent in the issued HTTP requests.
See CURLINFO_REQUEST_SIZE(3)

## CURLINFO_SSL_VERIFYRESULT

Certificate verification result.
See CURLINFO_SSL_VERIFYRESULT(3)

## CURLINFO_PROXY_ERROR

Detailed proxy error.
See CURLINFO_PROXY_ERROR(3)

## CURLINFO_PROXY_SSL_VERIFYRESULT

Proxy certificate verification result.
See CURLINFO_PROXY_SSL_VERIFYRESULT(3)

## CURLINFO_SSL_ENGINES

A list of OpenSSL crypto engines.
See CURLINFO_SSL_ENGINES(3)

## CURLINFO_CONTENT_LENGTH_DOWNLOAD

(Deprecated) Content length from the Content-Length header.
See CURLINFO_CONTENT_LENGTH_DOWNLOAD(3)

## CURLINFO_CONTENT_LENGTH_DOWNLOAD_T

Content length from the Content-Length header.
See CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3)

## CURLINFO_CONTENT_LENGTH_UPLOAD

(Deprecated) Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD(3)

## CURLINFO_CONTENT_LENGTH_UPLOAD_T

Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD_T(3)

## CURLINFO_CONTENT_TYPE

Content type from the Content-Type header.
See CURLINFO_CONTENT_TYPE(3)

## CURLINFO_RETRY_AFTER


The value from the Retry-After header.








See CURLINFO_RETRY_AFTER(3)



## CURLINFO_PRIVATE


User's private data pointer.





See CURLINFO_PRIVATE(3)



## CURLINFO_HTTPAUTH_AVAIL

Available HTTP authentication methods.





See CURLINFO_HTTPAUTH_AVAIL(3)



## CURLINFO_PROXYAUTH_AVAIL


Available HTTP proxy authentication methods.
See CURLINFO_PROXYAUTH_AVAIL(3)



## CURLINFO_OS_ERRNO


The errno from the last failure to connect.
See CURLINFO_OS_ERRNO(3)









## CURLINFO_NUM_CONNECTS

Number of new successful connections used for previous transfer.
See CURLINFO_NUM_CONNECTS(3)



















## CURLINFO_PRIMARY_IP

Destination IP address of the last connection.
See CURLINFO_PRIMARY_IP(3)

## CURLINFO_PRIMARY_PORT

Destination port of the last connection.
See CURLINFO_PRIMARY_PORT(3)

## CURLINFO_LOCAL_IP

Source IP address of the last connection.
See CURLINFO_LOCAL_IP(3)

## CURLINFO_LOCAL_PORT

Source port number of the last connection.
See CURLINFO_LOCAL_PORT(3)

## CURLINFO_COOKIELIST

List of all known cookies.
See CURLINFO_COOKIELIST(3)

## CURLINFO_LASTSOCKET

(Deprecated) Last socket used.
See CURLINFO_LASTSOCKET(3)

## CURLINFO_ACTIVESOCKET

The session's active socket.
See CURLINFO_ACTIVESOCKET(3)

## CURLINFO_FTP_ENTRY_PATH

The entry path after logging in to an FTP server.


See CURLINFO_FTP_ENTRY_PATH(3)

## CURLINFO_CAPATH




Get the default value for CURLOPT_CAPATH(3).


See CURLINFO_CAPATH(3)

## CURLINFO_CAINFO

Get the default value for CURLOPT_CAINFO(3).



See CURLINFO_CAINFO(3)

## CURLINFO_CERTINFO

Certificate chain.

See CURLINFO_CERTINFO(3)

## CURLINFO_TLS_SSL_PTR

TLS session info that can be used for further processing.
See CURLINFO_TLS_SSL_PTR(3)

## CURLINFO_TLS_SESSION

TLS session info that can be used for further processing. See
CURLINFO_TLS_SESSION(3). Deprecated option, use
CURLINFO_TLS_SSL_PTR(3) instead!

## CURLINFO_CONDITION_UNMET

Whether or not a time conditional was met or 304 HTTP response.
See CURLINFO_CONDITION_UNMET(3)

## CURLINFO_RTSP_SESSION_ID

RTSP session ID.
See CURLINFO_RTSP_SESSION_ID(3)

## CURLINFO_RTSP_CLIENT_CSEQ

The RTSP client CSeq that is expected next.
See CURLINFO_RTSP_CLIENT_CSEQ(3)

## CURLINFO_RTSP_SERVER_CSEQ

The RTSP server CSeq that is expected next.
See CURLINFO_RTSP_SERVER_CSEQ(3)

## CURLINFO_RTSP_CSEQ_RECV

RTSP CSeq last received.

See CURLINFO_RTSP_CSEQ_RECV(3)



## CURLINFO_PROTOCOL

(Deprecated) The protocol used for the connection. (Added in 7.52.0)
See CURLINFO_PROTOCOL(3)

## CURLINFO_SCHEME

The scheme used for the connection. (Added in 7.52.0)









See CURLINFO_SCHEME(3)




















































## CURLINFO_CONN_ID









The ID of the last connection used by the transfer. (Added in 8.2.0)
See CURLINFO_CONN_ID(3)

## CURLINFO_XFER_ID

The ID of the transfer. (Added in 8.2.0)
See CURLINFO_XFER_ID(3)

# TIMES

An overview of the time values available from curl_easy_getinfo(3)

    curl_easy_perform()
        |
        |--QUEUE
        |--|--NAMELOOKUP
        |--|--|--CONNECT
        |--|--|--|--APPCONNECT
        |--|--|--|--|--PRETRANSFER
        |--|--|--|--|--|--STARTTRANSFER
        |--|--|--|--|--|--|--TOTAL
        |--|--|--|--|--|--|--REDIRECT

## CURLINFO_QUEUE_TIME

CURLINFO_QUEUE_TIME_T(3). The time during which the transfer was held in a
waiting queue before it could start for real. (Added in 8.6.0)

## CURLINFO_NAMELOOKUP_TIME

CURLINFO_NAMELOOKUP_TIME(3) and CURLINFO_NAMELOOKUP_TIME_T(3). The time it
took from the start until the name resolving was completed.

## CURLINFO_CONNECT_TIME

CURLINFO_CONNECT_TIME(3) and CURLINFO_CONNECT_TIME_T(3). The time it took from
the start until the connect to the remote host (or proxy) was completed.

## CURLINFO_APPCONNECT_TIME

CURLINFO_APPCONNECT_TIME(3) and CURLINFO_APPCONNECT_TIME_T(3). The time it
took from the start until the SSL connect/handshake with the remote host was
completed. (Added in 7.19.0) The latter is the integer version (measuring
microseconds). (Added in 7.60.0)

## CURLINFO_PRETRANSFER_TIME

CURLINFO_PRETRANSFER_TIME(3) and CURLINFO_PRETRANSFER_TIME_T(3). The time it
took from the start until the file transfer is just about to begin. This
includes all pre-transfer commands and negotiations that are specific to the
particular protocol(s) involved.

## CURLINFO_STARTTRANSFER_TIME

CURLINFO_STARTTRANSFER_TIME(3) and CURLINFO_STARTTRANSFER_TIME_T(3). The time
it took from the start until the first byte is received by libcurl.

## CURLINFO_TOTAL_TIME

CURLINFO_TOTAL_TIME(3) and CURLINFO_TOTAL_TIME_T(3). Total time
of the previous request.

## CURLINFO_REDIRECT_TIME

CURLINFO_REDIRECT_TIME(3) and CURLINFO_REDIRECT_TIME_T(3). The time it took
for all redirection steps include name lookup, connect, pretransfer and
transfer before final transaction was started. So, this is zero if no
redirection took place.

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







|



|

|

|

<
|
<
|
<

|

<
|
<
|
<
<
|

<
<
|

<
|
<

<
<
|

|

|

|

|

<
<
|
|
<
<
<



|
|



|
|

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|

<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



|









|







|
|

|

>
|
>
>
>
>
>
>
>
>
|

>
>
|

>
|
>
>
>
>
>
|
>
>



|
>
>
>
>
>
|

>
>
|

>
|
|

>
>
|

>
|
|

>
>
>
>
>
>
>
>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


|
<



|
<

|

<
|

|

|
|

|

<
|

|

<
|

|

<
|

|

<
>
>
|

|
>
>

>
|
>
>
|

|

<
>
>
>
|

|

<
>
|

|

<
|

|

<
<
|

|

<
|

|

<
|



|
<
<
<
<
<
<



|
>
|

>
>
|

<
|



|
>
>
>
>
>
>
>
>
>
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>

<
|



|
<
















<

<
<
<
|
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
|

<
<
|
<
<
<
<
<
<







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

47

48

49
50
51

52

53


54
55


56
57

58

59


60
61
62
63
64
65
66
67
68
69


70
71



72
73
74
75
76
77
78
79
80
81
82

























83
84

85




























86






































































87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199

200
201
202
203

204
205
206

207
208
209
210
211
212
213
214
215

216
217
218
219

220
221
222
223

224
225
226
227

228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

244
245
246
247
248
249
250

251
252
253
254
255

256
257
258
259


260
261
262
263

264
265
266
267

268
269
270
271
272






273
274
275
276
277
278
279
280
281
282
283

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360

361
362
363
364
365

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381

382



383









384













385




386
387


388






389
390
391
392
393
394
395
man page of the *info* option. The data is stored accordingly and can be
relied upon only if this function returns CURLE_OK. Use this function after a
performed transfer if you want to get transfer related data.

You should not free the memory returned by this function unless it is
explicitly mentioned below.

# OPTIONS

The following information can be extracted:

## CURLINFO_ACTIVESOCKET

The session's active socket. See CURLINFO_ACTIVESOCKET(3)

## CURLINFO_APPCONNECT_TIME


The time it took from the start until the SSL connect/handshake with the

remote host was completed as a double in number of seconds. (Added in 7.19.0)


## CURLINFO_APPCONNECT_TIME_T


The time it took from the start until the SSL connect/handshake with the

remote host was completed in number of microseconds. (Added in 7.60.0) See


CURLINFO_APPCONNECT_TIME_T(3)



## CURLINFO_CAINFO


Get the default value for CURLOPT_CAINFO(3). See CURLINFO_CAINFO(3)




## CURLINFO_CAPATH

Get the default value for CURLOPT_CAPATH(3). See CURLINFO_CAPATH(3)

## CURLINFO_CERTINFO

Certificate chain. See CURLINFO_CERTINFO(3)

## CURLINFO_CONDITION_UNMET



Whether or not a time conditional was met or 304 HTTP response.
See CURLINFO_CONDITION_UNMET(3)




## CURLINFO_CONNECT_TIME

The time it took from the start until the connect to the remote host (or
proxy) was completed. As a double. See CURLINFO_CONNECT_TIME(3)

## CURLINFO_CONNECT_TIME_T

The time it took from the start until the connect to the remote host (or
proxy) was completed. In microseconds. See CURLINFO_CONNECT_TIME_T(3).


























## CURLINFO_CONN_ID


The ID of the last connection used by the transfer. (Added in 8.2.0)




























See CURLINFO_CONN_ID(3)







































































## CURLINFO_CONTENT_LENGTH_DOWNLOAD

(**Deprecated**) Content length from the Content-Length header.
See CURLINFO_CONTENT_LENGTH_DOWNLOAD(3)

## CURLINFO_CONTENT_LENGTH_DOWNLOAD_T

Content length from the Content-Length header.
See CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3)

## CURLINFO_CONTENT_LENGTH_UPLOAD

(**Deprecated**) Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD(3)

## CURLINFO_CONTENT_LENGTH_UPLOAD_T

Upload size. See CURLINFO_CONTENT_LENGTH_UPLOAD_T(3)

## CURLINFO_CONTENT_TYPE

Content type from the `Content-Type:` header. We recommend using
curl_easy_header(3) instead. See CURLINFO_CONTENT_TYPE(3)

## CURLINFO_COOKIELIST

List of all known cookies. See CURLINFO_COOKIELIST(3)

## CURLINFO_EFFECTIVE_METHOD

Last used HTTP method. See CURLINFO_EFFECTIVE_METHOD(3)

## CURLINFO_EFFECTIVE_URL

Last used URL. See CURLINFO_EFFECTIVE_URL(3)

## CURLINFO_FILETIME

Remote time of the retrieved document. See CURLINFO_FILETIME(3)

## CURLINFO_FILETIME_T

Remote time of the retrieved document. See CURLINFO_FILETIME_T(3)

## CURLINFO_FTP_ENTRY_PATH

The entry path after logging in to an FTP server. See
CURLINFO_FTP_ENTRY_PATH(3)

## CURLINFO_HEADER_SIZE

Number of bytes of all headers received. See CURLINFO_HEADER_SIZE(3)

## CURLINFO_HTTPAUTH_AVAIL

Available HTTP authentication methods. See CURLINFO_HTTPAUTH_AVAIL(3)

## CURLINFO_HTTP_CONNECTCODE

Last proxy CONNECT response code. See CURLINFO_HTTP_CONNECTCODE(3)

## CURLINFO_HTTP_VERSION

The http version used in the connection. See CURLINFO_HTTP_VERSION(3)

## CURLINFO_LASTSOCKET

(**Deprecated**) Last socket used. See CURLINFO_LASTSOCKET(3)

## CURLINFO_LOCAL_IP

Source IP address of the last connection. See CURLINFO_LOCAL_IP(3)

## CURLINFO_LOCAL_PORT

Source port number of the last connection. See CURLINFO_LOCAL_PORT(3)

## CURLINFO_NAMELOOKUP_TIME

Time from start until name resolving completed as a double. See
CURLINFO_NAMELOOKUP_TIME(3)

## CURLINFO_NAMELOOKUP_TIME_T

Time from start until name resolving completed in number of microseconds. See
CURLINFO_NAMELOOKUP_TIME_T(3)

## CURLINFO_NUM_CONNECTS

Number of new successful connections used for previous transfer.
See CURLINFO_NUM_CONNECTS(3)

## CURLINFO_OS_ERRNO

The errno from the last failure to connect. See CURLINFO_OS_ERRNO(3)

## CURLINFO_PRETRANSFER_TIME

The time it took from the start until the file transfer is just about to
begin. This includes all pre-transfer commands and negotiations that are
specific to the particular protocol(s) involved. See
CURLINFO_PRETRANSFER_TIME(3)

## CURLINFO_PRETRANSFER_TIME_T

The time it took from the start until the file transfer is just about to
begin. This includes all pre-transfer commands and negotiations that are
specific to the particular protocol(s) involved. In microseconds. See
CURLINFO_PRETRANSFER_TIME_T(3)

## CURLINFO_PRIMARY_IP

Destination IP address of the last connection. See CURLINFO_PRIMARY_IP(3)


## CURLINFO_PRIMARY_PORT

Destination port of the last connection. See CURLINFO_PRIMARY_PORT(3)


## CURLINFO_PRIVATE


User's private data pointer. See CURLINFO_PRIVATE(3)

## CURLINFO_PROTOCOL

(**Deprecated**) The protocol used for the connection. (Added in 7.52.0) See
CURLINFO_PROTOCOL(3)

## CURLINFO_PROXYAUTH_AVAIL


Available HTTP proxy authentication methods. See CURLINFO_PROXYAUTH_AVAIL(3)

## CURLINFO_PROXY_ERROR


Detailed proxy error. See CURLINFO_PROXY_ERROR(3)

## CURLINFO_PROXY_SSL_VERIFYRESULT


Proxy certificate verification result. See CURLINFO_PROXY_SSL_VERIFYRESULT(3)

## CURLINFO_QUEUE_TIME_T


The time during which the transfer was held in a waiting queue before it could
start for real in number of microseconds. (Added in 8.6.0) See
CURLINFO_QUEUE_TIME_T(3)

## CURLINFO_REDIRECT_COUNT

Total number of redirects that were followed. See CURLINFO_REDIRECT_COUNT(3)

## CURLINFO_REDIRECT_TIME

The time it took for all redirection steps include name lookup, connect,
pretransfer and transfer before final transaction was started. So, this is
zero if no redirection took place. As a double. See CURLINFO_REDIRECT_TIME(3)

## CURLINFO_REDIRECT_TIME_T


The time it took for all redirection steps include name lookup, connect,
pretransfer and transfer before final transaction was started. So, this is
zero if no redirection took place. In number of microseconds. See
CURLINFO_REDIRECT_TIME_T(3)

## CURLINFO_REDIRECT_URL


URL a redirect would take you to, had you enabled redirects. See
CURLINFO_REDIRECT_URL(3)

## CURLINFO_REFERER


Referrer header. See CURLINFO_REFERER(3)

## CURLINFO_REQUEST_SIZE



Number of bytes sent in the issued HTTP requests. See CURLINFO_REQUEST_SIZE(3)

## CURLINFO_RESPONSE_CODE


Last received response code. See CURLINFO_RESPONSE_CODE(3)

## CURLINFO_RETRY_AFTER


The value from the Retry-After header. See CURLINFO_RETRY_AFTER(3)

## CURLINFO_RTSP_CLIENT_CSEQ

The RTSP client CSeq that is expected next. See CURLINFO_RTSP_CLIENT_CSEQ(3)







## CURLINFO_RTSP_CSEQ_RECV

RTSP CSeq last received. See CURLINFO_RTSP_CSEQ_RECV(3)

## CURLINFO_RTSP_SERVER_CSEQ

The RTSP server CSeq that is expected next. See CURLINFO_RTSP_SERVER_CSEQ(3)

## CURLINFO_RTSP_SESSION_ID


RTSP session ID. See CURLINFO_RTSP_SESSION_ID(3)

## CURLINFO_SCHEME

The scheme used for the connection. (Added in 7.52.0) See CURLINFO_SCHEME(3)

## CURLINFO_SIZE_DOWNLOAD

(**Deprecated**) Number of bytes downloaded. See CURLINFO_SIZE_DOWNLOAD(3)

## CURLINFO_SIZE_DOWNLOAD_T

Number of bytes downloaded. See CURLINFO_SIZE_DOWNLOAD_T(3)

## CURLINFO_SIZE_UPLOAD

(**Deprecated**) Number of bytes uploaded. See CURLINFO_SIZE_UPLOAD(3)

## CURLINFO_SIZE_UPLOAD_T

Number of bytes uploaded. See CURLINFO_SIZE_UPLOAD_T(3)

## CURLINFO_SPEED_DOWNLOAD

(**Deprecated**) Average download speed. See CURLINFO_SPEED_DOWNLOAD(3)

## CURLINFO_SPEED_DOWNLOAD_T

Average download speed. See CURLINFO_SPEED_DOWNLOAD_T(3)

## CURLINFO_SPEED_UPLOAD

(**Deprecated**) Average upload speed. See CURLINFO_SPEED_UPLOAD(3)

## CURLINFO_SPEED_UPLOAD_T

Average upload speed in number of bytes per second. See
CURLINFO_SPEED_UPLOAD_T(3)

## CURLINFO_SSL_ENGINES

A list of OpenSSL crypto engines. See CURLINFO_SSL_ENGINES(3)

## CURLINFO_SSL_VERIFYRESULT

Certificate verification result. See CURLINFO_SSL_VERIFYRESULT(3)

## CURLINFO_STARTTRANSFER_TIME

The time it took from the start until the first byte is received by libcurl.
As a double. See CURLINFO_STARTTRANSFER_TIME(3)

## CURLINFO_STARTTRANSFER_TIME_T

The time it took from the start until the first byte is received by libcurl.
In microseconds. See CURLINFO_STARTTRANSFER_TIME_T(3)

## CURLINFO_TLS_SESSION

(**Deprecated**) TLS session info that can be used for further processing. See
CURLINFO_TLS_SESSION(3). Use CURLINFO_TLS_SSL_PTR(3) instead!

## CURLINFO_TLS_SSL_PTR

TLS session info that can be used for further processing. See
CURLINFO_TLS_SSL_PTR(3)

## CURLINFO_TOTAL_TIME

Total time of previous transfer. See CURLINFO_TOTAL_TIME(3)

## CURLINFO_TOTAL_TIME_T

Total time of previous transfer. See CURLINFO_TOTAL_TIME_T(3)

## CURLINFO_USED_PROXY


Whether the proxy was used (Added in 8.7.0). See CURLINFO_USED_PROXY(3)

## CURLINFO_XFER_ID

The ID of the transfer. (Added in 8.2.0) See CURLINFO_XFER_ID(3)


# TIMES

An overview of the time values available from curl_easy_getinfo(3)

    curl_easy_perform()
        |
        |--QUEUE
        |--|--NAMELOOKUP
        |--|--|--CONNECT
        |--|--|--|--APPCONNECT
        |--|--|--|--|--PRETRANSFER
        |--|--|--|--|--|--STARTTRANSFER
        |--|--|--|--|--|--|--TOTAL
        |--|--|--|--|--|--|--REDIRECT






 CURLINFO_QUEUE_TIME_T(3), CURLINFO_NAMELOOKUP_TIME_T(3),









 CURLINFO_CONNECT_TIME_T(3), CURLINFO_APPCONNECT_TIME_T(3),













 CURLINFO_PRETRANSFER_TIME_T(3), CURLINFO_STARTTRANSFER_TIME_T(3),




 CURLINFO_TOTAL_TIME_T(3), CURLINFO_REDIRECT_TIME_T(3)



# %PROTOCOLS%







# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.4.1

# RETURN VALUE

If the operation was successful, CURLE_OK is returned. Otherwise an
appropriate error code is returned.







|
<
<





409
410
411
412
413
414
415
416


417
418
419
420
421

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

If the operation was successful, CURLE_OK is returned. Otherwise an
appropriate error code is returned.
Changes to jni/curl/docs/libcurl/curl_easy_header.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_CONTENT_TYPE (3)
  - CURLOPT_HEADERFUNCTION (3)
  - curl_easy_nextheader (3)
  - curl_easy_perform (3)
  - libcurl-errors (3)
Protocol:
  - HTTP

---

# NAME

curl_easy_header - get an HTTP header

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_CONTENT_TYPE (3)
  - CURLOPT_HEADERFUNCTION (3)
  - curl_easy_nextheader (3)
  - curl_easy_perform (3)
  - libcurl-errors (3)
Protocol:
  - HTTP
Added-in: 7.83.0
---

# NAME

curl_easy_header - get an HTTP header

# SYNOPSIS
132
133
134
135
136
137
138


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
The header arrived in an HTTP 1xx response. A 1xx response is an "intermediate"
response that might happen before the "real" response.

## CURLH_PSEUDO

The header is an HTTP/2 or HTTP/3 pseudo header



# EXAMPLE

~~~c
int main(void)
{
  struct curl_header *type;
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLHcode h;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_perform(curl);
    h = curl_easy_header(curl, "Content-Type", 0, CURLH_HEADER, -1, &type);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.83.0. Officially supported since 7.84.0.

# RETURN VALUE

This function returns a CURLHcode indicating success or error.







>
>

















|
<
<




133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159


160
161
162
163
The header arrived in an HTTP 1xx response. A 1xx response is an "intermediate"
response that might happen before the "real" response.

## CURLH_PSEUDO

The header is an HTTP/2 or HTTP/3 pseudo header

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  struct curl_header *type;
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLHcode h;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_perform(curl);
    h = curl_easy_header(curl, "Content-Type", 0, CURLH_HEADER, -1, &type);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

This function returns a CURLHcode indicating success or error.
Changes to jni/curl/docs/libcurl/curl_easy_init.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
  - curl_easy_duphandle (3)
  - curl_easy_perform (3)
  - curl_easy_reset (3)
  - curl_global_init (3)
  - curl_multi_init (3)
Protocol:
  - All

---

# NAME

curl_easy_init - Start a libcurl easy session

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURL *curl_easy_init();







>




|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  - curl_easy_duphandle (3)
  - curl_easy_perform (3)
  - curl_easy_reset (3)
  - curl_global_init (3)
  - curl_multi_init (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_easy_init - create an easy handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURL *curl_easy_init();
38
39
40
41
42
43
44
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

An alternative way to get a new easy handle is to duplicate an already
existing one with curl_easy_duphandle(3), which has the upside that it gets
all the options that were set in the source handle set in the new copy as
well.

If you did not already call curl_global_init(3) before calling this function,
curl_easy_init(3) does it automatically. This may be lethal in multi-threaded
cases, if curl_global_init(3) is not thread-safe in your system, and it may
then result in resource problems because there is no corresponding cleanup.

You are strongly advised to not allow this automatic behavior, by calling
curl_global_init(3) yourself properly. See the description in libcurl(3) of
global environment requirements for details of how to use this function.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

If this function returns NULL, something went wrong and you cannot use the
other curl functions.







|
|





>
>
















|
<
<





39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71


72
73
74
75
76

An alternative way to get a new easy handle is to duplicate an already
existing one with curl_easy_duphandle(3), which has the upside that it gets
all the options that were set in the source handle set in the new copy as
well.

If you did not already call curl_global_init(3) before calling this function,
curl_easy_init(3) does it automatically. This can be lethal in multi-threaded
cases for platforms where curl_global_init(3) is not thread-safe, and it may
then result in resource problems because there is no corresponding cleanup.

You are strongly advised to not allow this automatic behavior, by calling
curl_global_init(3) yourself properly. See the description in libcurl(3) of
global environment requirements for details of how to use this function.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

If this function returns NULL, something went wrong and you cannot use the
other curl functions.
Changes to jni/curl/docs/libcurl/curl_easy_nextheader.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_nextheader
Section: 3
Source: libcurl
See-also:
  - curl_easy_header (3)
  - curl_easy_perform (3)
Protocol:
  - HTTP

---

# NAME

curl_easy_nextheader - get the next HTTP header

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_nextheader
Section: 3
Source: libcurl
See-also:
  - curl_easy_header (3)
  - curl_easy_perform (3)
Protocol:
  - HTTP
Added-in: 7.83.0
---

# NAME

curl_easy_nextheader - get the next HTTP header

# SYNOPSIS
56
57
58
59
60
61
62


63
64
65
66
67
68
69
curl_easy_nextheader(3) returns a pointer the next header stored within the
given scope. This way, an application can iterate over all available headers.

The memory for the struct this points to, is owned and managed by libcurl and
is associated with the easy handle. Applications must copy the data if they
want it to survive subsequent API calls or the life-time of the easy handle.



# EXAMPLE

~~~c
int main(void)
{
  struct curl_header *prev = NULL;
  struct curl_header *h;







>
>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
curl_easy_nextheader(3) returns a pointer the next header stored within the
given scope. This way, an application can iterate over all available headers.

The memory for the struct this points to, is owned and managed by libcurl and
is associated with the easy handle. Applications must copy the data if they
want it to survive subsequent API calls or the life-time of the easy handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  struct curl_header *prev = NULL;
  struct curl_header *h;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
      printf("%s: %s\n", h->name, h->value);
      prev = h;
    }
  }
}
~~~

# AVAILABILITY

Added in 7.83.0. Officially supported since 7.84.0.

# RETURN VALUE

This function returns the next header, or NULL when there are no more
(matching) headers or an error occurred.

If this function returns NULL when *prev* was set to NULL, then there are no
headers available within the scope to return.







|
<
<








88
89
90
91
92
93
94
95


96
97
98
99
100
101
102
103
      printf("%s: %s\n", h->name, h->value);
      prev = h;
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

This function returns the next header, or NULL when there are no more
(matching) headers or an error occurred.

If this function returns NULL when *prev* was set to NULL, then there are no
headers available within the scope to return.
Changes to jni/curl/docs/libcurl/curl_easy_option_by_id.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_option_by_id
Section: 3
Source: libcurl
See-also:
  - curl_easy_option_by_name (3)
  - curl_easy_option_next (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

curl_easy_option_by_id - find an easy setopt option by id

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_option_by_id
Section: 3
Source: libcurl
See-also:
  - curl_easy_option_by_name (3)
  - curl_easy_option_next (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.73.0
---

# NAME

curl_easy_option_by_id - find an easy setopt option by id

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
curl_easy_setopt(3) option using that id. The option id is the CURLOPT_
prefix ones provided in the standard curl/curl.h header file. This function
returns the non-alias version of the cases where there is an alias function as
well.

If libcurl has no option with the given id, this function returns NULL.



# EXAMPLE

~~~c
int main(void)
{
  const struct curl_easyoption *opt = curl_easy_option_by_id(CURLOPT_URL);
  if(opt) {
    printf("This option wants type %x\n", opt->type);
  }
}
~~~

# AVAILABILITY

This function was added in libcurl 7.73.0

# RETURN VALUE

A pointer to the *curl_easyoption* struct for the option or NULL.







>
>












|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53


54
55
56
57
curl_easy_setopt(3) option using that id. The option id is the CURLOPT_
prefix ones provided in the standard curl/curl.h header file. This function
returns the non-alias version of the cases where there is an alias function as
well.

If libcurl has no option with the given id, this function returns NULL.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  const struct curl_easyoption *opt = curl_easy_option_by_id(CURLOPT_URL);
  if(opt) {
    printf("This option wants type %x\n", opt->type);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to the *curl_easyoption* struct for the option or NULL.
Changes to jni/curl/docs/libcurl/curl_easy_option_by_name.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_option_by_name
Section: 3
Source: libcurl
See-also:
  - curl_easy_option_by_id (3)
  - curl_easy_option_next (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

curl_easy_option_by_name - find an easy setopt option by name

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_option_by_name
Section: 3
Source: libcurl
See-also:
  - curl_easy_option_by_id (3)
  - curl_easy_option_next (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.73.0
---

# NAME

curl_easy_option_by_name - find an easy setopt option by name

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
*curl_easyoption* struct, holding information about the
curl_easy_setopt(3) option using that name. The name should be specified
without the "CURLOPT_" prefix and the name comparison is made case
insensitive.

If libcurl has no option with the given name, this function returns NULL.



# EXAMPLE

~~~c
int main(void)
{
  const struct curl_easyoption *opt = curl_easy_option_by_name("URL");
  if(opt) {
    printf("This option wants CURLoption %x\n", (int)opt->id);
  }
}
~~~

# AVAILABILITY

This function was added in libcurl 7.73.0

# RETURN VALUE

A pointer to the *curl_easyoption* struct for the option or NULL.







>
>












|
<
<




31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52


53
54
55
56
*curl_easyoption* struct, holding information about the
curl_easy_setopt(3) option using that name. The name should be specified
without the "CURLOPT_" prefix and the name comparison is made case
insensitive.

If libcurl has no option with the given name, this function returns NULL.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  const struct curl_easyoption *opt = curl_easy_option_by_name("URL");
  if(opt) {
    printf("This option wants CURLoption %x\n", (int)opt->id);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to the *curl_easyoption* struct for the option or NULL.
Changes to jni/curl/docs/libcurl/curl_easy_option_next.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_option_next
Section: 3
Source: libcurl
See-also:
  - curl_easy_option_by_id (3)
  - curl_easy_option_by_name (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

curl_easy_option_next - iterate over easy setopt options

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_option_next
Section: 3
Source: libcurl
See-also:
  - curl_easy_option_by_id (3)
  - curl_easy_option_by_name (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.73.0
---

# NAME

curl_easy_option_next - iterate over easy setopt options

# SYNOPSIS
62
63
64
65
66
67
68


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  const char *name;
  CURLoption id;
  curl_easytype type;
  unsigned int flags;
};
~~~



# EXAMPLE

~~~c
int main(void)
{
  /* iterate over all available options */
  const struct curl_easyoption *opt;
  opt = curl_easy_option_next(NULL);
  while(opt) {
    printf("Name: %s\n", opt->name);
    opt = curl_easy_option_next(opt);
  }
}
~~~

# AVAILABILITY

This function was added in libcurl 7.73.0

# RETURN VALUE

A pointer to the *curl_easyoption* struct for the next option or NULL if
no more options.







>
>















|
<
<





63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87


88
89
90
91
92
  const char *name;
  CURLoption id;
  curl_easytype type;
  unsigned int flags;
};
~~~

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  /* iterate over all available options */
  const struct curl_easyoption *opt;
  opt = curl_easy_option_next(NULL);
  while(opt) {
    printf("Name: %s\n", opt->name);
    opt = curl_easy_option_next(opt);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to the *curl_easyoption* struct for the next option or NULL if
no more options.
Changes to jni/curl/docs/libcurl/curl_easy_pause.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_pause
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_reset (3)
Protocol:
  - All

---

# NAME

curl_easy_pause - pause and unpause a connection

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_pause
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_reset (3)
Protocol:
  - All
Added-in: 7.18.0
---

# NAME

curl_easy_pause - pause and unpause a connection

# SYNOPSIS
93
94
95
96
97
98
99


100
101
102
103
104
105
106
continue sending data up to that window size amount. By default, libcurl
announces a 32 megabyte window size, which thus can make libcurl end up
buffering 32 megabyte of data for a paused stream.

When such a paused stream is unpaused again, any buffered data is delivered
first.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
continue sending data up to that window size amount. By default, libcurl
announces a 32 megabyte window size, which thus can make libcurl end up
buffering 32 megabyte of data for a paused stream.

When such a paused stream is unpaused again, any buffered data is delivered
first.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
data automatically.

If the download is done with HTTP/2 or HTTP/3, there is up to a stream window
size worth of data that curl cannot stop but instead needs to cache while the
transfer is paused. This means that if a window size of 64 MB is used, libcurl
might end up having to cache 64 MB of data.

# AVAILABILITY

Added in 7.18.0.

# RETURN VALUE

CURLE_OK (zero) means that the option was set properly, and a non-zero return
code means something wrong occurred after the new state was set. See the
libcurl-errors(3) man page for the full list with descriptions.







|
<
<






130
131
132
133
134
135
136
137


138
139
140
141
142
143
data automatically.

If the download is done with HTTP/2 or HTTP/3, there is up to a stream window
size worth of data that curl cannot stop but instead needs to cache while the
transfer is paused. This means that if a window size of 64 MB is used, libcurl
might end up having to cache 64 MB of data.

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK (zero) means that the option was set properly, and a non-zero return
code means something wrong occurred after the new state was set. See the
libcurl-errors(3) man page for the full list with descriptions.
Changes to jni/curl/docs/libcurl/curl_easy_perform.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
  - curl_easy_init (3)
  - curl_easy_setopt (3)
  - curl_multi_add_handle (3)
  - curl_multi_perform (3)
  - libcurl-errors (3)
Protocol:
  - All

---

# NAME

curl_easy_perform - perform a blocking file transfer

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_perform(CURL *easy_handle);







>




|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  - curl_easy_init (3)
  - curl_easy_setopt (3)
  - curl_multi_add_handle (3)
  - curl_multi_perform (3)
  - libcurl-errors (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_easy_perform - perform a blocking network transfer

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_perform(CURL *easy_handle);
54
55
56
57
58
59
60


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
CURLOPT_WRITEDATA(3) options. To tell libcurl what data to send, there are a
few more alternatives but two common ones are CURLOPT_READFUNCTION(3) and
CURLOPT_POSTFIELDS(3).

While the **easy_handle** is added to a multi handle, it cannot be used by
curl_easy_perform(3).



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

CURLE_OK (0) means everything was OK, non-zero means an error occurred as
*\<curl/curl.h\>* defines - see libcurl-errors(3). If CURLOPT_ERRORBUFFER(3)
was set with curl_easy_setopt(3) there is an error message stored in the error
buffer when non-zero is returned.







>
>















|
<
<







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79


80
81
82
83
84
85
86
CURLOPT_WRITEDATA(3) options. To tell libcurl what data to send, there are a
few more alternatives but two common ones are CURLOPT_READFUNCTION(3) and
CURLOPT_POSTFIELDS(3).

While the **easy_handle** is added to a multi handle, it cannot be used by
curl_easy_perform(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK (0) means everything was OK, non-zero means an error occurred as
*\<curl/curl.h\>* defines - see libcurl-errors(3). If CURLOPT_ERRORBUFFER(3)
was set with curl_easy_setopt(3) there is an error message stored in the error
buffer when non-zero is returned.
Changes to jni/curl/docs/libcurl/curl_easy_recv.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_recv
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_perform (3)
  - curl_easy_send (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

curl_easy_recv - receives raw data on an "easy" connection

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_recv
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_perform (3)
  - curl_easy_send (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.18.2
---

# NAME

curl_easy_recv - receives raw data on an "easy" connection

# SYNOPSIS
53
54
55
56
57
58
59


60
61
62
63
64
65
66
data, therefore you should call curl_easy_recv(3) until all data is
read which would include any cached data.

Furthermore if you wait on the socket and it tells you there is data to read,
curl_easy_recv(3) may return **CURLE_AGAIN** if the only data that was
read was for internal SSL processing, and no other data is available.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
data, therefore you should call curl_easy_recv(3) until all data is
read which would include any cached data.

Furthermore if you wait on the socket and it tells you there is data to read,
curl_easy_recv(3) may return **CURLE_AGAIN** if the only data that was
read was for internal SSL processing, and no other data is available.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
      /* read data */
      res = curl_easy_recv(curl, buf, sizeof(buf), &nread);
    }
  }
}
~~~

# AVAILABILITY

Added in 7.18.2.

# RETURN VALUE

On success, returns **CURLE_OK**, stores the received data into
**buffer**, and the number of bytes it actually read into ***n**.

On failure, returns the appropriate error code.







|
<
<







84
85
86
87
88
89
90
91


92
93
94
95
96
97
98
      /* read data */
      res = curl_easy_recv(curl, buf, sizeof(buf), &nread);
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

On success, returns **CURLE_OK**, stores the received data into
**buffer**, and the number of bytes it actually read into ***n**.

On failure, returns the appropriate error code.
Changes to jni/curl/docs/libcurl/curl_easy_reset.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_reset
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_duphandle (3)
  - curl_easy_init (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

curl_easy_reset - reset all options of a libcurl session handle

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_reset
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_duphandle (3)
  - curl_easy_init (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.12.1
---

# NAME

curl_easy_reset - reset all options of a libcurl session handle

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
default values. This puts back the handle to the same state as it was in when
it was just created with curl_easy_init(3).

It does not change the following information kept in the handle: live
connections, the Session ID cache, the DNS cache, the cookies, the shares or
the alt-svc cache.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {

    /* ... the handle is used and options are set ... */
    curl_easy_reset(curl);
  }
}
~~~

# AVAILABILITY

This function was added in libcurl 7.12.1

# RETURN VALUE

Nothing







>
>














|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


56
57
58
59
default values. This puts back the handle to the same state as it was in when
it was just created with curl_easy_init(3).

It does not change the following information kept in the handle: live
connections, the Session ID cache, the DNS cache, the cookies, the shares or
the alt-svc cache.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {

    /* ... the handle is used and options are set ... */
    curl_easy_reset(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Nothing
Changes to jni/curl/docs/libcurl/curl_easy_send.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_send
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_perform (3)
  - curl_easy_recv (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

curl_easy_send - sends raw data over an "easy" connection

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_send
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_perform (3)
  - curl_easy_recv (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.18.2
---

# NAME

curl_easy_send - sends raw data over an "easy" connection

# SYNOPSIS
48
49
50
51
52
53
54


55
56
57
58
59
60
61
until the socket is writable. The socket may be obtained using
curl_easy_getinfo(3) with CURLINFO_ACTIVESOCKET(3).

Furthermore if you wait on the socket and it tells you it is writable,
curl_easy_send(3) may return **CURLE_AGAIN** if the only data that was sent
was for internal SSL processing, and no other data could be sent.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
until the socket is writable. The socket may be obtained using
curl_easy_getinfo(3) with CURLINFO_ACTIVESOCKET(3).

Furthermore if you wait on the socket and it tells you it is writable,
curl_easy_send(3) may return **CURLE_AGAIN** if the only data that was sent
was for internal SSL processing, and no other data could be sent.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
      /* send data */
      res = curl_easy_send(curl, "hello", 5, &sent);
    }
  }
}
~~~

# AVAILABILITY

Added in 7.18.2.

# RETURN VALUE

On success, returns **CURLE_OK** and stores the number of bytes actually
sent into ***n**. Note that this may be less than the amount you wanted to
send.








|
<
<







77
78
79
80
81
82
83
84


85
86
87
88
89
90
91
      /* send data */
      res = curl_easy_send(curl, "hello", 5, &sent);
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

On success, returns **CURLE_OK** and stores the number of bytes actually
sent into ***n**. Note that this may be less than the amount you wanted to
send.

Changes to jni/curl/docs/libcurl/curl_easy_setopt.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - curl_easy_option_by_id (3)
  - curl_easy_option_by_name (3)
  - curl_easy_option_next (3)
  - curl_easy_reset (3)
  - curl_multi_setopt (3)
Protocol:
  - All

---

# NAME

curl_easy_setopt - set options for a curl easy handle

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - curl_easy_option_by_id (3)
  - curl_easy_option_by_name (3)
  - curl_easy_option_next (3)
  - curl_easy_reset (3)
  - curl_multi_setopt (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_easy_setopt - set options for a curl easy handle

# SYNOPSIS
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73

74



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

108
109
110


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872

873







874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003

Before version 7.17.0, strings were not copied. Instead the user was forced
keep them available until libcurl no longer needed them.

The *handle* is the return code from a curl_easy_init(3) or
curl_easy_duphandle(3) call.

# BEHAVIOR OPTIONS

## CURLOPT_VERBOSE

Display verbose information. See CURLOPT_VERBOSE(3)

## CURLOPT_HEADER



Include the header in the body output. See CURLOPT_HEADER(3)





## CURLOPT_NOPROGRESS

Shut off the progress meter. See CURLOPT_NOPROGRESS(3)

## CURLOPT_NOSIGNAL

Do not install signal handlers. See CURLOPT_NOSIGNAL(3)

## CURLOPT_WILDCARDMATCH

Transfer multiple files according to a filename pattern. See
CURLOPT_WILDCARDMATCH(3)

# CALLBACK OPTIONS

## CURLOPT_WRITEFUNCTION

Callback for writing data. See CURLOPT_WRITEFUNCTION(3)

## CURLOPT_WRITEDATA

Data pointer to pass to the write callback. See CURLOPT_WRITEDATA(3)

## CURLOPT_READFUNCTION

Callback for reading data. See CURLOPT_READFUNCTION(3)

## CURLOPT_READDATA

Data pointer to pass to the read callback. See CURLOPT_READDATA(3)

## CURLOPT_IOCTLFUNCTION


**Deprecated option** Callback for I/O operations.
See CURLOPT_IOCTLFUNCTION(3)



## CURLOPT_IOCTLDATA

**Deprecated option** Data pointer to pass to the I/O callback.
See CURLOPT_IOCTLDATA(3)

## CURLOPT_SEEKFUNCTION

Callback for seek operations. See CURLOPT_SEEKFUNCTION(3)

## CURLOPT_SEEKDATA

Data pointer to pass to the seek callback. See CURLOPT_SEEKDATA(3)

## CURLOPT_SOCKOPTFUNCTION

Callback for sockopt operations. See CURLOPT_SOCKOPTFUNCTION(3)


## CURLOPT_SOCKOPTDATA

Data pointer to pass to the sockopt callback. See CURLOPT_SOCKOPTDATA(3)

## CURLOPT_OPENSOCKETFUNCTION

Callback for socket creation. See CURLOPT_OPENSOCKETFUNCTION(3)

## CURLOPT_OPENSOCKETDATA

Data pointer to pass to the open socket callback. See CURLOPT_OPENSOCKETDATA(3)


## CURLOPT_CLOSESOCKETFUNCTION

Callback for closing socket. See CURLOPT_CLOSESOCKETFUNCTION(3)

## CURLOPT_CLOSESOCKETDATA

Data pointer to pass to the close socket callback. See CURLOPT_CLOSESOCKETDATA(3)

## CURLOPT_PROGRESSFUNCTION

**OBSOLETE** callback for progress meter.
See CURLOPT_PROGRESSFUNCTION(3)

## CURLOPT_PROGRESSDATA

Data pointer to pass to the progress meter callback. See CURLOPT_PROGRESSDATA(3)

## CURLOPT_XFERINFOFUNCTION

Callback for progress meter. See CURLOPT_XFERINFOFUNCTION(3)

## CURLOPT_XFERINFODATA

Data pointer to pass to the progress meter callback. See CURLOPT_XFERINFODATA(3)

## CURLOPT_HEADERFUNCTION

Callback for writing received headers. See CURLOPT_HEADERFUNCTION(3)

## CURLOPT_HEADERDATA

Data pointer to pass to the header callback. See CURLOPT_HEADERDATA(3)

## CURLOPT_DEBUGFUNCTION

Callback for debug information. See CURLOPT_DEBUGFUNCTION(3)

## CURLOPT_DEBUGDATA

Data pointer to pass to the debug callback. See CURLOPT_DEBUGDATA(3)

## CURLOPT_SSL_CTX_FUNCTION

Callback for SSL context logic. See CURLOPT_SSL_CTX_FUNCTION(3)

## CURLOPT_SSL_CTX_DATA

Data pointer to pass to the SSL context callback. See CURLOPT_SSL_CTX_DATA(3)

## CURLOPT_CONV_TO_NETWORK_FUNCTION

**OBSOLETE** Callback for code base conversion.
See CURLOPT_CONV_TO_NETWORK_FUNCTION(3)

## CURLOPT_CONV_FROM_NETWORK_FUNCTION

**OBSOLETE** Callback for code base conversion.
See CURLOPT_CONV_FROM_NETWORK_FUNCTION(3)

## CURLOPT_CONV_FROM_UTF8_FUNCTION

**OBSOLETE** Callback for code base conversion.
See CURLOPT_CONV_FROM_UTF8_FUNCTION(3)

## CURLOPT_INTERLEAVEFUNCTION

Callback for RTSP interleaved data. See CURLOPT_INTERLEAVEFUNCTION(3)

## CURLOPT_INTERLEAVEDATA

Data pointer to pass to the RTSP interleave callback. See CURLOPT_INTERLEAVEDATA(3)

## CURLOPT_CHUNK_BGN_FUNCTION

Callback for wildcard download start of chunk. See CURLOPT_CHUNK_BGN_FUNCTION(3)

## CURLOPT_CHUNK_END_FUNCTION

Callback for wildcard download end of chunk. See CURLOPT_CHUNK_END_FUNCTION(3)

## CURLOPT_CHUNK_DATA

Data pointer to pass to the chunk callbacks. See CURLOPT_CHUNK_DATA(3)

## CURLOPT_FNMATCH_FUNCTION

Callback for wildcard matching. See CURLOPT_FNMATCH_FUNCTION(3)

## CURLOPT_FNMATCH_DATA

Data pointer to pass to the wildcard matching callback. See CURLOPT_FNMATCH_DATA(3)

## CURLOPT_SUPPRESS_CONNECT_HEADERS

Suppress proxy CONNECT response headers from user callbacks. See
CURLOPT_SUPPRESS_CONNECT_HEADERS(3)

## CURLOPT_RESOLVER_START_FUNCTION

Callback to be called before a new resolve request is started. See
CURLOPT_RESOLVER_START_FUNCTION(3)

## CURLOPT_RESOLVER_START_DATA

Data pointer to pass to resolver start callback. See CURLOPT_RESOLVER_START_DATA(3)

## CURLOPT_PREREQFUNCTION

Callback to be called after a connection is established but before a request
is made on that connection. See CURLOPT_PREREQFUNCTION(3)

## CURLOPT_PREREQDATA

Data pointer to pass to the CURLOPT_PREREQFUNCTION callback. See
CURLOPT_PREREQDATA(3)

# ERROR OPTIONS

## CURLOPT_ERRORBUFFER

Error message buffer. See CURLOPT_ERRORBUFFER(3)

## CURLOPT_STDERR

stderr replacement stream. See CURLOPT_STDERR(3)

## CURLOPT_FAILONERROR

Fail on HTTP 4xx errors. CURLOPT_FAILONERROR(3)

## CURLOPT_KEEP_SENDING_ON_ERROR

Keep sending on HTTP \>= 300 errors. CURLOPT_KEEP_SENDING_ON_ERROR(3)

# NETWORK OPTIONS

## CURLOPT_URL

URL to work on. See CURLOPT_URL(3)

## CURLOPT_PATH_AS_IS

Disable squashing /../ and /./ sequences in the path. See CURLOPT_PATH_AS_IS(3)

## CURLOPT_PROTOCOLS

**Deprecated option** Allowed protocols. See CURLOPT_PROTOCOLS(3)

## CURLOPT_PROTOCOLS_STR

Allowed protocols. See CURLOPT_PROTOCOLS_STR(3)

## CURLOPT_REDIR_PROTOCOLS

**Deprecated option** Protocols to allow redirects to. See
CURLOPT_REDIR_PROTOCOLS(3)

## CURLOPT_REDIR_PROTOCOLS_STR

Protocols to allow redirects to. See CURLOPT_REDIR_PROTOCOLS_STR(3)

## CURLOPT_DEFAULT_PROTOCOL

Default protocol. See CURLOPT_DEFAULT_PROTOCOL(3)

## CURLOPT_PROXY

Proxy to use. See CURLOPT_PROXY(3)

## CURLOPT_PRE_PROXY

Socks proxy to use. See CURLOPT_PRE_PROXY(3)

## CURLOPT_PROXYPORT

Proxy port to use. See CURLOPT_PROXYPORT(3)

## CURLOPT_PROXYTYPE

Proxy type. See CURLOPT_PROXYTYPE(3)

## CURLOPT_NOPROXY

Filter out hosts from proxy use. CURLOPT_NOPROXY(3)

## CURLOPT_HTTPPROXYTUNNEL

Tunnel through the HTTP proxy. CURLOPT_HTTPPROXYTUNNEL(3)

## CURLOPT_CONNECT_TO

Connect to a specific host and port. See CURLOPT_CONNECT_TO(3)

## CURLOPT_SOCKS5_AUTH

Socks5 authentication methods. See CURLOPT_SOCKS5_AUTH(3)

## CURLOPT_SOCKS5_GSSAPI_SERVICE

**Deprecated option** Socks5 GSSAPI service name.
See CURLOPT_SOCKS5_GSSAPI_SERVICE(3)

## CURLOPT_SOCKS5_GSSAPI_NEC

Socks5 GSSAPI NEC mode. See CURLOPT_SOCKS5_GSSAPI_NEC(3)

## CURLOPT_PROXY_SERVICE_NAME

Proxy authentication service name. CURLOPT_PROXY_SERVICE_NAME(3)

## CURLOPT_HAPROXYPROTOCOL

Send an HAProxy PROXY protocol v1 header. See CURLOPT_HAPROXYPROTOCOL(3)

## CURLOPT_HAPROXY_CLIENT_IP

Spoof the client IP in an HAProxy PROXY protocol v1 header. See
CURLOPT_HAPROXY_CLIENT_IP(3)

## CURLOPT_SERVICE_NAME

Authentication service name. CURLOPT_SERVICE_NAME(3)

## CURLOPT_INTERFACE

Bind connection locally to this. See CURLOPT_INTERFACE(3)

## CURLOPT_LOCALPORT

Bind connection locally to this port. See CURLOPT_LOCALPORT(3)

## CURLOPT_LOCALPORTRANGE

Bind connection locally to port range. See CURLOPT_LOCALPORTRANGE(3)

## CURLOPT_DNS_CACHE_TIMEOUT

Timeout for DNS cache. See CURLOPT_DNS_CACHE_TIMEOUT(3)

## CURLOPT_DNS_USE_GLOBAL_CACHE

**OBSOLETE** Enable global DNS cache.
See CURLOPT_DNS_USE_GLOBAL_CACHE(3)

## CURLOPT_DOH_URL

Use this DoH server for name resolves. See CURLOPT_DOH_URL(3)

## CURLOPT_BUFFERSIZE

Ask for alternate buffer size. See CURLOPT_BUFFERSIZE(3)

## CURLOPT_PORT

Port number to connect to. See CURLOPT_PORT(3)

## CURLOPT_TCP_FASTOPEN

Enable TCP Fast Open. See CURLOPT_TCP_FASTOPEN(3)

## CURLOPT_TCP_NODELAY

Disable the Nagle algorithm. See CURLOPT_TCP_NODELAY(3)

## CURLOPT_ADDRESS_SCOPE

IPv6 scope for local addresses. See CURLOPT_ADDRESS_SCOPE(3)

## CURLOPT_TCP_KEEPALIVE

Enable TCP keep-alive. See CURLOPT_TCP_KEEPALIVE(3)

## CURLOPT_TCP_KEEPIDLE

Idle time before sending keep-alive. See CURLOPT_TCP_KEEPIDLE(3)

## CURLOPT_TCP_KEEPINTVL

Interval between keep-alive probes. See CURLOPT_TCP_KEEPINTVL(3)

## CURLOPT_UNIX_SOCKET_PATH

Path to a Unix domain socket. See CURLOPT_UNIX_SOCKET_PATH(3)

## CURLOPT_ABSTRACT_UNIX_SOCKET

Path to an abstract Unix domain socket. See CURLOPT_ABSTRACT_UNIX_SOCKET(3)

# NAMES and PASSWORDS OPTIONS (Authentication)

## CURLOPT_NETRC

Enable .netrc parsing. See CURLOPT_NETRC(3)

## CURLOPT_NETRC_FILE

.netrc filename. See CURLOPT_NETRC_FILE(3)

## CURLOPT_USERPWD

Username and password. See CURLOPT_USERPWD(3)

## CURLOPT_PROXYUSERPWD

Proxy username and password. See CURLOPT_PROXYUSERPWD(3)

## CURLOPT_USERNAME

Username. See CURLOPT_USERNAME(3)

## CURLOPT_PASSWORD

Password. See CURLOPT_PASSWORD(3)

## CURLOPT_LOGIN_OPTIONS

Login options. See CURLOPT_LOGIN_OPTIONS(3)

## CURLOPT_PROXYUSERNAME

Proxy username. See CURLOPT_PROXYUSERNAME(3)

## CURLOPT_PROXYPASSWORD

Proxy password. See CURLOPT_PROXYPASSWORD(3)

## CURLOPT_HTTPAUTH

HTTP server authentication methods. See CURLOPT_HTTPAUTH(3)

## CURLOPT_TLSAUTH_USERNAME

TLS authentication username. See CURLOPT_TLSAUTH_USERNAME(3)

## CURLOPT_PROXY_TLSAUTH_USERNAME

Proxy TLS authentication username. See CURLOPT_PROXY_TLSAUTH_USERNAME(3)

## CURLOPT_TLSAUTH_PASSWORD

TLS authentication password. See CURLOPT_TLSAUTH_PASSWORD(3)

## CURLOPT_PROXY_TLSAUTH_PASSWORD

Proxy TLS authentication password. See CURLOPT_PROXY_TLSAUTH_PASSWORD(3)

## CURLOPT_TLSAUTH_TYPE

TLS authentication methods. See CURLOPT_TLSAUTH_TYPE(3)

## CURLOPT_PROXY_TLSAUTH_TYPE

Proxy TLS authentication methods. See CURLOPT_PROXY_TLSAUTH_TYPE(3)

## CURLOPT_PROXYAUTH

HTTP proxy authentication methods. See CURLOPT_PROXYAUTH(3)

## CURLOPT_SASL_AUTHZID

SASL authorization identity (identity to act as). See CURLOPT_SASL_AUTHZID(3)

## CURLOPT_SASL_IR

Enable SASL initial response. See CURLOPT_SASL_IR(3)

## CURLOPT_XOAUTH2_BEARER

OAuth2 bearer token. See CURLOPT_XOAUTH2_BEARER(3)

## CURLOPT_DISALLOW_USERNAME_IN_URL

Do not allow username in URL. See CURLOPT_DISALLOW_USERNAME_IN_URL(3)

# HTTP OPTIONS

## CURLOPT_AUTOREFERER

Automatically set Referer: header. See CURLOPT_AUTOREFERER(3)

## CURLOPT_ACCEPT_ENCODING

Accept-Encoding and automatic decompressing data. See CURLOPT_ACCEPT_ENCODING(3)

## CURLOPT_TRANSFER_ENCODING

Request Transfer-Encoding. See CURLOPT_TRANSFER_ENCODING(3)

## CURLOPT_FOLLOWLOCATION

Follow HTTP redirects. See CURLOPT_FOLLOWLOCATION(3)

## CURLOPT_UNRESTRICTED_AUTH

Do not restrict authentication to original host. CURLOPT_UNRESTRICTED_AUTH(3)

## CURLOPT_MAXREDIRS

Maximum number of redirects to follow. See CURLOPT_MAXREDIRS(3)

## CURLOPT_POSTREDIR

How to act on redirects after POST. See CURLOPT_POSTREDIR(3)

## CURLOPT_PUT

**Deprecated option** Issue an HTTP PUT request. See CURLOPT_PUT(3)

## CURLOPT_POST

Issue an HTTP POST request. See CURLOPT_POST(3)

## CURLOPT_POSTFIELDS

Send a POST with this data. See CURLOPT_POSTFIELDS(3)

## CURLOPT_POSTFIELDSIZE

The POST data is this big. See CURLOPT_POSTFIELDSIZE(3)

## CURLOPT_POSTFIELDSIZE_LARGE

The POST data is this big. See CURLOPT_POSTFIELDSIZE_LARGE(3)

## CURLOPT_COPYPOSTFIELDS

Send a POST with this data - and copy it. See CURLOPT_COPYPOSTFIELDS(3)

## CURLOPT_HTTPPOST

**Deprecated option** Multipart formpost HTTP POST.
See CURLOPT_HTTPPOST(3)

## CURLOPT_REFERER

Referer: header. See CURLOPT_REFERER(3)

## CURLOPT_USERAGENT

User-Agent: header. See CURLOPT_USERAGENT(3)

## CURLOPT_HTTPHEADER

Custom HTTP headers. See CURLOPT_HTTPHEADER(3)

## CURLOPT_HEADEROPT

Control custom headers. See CURLOPT_HEADEROPT(3)

## CURLOPT_PROXYHEADER

Custom HTTP headers sent to proxy. See CURLOPT_PROXYHEADER(3)

## CURLOPT_HTTP200ALIASES

Alternative versions of 200 OK. See CURLOPT_HTTP200ALIASES(3)

## CURLOPT_COOKIE

Cookie(s) to send. See CURLOPT_COOKIE(3)

## CURLOPT_COOKIEFILE

File to read cookies from. See CURLOPT_COOKIEFILE(3)

## CURLOPT_COOKIEJAR

File to write cookies to. See CURLOPT_COOKIEJAR(3)

## CURLOPT_COOKIESESSION

Start a new cookie session. See CURLOPT_COOKIESESSION(3)

## CURLOPT_COOKIELIST

Add or control cookies. See CURLOPT_COOKIELIST(3)

## CURLOPT_ALTSVC

Specify the Alt-Svc: cache filename. See CURLOPT_ALTSVC(3)

## CURLOPT_ALTSVC_CTRL

Enable and configure Alt-Svc: treatment. See CURLOPT_ALTSVC_CTRL(3)

## CURLOPT_HSTS

Set HSTS cache file. See CURLOPT_HSTS(3)

## CURLOPT_HSTS_CTRL

Enable HSTS. See CURLOPT_HSTS_CTRL(3)

## CURLOPT_HSTSREADFUNCTION

Set HSTS read callback. See CURLOPT_HSTSREADFUNCTION(3)

## CURLOPT_HSTSREADDATA

Pass pointer to the HSTS read callback. See CURLOPT_HSTSREADDATA(3)

## CURLOPT_HSTSWRITEFUNCTION

Set HSTS write callback. See CURLOPT_HSTSWRITEFUNCTION(3)

## CURLOPT_HSTSWRITEDATA

Pass pointer to the HSTS write callback. See CURLOPT_HSTSWRITEDATA(3)

## CURLOPT_HTTPGET

Do an HTTP GET request. See CURLOPT_HTTPGET(3)

## CURLOPT_REQUEST_TARGET

Set the request target. CURLOPT_REQUEST_TARGET(3)

## CURLOPT_HTTP_VERSION

HTTP version to use. CURLOPT_HTTP_VERSION(3)

## CURLOPT_HTTP09_ALLOWED

Allow HTTP/0.9 responses. CURLOPT_HTTP09_ALLOWED(3)

## CURLOPT_IGNORE_CONTENT_LENGTH

Ignore Content-Length. See CURLOPT_IGNORE_CONTENT_LENGTH(3)

## CURLOPT_HTTP_CONTENT_DECODING

Disable Content decoding. See CURLOPT_HTTP_CONTENT_DECODING(3)

## CURLOPT_HTTP_TRANSFER_DECODING

Disable Transfer decoding. See CURLOPT_HTTP_TRANSFER_DECODING(3)

## CURLOPT_EXPECT_100_TIMEOUT_MS

100-continue timeout. See CURLOPT_EXPECT_100_TIMEOUT_MS(3)

## CURLOPT_TRAILERFUNCTION

Set callback for sending trailing headers. See
CURLOPT_TRAILERFUNCTION(3)

## CURLOPT_TRAILERDATA

Custom pointer passed to the trailing headers callback. See
CURLOPT_TRAILERDATA(3)

## CURLOPT_PIPEWAIT

Wait on connection to pipeline on it. See CURLOPT_PIPEWAIT(3)

## CURLOPT_STREAM_DEPENDS

This HTTP/2 stream depends on another. See CURLOPT_STREAM_DEPENDS(3)

## CURLOPT_STREAM_DEPENDS_E

This HTTP/2 stream depends on another exclusively. See
CURLOPT_STREAM_DEPENDS_E(3)

## CURLOPT_STREAM_WEIGHT

Set this HTTP/2 stream's weight. See CURLOPT_STREAM_WEIGHT(3)

# SMTP OPTIONS

## CURLOPT_MAIL_FROM

Address of the sender. See CURLOPT_MAIL_FROM(3)

## CURLOPT_MAIL_RCPT

Address of the recipients. See CURLOPT_MAIL_RCPT(3)

## CURLOPT_MAIL_AUTH

Authentication address. See CURLOPT_MAIL_AUTH(3)

## CURLOPT_MAIL_RCPT_ALLOWFAILS

Allow RCPT TO command to fail for some recipients. See
CURLOPT_MAIL_RCPT_ALLOWFAILS(3)

# TFTP OPTIONS

## CURLOPT_TFTP_BLKSIZE

TFTP block size. See CURLOPT_TFTP_BLKSIZE(3)

## CURLOPT_TFTP_NO_OPTIONS

Do not send TFTP options requests. See CURLOPT_TFTP_NO_OPTIONS(3)

# FTP OPTIONS

## CURLOPT_FTPPORT

Use active FTP. See CURLOPT_FTPPORT(3)

## CURLOPT_QUOTE

Commands to run before transfer. See CURLOPT_QUOTE(3)

## CURLOPT_POSTQUOTE

Commands to run after transfer. See CURLOPT_POSTQUOTE(3)

## CURLOPT_PREQUOTE

Commands to run just before transfer. See CURLOPT_PREQUOTE(3)

## CURLOPT_APPEND

Append to remote file. See CURLOPT_APPEND(3)

## CURLOPT_FTP_USE_EPRT

Use EPRT. See CURLOPT_FTP_USE_EPRT(3)

## CURLOPT_FTP_USE_EPSV

Use EPSV. See CURLOPT_FTP_USE_EPSV(3)

## CURLOPT_FTP_USE_PRET

Use PRET. See CURLOPT_FTP_USE_PRET(3)

## CURLOPT_FTP_CREATE_MISSING_DIRS

Create missing directories on the remote server. See CURLOPT_FTP_CREATE_MISSING_DIRS(3)

## CURLOPT_SERVER_RESPONSE_TIMEOUT

Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT(3)

## CURLOPT_SERVER_RESPONSE_TIMEOUT_MS

Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3)

## CURLOPT_FTP_ALTERNATIVE_TO_USER

Alternative to USER. See CURLOPT_FTP_ALTERNATIVE_TO_USER(3)

## CURLOPT_FTP_SKIP_PASV_IP

Ignore the IP address in the PASV response. See CURLOPT_FTP_SKIP_PASV_IP(3)

## CURLOPT_FTPSSLAUTH

Control how to do TLS. See CURLOPT_FTPSSLAUTH(3)

## CURLOPT_FTP_SSL_CCC

Back to non-TLS again after authentication. See CURLOPT_FTP_SSL_CCC(3)

## CURLOPT_FTP_ACCOUNT

Send ACCT command. See CURLOPT_FTP_ACCOUNT(3)

## CURLOPT_FTP_FILEMETHOD

Specify how to reach files. See CURLOPT_FTP_FILEMETHOD(3)

# RTSP OPTIONS

## CURLOPT_RTSP_REQUEST

RTSP request. See CURLOPT_RTSP_REQUEST(3)

## CURLOPT_RTSP_SESSION_ID

RTSP session-id. See CURLOPT_RTSP_SESSION_ID(3)

## CURLOPT_RTSP_STREAM_URI

RTSP stream URI. See CURLOPT_RTSP_STREAM_URI(3)

## CURLOPT_RTSP_TRANSPORT

RTSP Transport: header. See CURLOPT_RTSP_TRANSPORT(3)

## CURLOPT_RTSP_CLIENT_CSEQ

Client CSEQ number. See CURLOPT_RTSP_CLIENT_CSEQ(3)

## CURLOPT_RTSP_SERVER_CSEQ

CSEQ number for RTSP Server-\>Client request. See CURLOPT_RTSP_SERVER_CSEQ(3)

## CURLOPT_AWS_SIGV4

AWS HTTP V4 Signature. See CURLOPT_AWS_SIGV4(3)

# PROTOCOL OPTIONS

## CURLOPT_TRANSFERTEXT

Use text transfer. See CURLOPT_TRANSFERTEXT(3)

## CURLOPT_PROXY_TRANSFER_MODE

Add transfer mode to URL over proxy. See CURLOPT_PROXY_TRANSFER_MODE(3)

## CURLOPT_CRLF

Convert newlines. See CURLOPT_CRLF(3)

## CURLOPT_RANGE

Range requests. See CURLOPT_RANGE(3)

## CURLOPT_RESUME_FROM

Resume a transfer. See CURLOPT_RESUME_FROM(3)

## CURLOPT_RESUME_FROM_LARGE

Resume a transfer. See CURLOPT_RESUME_FROM_LARGE(3)

## CURLOPT_CURLU

Set URL to work on with a URL handle. See CURLOPT_CURLU(3)

## CURLOPT_CUSTOMREQUEST

Custom request/method. See CURLOPT_CUSTOMREQUEST(3)

## CURLOPT_FILETIME


Request file modification date and time. See CURLOPT_FILETIME(3)








## CURLOPT_DIRLISTONLY

List only. See CURLOPT_DIRLISTONLY(3)

## CURLOPT_NOBODY

Do not get the body contents. See CURLOPT_NOBODY(3)

## CURLOPT_INFILESIZE

Size of file to send. CURLOPT_INFILESIZE(3)

## CURLOPT_INFILESIZE_LARGE

Size of file to send. CURLOPT_INFILESIZE_LARGE(3)

## CURLOPT_UPLOAD

Upload data. See CURLOPT_UPLOAD(3)

## CURLOPT_UPLOAD_BUFFERSIZE

Set upload buffer size. See CURLOPT_UPLOAD_BUFFERSIZE(3)

## CURLOPT_MIMEPOST

Post/send MIME data. See CURLOPT_MIMEPOST(3)

## CURLOPT_MIME_OPTIONS

Set MIME option flags. See CURLOPT_MIME_OPTIONS(3)

## CURLOPT_MAXFILESIZE

Maximum file size to get. See CURLOPT_MAXFILESIZE(3)

## CURLOPT_MAXFILESIZE_LARGE

Maximum file size to get. See CURLOPT_MAXFILESIZE_LARGE(3)

## CURLOPT_TIMECONDITION

Make a time conditional request. See CURLOPT_TIMECONDITION(3)

## CURLOPT_TIMEVALUE

Time value for the time conditional request. See CURLOPT_TIMEVALUE(3)

## CURLOPT_TIMEVALUE_LARGE

Time value for the time conditional request. See CURLOPT_TIMEVALUE_LARGE(3)

# CONNECTION OPTIONS

## CURLOPT_TIMEOUT

Timeout for the entire request. See CURLOPT_TIMEOUT(3)

## CURLOPT_TIMEOUT_MS

Millisecond timeout for the entire request. See CURLOPT_TIMEOUT_MS(3)

## CURLOPT_LOW_SPEED_LIMIT

Low speed limit to abort transfer. See CURLOPT_LOW_SPEED_LIMIT(3)

## CURLOPT_LOW_SPEED_TIME

Time to be below the speed to trigger low speed abort. See CURLOPT_LOW_SPEED_TIME(3)

## CURLOPT_MAX_SEND_SPEED_LARGE

Cap the upload speed to this. See CURLOPT_MAX_SEND_SPEED_LARGE(3)

## CURLOPT_MAX_RECV_SPEED_LARGE

Cap the download speed to this. See CURLOPT_MAX_RECV_SPEED_LARGE(3)

## CURLOPT_MAXCONNECTS

Maximum number of connections in the connection pool. See CURLOPT_MAXCONNECTS(3)

## CURLOPT_FRESH_CONNECT

Use a new connection. CURLOPT_FRESH_CONNECT(3)

## CURLOPT_FORBID_REUSE

Prevent subsequent connections from reusing this. See CURLOPT_FORBID_REUSE(3)

## CURLOPT_MAXAGE_CONN

Limit the age (idle time) of connections for reuse. See CURLOPT_MAXAGE_CONN(3)

## CURLOPT_MAXLIFETIME_CONN

Limit the age (since creation) of connections for reuse. See
CURLOPT_MAXLIFETIME_CONN(3)

## CURLOPT_CONNECTTIMEOUT

Timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT(3)

## CURLOPT_CONNECTTIMEOUT_MS

Millisecond timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT_MS(3)

## CURLOPT_IPRESOLVE

IP version to use. See CURLOPT_IPRESOLVE(3)

## CURLOPT_CONNECT_ONLY

Only connect, nothing else. See CURLOPT_CONNECT_ONLY(3)

## CURLOPT_USE_SSL

Use TLS/SSL. See CURLOPT_USE_SSL(3)

## CURLOPT_RESOLVE

Provide fixed/fake name resolves. See CURLOPT_RESOLVE(3)

## CURLOPT_DNS_INTERFACE

Bind name resolves to this interface. See CURLOPT_DNS_INTERFACE(3)

## CURLOPT_DNS_LOCAL_IP4








|

|

|

|

>
>
|
>

>
>
>
|

|

|

|

|

<
<
|
<

|

|

|

|

|

|

|

|

|

>
|
|

>
>
|

<
|

|

|

|

|

|

|
>

|

|

|

|

|

|
>





|

<
|
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|

<
|
<

<
<
|

<
|
<

<
<
|

<
|
<
<
<
<











<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|

<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<













<
<
<
<




<
<
<
<
<
<
<
<
|

<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
|

<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<





|

<
|
<
<
<
<
<
<
<









|

>
|
>
>
>
>
>
>
>





|

<
|
<

<
<
<
<
<
<
|

<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91


92

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

154

155



















156
157

158

159


160
161

162

163


164
165

166




167
168
169
170
171
172
173
174
175
176
177




















































































































































































































































































































































178
179

180























181
























182
183
184
185
186
187
188
189
190
191
192
193
194




195
196
197
198








199
200

201







































































































202










203
204

205



































































































206
207
208
209
210
211
212

213







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240

241

242






243
244

245






































































































246
247
248
249
250
251
252

Before version 7.17.0, strings were not copied. Instead the user was forced
keep them available until libcurl no longer needed them.

The *handle* is the return code from a curl_easy_init(3) or
curl_easy_duphandle(3) call.

# OPTIONS

## CURLOPT_ABSTRACT_UNIX_SOCKET

Path to an abstract Unix domain socket. See CURLOPT_ABSTRACT_UNIX_SOCKET(3)

## CURLOPT_ACCEPTTIMEOUT_MS

Timeout for waiting for the server's connect back to be accepted. See
CURLOPT_ACCEPTTIMEOUT_MS(3)

## CURLOPT_ACCEPT_ENCODING

Accept-Encoding and automatic decompressing data. See
CURLOPT_ACCEPT_ENCODING(3)

## CURLOPT_ADDRESS_SCOPE

IPv6 scope for local addresses. See CURLOPT_ADDRESS_SCOPE(3)

## CURLOPT_ALTSVC

Specify the Alt-Svc: cache filename. See CURLOPT_ALTSVC(3)

## CURLOPT_ALTSVC_CTRL



Enable and configure Alt-Svc: treatment. See CURLOPT_ALTSVC_CTRL(3)


## CURLOPT_APPEND

Append to remote file. See CURLOPT_APPEND(3)

## CURLOPT_AUTOREFERER

Automatically set Referer: header. See CURLOPT_AUTOREFERER(3)

## CURLOPT_AWS_SIGV4

AWS HTTP V4 Signature. See CURLOPT_AWS_SIGV4(3)

## CURLOPT_BUFFERSIZE

Ask for alternate buffer size. See CURLOPT_BUFFERSIZE(3)

## CURLOPT_CAINFO

CA cert bundle. See CURLOPT_CAINFO(3)

## CURLOPT_CAINFO_BLOB

CA cert bundle memory buffer. See CURLOPT_CAINFO_BLOB(3)

## CURLOPT_CAPATH


Path to CA cert bundle. See CURLOPT_CAPATH(3)

## CURLOPT_CA_CACHE_TIMEOUT

Timeout for CA cache. See CURLOPT_CA_CACHE_TIMEOUT(3)

## CURLOPT_CERTINFO

Extract certificate info. See CURLOPT_CERTINFO(3)

## CURLOPT_CHUNK_BGN_FUNCTION

Callback for wildcard download start of chunk. See
CURLOPT_CHUNK_BGN_FUNCTION(3)

## CURLOPT_CHUNK_DATA

Data pointer to pass to the chunk callbacks. See CURLOPT_CHUNK_DATA(3)

## CURLOPT_CHUNK_END_FUNCTION

Callback for wildcard download end of chunk. See CURLOPT_CHUNK_END_FUNCTION(3)

## CURLOPT_CLOSESOCKETDATA

Data pointer to pass to the close socket callback. See
CURLOPT_CLOSESOCKETDATA(3)

## CURLOPT_CLOSESOCKETFUNCTION

Callback for closing socket. See CURLOPT_CLOSESOCKETFUNCTION(3)

## CURLOPT_CONNECTTIMEOUT


Timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT(3)





















## CURLOPT_CONNECTTIMEOUT_MS


Millisecond timeout for the connection phase. See CURLOPT_CONNECTTIMEOUT_MS(3)




## CURLOPT_CONNECT_ONLY


Only connect, nothing else. See CURLOPT_CONNECT_ONLY(3)




## CURLOPT_CONNECT_TO


Connect to a specific host and port. See CURLOPT_CONNECT_TO(3)





## CURLOPT_CONV_FROM_NETWORK_FUNCTION

**OBSOLETE** Callback for code base conversion.
See CURLOPT_CONV_FROM_NETWORK_FUNCTION(3)

## CURLOPT_CONV_FROM_UTF8_FUNCTION

**OBSOLETE** Callback for code base conversion.
See CURLOPT_CONV_FROM_UTF8_FUNCTION(3)





















































































































































































































































































































































## CURLOPT_CONV_TO_NETWORK_FUNCTION


**OBSOLETE** Callback for code base conversion.























See CURLOPT_CONV_TO_NETWORK_FUNCTION(3)

























## CURLOPT_COOKIE

Cookie(s) to send. See CURLOPT_COOKIE(3)

## CURLOPT_COOKIEFILE

File to read cookies from. See CURLOPT_COOKIEFILE(3)

## CURLOPT_COOKIEJAR

File to write cookies to. See CURLOPT_COOKIEJAR(3)





## CURLOPT_COOKIELIST

Add or control cookies. See CURLOPT_COOKIELIST(3)









## CURLOPT_COOKIESESSION


Start a new cookie session. See CURLOPT_COOKIESESSION(3)


















































































































## CURLOPT_COPYPOSTFIELDS


Send a POST with this data - and copy it. See CURLOPT_COPYPOSTFIELDS(3)




































































































## CURLOPT_CRLF

Convert newlines. See CURLOPT_CRLF(3)

## CURLOPT_CRLFILE


Certificate Revocation List. See CURLOPT_CRLFILE(3)








## CURLOPT_CURLU

Set URL to work on with a URL handle. See CURLOPT_CURLU(3)

## CURLOPT_CUSTOMREQUEST

Custom request/method. See CURLOPT_CUSTOMREQUEST(3)

## CURLOPT_DEBUGDATA

Data pointer to pass to the debug callback. See CURLOPT_DEBUGDATA(3)

## CURLOPT_DEBUGFUNCTION

Callback for debug information. See CURLOPT_DEBUGFUNCTION(3)

## CURLOPT_DEFAULT_PROTOCOL

Default protocol. See CURLOPT_DEFAULT_PROTOCOL(3)

## CURLOPT_DIRLISTONLY

List only. See CURLOPT_DIRLISTONLY(3)

## CURLOPT_DISALLOW_USERNAME_IN_URL


Do not allow username in URL. See CURLOPT_DISALLOW_USERNAME_IN_URL(3)








## CURLOPT_DNS_CACHE_TIMEOUT


Timeout for DNS cache. See CURLOPT_DNS_CACHE_TIMEOUT(3)







































































































## CURLOPT_DNS_INTERFACE

Bind name resolves to this interface. See CURLOPT_DNS_INTERFACE(3)

## CURLOPT_DNS_LOCAL_IP4

1011
1012
1013
1014
1015
1016
1017























1018
1019

1020









































1021















































1022
1023
1024
1025
1026









1027
1028

1029

1030

1031

1032

1033
1034
1035
1036
1037
1038










1039

1040

1041




1042
1043
1044
1045








1046
1047

1048

1049


1050
1051

1052

1053



1054
1055

1056

1057






1058
1059

1060

1061


1062
1063

1064

1065


1066


1067

1068


1069




1070
1071


1072

1073



1074
1075
1076
1077
1078
1079

1080







1081
1082
1083
1084
1085


































































































































































































































































1086
1087
1088
1089
























































































































































































































































































































1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163

1164
1165
1166
1167
1168
1169
1170
1171

1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257


1258




1259
1260
1261
1262
1263
1264
1265
1266
1267

1268

1269
1270
1271

1272

1273



1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291

1292



1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303

1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379

Preferred DNS servers. See CURLOPT_DNS_SERVERS(3)

## CURLOPT_DNS_SHUFFLE_ADDRESSES

Shuffle addresses before use. See CURLOPT_DNS_SHUFFLE_ADDRESSES(3)
























## CURLOPT_ACCEPTTIMEOUT_MS


Timeout for waiting for the server's connect back to be accepted. See









































CURLOPT_ACCEPTTIMEOUT_MS(3)
















































## CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS

Timeout for happy eyeballs. See CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS(3)










## CURLOPT_UPKEEP_INTERVAL_MS


Sets the interval at which connection upkeep are performed. See

CURLOPT_UPKEEP_INTERVAL_MS(3)



# SSL and SECURITY OPTIONS


## CURLOPT_SSLCERT

Client cert. See CURLOPT_SSLCERT(3)

## CURLOPT_SSLCERT_BLOB












Client cert memory buffer. See CURLOPT_SSLCERT_BLOB(3)






## CURLOPT_PROXY_SSLCERT

Proxy client cert. See CURLOPT_PROXY_SSLCERT(3)









## CURLOPT_PROXY_SSLCERT_BLOB


Proxy client cert memory buffer. See CURLOPT_PROXY_SSLCERT_BLOB(3)




## CURLOPT_SSLCERTTYPE


Client cert type. See CURLOPT_SSLCERTTYPE(3)





## CURLOPT_PROXY_SSLCERTTYPE


Proxy client cert type. See CURLOPT_PROXY_SSLCERTTYPE(3)








## CURLOPT_SSLKEY


Client key. See CURLOPT_SSLKEY(3)




## CURLOPT_SSLKEY_BLOB


Client key memory buffer. See CURLOPT_SSLKEY_BLOB(3)




## CURLOPT_PROXY_SSLKEY




Proxy client key. See CURLOPT_PROXY_SSLKEY(3)







## CURLOPT_PROXY_SSLKEY_BLOB



Proxy client key. See CURLOPT_PROXY_SSLKEY_BLOB(3)





## CURLOPT_SSLKEYTYPE

Client key type. See CURLOPT_SSLKEYTYPE(3)

## CURLOPT_PROXY_SSLKEYTYPE


Proxy client key type. See CURLOPT_PROXY_SSLKEYTYPE(3)








## CURLOPT_KEYPASSWD

Client key password. See CURLOPT_KEYPASSWD(3)



































































































































































































































































## CURLOPT_PROXY_KEYPASSWD

Proxy client key password. See CURLOPT_PROXY_KEYPASSWD(3)

























































































































































































































































































































## CURLOPT_SSL_EC_CURVES

Set key exchange curves. See CURLOPT_SSL_EC_CURVES(3)

## CURLOPT_SSL_ENABLE_ALPN

Enable use of ALPN. See CURLOPT_SSL_ENABLE_ALPN(3)

## CURLOPT_SSL_ENABLE_NPN

**OBSOLETE** Enable use of NPN. See CURLOPT_SSL_ENABLE_NPN(3)

## CURLOPT_SSLENGINE

Use identifier with SSL engine. See CURLOPT_SSLENGINE(3)

## CURLOPT_SSLENGINE_DEFAULT

Default SSL engine. See CURLOPT_SSLENGINE_DEFAULT(3)

## CURLOPT_SSL_FALSESTART

Enable TLS False Start. See CURLOPT_SSL_FALSESTART(3)

## CURLOPT_SSLVERSION

SSL version to use. See CURLOPT_SSLVERSION(3)

## CURLOPT_PROXY_SSLVERSION

Proxy SSL version to use. See CURLOPT_PROXY_SSLVERSION(3)

## CURLOPT_SSL_VERIFYHOST

Verify the hostname in the SSL certificate. See CURLOPT_SSL_VERIFYHOST(3)

## CURLOPT_DOH_SSL_VERIFYHOST

Verify the hostname in the DoH (DNS-over-HTTPS) SSL certificate. See
CURLOPT_DOH_SSL_VERIFYHOST(3)

## CURLOPT_PROXY_SSL_VERIFYHOST

Verify the hostname in the proxy SSL certificate. See
CURLOPT_PROXY_SSL_VERIFYHOST(3)

## CURLOPT_SSL_VERIFYPEER

Verify the SSL certificate. See CURLOPT_SSL_VERIFYPEER(3)

## CURLOPT_DOH_SSL_VERIFYPEER

Verify the DoH (DNS-over-HTTPS) SSL certificate. See
CURLOPT_DOH_SSL_VERIFYPEER(3)

## CURLOPT_PROXY_SSL_VERIFYPEER

Verify the proxy SSL certificate. See CURLOPT_PROXY_SSL_VERIFYPEER(3)

## CURLOPT_SSL_VERIFYSTATUS

Verify the SSL certificate's status. See CURLOPT_SSL_VERIFYSTATUS(3)

## CURLOPT_DOH_SSL_VERIFYSTATUS

Verify the DoH (DNS-over-HTTPS) SSL certificate's status. See
CURLOPT_DOH_SSL_VERIFYSTATUS(3)

## CURLOPT_CAINFO

CA cert bundle. See CURLOPT_CAINFO(3)

## CURLOPT_CAINFO_BLOB


CA cert bundle memory buffer. See CURLOPT_CAINFO_BLOB(3)

## CURLOPT_PROXY_CAINFO

Proxy CA cert bundle. See CURLOPT_PROXY_CAINFO(3)

## CURLOPT_PROXY_CAINFO_BLOB


Proxy CA cert bundle memory buffer. See CURLOPT_PROXY_CAINFO_BLOB(3)

## CURLOPT_ISSUERCERT

Issuer certificate. See CURLOPT_ISSUERCERT(3)

## CURLOPT_ISSUERCERT_BLOB

Issuer certificate memory buffer. See CURLOPT_ISSUERCERT_BLOB(3)

## CURLOPT_PROXY_ISSUERCERT

Proxy issuer certificate. See CURLOPT_PROXY_ISSUERCERT(3)

## CURLOPT_PROXY_ISSUERCERT_BLOB

Proxy issuer certificate memory buffer. See CURLOPT_PROXY_ISSUERCERT_BLOB(3)

## CURLOPT_CAPATH

Path to CA cert bundle. See CURLOPT_CAPATH(3)

## CURLOPT_PROXY_CAPATH

Path to proxy CA cert bundle. See CURLOPT_PROXY_CAPATH(3)

## CURLOPT_CRLFILE

Certificate Revocation List. See CURLOPT_CRLFILE(3)

## CURLOPT_PROXY_CRLFILE

Proxy Certificate Revocation List. See CURLOPT_PROXY_CRLFILE(3)

## CURLOPT_CA_CACHE_TIMEOUT

Timeout for CA cache. See CURLOPT_CA_CACHE_TIMEOUT(3)

## CURLOPT_CERTINFO

Extract certificate info. See CURLOPT_CERTINFO(3)

## CURLOPT_PINNEDPUBLICKEY

Set pinned SSL public key . See CURLOPT_PINNEDPUBLICKEY(3)

## CURLOPT_PROXY_PINNEDPUBLICKEY

Set the proxy's pinned SSL public key. See
CURLOPT_PROXY_PINNEDPUBLICKEY(3)

## CURLOPT_RANDOM_FILE

**OBSOLETE** Provide source for entropy random data.
See CURLOPT_RANDOM_FILE(3)

## CURLOPT_EGDSOCKET

**OBSOLETE** Identify EGD socket for entropy. See CURLOPT_EGDSOCKET(3)

## CURLOPT_SSL_CIPHER_LIST

Ciphers to use. See CURLOPT_SSL_CIPHER_LIST(3)

## CURLOPT_PROXY_SSL_CIPHER_LIST

Proxy ciphers to use. See CURLOPT_PROXY_SSL_CIPHER_LIST(3)

## CURLOPT_TLS13_CIPHERS

TLS 1.3 cipher suites to use. See CURLOPT_TLS13_CIPHERS(3)

## CURLOPT_PROXY_TLS13_CIPHERS

Proxy TLS 1.3 cipher suites to use. See CURLOPT_PROXY_TLS13_CIPHERS(3)

## CURLOPT_SSL_SESSIONID_CACHE

Disable SSL session-id cache. See CURLOPT_SSL_SESSIONID_CACHE(3)

## CURLOPT_SSL_OPTIONS

Control SSL behavior. See CURLOPT_SSL_OPTIONS(3)

## CURLOPT_PROXY_SSL_OPTIONS



Control proxy SSL behavior. See CURLOPT_PROXY_SSL_OPTIONS(3)





## CURLOPT_KRBLEVEL

Kerberos security level. See CURLOPT_KRBLEVEL(3)

## CURLOPT_GSSAPI_DELEGATION

Disable GSS-API delegation. See CURLOPT_GSSAPI_DELEGATION(3)


# SSH OPTIONS


## CURLOPT_SSH_AUTH_TYPES


SSH authentication types. See CURLOPT_SSH_AUTH_TYPES(3)





## CURLOPT_SSH_COMPRESSION

Enable SSH compression. See CURLOPT_SSH_COMPRESSION(3)

## CURLOPT_SSH_HOST_PUBLIC_KEY_MD5

MD5 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_MD5(3)

## CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256

SHA256 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3)

## CURLOPT_SSH_PUBLIC_KEYFILE

Filename of the public key. See CURLOPT_SSH_PUBLIC_KEYFILE(3)

## CURLOPT_SSH_PRIVATE_KEYFILE


Filename of the private key. See CURLOPT_SSH_PRIVATE_KEYFILE(3)




## CURLOPT_SSH_KNOWNHOSTS

Filename with known hosts. See CURLOPT_SSH_KNOWNHOSTS(3)

## CURLOPT_SSH_KEYFUNCTION

Callback for known hosts handling. See CURLOPT_SSH_KEYFUNCTION(3)

## CURLOPT_SSH_KEYDATA


Custom pointer to pass to ssh key callback. See CURLOPT_SSH_KEYDATA(3)

## CURLOPT_SSH_HOSTKEYFUNCTION

Callback for checking host key handling. See CURLOPT_SSH_HOSTKEYFUNCTION(3)

## CURLOPT_SSH_HOSTKEYDATA

Custom pointer to pass to ssh host key callback. See CURLOPT_SSH_HOSTKEYDATA(3)

# WEBSOCKET

## CURLOPT_WS_OPTIONS

Set WebSocket options. See CURLOPT_WS_OPTIONS(3)

# OTHER OPTIONS

## CURLOPT_PRIVATE

Private pointer to store. See CURLOPT_PRIVATE(3)

## CURLOPT_SHARE

Share object to use. See CURLOPT_SHARE(3)

## CURLOPT_NEW_FILE_PERMS

Mode for creating new remote files. See CURLOPT_NEW_FILE_PERMS(3)

## CURLOPT_NEW_DIRECTORY_PERMS

Mode for creating new remote directories. See CURLOPT_NEW_DIRECTORY_PERMS(3)

## CURLOPT_QUICK_EXIT

To be set by toplevel tools like "curl" to skip lengthy cleanups when they are
about to call exit() anyway. See CURLOPT_QUICK_EXIT(3)

# TELNET OPTIONS

## CURLOPT_TELNETOPTIONS

TELNET options. See CURLOPT_TELNETOPTIONS(3)

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# ENCRYPTED CLIENT HELLO OPTIONS

## CURLOPT_ECH

Set the configuration for ECH. See CURLOPT_ECH(3)

# AVAILABILITY

Always

# RETURN VALUE

*CURLE_OK* (zero) means that the option was set properly, non-zero means an
error occurred as *\<curl/curl.h\>* defines. See the libcurl-errors(3) man
page for the full list with descriptions.








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





>
>
>
>
>
>
>
>
>
|

>
|
>
|
>

>
|
>

|

|

|
>
>
>
>
>
>
>
>
>
>

>
|
>

>
>
>
>
|

|

>
>
>
>
>
>
>
>
|

>
|
>

>
>
|

>
|
>

>
>
>
|

>
|
>

>
>
>
>
>
>
|

>
|
>

>
>
|

>
|
>

>
>
|
>
>

>
|
>
>

>
>
>
>
|

>
>
|
>

>
>
>
|

|

|

>
|
>
>
>
>
>
>
>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












<
<
<
<
<
<
<
<




|

|

|

|





<
<
<
<
<
<
<
<
<
<




<
<
<
<
<
<
<
<
<




|

<
|

|

|

|

>
|

|

|

|

>
|

|

|

|

|

|

<
|
<

<
<
|

<
|
<
<
<

|

|

|

|

|

|

|

|

|

|

|

<
|

|

<
|

|

|

|

|

|

|





|

|

|

|

|

|

|

>
>
|
>
>
>
>

|

|

|

|

>
|
>

|

>
|
>

>
>
>
|

|

|

|

|

|

|

|

|

>
|
>
>
>

|

|

|

|

|

>
|

|

|

|

<
|
<





<
<
|

<
|
|

<
<
|

<
|
<

<
<
|

<
<
|
<

<
|
<
















<
<
<
<
<
<
|
<
<







260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118








1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134










1135
1136
1137
1138









1139
1140
1141
1142
1143
1144

1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174

1175

1176


1177
1178

1179



1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202

1203
1204
1205
1206

1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310

1311

1312
1313
1314
1315
1316


1317
1318

1319
1320
1321


1322
1323

1324

1325


1326
1327


1328

1329

1330

1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346






1347


1348
1349
1350
1351
1352
1353
1354

Preferred DNS servers. See CURLOPT_DNS_SERVERS(3)

## CURLOPT_DNS_SHUFFLE_ADDRESSES

Shuffle addresses before use. See CURLOPT_DNS_SHUFFLE_ADDRESSES(3)

## CURLOPT_DNS_USE_GLOBAL_CACHE

**OBSOLETE** Enable global DNS cache. See CURLOPT_DNS_USE_GLOBAL_CACHE(3)

## CURLOPT_DOH_SSL_VERIFYHOST

Verify the hostname in the DoH (DNS-over-HTTPS) SSL certificate. See
CURLOPT_DOH_SSL_VERIFYHOST(3)

## CURLOPT_DOH_SSL_VERIFYPEER

Verify the DoH (DNS-over-HTTPS) SSL certificate. See
CURLOPT_DOH_SSL_VERIFYPEER(3)

## CURLOPT_DOH_SSL_VERIFYSTATUS

Verify the DoH (DNS-over-HTTPS) SSL certificate's status. See
CURLOPT_DOH_SSL_VERIFYSTATUS(3)

## CURLOPT_DOH_URL

Use this DoH server for name resolves. See CURLOPT_DOH_URL(3)

## CURLOPT_ECH

Set the configuration for ECH. See CURLOPT_ECH(3)

## CURLOPT_EGDSOCKET

**OBSOLETE** Identify EGD socket for entropy. See CURLOPT_EGDSOCKET(3)

## CURLOPT_ERRORBUFFER

Error message buffer. See CURLOPT_ERRORBUFFER(3)

## CURLOPT_EXPECT_100_TIMEOUT_MS

100-continue timeout. See CURLOPT_EXPECT_100_TIMEOUT_MS(3)

## CURLOPT_FAILONERROR

Fail on HTTP 4xx errors. CURLOPT_FAILONERROR(3)

## CURLOPT_FILETIME

Request file modification date and time. See CURLOPT_FILETIME(3)

## CURLOPT_FNMATCH_DATA

Data pointer to pass to the wildcard matching callback. See
CURLOPT_FNMATCH_DATA(3)

## CURLOPT_FNMATCH_FUNCTION

Callback for wildcard matching. See CURLOPT_FNMATCH_FUNCTION(3)

## CURLOPT_FOLLOWLOCATION

Follow HTTP redirects. See CURLOPT_FOLLOWLOCATION(3)

## CURLOPT_FORBID_REUSE

Prevent subsequent connections from reusing this. See CURLOPT_FORBID_REUSE(3)

## CURLOPT_FRESH_CONNECT

Use a new connection. CURLOPT_FRESH_CONNECT(3)

## CURLOPT_FTPPORT

Use active FTP. See CURLOPT_FTPPORT(3)

## CURLOPT_FTPSSLAUTH

Control how to do TLS. See CURLOPT_FTPSSLAUTH(3)

## CURLOPT_FTP_ACCOUNT

Send ACCT command. See CURLOPT_FTP_ACCOUNT(3)

## CURLOPT_FTP_ALTERNATIVE_TO_USER

Alternative to USER. See CURLOPT_FTP_ALTERNATIVE_TO_USER(3)

## CURLOPT_FTP_CREATE_MISSING_DIRS

Create missing directories on the remote server. See
CURLOPT_FTP_CREATE_MISSING_DIRS(3)

## CURLOPT_FTP_FILEMETHOD

Specify how to reach files. See CURLOPT_FTP_FILEMETHOD(3)

## CURLOPT_FTP_SKIP_PASV_IP

Ignore the IP address in the PASV response. See CURLOPT_FTP_SKIP_PASV_IP(3)

## CURLOPT_FTP_SSL_CCC

Back to non-TLS again after authentication. See CURLOPT_FTP_SSL_CCC(3)

## CURLOPT_FTP_USE_EPRT

Use EPRT. See CURLOPT_FTP_USE_EPRT(3)

## CURLOPT_FTP_USE_EPSV

Use EPSV. See CURLOPT_FTP_USE_EPSV(3)

## CURLOPT_FTP_USE_PRET

Use PRET. See CURLOPT_FTP_USE_PRET(3)

## CURLOPT_GSSAPI_DELEGATION

Disable GSS-API delegation. See CURLOPT_GSSAPI_DELEGATION(3)

## CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS

Timeout for happy eyeballs. See CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS(3)

## CURLOPT_HAPROXYPROTOCOL

Send an HAProxy PROXY protocol v1 header. See CURLOPT_HAPROXYPROTOCOL(3)

## CURLOPT_HAPROXY_CLIENT_IP

Spoof the client IP in an HAProxy PROXY protocol v1 header. See
CURLOPT_HAPROXY_CLIENT_IP(3)

## CURLOPT_HEADER

Include the header in the body output. See CURLOPT_HEADER(3)

## CURLOPT_HEADERDATA

Data pointer to pass to the header callback. See CURLOPT_HEADERDATA(3)

## CURLOPT_HEADERFUNCTION

Callback for writing received headers. See CURLOPT_HEADERFUNCTION(3)

## CURLOPT_HEADEROPT

Control custom headers. See CURLOPT_HEADEROPT(3)

## CURLOPT_HSTS

Set HSTS cache file. See CURLOPT_HSTS(3)

## CURLOPT_HSTSREADDATA

Pass pointer to the HSTS read callback. See CURLOPT_HSTSREADDATA(3)

## CURLOPT_HSTSREADFUNCTION

Set HSTS read callback. See CURLOPT_HSTSREADFUNCTION(3)

## CURLOPT_HSTSWRITEDATA

Pass pointer to the HSTS write callback. See CURLOPT_HSTSWRITEDATA(3)

## CURLOPT_HSTSWRITEFUNCTION

Set HSTS write callback. See CURLOPT_HSTSWRITEFUNCTION(3)

## CURLOPT_HSTS_CTRL

Enable HSTS. See CURLOPT_HSTS_CTRL(3)

## CURLOPT_HTTP09_ALLOWED

Allow HTTP/0.9 responses. CURLOPT_HTTP09_ALLOWED(3)

## CURLOPT_HTTP200ALIASES

Alternative versions of 200 OK. See CURLOPT_HTTP200ALIASES(3)

## CURLOPT_HTTPAUTH

HTTP server authentication methods. See CURLOPT_HTTPAUTH(3)

## CURLOPT_HTTPGET

Do an HTTP GET request. See CURLOPT_HTTPGET(3)

## CURLOPT_HTTPHEADER

Custom HTTP headers. See CURLOPT_HTTPHEADER(3)

## CURLOPT_HTTPPOST

**Deprecated option** Multipart formpost HTTP POST.
See CURLOPT_HTTPPOST(3)

## CURLOPT_HTTPPROXYTUNNEL

Tunnel through the HTTP proxy. CURLOPT_HTTPPROXYTUNNEL(3)

## CURLOPT_HTTP_CONTENT_DECODING

Disable Content decoding. See CURLOPT_HTTP_CONTENT_DECODING(3)

## CURLOPT_HTTP_TRANSFER_DECODING

Disable Transfer decoding. See CURLOPT_HTTP_TRANSFER_DECODING(3)

## CURLOPT_HTTP_VERSION

HTTP version to use. CURLOPT_HTTP_VERSION(3)

## CURLOPT_IGNORE_CONTENT_LENGTH

Ignore Content-Length. See CURLOPT_IGNORE_CONTENT_LENGTH(3)

## CURLOPT_INFILESIZE

Size of file to send. CURLOPT_INFILESIZE(3)

## CURLOPT_INFILESIZE_LARGE

Size of file to send. CURLOPT_INFILESIZE_LARGE(3)

## CURLOPT_INTERFACE

Bind connection locally to this. See CURLOPT_INTERFACE(3)

## CURLOPT_INTERLEAVEDATA

Data pointer to pass to the RTSP interleave callback. See
CURLOPT_INTERLEAVEDATA(3)

## CURLOPT_INTERLEAVEFUNCTION

Callback for RTSP interleaved data. See CURLOPT_INTERLEAVEFUNCTION(3)

## CURLOPT_IOCTLDATA

**Deprecated option** Data pointer to pass to the I/O callback.
See CURLOPT_IOCTLDATA(3)

## CURLOPT_IOCTLFUNCTION

**Deprecated option** Callback for I/O operations.
See CURLOPT_IOCTLFUNCTION(3)

## CURLOPT_IPRESOLVE

IP version to use. See CURLOPT_IPRESOLVE(3)

## CURLOPT_ISSUERCERT

Issuer certificate. See CURLOPT_ISSUERCERT(3)

## CURLOPT_ISSUERCERT_BLOB

Issuer certificate memory buffer. See CURLOPT_ISSUERCERT_BLOB(3)

## CURLOPT_KEEP_SENDING_ON_ERROR

Keep sending on HTTP \>= 300 errors. CURLOPT_KEEP_SENDING_ON_ERROR(3)

## CURLOPT_KEYPASSWD

Client key password. See CURLOPT_KEYPASSWD(3)

## CURLOPT_KRBLEVEL

Kerberos security level. See CURLOPT_KRBLEVEL(3)

## CURLOPT_LOCALPORT

Bind connection locally to this port. See CURLOPT_LOCALPORT(3)

## CURLOPT_LOCALPORTRANGE

Bind connection locally to port range. See CURLOPT_LOCALPORTRANGE(3)

## CURLOPT_LOGIN_OPTIONS

Login options. See CURLOPT_LOGIN_OPTIONS(3)

## CURLOPT_LOW_SPEED_LIMIT

Low speed limit to abort transfer. See CURLOPT_LOW_SPEED_LIMIT(3)

## CURLOPT_LOW_SPEED_TIME

Time to be below the speed to trigger low speed abort. See
CURLOPT_LOW_SPEED_TIME(3)

## CURLOPT_MAIL_AUTH

Authentication address. See CURLOPT_MAIL_AUTH(3)

## CURLOPT_MAIL_FROM

Address of the sender. See CURLOPT_MAIL_FROM(3)

## CURLOPT_MAIL_RCPT

Address of the recipients. See CURLOPT_MAIL_RCPT(3)

## CURLOPT_MAIL_RCPT_ALLOWFAILS

Allow RCPT TO command to fail for some recipients. See
CURLOPT_MAIL_RCPT_ALLOWFAILS(3)

## CURLOPT_MAXAGE_CONN

Limit the age (idle time) of connections for reuse. See CURLOPT_MAXAGE_CONN(3)

## CURLOPT_MAXCONNECTS

Maximum number of connections in the connection pool. See
CURLOPT_MAXCONNECTS(3)

## CURLOPT_MAXFILESIZE

Maximum file size to get. See CURLOPT_MAXFILESIZE(3)

## CURLOPT_MAXFILESIZE_LARGE

Maximum file size to get. See CURLOPT_MAXFILESIZE_LARGE(3)

## CURLOPT_MAXLIFETIME_CONN

Limit the age (since creation) of connections for reuse. See
CURLOPT_MAXLIFETIME_CONN(3)

## CURLOPT_MAXREDIRS

Maximum number of redirects to follow. See CURLOPT_MAXREDIRS(3)

## CURLOPT_MAX_RECV_SPEED_LARGE

Cap the download speed to this. See CURLOPT_MAX_RECV_SPEED_LARGE(3)

## CURLOPT_MAX_SEND_SPEED_LARGE

Cap the upload speed to this. See CURLOPT_MAX_SEND_SPEED_LARGE(3)

## CURLOPT_MIMEPOST

Post/send MIME data. See CURLOPT_MIMEPOST(3)

## CURLOPT_MIME_OPTIONS

Set MIME option flags. See CURLOPT_MIME_OPTIONS(3)

## CURLOPT_NETRC

Enable .netrc parsing. See CURLOPT_NETRC(3)

## CURLOPT_NETRC_FILE

.netrc filename. See CURLOPT_NETRC_FILE(3)

## CURLOPT_NEW_DIRECTORY_PERMS

Mode for creating new remote directories. See CURLOPT_NEW_DIRECTORY_PERMS(3)

## CURLOPT_NEW_FILE_PERMS

Mode for creating new remote files. See CURLOPT_NEW_FILE_PERMS(3)

## CURLOPT_NOBODY

Do not get the body contents. See CURLOPT_NOBODY(3)

## CURLOPT_NOPROGRESS

Shut off the progress meter. See CURLOPT_NOPROGRESS(3)

## CURLOPT_NOPROXY

Filter out hosts from proxy use. CURLOPT_NOPROXY(3)

## CURLOPT_NOSIGNAL

Do not install signal handlers. See CURLOPT_NOSIGNAL(3)

## CURLOPT_OPENSOCKETDATA

Data pointer to pass to the open socket callback. See CURLOPT_OPENSOCKETDATA(3)

## CURLOPT_OPENSOCKETFUNCTION

Callback for socket creation. See CURLOPT_OPENSOCKETFUNCTION(3)

## CURLOPT_PASSWORD

Password. See CURLOPT_PASSWORD(3)

## CURLOPT_PATH_AS_IS

Disable squashing /../ and /./ sequences in the path. See CURLOPT_PATH_AS_IS(3)

## CURLOPT_PINNEDPUBLICKEY

Set pinned SSL public key . See CURLOPT_PINNEDPUBLICKEY(3)

## CURLOPT_PIPEWAIT

Wait on connection to pipeline on it. See CURLOPT_PIPEWAIT(3)

## CURLOPT_PORT

Port number to connect to. See CURLOPT_PORT(3)

## CURLOPT_POST

Make an HTTP POST. See CURLOPT_POST(3)

## CURLOPT_POSTFIELDSIZE

The POST data is this big. See CURLOPT_POSTFIELDSIZE(3)

## CURLOPT_POSTFIELDSIZE_LARGE

The POST data is this big. See CURLOPT_POSTFIELDSIZE_LARGE(3)

## CURLOPT_POSTQUOTE

Commands to run after transfer. See CURLOPT_POSTQUOTE(3)

## CURLOPT_POSTREDIR

How to act on redirects after POST. See CURLOPT_POSTREDIR(3)

## CURLOPT_PREQUOTE

Commands to run just before transfer. See CURLOPT_PREQUOTE(3)

## CURLOPT_PREREQDATA

Data pointer to pass to the CURLOPT_PREREQFUNCTION callback. See
CURLOPT_PREREQDATA(3)

## CURLOPT_PREREQFUNCTION

Callback to be called after a connection is established but before a request
is made on that connection. See CURLOPT_PREREQFUNCTION(3)

## CURLOPT_PRE_PROXY

Socks proxy to use. See CURLOPT_PRE_PROXY(3)

## CURLOPT_PRIVATE

Private pointer to store. See CURLOPT_PRIVATE(3)

## CURLOPT_PROGRESSDATA

Data pointer to pass to the progress meter callback. See
CURLOPT_PROGRESSDATA(3)

## CURLOPT_PROGRESSFUNCTION

**OBSOLETE** callback for progress meter. See CURLOPT_PROGRESSFUNCTION(3)

## CURLOPT_PROTOCOLS

**Deprecated option** Allowed protocols. See CURLOPT_PROTOCOLS(3)

## CURLOPT_PROTOCOLS_STR

Allowed protocols. See CURLOPT_PROTOCOLS_STR(3)

## CURLOPT_PROXY

Proxy to use. See CURLOPT_PROXY(3)

## CURLOPT_PROXYAUTH

HTTP proxy authentication methods. See CURLOPT_PROXYAUTH(3)

## CURLOPT_PROXYHEADER

Custom HTTP headers sent to proxy. See CURLOPT_PROXYHEADER(3)

## CURLOPT_PROXYPASSWORD

Proxy password. See CURLOPT_PROXYPASSWORD(3)

## CURLOPT_PROXYPORT

Proxy port to use. See CURLOPT_PROXYPORT(3)

## CURLOPT_PROXYTYPE

Proxy type. See CURLOPT_PROXYTYPE(3)

## CURLOPT_PROXYUSERNAME
Proxy username. See CURLOPT_PROXYUSERNAME(3)

## CURLOPT_PROXYUSERPWD

Proxy username and password. See CURLOPT_PROXYUSERPWD(3)

## CURLOPT_PROXY_CAINFO

Proxy CA cert bundle. See CURLOPT_PROXY_CAINFO(3)

## CURLOPT_PROXY_CAINFO_BLOB

Proxy CA cert bundle memory buffer. See CURLOPT_PROXY_CAINFO_BLOB(3)

## CURLOPT_PROXY_CAPATH

Path to proxy CA cert bundle. See CURLOPT_PROXY_CAPATH(3)

## CURLOPT_PROXY_CRLFILE

Proxy Certificate Revocation List. See CURLOPT_PROXY_CRLFILE(3)

## CURLOPT_PROXY_ISSUERCERT

Proxy issuer certificate. See CURLOPT_PROXY_ISSUERCERT(3)

## CURLOPT_PROXY_ISSUERCERT_BLOB

Proxy issuer certificate memory buffer. See CURLOPT_PROXY_ISSUERCERT_BLOB(3)

## CURLOPT_PROXY_KEYPASSWD

Proxy client key password. See CURLOPT_PROXY_KEYPASSWD(3)

## CURLOPT_PROXY_PINNEDPUBLICKEY

Set the proxy's pinned SSL public key. See
CURLOPT_PROXY_PINNEDPUBLICKEY(3)

## CURLOPT_PROXY_SERVICE_NAME

Proxy authentication service name. CURLOPT_PROXY_SERVICE_NAME(3)

## CURLOPT_PROXY_SSLCERT

Proxy client cert. See CURLOPT_PROXY_SSLCERT(3)

## CURLOPT_PROXY_SSLCERTTYPE

Proxy client cert type. See CURLOPT_PROXY_SSLCERTTYPE(3)

## CURLOPT_PROXY_SSLCERT_BLOB

Proxy client cert memory buffer. See CURLOPT_PROXY_SSLCERT_BLOB(3)

## CURLOPT_PROXY_SSLKEY

Proxy client key. See CURLOPT_PROXY_SSLKEY(3)

## CURLOPT_PROXY_SSLKEYTYPE

Proxy client key type. See CURLOPT_PROXY_SSLKEYTYPE(3)

## CURLOPT_PROXY_SSLKEY_BLOB

Proxy client key. See CURLOPT_PROXY_SSLKEY_BLOB(3)

## CURLOPT_PROXY_SSLVERSION

Proxy SSL version to use. See CURLOPT_PROXY_SSLVERSION(3)

## CURLOPT_PROXY_SSL_CIPHER_LIST

Proxy ciphers to use. See CURLOPT_PROXY_SSL_CIPHER_LIST(3)

## CURLOPT_PROXY_SSL_OPTIONS

Control proxy SSL behavior. See CURLOPT_PROXY_SSL_OPTIONS(3)

## CURLOPT_PROXY_SSL_VERIFYHOST

Verify the hostname in the proxy SSL certificate. See
CURLOPT_PROXY_SSL_VERIFYHOST(3)

## CURLOPT_PROXY_SSL_VERIFYPEER

Verify the proxy SSL certificate. See CURLOPT_PROXY_SSL_VERIFYPEER(3)

## CURLOPT_PROXY_TLS13_CIPHERS

Proxy TLS 1.3 cipher suites to use. See CURLOPT_PROXY_TLS13_CIPHERS(3)

## CURLOPT_PROXY_TLSAUTH_PASSWORD

Proxy TLS authentication password. See CURLOPT_PROXY_TLSAUTH_PASSWORD(3)

## CURLOPT_PROXY_TLSAUTH_TYPE

Proxy TLS authentication methods. See CURLOPT_PROXY_TLSAUTH_TYPE(3)

## CURLOPT_PROXY_TLSAUTH_USERNAME

Proxy TLS authentication username. See CURLOPT_PROXY_TLSAUTH_USERNAME(3)

## CURLOPT_PROXY_TRANSFER_MODE

Add transfer mode to URL over proxy. See CURLOPT_PROXY_TRANSFER_MODE(3)

## CURLOPT_PUT

**Deprecated option** Issue an HTTP PUT request. See CURLOPT_PUT(3)

## CURLOPT_QUICK_EXIT

To be set by toplevel tools like "curl" to skip lengthy cleanups when they are
about to call exit() anyway. See CURLOPT_QUICK_EXIT(3)

## CURLOPT_QUOTE

Commands to run before transfer. See CURLOPT_QUOTE(3)

## CURLOPT_RANDOM_FILE

**OBSOLETE** Provide source for entropy random data.
See CURLOPT_RANDOM_FILE(3)

## CURLOPT_RANGE

Range requests. See CURLOPT_RANGE(3)

## CURLOPT_READDATA

Data pointer to pass to the read callback. See CURLOPT_READDATA(3)

## CURLOPT_READFUNCTION

Callback for reading data. See CURLOPT_READFUNCTION(3)

## CURLOPT_REDIR_PROTOCOLS

**Deprecated option** Protocols to allow redirects to. See
CURLOPT_REDIR_PROTOCOLS(3)

## CURLOPT_REDIR_PROTOCOLS_STR

Protocols to allow redirects to. See CURLOPT_REDIR_PROTOCOLS_STR(3)

## CURLOPT_REFERER

Referer: header. See CURLOPT_REFERER(3)

## CURLOPT_REQUEST_TARGET

Set the request target. CURLOPT_REQUEST_TARGET(3)

## CURLOPT_RESOLVE

Provide fixed/fake name resolves. See CURLOPT_RESOLVE(3)

## CURLOPT_RESOLVER_START_DATA

Data pointer to pass to resolver start callback. See
CURLOPT_RESOLVER_START_DATA(3)

## CURLOPT_RESOLVER_START_FUNCTION

Callback to be called before a new resolve request is started. See
CURLOPT_RESOLVER_START_FUNCTION(3)

## CURLOPT_RESUME_FROM

Resume a transfer. See CURLOPT_RESUME_FROM(3)

## CURLOPT_RESUME_FROM_LARGE

Resume a transfer. See CURLOPT_RESUME_FROM_LARGE(3)

## CURLOPT_RTSP_CLIENT_CSEQ

Client CSEQ number. See CURLOPT_RTSP_CLIENT_CSEQ(3)

## CURLOPT_RTSP_REQUEST

RTSP request. See CURLOPT_RTSP_REQUEST(3)

## CURLOPT_RTSP_SERVER_CSEQ

CSEQ number for RTSP Server-\>Client request. See CURLOPT_RTSP_SERVER_CSEQ(3)

## CURLOPT_RTSP_SESSION_ID

RTSP session-id. See CURLOPT_RTSP_SESSION_ID(3)

## CURLOPT_RTSP_STREAM_URI

RTSP stream URI. See CURLOPT_RTSP_STREAM_URI(3)

## CURLOPT_RTSP_TRANSPORT

RTSP Transport: header. See CURLOPT_RTSP_TRANSPORT(3)

## CURLOPT_SASL_AUTHZID

SASL authorization identity (identity to act as). See CURLOPT_SASL_AUTHZID(3)

## CURLOPT_SASL_IR

Enable SASL initial response. See CURLOPT_SASL_IR(3)

## CURLOPT_SEEKDATA

Data pointer to pass to the seek callback. See CURLOPT_SEEKDATA(3)

## CURLOPT_SEEKFUNCTION

Callback for seek operations. See CURLOPT_SEEKFUNCTION(3)

## CURLOPT_SERVER_RESPONSE_TIMEOUT

Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT(3)

## CURLOPT_SERVER_RESPONSE_TIMEOUT_MS

Timeout for server responses. See CURLOPT_SERVER_RESPONSE_TIMEOUT_MS(3)

## CURLOPT_SERVICE_NAME

Authentication service name. CURLOPT_SERVICE_NAME(3)

## CURLOPT_SHARE

Share object to use. See CURLOPT_SHARE(3)

## CURLOPT_SOCKOPTDATA

Data pointer to pass to the sockopt callback. See CURLOPT_SOCKOPTDATA(3)

## CURLOPT_SOCKOPTFUNCTION

Callback for sockopt operations. See CURLOPT_SOCKOPTFUNCTION(3)

## CURLOPT_SOCKS5_AUTH

Socks5 authentication methods. See CURLOPT_SOCKS5_AUTH(3)

## CURLOPT_SOCKS5_GSSAPI_NEC

Socks5 GSSAPI NEC mode. See CURLOPT_SOCKS5_GSSAPI_NEC(3)

## CURLOPT_SOCKS5_GSSAPI_SERVICE

**Deprecated option** Socks5 GSSAPI service name.
See CURLOPT_SOCKS5_GSSAPI_SERVICE(3)

## CURLOPT_SSH_AUTH_TYPES

SSH authentication types. See CURLOPT_SSH_AUTH_TYPES(3)

## CURLOPT_SSH_COMPRESSION

Enable SSH compression. See CURLOPT_SSH_COMPRESSION(3)

## CURLOPT_SSH_HOSTKEYDATA

Custom pointer to pass to ssh host key callback. See CURLOPT_SSH_HOSTKEYDATA(3)

## CURLOPT_SSH_HOSTKEYFUNCTION

Callback for checking host key handling. See CURLOPT_SSH_HOSTKEYFUNCTION(3)

## CURLOPT_SSH_HOST_PUBLIC_KEY_MD5

MD5 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_MD5(3)

## CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256

SHA256 of host's public key. See CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3)

## CURLOPT_SSH_KEYDATA

Custom pointer to pass to ssh key callback. See CURLOPT_SSH_KEYDATA(3)

## CURLOPT_SSH_KEYFUNCTION

Callback for known hosts handling. See CURLOPT_SSH_KEYFUNCTION(3)

## CURLOPT_SSH_KNOWNHOSTS

Filename with known hosts. See CURLOPT_SSH_KNOWNHOSTS(3)

## CURLOPT_SSH_PRIVATE_KEYFILE

Filename of the private key. See CURLOPT_SSH_PRIVATE_KEYFILE(3)

## CURLOPT_SSH_PUBLIC_KEYFILE

Filename of the public key. See CURLOPT_SSH_PUBLIC_KEYFILE(3)

## CURLOPT_SSLCERT

Client cert. See CURLOPT_SSLCERT(3)

## CURLOPT_SSLCERTTYPE

Client cert type. See CURLOPT_SSLCERTTYPE(3)

## CURLOPT_SSLCERT_BLOB

Client cert memory buffer. See CURLOPT_SSLCERT_BLOB(3)

## CURLOPT_SSLENGINE

Use identifier with SSL engine. See CURLOPT_SSLENGINE(3)

## CURLOPT_SSLENGINE_DEFAULT

Default SSL engine. See CURLOPT_SSLENGINE_DEFAULT(3)

## CURLOPT_SSLKEY

Client key. See CURLOPT_SSLKEY(3)

## CURLOPT_SSLKEYTYPE

Client key type. See CURLOPT_SSLKEYTYPE(3)

## CURLOPT_SSLKEY_BLOB

Client key memory buffer. See CURLOPT_SSLKEY_BLOB(3)

## CURLOPT_SSLVERSION

SSL version to use. See CURLOPT_SSLVERSION(3)

## CURLOPT_SSL_CIPHER_LIST

Ciphers to use. See CURLOPT_SSL_CIPHER_LIST(3)

## CURLOPT_SSL_CTX_DATA

Data pointer to pass to the SSL context callback. See CURLOPT_SSL_CTX_DATA(3)

## CURLOPT_SSL_CTX_FUNCTION

Callback for SSL context logic. See CURLOPT_SSL_CTX_FUNCTION(3)

## CURLOPT_SSL_EC_CURVES

Set key exchange curves. See CURLOPT_SSL_EC_CURVES(3)

## CURLOPT_SSL_ENABLE_ALPN

Enable use of ALPN. See CURLOPT_SSL_ENABLE_ALPN(3)

## CURLOPT_SSL_ENABLE_NPN

**OBSOLETE** Enable use of NPN. See CURLOPT_SSL_ENABLE_NPN(3)









## CURLOPT_SSL_FALSESTART

Enable TLS False Start. See CURLOPT_SSL_FALSESTART(3)

## CURLOPT_SSL_OPTIONS

Control SSL behavior. See CURLOPT_SSL_OPTIONS(3)

## CURLOPT_SSL_SESSIONID_CACHE

Disable SSL session-id cache. See CURLOPT_SSL_SESSIONID_CACHE(3)

## CURLOPT_SSL_VERIFYHOST

Verify the hostname in the SSL certificate. See CURLOPT_SSL_VERIFYHOST(3)











## CURLOPT_SSL_VERIFYPEER

Verify the SSL certificate. See CURLOPT_SSL_VERIFYPEER(3)










## CURLOPT_SSL_VERIFYSTATUS

Verify the SSL certificate's status. See CURLOPT_SSL_VERIFYSTATUS(3)

## CURLOPT_STDERR


Redirect stderr to another stream. See CURLOPT_STDERR(3)

## CURLOPT_STREAM_DEPENDS

This HTTP/2 stream depends on another. See CURLOPT_STREAM_DEPENDS(3)

## CURLOPT_STREAM_DEPENDS_E

This HTTP/2 stream depends on another exclusively. See
CURLOPT_STREAM_DEPENDS_E(3)

## CURLOPT_STREAM_WEIGHT

Set this HTTP/2 stream's weight. See CURLOPT_STREAM_WEIGHT(3)

## CURLOPT_SUPPRESS_CONNECT_HEADERS

Suppress proxy CONNECT response headers from user callbacks. See
CURLOPT_SUPPRESS_CONNECT_HEADERS(3)

## CURLOPT_TCP_FASTOPEN

Enable TCP Fast Open. See CURLOPT_TCP_FASTOPEN(3)

## CURLOPT_TCP_KEEPALIVE

Enable TCP keep-alive. See CURLOPT_TCP_KEEPALIVE(3)

## CURLOPT_TCP_KEEPCNT


Maximum number of keep-alive probes. See CURLOPT_TCP_KEEPCNT(3)




## CURLOPT_TCP_KEEPIDLE


Idle time before sending keep-alive. See CURLOPT_TCP_KEEPIDLE(3)




## CURLOPT_TCP_KEEPINTVL

Interval between keep-alive probes. See CURLOPT_TCP_KEEPINTVL(3)

## CURLOPT_TCP_NODELAY

Disable the Nagle algorithm. See CURLOPT_TCP_NODELAY(3)

## CURLOPT_TELNETOPTIONS

TELNET options. See CURLOPT_TELNETOPTIONS(3)

## CURLOPT_TFTP_BLKSIZE

TFTP block size. See CURLOPT_TFTP_BLKSIZE(3)

## CURLOPT_TFTP_NO_OPTIONS

Do not send TFTP options requests. See CURLOPT_TFTP_NO_OPTIONS(3)

## CURLOPT_TIMECONDITION


Make a time conditional request. See CURLOPT_TIMECONDITION(3)

## CURLOPT_TIMEOUT


Timeout for the entire request. See CURLOPT_TIMEOUT(3)

## CURLOPT_TIMEOUT_MS

Millisecond timeout for the entire request. See CURLOPT_TIMEOUT_MS(3)

## CURLOPT_TIMEVALUE

Time value for the time conditional request. See CURLOPT_TIMEVALUE(3)

## CURLOPT_TIMEVALUE_LARGE

Time value for the time conditional request. See CURLOPT_TIMEVALUE_LARGE(3)

## CURLOPT_TLS13_CIPHERS

TLS 1.3 cipher suites to use. See CURLOPT_TLS13_CIPHERS(3)

## CURLOPT_TLSAUTH_PASSWORD

TLS authentication password. See CURLOPT_TLSAUTH_PASSWORD(3)

## CURLOPT_TLSAUTH_TYPE

TLS authentication methods. See CURLOPT_TLSAUTH_TYPE(3)

## CURLOPT_TLSAUTH_USERNAME

TLS authentication username. See CURLOPT_TLSAUTH_USERNAME(3)

## CURLOPT_TRAILERDATA

Custom pointer passed to the trailing headers callback. See
CURLOPT_TRAILERDATA(3)

## CURLOPT_TRAILERFUNCTION

Set callback for sending trailing headers. See
CURLOPT_TRAILERFUNCTION(3)

## CURLOPT_TRANSFERTEXT

Use text transfer. See CURLOPT_TRANSFERTEXT(3)

## CURLOPT_TRANSFER_ENCODING

Request Transfer-Encoding. See CURLOPT_TRANSFER_ENCODING(3)

## CURLOPT_UNIX_SOCKET_PATH

Path to a Unix domain socket. See CURLOPT_UNIX_SOCKET_PATH(3)

## CURLOPT_UNRESTRICTED_AUTH

Do not restrict authentication to original host. CURLOPT_UNRESTRICTED_AUTH(3)

## CURLOPT_UPKEEP_INTERVAL_MS

Sets the interval at which connection upkeep are performed. See
CURLOPT_UPKEEP_INTERVAL_MS(3)

## CURLOPT_UPLOAD

Upload data. See CURLOPT_UPLOAD(3)

## CURLOPT_UPLOAD_BUFFERSIZE

Set upload buffer size. See CURLOPT_UPLOAD_BUFFERSIZE(3)

## CURLOPT_URL

URL to work on. See CURLOPT_URL(3)

## CURLOPT_USERAGENT

User-Agent: header. See CURLOPT_USERAGENT(3)

## CURLOPT_USERNAME

Username. See CURLOPT_USERNAME(3)

## CURLOPT_USERPWD

Username and password. See CURLOPT_USERPWD(3)

## CURLOPT_USE_SSL

Use TLS/SSL. See CURLOPT_USE_SSL(3)

## CURLOPT_VERBOSE

Display verbose information. See CURLOPT_VERBOSE(3)

## CURLOPT_WILDCARDMATCH

Transfer multiple files according to a filename pattern. See
CURLOPT_WILDCARDMATCH(3)

## CURLOPT_WRITEDATA

Data pointer to pass to the write callback. See CURLOPT_WRITEDATA(3)

## CURLOPT_WRITEFUNCTION


Callback for writing data. See CURLOPT_WRITEFUNCTION(3)


## CURLOPT_WS_OPTIONS

Set WebSocket options. See CURLOPT_WS_OPTIONS(3)



## CURLOPT_XFERINFODATA


Data pointer to pass to the progress meter callback. See
CURLOPT_XFERINFODATA(3)



## CURLOPT_XFERINFOFUNCTION


Callback for progress meter. See CURLOPT_XFERINFOFUNCTION(3)




## CURLOPT_XOAUTH2_BEARER



OAuth2 bearer token. See CURLOPT_XOAUTH2_BEARER(3)



# %PROTOCOLS%


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~







# %AVAILABILITY%



# RETURN VALUE

*CURLE_OK* (zero) means that the option was set properly, non-zero means an
error occurred as *\<curl/curl.h\>* defines. See the libcurl-errors(3) man
page for the full list with descriptions.

Changes to jni/curl/docs/libcurl/curl_easy_strerror.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_strerror
Section: 3
Source: libcurl
See-also:
  - curl_multi_strerror (3)
  - curl_share_strerror (3)
  - curl_url_strerror (3)
  - libcurl-errors (3)
Protocol:
  - All

---

# NAME

curl_easy_strerror - return string describing error code

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_strerror
Section: 3
Source: libcurl
See-also:
  - curl_multi_strerror (3)
  - curl_share_strerror (3)
  - curl_url_strerror (3)
  - libcurl-errors (3)
Protocol:
  - All
Added-in: 7.12.0
---

# NAME

curl_easy_strerror - return string describing error code

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

The curl_easy_strerror(3) function returns a string describing the
CURLcode error code passed in the argument *errornum*.

Typically applications also appreciate CURLOPT_ERRORBUFFER(3) for more
specific error descriptions generated at runtime.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    /* set options */
    /* Perform the entire transfer */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
  }
}
~~~

# AVAILABILITY

This function was added in libcurl 7.12.0

# RETURN VALUE

A pointer to a null-terminated string.







>
>



















|
<
<




30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


59
60
61
62

The curl_easy_strerror(3) function returns a string describing the
CURLcode error code passed in the argument *errornum*.

Typically applications also appreciate CURLOPT_ERRORBUFFER(3) for more
specific error descriptions generated at runtime.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    /* set options */
    /* Perform the entire transfer */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a null-terminated string.
Changes to jni/curl/docs/libcurl/curl_easy_unescape.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_unescape
Section: 3
Source: libcurl
See-also:
  - curl_easy_escape (3)
  - curl_free (3)
Protocol:
  - All

---

# NAME

curl_easy_unescape - URL decodes the given string

# SYNOPSIS

~~~c
#include <curl/curl.h>

char *curl_easy_unescape(CURL *curl, const char *input,








|


>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_unescape
Section: 3
Source: libcurl
See-also:
  - curl_easy_escape (3)
  - curl_url_get (3)
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

curl_easy_unescape - URL decode a string

# SYNOPSIS

~~~c
#include <curl/curl.h>

char *curl_easy_unescape(CURL *curl, const char *input,
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

Since 7.82.0, the **curl** parameter is ignored. Prior to that there was
per-handle character conversion support for some old operating systems such as
TPF, but it was otherwise ignored.

You must curl_free(3) the returned string when you are done with it.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    int decodelen;
    char *decoded = curl_easy_unescape(curl, "%63%75%72%6c", 12, &decodelen);
    if(decoded) {
      /* do not assume printf() works on the decoded data! */
      printf("Decoded: ");
      /* ... */
      curl_free(decoded);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.4 and replaces the old curl_unescape(3) function.

# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed.







>
>




















|
<
<




43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76

Since 7.82.0, the **curl** parameter is ignored. Prior to that there was
per-handle character conversion support for some old operating systems such as
TPF, but it was otherwise ignored.

You must curl_free(3) the returned string when you are done with it.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    int decodelen;
    char *decoded = curl_easy_unescape(curl, "%63%75%72%6c", 12, &decodelen);
    if(decoded) {
      /* do not assume printf() works on the decoded data! */
      printf("Decoded: ");
      /* ... */
      curl_free(decoded);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed.
Changes to jni/curl/docs/libcurl/curl_easy_upkeep.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_upkeep
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TCP_KEEPIDLE (3)
Protocol:
  - All

---

# NAME

curl_easy_upkeep - Perform any connection upkeep checks.

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_upkeep(CURL *handle);











>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_easy_upkeep
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TCP_KEEPIDLE (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

curl_easy_upkeep - keep existing connections alive

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_upkeep(CURL *handle);
33
34
35
36
37
38
39


40
41
42
43
44
45
46
Currently the only protocol with a connection upkeep mechanism is HTTP/2: when
the connection upkeep interval is exceeded and curl_easy_upkeep(3)
is called, an HTTP/2 PING frame is sent on the connection.

This function must be explicitly called in order to perform the upkeep work.
The connection upkeep interval is set with
CURLOPT_UPKEEP_INTERVAL_MS(3).



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Currently the only protocol with a connection upkeep mechanism is HTTP/2: when
the connection upkeep interval is exceeded and curl_easy_upkeep(3)
is called, an HTTP/2 PING frame is sent on the connection.

This function must be explicitly called in order to perform the upkeep work.
The connection upkeep interval is set with
CURLOPT_UPKEEP_INTERVAL_MS(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.62.0.

# RETURN VALUE

On success, returns **CURLE_OK**.

On failure, returns the appropriate error code.







|
<
<






67
68
69
70
71
72
73
74


75
76
77
78
79
80

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

On success, returns **CURLE_OK**.

On failure, returns the appropriate error code.
Changes to jni/curl/docs/libcurl/curl_escape.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_escape
Section: 3
Source: libcurl
See-also:
  - curl_free (3)
  - curl_unescape (3)
Protocol:
  - All

---

# NAME

curl_escape - URL encodes the given string

# SYNOPSIS

~~~c
#include <curl/curl.h>

char *curl_escape(const char *string, int length);











>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_escape
Section: 3
Source: libcurl
See-also:
  - curl_free (3)
  - curl_unescape (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_escape - URL encode a string

# SYNOPSIS

~~~c
#include <curl/curl.h>

char *curl_escape(const char *string, int length);
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
**NN** is a two-digit hexadecimal number).

If the **length** argument is set to 0, curl_escape(3) uses strlen()
on **string** to find out the size.

You must curl_free(3) the returned string when you are done with it.



# EXAMPLE

~~~c
int main(void)
{
  char *output = curl_escape("data to convert", 15);
  if(output) {
    printf("Encoded: %s\n", output);
    curl_free(output);
  }
}
~~~

# AVAILABILITY

Since 7.15.4, curl_easy_escape(3) should be used. This function might be
removed in a future release.



# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed.







>
>













|



>
>




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
**NN** is a two-digit hexadecimal number).

If the **length** argument is set to 0, curl_escape(3) uses strlen()
on **string** to find out the size.

You must curl_free(3) the returned string when you are done with it.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  char *output = curl_escape("data to convert", 15);
  if(output) {
    printf("Encoded: %s\n", output);
    curl_free(output);
  }
}
~~~

# HISTORY

Since 7.15.4, curl_easy_escape(3) should be used. This function might be
removed in a future release.

# %AVAILABILITY%

# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed.
Changes to jni/curl/docs/libcurl/curl_formadd.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_formadd
Section: 3
Source: libcurl
See-also:
  - curl_easy_setopt (3)
  - curl_formfree (3)
  - curl_mime_init (3)
Protocol:
  - HTTP

---

# NAME

curl_formadd - add a section to a multipart form POST

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_formadd
Section: 3
Source: libcurl
See-also:
  - curl_easy_setopt (3)
  - curl_formfree (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

curl_formadd - add a section to a multipart form POST

# SYNOPSIS
198
199
200
201
202
203
204


205
206
207
208
209
210
211
When you have passed the *struct curl_httppost* pointer to
curl_easy_setopt(3) (using the CURLOPT_HTTPPOST(3) option), you
must not free the list until after you have called curl_easy_cleanup(3)
for the curl handle.

See example below.



# EXAMPLE

~~~c
#include <string.h> /* for strlen */

static const char record[]="data in a buffer";








>
>







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
When you have passed the *struct curl_httppost* pointer to
curl_easy_setopt(3) (using the CURLOPT_HTTPPOST(3) option), you
must not free the list until after you have called curl_easy_cleanup(3)
for the curl handle.

See example below.

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h> /* for strlen */

static const char record[]="data in a buffer";

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309


310
311
312
313
314
    curl_easy_cleanup(curl);

    curl_formfree(post);
  }
}
~~~

# AVAILABILITY

Deprecated in 7.56.0. Before this release, field names were allowed to contain
zero-valued bytes. The pseudo-filename "-" to read stdin is discouraged
although still supported, but data is not read before being actually sent: the
effective data size can then not be automatically determined, resulting in a
chunked encoding transfer. Backslashes and double quotes in field and
filenames are now escaped before transmission.



# RETURN VALUE

0 means everything was OK, non-zero means an error occurred corresponding to a
CURL_FORMADD_* constant defined in *\<curl/curl.h\>*.







|







>
>





298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    curl_easy_cleanup(curl);

    curl_formfree(post);
  }
}
~~~

# DEPRECATED

Deprecated in 7.56.0. Before this release, field names were allowed to contain
zero-valued bytes. The pseudo-filename "-" to read stdin is discouraged
although still supported, but data is not read before being actually sent: the
effective data size can then not be automatically determined, resulting in a
chunked encoding transfer. Backslashes and double quotes in field and
filenames are now escaped before transmission.

# %AVAILABILITY%

# RETURN VALUE

0 means everything was OK, non-zero means an error occurred corresponding to a
CURL_FORMADD_* constant defined in *\<curl/curl.h\>*.
Changes to jni/curl/docs/libcurl/curl_formfree.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_formfree
Section: 3
Source: libcurl
See-also:
  - curl_formadd (3)
  - curl_mime_free (3)
  - curl_mime_init (3)
Protocol:
  - HTTP

---

# NAME

curl_formfree - free a previously build multipart form post chain

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_formfree
Section: 3
Source: libcurl
See-also:
  - curl_formadd (3)
  - curl_mime_free (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

curl_formfree - free a previously build multipart form post chain

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51

**form** is the pointer as returned from a previous call to
curl_formadd(3) and may be NULL.

Passing in a NULL pointer in *form* makes this function return immediately
with no action.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

**form** is the pointer as returned from a previous call to
curl_formadd(3) and may be NULL.

Passing in a NULL pointer in *form* makes this function return immediately
with no action.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
65
66
67
68
69
70
71
72
73
74


75
76
77
78

    /* then cleanup the formpost chain */
    curl_formfree(formpost);
  }
}
~~~

# AVAILABILITY

Deprecated in 7.56.0.



# RETURN VALUE

None







|


>
>




68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

    /* then cleanup the formpost chain */
    curl_formfree(formpost);
  }
}
~~~

# DEPRECATED

Deprecated in 7.56.0.

# %AVAILABILITY%

# RETURN VALUE

None
Changes to jni/curl/docs/libcurl/curl_formget.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_formget
Section: 3
Source: libcurl
See-also:
  - curl_formadd (3)
  - curl_mime_init (3)
Protocol:
  - HTTP

---

# NAME

curl_formget - serialize a previously built multipart form POST chain

# SYNOPSIS

~~~c
#include <curl/curl.h>

int curl_formget(struct curl_httppost * form, void *userp,
                 curl_formget_callback append);
~~~

# DESCRIPTION



curl_formget() serializes data previously built with curl_formadd(3). It
accepts a void pointer as second argument named *userp* which is passed as
the first argument to the curl_formget_callback function.

~~~c
 typedef size_t (*curl_formget_callback)(void *userp, const char *buf,
                                         size_t len);"
~~~

The curl_formget_callback is invoked for each part of the HTTP POST chain. The
character buffer passed to the callback must not be freed. The callback should
return the buffer length passed to it on success.

If the **CURLFORM_STREAM** option is used in the formpost, it prevents
curl_formget(3) from working until you have performed the actual HTTP
request. This, because first then does libcurl known which actual read
callback to use!


# EXAMPLE

~~~c
size_t print_httppost_callback(void *arg, const char *buf, size_t len)
{
  fwrite(buf, len, 1, stdout);











>




|












>
>

|
|











|
|
|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_formget
Section: 3
Source: libcurl
See-also:
  - curl_formadd (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
Added-in: 7.15.5
---

# NAME

curl_formget - serialize a multipart form POST chain

# SYNOPSIS

~~~c
#include <curl/curl.h>

int curl_formget(struct curl_httppost * form, void *userp,
                 curl_formget_callback append);
~~~

# DESCRIPTION

The form API (including this function) is deprecated since libcurl 7.56.0.

curl_formget() serializes data previously built with curl_formadd(3). It
accepts a void pointer as second argument named *userp* which is passed as the
first argument to the curl_formget_callback function.

~~~c
 typedef size_t (*curl_formget_callback)(void *userp, const char *buf,
                                         size_t len);"
~~~

The curl_formget_callback is invoked for each part of the HTTP POST chain. The
character buffer passed to the callback must not be freed. The callback should
return the buffer length passed to it on success.

If the **CURLFORM_STREAM** option is used in the formpost, it prevents
curl_formget(3) from working until you have performed the actual HTTP request.
This, because first then does libcurl known which actual read callback to use!

# %PROTOCOLS%

# EXAMPLE

~~~c
size_t print_httppost_callback(void *arg, const char *buf, size_t len)
{
  fwrite(buf, len, 1, stdout);
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  if(curl_formget(post, &total_size, print_httppost_callback)) {
    return (size_t) -1;
  }
  return total_size;
}
~~~

# AVAILABILITY

This function was added in libcurl 7.15.5. The form API is deprecated in
libcurl 7.56.0.

# RETURN VALUE

0 means everything was OK, non-zero means an error occurred







|
<
<
<




64
65
66
67
68
69
70
71



72
73
74
75
  if(curl_formget(post, &total_size, print_httppost_callback)) {
    return (size_t) -1;
  }
  return total_size;
}
~~~

# %AVAILABILITY%




# RETURN VALUE

0 means everything was OK, non-zero means an error occurred
Changes to jni/curl/docs/libcurl/curl_free.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_free
Section: 3
Source: libcurl
See-also:
  - curl_easy_escape (3)
  - curl_easy_unescape (3)
Protocol:
  - All

---

# NAME

curl_free - reclaim memory that has been obtained through a libcurl call

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_free
Section: 3
Source: libcurl
See-also:
  - curl_easy_escape (3)
  - curl_easy_unescape (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_free - reclaim memory that has been obtained through a libcurl call

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
curl_free reclaims memory that has been obtained through a libcurl call. Use
curl_free(3) instead of free() to avoid anomalies that can result from
differences in memory management between your application and libcurl.

Passing in a NULL pointer in *ptr* makes this function return immediately
with no action.



# EXAMPLE

~~~c
int main(void)
{
  char *width = curl_getenv("COLUMNS");
  if(width) {
    /* it was set! */
    curl_free(width);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

None







>
>













|
<
<




29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51


52
53
54
55
curl_free reclaims memory that has been obtained through a libcurl call. Use
curl_free(3) instead of free() to avoid anomalies that can result from
differences in memory management between your application and libcurl.

Passing in a NULL pointer in *ptr* makes this function return immediately
with no action.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  char *width = curl_getenv("COLUMNS");
  if(width) {
    /* it was set! */
    curl_free(width);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

None
Changes to jni/curl/docs/libcurl/curl_getdate.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_getdate
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TIMECONDITION (3)
  - CURLOPT_TIMEVALUE (3)
  - curl_easy_escape (3)
  - curl_easy_unescape (3)
Protocol:
  - All

---

# NAME

curl_getdate - Convert a date string to number of seconds

# SYNOPSIS

~~~c
#include <curl/curl.h>

time_t curl_getdate(const char *datestring, const time_t *now);













>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_getdate
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TIMECONDITION (3)
  - CURLOPT_TIMEVALUE (3)
  - curl_easy_escape (3)
  - curl_easy_unescape (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_getdate - convert date string to number of seconds

# SYNOPSIS

~~~c
#include <curl/curl.h>

time_t curl_getdate(const char *datestring, const time_t *now);
70
71
72
73
74
75
76


77
78
79
80
81
82
83

## pure numbers

If a decimal number of the form YYYYMMDD appears, then YYYY is read as the
year, MM as the month number and DD as the day of the month, for the specified
calendar date.



# EXAMPLE

~~~c
int main(void)
{
  time_t t;
  t = curl_getdate("Sun, 06 Nov 1994 08:49:37 GMT", NULL);







>
>







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

## pure numbers

If a decimal number of the form YYYYMMDD appears, then YYYY is read as the
year, MM as the month number and DD as the day of the month, for the specified
calendar date.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  time_t t;
  t = curl_getdate("Sun, 06 Nov 1994 08:49:37 GMT", NULL);
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

This parser handles date formats specified in RFC 822 (including the update in
RFC 1123) using time zone name or time zone delta and RFC 850 (obsoleted by
RFC 1036) and ANSI C's *asctime()* format.

These formats are the only ones RFC 7231 says HTTP applications may use.

# AVAILABILITY

Always

# RETURN VALUE

This function returns -1 when it fails to parse the date string. Otherwise it
returns the number of seconds as described.

On systems with a signed 32 bit time_t: if the year is larger than 2037 or
less than 1903, this function returns -1.

On systems with an unsigned 32 bit time_t: if the year is larger than 2106 or
less than 1970, this function returns -1.

On systems with 64 bit time_t: if the year is less than 1583, this function
returns -1. (The Gregorian calendar was first introduced 1582 so no "real"
dates in this way of doing dates existed before then.)







|
<
<






|


|


|


112
113
114
115
116
117
118
119


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

This parser handles date formats specified in RFC 822 (including the update in
RFC 1123) using time zone name or time zone delta and RFC 850 (obsoleted by
RFC 1036) and ANSI C's *asctime()* format.

These formats are the only ones RFC 7231 says HTTP applications may use.

# %AVAILABILITY%



# RETURN VALUE

This function returns -1 when it fails to parse the date string. Otherwise it
returns the number of seconds as described.

On systems with a signed 32-bit time_t: if the year is larger than 2037 or
less than 1903, this function returns -1.

On systems with an unsigned 32-bit time_t: if the year is larger than 2106 or
less than 1970, this function returns -1.

On systems with 64-bit time_t: if the year is less than 1583, this function
returns -1. (The Gregorian calendar was first introduced 1582 so no "real"
dates in this way of doing dates existed before then.)
Changes to jni/curl/docs/libcurl/curl_getenv.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_getenv
Section: 3
Source: libcurl
See-also:
  - getenv (3C)
Protocol:
  - All

---

# NAME

curl_getenv - return value for environment name

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_getenv
Section: 3
Source: libcurl
See-also:
  - getenv (3C)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_getenv - return value for environment name

# SYNOPSIS
26
27
28
29
30
31
32


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

curl_getenv() is a portable wrapper for the getenv() function, meant to
emulate its behavior and provide an identical interface for all operating
systems libcurl builds on (including win32).

You must curl_free(3) the returned string when you are done with it.



# EXAMPLE

~~~c
int main(void)
{
  char *width = curl_getenv("COLUMNS");
  if(width) {
    /* it was set! */
    curl_free(width);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed to find the
specified name.

# NOTE

Under unix operating systems, there is no point in returning an allocated
memory, although other systems does not work properly if this is not done. The
unix implementation thus suffers slightly from the drawbacks of other systems.







>
>













|
<
<











27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60

curl_getenv() is a portable wrapper for the getenv() function, meant to
emulate its behavior and provide an identical interface for all operating
systems libcurl builds on (including win32).

You must curl_free(3) the returned string when you are done with it.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  char *width = curl_getenv("COLUMNS");
  if(width) {
    /* it was set! */
    curl_free(width);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed to find the
specified name.

# NOTE

Under unix operating systems, there is no point in returning an allocated
memory, although other systems does not work properly if this is not done. The
unix implementation thus suffers slightly from the drawbacks of other systems.
Changes to jni/curl/docs/libcurl/curl_global_cleanup.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_global_cleanup
Section: 3
Source: libcurl
See-also:
  - curl_global_init (3)
  - libcurl (3)
  - libcurl-thread (3)
Protocol:
  - All

---

# NAME

curl_global_cleanup - global libcurl cleanup

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_global_cleanup
Section: 3
Source: libcurl
See-also:
  - curl_global_init (3)
  - libcurl (3)
  - libcurl-thread (3)
Protocol:
  - All
Added-in: 7.8
---

# NAME

curl_global_cleanup - global libcurl cleanup

# SYNOPSIS
55
56
57
58
59
60
61


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
dynamically. This behavior may be addressed in the future.

libcurl may not be able to fully clean up after multi-threaded OpenSSL
depending on how OpenSSL was built and loaded as a library. It is possible in
some rare circumstances a memory leak could occur unless you implement your own
OpenSSL thread cleanup. Refer to libcurl-thread(3).



# EXAMPLE

~~~c
int main(void)
{
  curl_global_init(CURL_GLOBAL_DEFAULT);

  /* use libcurl, then before exiting... */

  curl_global_cleanup();
}
~~~

# AVAILABILITY

Added in 7.8

# RETURN VALUE

None







>
>













|
<
<




56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78


79
80
81
82
dynamically. This behavior may be addressed in the future.

libcurl may not be able to fully clean up after multi-threaded OpenSSL
depending on how OpenSSL was built and loaded as a library. It is possible in
some rare circumstances a memory leak could occur unless you implement your own
OpenSSL thread cleanup. Refer to libcurl-thread(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_global_init(CURL_GLOBAL_DEFAULT);

  /* use libcurl, then before exiting... */

  curl_global_cleanup();
}
~~~

# %AVAILABILITY%



# RETURN VALUE

None
Changes to jni/curl/docs/libcurl/curl_global_init.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
  - curl_global_cleanup (3)
  - curl_global_init_mem (3)
  - curl_global_sslset (3)
  - curl_global_trace (3)
  - libcurl (3)
Protocol:
  - All

---

# NAME

curl_global_init - Global libcurl initialization

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_global_init(long flags);







>




|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  - curl_global_cleanup (3)
  - curl_global_init_mem (3)
  - curl_global_sslset (3)
  - curl_global_trace (3)
  - libcurl (3)
Protocol:
  - All
Added-in: 7.8
---

# NAME

curl_global_init - global libcurl initialization

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_global_init(long flags);
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

The flags option is a bit pattern that tells libcurl exactly what features to
init, as described below. Set the desired bits by ORing the values together.
In normal operation, you must specify CURL_GLOBAL_ALL. Do not use any other
value unless you are familiar with it and mean to control internal operations
of libcurl.

This function is thread-safe since libcurl 7.84.0 if
curl_version_info(3) has the CURL_VERSION_THREADSAFE feature bit set
(most platforms).

If this is not thread-safe, you must not call this function when any other
thread in the program (i.e. a thread sharing the same memory) is running.
This does not just mean no other thread that is using libcurl. Because
curl_global_init(3) calls functions of other libraries that are
similarly thread unsafe, it could conflict with any other thread that uses
these other libraries.

If you are initializing libcurl from a Windows DLL you should not initialize
it from *DllMain* or a static initializer because Windows holds the loader
lock during that time and it could cause a deadlock.

See the description in libcurl(3) of global environment requirements for
details of how to use this function.







|
|
<

|
|
|
|
|
|







41
42
43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63

The flags option is a bit pattern that tells libcurl exactly what features to
init, as described below. Set the desired bits by ORing the values together.
In normal operation, you must specify CURL_GLOBAL_ALL. Do not use any other
value unless you are familiar with it and mean to control internal operations
of libcurl.

This function is thread-safe on most platforms. Then curl_version_info(3) has
the `threadsafe` feature set (added in 7.84.0).


If this is not thread-safe (the bit mentioned above is not set), you must not
call this function when any other thread in the program (i.e. a thread sharing
the same memory) is running. This does not just mean no other thread that is
using libcurl. Because curl_global_init(3) calls functions of other libraries
that are similarly thread unsafe, it could conflict with any other thread that
uses these other libraries.

If you are initializing libcurl from a Windows DLL you should not initialize
it from *DllMain* or a static initializer because Windows holds the loader
lock during that time and it could cause a deadlock.

See the description in libcurl(3) of global environment requirements for
details of how to use this function.
106
107
108
109
110
111
112


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

This bit has no point since 7.69.0 but its behavior is instead the default.

Before 7.69.0: when this flag is set, curl acknowledges EINTR condition when
connecting or when waiting for data. Otherwise, curl waits until full timeout
elapses. (Added in 7.30.0)



# EXAMPLE

~~~c
int main(void)
{
  curl_global_init(CURL_GLOBAL_DEFAULT);

  /* use libcurl, then before exiting... */

  curl_global_cleanup();
}
~~~

# AVAILABILITY

Added in 7.8

# RETURN VALUE

If this function returns non-zero, something went wrong and you cannot use the
other curl functions.







>
>













|
<
<





106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128


129
130
131
132
133

This bit has no point since 7.69.0 but its behavior is instead the default.

Before 7.69.0: when this flag is set, curl acknowledges EINTR condition when
connecting or when waiting for data. Otherwise, curl waits until full timeout
elapses. (Added in 7.30.0)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_global_init(CURL_GLOBAL_DEFAULT);

  /* use libcurl, then before exiting... */

  curl_global_cleanup();
}
~~~

# %AVAILABILITY%



# RETURN VALUE

If this function returns non-zero, something went wrong and you cannot use the
other curl functions.
Changes to jni/curl/docs/libcurl/curl_global_init_mem.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_global_init_mem
Section: 3
Source: libcurl
See-also:
  - curl_global_cleanup (3)
  - curl_global_init (3)
Protocol:
  - All

---

# NAME

curl_global_init_mem - Global libcurl initialization with memory callbacks

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_global_init_mem(long flags,











>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_global_init_mem
Section: 3
Source: libcurl
See-also:
  - curl_global_cleanup (3)
  - curl_global_init (3)
Protocol:
  - All
Added-in: 7.12.0
---

# NAME

curl_global_init_mem - global libcurl initialization with memory callbacks

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_global_init_mem(long flags,
66
67
68
69
70
71
72


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
to that man page for documentation.

# CAUTION

Manipulating these gives considerable powers to the application to severely
screw things up for libcurl. Take care!



# EXAMPLE

~~~c
extern void *malloc_cb(size_t);
extern void free_cb(void *);
extern void *realloc_cb(void *, size_t);
extern char *strdup_cb(const char *);
extern void *calloc_cb(size_t, size_t);

int main(void)
{
  curl_global_init_mem(CURL_GLOBAL_DEFAULT, malloc_cb,
                       free_cb, realloc_cb,
                       strdup_cb, calloc_cb);
}
~~~

# AVAILABILITY

Added in 7.12.0

# RETURN VALUE

CURLE_OK (0) means everything was OK, non-zero means an error occurred as
*\<curl/curl.h\>* defines - see libcurl-errors(3).







>
>

















|
<
<





67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93


94
95
96
97
98
to that man page for documentation.

# CAUTION

Manipulating these gives considerable powers to the application to severely
screw things up for libcurl. Take care!

# %PROTOCOLS%

# EXAMPLE

~~~c
extern void *malloc_cb(size_t);
extern void free_cb(void *);
extern void *realloc_cb(void *, size_t);
extern char *strdup_cb(const char *);
extern void *calloc_cb(size_t, size_t);

int main(void)
{
  curl_global_init_mem(CURL_GLOBAL_DEFAULT, malloc_cb,
                       free_cb, realloc_cb,
                       strdup_cb, calloc_cb);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK (0) means everything was OK, non-zero means an error occurred as
*\<curl/curl.h\>* defines - see libcurl-errors(3).
Changes to jni/curl/docs/libcurl/curl_global_sslset.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_global_sslset
Section: 3
Source: libcurl
See-also:
  - curl_global_init (3)
  - libcurl (3)
Protocol:
  - All

---

# NAME

curl_global_sslset - Select SSL backend to use with libcurl

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLsslset curl_global_sslset(curl_sslbackend id,











>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_global_sslset
Section: 3
Source: libcurl
See-also:
  - curl_global_init (3)
  - libcurl (3)
Protocol:
  - All
Added-in: 7.56.0
---

# NAME

curl_global_sslset - select SSL backend to use

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLsslset curl_global_sslset(curl_sslbackend id,
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
If this is not thread-safe, you must not call this function when any other
thread in the program (i.e. a thread sharing the same memory) is running.
This does not just mean no other thread that is using libcurl.

# OpenSSL

The name "OpenSSL" is used for all versions of OpenSSL and its associated
forks/flavors in this function. OpenSSL, BoringSSL, libressl, quictls and
AmiSSL are all supported by libcurl, but in the eyes of
curl_global_sslset(3) they are all just "OpenSSL". They all mostly
provide the same API.

curl_version_info(3) can return more specific info about the exact
OpenSSL flavor and version number is use.








|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
If this is not thread-safe, you must not call this function when any other
thread in the program (i.e. a thread sharing the same memory) is running.
This does not just mean no other thread that is using libcurl.

# OpenSSL

The name "OpenSSL" is used for all versions of OpenSSL and its associated
forks/flavors in this function. OpenSSL, BoringSSL, LibreSSL, quictls and
AmiSSL are all supported by libcurl, but in the eyes of
curl_global_sslset(3) they are all just "OpenSSL". They all mostly
provide the same API.

curl_version_info(3) can return more specific info about the exact
OpenSSL flavor and version number is use.

96
97
98
99
100
101
102


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  CURLSSLBACKEND_MBEDTLS = 11,
  CURLSSLBACKEND_MESALINK = 12, /* deprecated */
  CURLSSLBACKEND_BEARSSL = 13,
  CURLSSLBACKEND_RUSTLS = 14
} curl_sslbackend;
~~~



# EXAMPLE

~~~c
int main(void)
{
  int i;
  /* choose a specific backend */
  curl_global_sslset(CURLSSLBACKEND_WOLFSSL, NULL, NULL);

  /* list the available ones */
  const curl_ssl_backend **list;
  curl_global_sslset(CURLSSLBACKEND_NONE, NULL, &list);

  for(i = 0; list[i]; i++)
    printf("SSL backend #%d: '%s' (ID: %d)\n",
           i, list[i]->name, list[i]->id);
}
~~~

# AVAILABILITY

This function was added in libcurl 7.56.0. Before this version, there was no
support for choosing SSL backends at runtime.

# RETURN VALUE

If this function returns *CURLSSLSET_OK*, the backend was successfully
selected.

If the chosen backend is unknown (or support for the chosen backend has not







>
>



















|
<
<
<







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125



126
127
128
129
130
131
132
  CURLSSLBACKEND_MBEDTLS = 11,
  CURLSSLBACKEND_MESALINK = 12, /* deprecated */
  CURLSSLBACKEND_BEARSSL = 13,
  CURLSSLBACKEND_RUSTLS = 14
} curl_sslbackend;
~~~

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  int i;
  /* choose a specific backend */
  curl_global_sslset(CURLSSLBACKEND_WOLFSSL, NULL, NULL);

  /* list the available ones */
  const curl_ssl_backend **list;
  curl_global_sslset(CURLSSLBACKEND_NONE, NULL, &list);

  for(i = 0; list[i]; i++)
    printf("SSL backend #%d: '%s' (ID: %d)\n",
           i, list[i]->name, list[i]->id);
}
~~~

# %AVAILABILITY%




# RETURN VALUE

If this function returns *CURLSSLSET_OK*, the backend was successfully
selected.

If the chosen backend is unknown (or support for the chosen backend has not
Changes to jni/curl/docs/libcurl/curl_global_trace.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_global_trace
Section: 3
Source: libcurl
See-also:
  - curl_global_init (3)
  - libcurl (3)
Protocol:
  - All

---

# NAME

curl_global_trace - log configuration

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_global_trace
Section: 3
Source: libcurl
See-also:
  - curl_global_init (3)
  - libcurl (3)
Protocol:
  - All
Added-in: 8.3
---

# NAME

curl_global_trace - log configuration

# SYNOPSIS
104
105
106
107
108
109
110


111
112
113
114
115
116
117

Traces reading of upload data from the application in order to send it to the server.

## `write`

Traces writing of download data, received from the server, to the application.



# EXAMPLE

~~~c
int main(void)
{
  /* log details of HTTP/2 and SSL handling */
  curl_global_trace("http/2,ssl");







>
>







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

Traces reading of upload data from the application in order to send it to the server.

## `write`

Traces writing of download data, received from the server, to the application.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  /* log details of HTTP/2 and SSL handling */
  curl_global_trace("http/2,ssl");
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
* [HTTP/2] [h2sid=1] cf_send(len=96) submit https://example.com/
...
* [HTTP/2] [h2sid=1] FRAME[HEADERS]
* [HTTP/2] [h2sid=1] 249 header bytes
...
~~~

# AVAILABILITY

Added in 8.3

# RETURN VALUE

If this function returns non-zero, something went wrong and the configuration
may not have any effects or may only been applied partially.







|
<
<





130
131
132
133
134
135
136
137


138
139
140
141
142
* [HTTP/2] [h2sid=1] cf_send(len=96) submit https://example.com/
...
* [HTTP/2] [h2sid=1] FRAME[HEADERS]
* [HTTP/2] [h2sid=1] 249 header bytes
...
~~~

# %AVAILABILITY%



# RETURN VALUE

If this function returns non-zero, something went wrong and the configuration
may not have any effects or may only been applied partially.
Changes to jni/curl/docs/libcurl/curl_mime_addpart.md.
15
16
17
18
19
20
21

22
23
24
25
26
27
28
  - curl_mime_name (3)
  - curl_mime_subparts (3)
  - curl_mime_type (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_addpart - append a new empty part to a mime structure

# SYNOPSIS







>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  - curl_mime_name (3)
  - curl_mime_subparts (3)
  - curl_mime_type (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_addpart - append a new empty part to a mime structure

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50

curl_mime_addpart(3) creates and appends a new empty part to the given
mime structure and returns a handle to it. The returned part handle can
subsequently be populated using functions from the mime API.

*mime* is the handle of the mime structure in which the new part must be
appended.



# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

curl_mime_addpart(3) creates and appends a new empty part to the given
mime structure and returns a handle to it. The returned part handle can
subsequently be populated using functions from the mime API.

*mime* is the handle of the mime structure in which the new part must be
appended.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    /* continue and set name + data to the part */
    curl_mime_data(part, "This is the field data", CURL_ZERO_TERMINATED);
    curl_mime_name(part, "data");
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

A mime part structure handle, or NULL upon failure.







|
<
<




64
65
66
67
68
69
70
71


72
73
74
75
    /* continue and set name + data to the part */
    curl_mime_data(part, "This is the field data", CURL_ZERO_TERMINATED);
    curl_mime_name(part, "data");
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A mime part structure handle, or NULL upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_data.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_mime_data_cb (3)
  - curl_mime_name (3)
  - curl_mime_type (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_data - set a mime part's body data from memory

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_mime_data_cb (3)
  - curl_mime_name (3)
  - curl_mime_type (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_data - set a mime part's body data from memory

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58
Setting a part's contents multiple times is valid: only the value set by the
last call is retained. It is possible to unassign part's contents by setting
*data* to NULL.

Setting large data is memory consuming: one might consider using
curl_mime_data_cb(3) in such a case.



# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;







>
>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Setting a part's contents multiple times is valid: only the value set by the
last call is retained. It is possible to unassign part's contents by setting
*data* to NULL.

Setting large data is memory consuming: one might consider using
curl_mime_data_cb(3) in such a case.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;
67
68
69
70
71
72
73
74
75
76
77
78
79
80

    /* add data to the part  */
    curl_mime_data(part, "raw contents to send", CURL_ZERO_TERMINATED);
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure.







|
<
<




70
71
72
73
74
75
76
77


78
79
80
81

    /* add data to the part  */
    curl_mime_data(part, "raw contents to send", CURL_ZERO_TERMINATED);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_data_cb.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_mime_addpart (3)
  - curl_mime_data (3)
  - curl_mime_name (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_data_cb - set a callback-based data source for a mime part's body

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_mime_addpart (3)
  - curl_mime_data (3)
  - curl_mime_name (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_data_cb - set a callback-based data source for a mime part's body

# SYNOPSIS
93
94
95
96
97
98
99


100
101
102
103
104
105
106

Care must be taken if the part is bound to a curl easy handle that is later
duplicated: the *arg* pointer argument is also duplicated, resulting in
the pointed item to be shared between the original and the copied handle. In
particular, special attention should be given to the *freefunc* procedure
code since it then gets called twice with the same argument.



# EXAMPLE

Sending a huge data string causes the same amount of memory to be allocated:
to avoid overhead resources consumption, one might want to use a callback
source to avoid data duplication. In this case, original data must be retained
until after the transfer terminates.
~~~c







>
>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

Care must be taken if the part is bound to a curl easy handle that is later
duplicated: the *arg* pointer argument is also duplicated, resulting in
the pointed item to be shared between the original and the copied handle. In
particular, special attention should be given to the *freefunc* procedure
code since it then gets called twice with the same argument.

# %PROTOCOLS%

# EXAMPLE

Sending a huge data string causes the same amount of memory to be allocated:
to avoid overhead resources consumption, one might want to use a callback
source to avoid data duplication. In this case, original data must be retained
until after the transfer terminates.
~~~c
159
160
161
162
163
164
165
166
167
168
169
170
171
172
    hugectl.position = 0;
    curl_mime_data_cb(part, hugectl.size, read_callback, seek_callback, NULL,
                      &hugectl);
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure.







|
<
<




162
163
164
165
166
167
168
169


170
171
172
173
    hugectl.position = 0;
    curl_mime_data_cb(part, hugectl.size, read_callback, seek_callback, NULL,
                      &hugectl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_encoder.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_mime_addpart (3)
  - curl_mime_headers (3)
  - curl_mime_subparts (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_encoder - set a mime part's encoder and content transfer encoding

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_mime_addpart (3)
  - curl_mime_headers (3)
  - curl_mime_subparts (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_encoder - set a mime part's encoder and content transfer encoding

# SYNOPSIS
66
67
68
69
70
71
72


73
74
75
76
77
78
79
*Content-Transfer-Encoding* header should be added with
curl_mime_headers(3) instead of setting a part encoder.

Encoding should not be applied to multiparts, thus the use of this function on
a part with content set with curl_mime_subparts(3) is strongly
discouraged.



# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;







>
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
*Content-Transfer-Encoding* header should be added with
curl_mime_headers(3) instead of setting a part encoder.

Encoding should not be applied to multiparts, thus the use of this function on
a part with content set with curl_mime_subparts(3) is strongly
discouraged.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;
91
92
93
94
95
96
97
98
99
100
101
102
103
104

    /* encode file data in base64 for transfer */
    curl_mime_encoder(part, "base64");
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure.







|
<
<




94
95
96
97
98
99
100
101


102
103
104
105

    /* encode file data in base64 for transfer */
    curl_mime_encoder(part, "base64");
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_filedata.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_mime_data (3)
  - curl_mime_filename (3)
  - curl_mime_name (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_filedata - set a mime part's body data from a file contents

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_mime_data (3)
  - curl_mime_filename (3)
  - curl_mime_name (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_filedata - set a mime part's body data from a file contents

# SYNOPSIS
51
52
53
54
55
56
57


58
59
60
61
62
63
64
If the file size cannot be determined before actually reading it (such as for
a character device or named pipe), the whole mime structure containing the
part is transferred using chunks by HTTP but is rejected by IMAP.

Setting a part's contents multiple times is valid: only the value set by the
last call is retained.



# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;







>
>







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
If the file size cannot be determined before actually reading it (such as for
a character device or named pipe), the whole mime structure containing the
part is transferred using chunks by HTTP but is rejected by IMAP.

Setting a part's contents multiple times is valid: only the value set by the
last call is retained.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

    /* set name */
    curl_mime_name(part, "data");
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure. CURLE_READ_ERROR is only an
indication that the file is not yet readable: it can be safely ignored at
this time, but the file must be made readable before the pertaining
easy handle is performed.







|
<
<







79
80
81
82
83
84
85
86


87
88
89
90
91
92
93

    /* set name */
    curl_mime_name(part, "data");
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure. CURLE_READ_ERROR is only an
indication that the file is not yet readable: it can be safely ignored at
this time, but the file must be made readable before the pertaining
easy handle is performed.
Changes to jni/curl/docs/libcurl/curl_mime_filename.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_mime_addpart (3)
  - curl_mime_data (3)
  - curl_mime_filedata (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_filename - set a mime part's remote filename

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_mime_addpart (3)
  - curl_mime_data (3)
  - curl_mime_filedata (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_filename - set a mime part's remote filename

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51

*filename* points to the null-terminated filename string; it may be set
to NULL to remove a previously attached remote filename.

The remote filename string is copied into the part, thus the associated
storage may safely be released or reused after call. Setting a part's file
name multiple times is valid: only the value set by the last call is retained.



# EXAMPLE

~~~c

static char imagebuf[]="imagedata";








>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

*filename* points to the null-terminated filename string; it may be set
to NULL to remove a previously attached remote filename.

The remote filename string is copied into the part, thus the associated
storage may safely be released or reused after call. Setting a part's file
name multiple times is valid: only the value set by the last call is retained.

# %PROTOCOLS%

# EXAMPLE

~~~c

static char imagebuf[]="imagedata";

70
71
72
73
74
75
76
77
78
79
80
81
82
83

    /* set name */
    curl_mime_name(part, "data");
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure.







|
<
<




73
74
75
76
77
78
79
80


81
82
83
84

    /* set name */
    curl_mime_name(part, "data");
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_free.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_mime_free
Section: 3
Source: libcurl
See-also:
  - curl_free (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_free - free a previously built mime structure

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_mime_free
Section: 3
Source: libcurl
See-also:
  - curl_free (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_free - free a previously built mime structure

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

**mime** is the handle as returned from a previous call to
curl_mime_init(3) and may be NULL.

Passing in a NULL pointer in *mime* makes this function return immediately
with no action.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* Build the mime message. */
    curl_mime *mime = curl_mime_init(curl);

    /* send off the transfer */

    /* Free multipart message. */
    curl_mime_free(mime);
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

None







>
>


















|
<
<




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70

**mime** is the handle as returned from a previous call to
curl_mime_init(3) and may be NULL.

Passing in a NULL pointer in *mime* makes this function return immediately
with no action.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* Build the mime message. */
    curl_mime *mime = curl_mime_init(curl);

    /* send off the transfer */

    /* Free multipart message. */
    curl_mime_free(mime);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

None
Changes to jni/curl/docs/libcurl/curl_mime_headers.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_mime_headers
Section: 3
Source: libcurl
See-also:
  - curl_mime_addpart (3)
  - curl_mime_name (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_headers - set a mime part's custom headers

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_mime_headers
Section: 3
Source: libcurl
See-also:
  - curl_mime_addpart (3)
  - curl_mime_name (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_headers - set a mime part's custom headers

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50

*take_ownership*: when non-zero, causes the list to be freed upon
replacement or mime structure deletion; in this case the list must not be
freed explicitly.

Setting a part's custom headers list multiple times is valid: only the value
set by the last call is retained.



# EXAMPLE

~~~c
int main(void)
{
  struct curl_slist *headers = NULL;







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

*take_ownership*: when non-zero, causes the list to be freed upon
replacement or mime structure deletion; in this case the list must not be
freed explicitly.

Setting a part's custom headers list multiple times is valid: only the value
set by the last call is retained.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  struct curl_slist *headers = NULL;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  /* Post and send it. */
  curl_easy_setopt(easy, CURLOPT_MIMEPOST, mime);
  curl_easy_setopt(easy, CURLOPT_URL, "https://example.com");
  curl_easy_perform(easy);
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure.







|
<
<




72
73
74
75
76
77
78
79


80
81
82
83
  /* Post and send it. */
  curl_easy_setopt(easy, CURLOPT_MIMEPOST, mime);
  curl_easy_setopt(easy, CURLOPT_URL, "https://example.com");
  curl_easy_perform(easy);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_init.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_mime_addpart (3)
  - curl_mime_free (3)
  - curl_mime_subparts (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_init - create a mime handle

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_mime_addpart (3)
  - curl_mime_free (3)
  - curl_mime_subparts (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_init - create a mime handle

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50

*easy_handle* is used for part separator randomization and error
reporting. Since 7.87.0, it does not need to be the final target handle.

Using a mime handle is the recommended way to post an HTTP form, format and
send a multi-part email with SMTP or upload such an email to an IMAP server.



# EXAMPLE

~~~c
int main(void)
{
  CURL *easy = curl_easy_init();
  curl_mime *mime;







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

*easy_handle* is used for part separator randomization and error
reporting. Since 7.87.0, it does not need to be the final target handle.

Using a mime handle is the recommended way to post an HTTP form, format and
send a multi-part email with SMTP or upload such an email to an IMAP server.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *easy = curl_easy_init();
  curl_mime *mime;
63
64
65
66
67
68
69
70
71
72
73
74
75
76

  /* Clean-up. */
  curl_easy_cleanup(easy);
  curl_mime_free(mime);
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

A mime struct handle, or NULL upon failure.







|
<
<




66
67
68
69
70
71
72
73


74
75
76
77

  /* Clean-up. */
  curl_easy_cleanup(easy);
  curl_mime_free(mime);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A mime struct handle, or NULL upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_name.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_mime_addpart (3)
  - curl_mime_data (3)
  - curl_mime_type (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_name - set a mime part's name

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_mime_addpart (3)
  - curl_mime_data (3)
  - curl_mime_type (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_name - set a mime part's name

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
*name* points to the null-terminated name string.

The name string is copied into the part, thus the associated storage may
safely be released or reused after call. Setting a part's name multiple times
is valid: only the value set by the last call is retained. It is possible to
reset the name of a part by setting *name* to NULL.



# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;







>
>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
*name* points to the null-terminated name string.

The name string is copied into the part, thus the associated storage may
safely be released or reused after call. Setting a part's name multiple times
is valid: only the value set by the last call is retained. It is possible to
reset the name of a part by setting *name* to NULL.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;
58
59
60
61
62
63
64
65
66
67
68
69
70
71

    /* give the part a name */
    curl_mime_name(part, "shoe_size");
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure.







|
<
<




61
62
63
64
65
66
67
68


69
70
71
72

    /* give the part a name */
    curl_mime_name(part, "shoe_size");
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_subparts.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_mime_subparts
Section: 3
Source: libcurl
See-also:
  - curl_mime_addpart (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_subparts - set sub-parts of a multipart mime part

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_mime_subparts
Section: 3
Source: libcurl
See-also:
  - curl_mime_addpart (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_subparts - set sub-parts of a multipart mime part

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
curl_mime_subparts(3) succeeds, the mime structure handle belongs to the
multipart part and must not be freed explicitly. It may however be updated by
subsequent calls to mime API functions.

Setting a part's contents multiple times is valid: only the value set by the
last call is retained. It is possible to unassign previous part's contents by
setting *subparts* to NULL.



# EXAMPLE

~~~c

static char *inline_html = "<title>example</title>";
static char *inline_text = "once upon the time";







>
>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
curl_mime_subparts(3) succeeds, the mime structure handle belongs to the
multipart part and must not be freed explicitly. It may however be updated by
subsequent calls to mime API functions.

Setting a part's contents multiple times is valid: only the value set by the
last call is retained. It is possible to unassign previous part's contents by
setting *subparts* to NULL.

# %PROTOCOLS%

# EXAMPLE

~~~c

static char *inline_html = "<title>example</title>";
static char *inline_text = "once upon the time";
74
75
76
77
78
79
80
81
82
83
84
85
86
87
    curl_mime_type(part, "multipart/alternative");
    slist = curl_slist_append(NULL, "Content-Disposition: inline");
    curl_mime_headers(part, slist, 1);
  }
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure.







|
<
<




77
78
79
80
81
82
83
84


85
86
87
88
    curl_mime_type(part, "multipart/alternative");
    slist = curl_slist_append(NULL, "Content-Disposition: inline");
    curl_mime_headers(part, slist, 1);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure.
Changes to jni/curl/docs/libcurl/curl_mime_type.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_mime_addpart (3)
  - curl_mime_data (3)
  - curl_mime_name (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

curl_mime_type - set a mime part's content type

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_mime_addpart (3)
  - curl_mime_data (3)
  - curl_mime_name (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.56.0
---

# NAME

curl_mime_type - set a mime part's content type

# SYNOPSIS
49
50
51
52
53
54
55


56
57
58
59
60
61
62
- If a remote filename is set, the mime type is taken from the filename
extension, or application/octet-stream by default.

- For a multipart part, multipart/mixed.

- text/plain in other cases.



# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;







>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
- If a remote filename is set, the mime type is taken from the filename
extension, or application/octet-stream by default.

- For a multipart part, multipart/mixed.

- text/plain in other cases.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_mime *mime;
  curl_mimepart *part;
77
78
79
80
81
82
83
84
85
86
87
88
89
90

    /* set name */
    curl_mime_name(part, "image");
}
}
~~~

# AVAILABILITY

As long as at least one of HTTP, SMTP or IMAP is enabled. Added in 7.56.0.

# RETURN VALUE

CURLE_OK or a CURL error code upon failure.







|
<
<




80
81
82
83
84
85
86
87


88
89
90
91

    /* set name */
    curl_mime_name(part, "image");
}
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or a CURL error code upon failure.
Changes to jni/curl/docs/libcurl/curl_mprintf.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_printf
Section: 3
Source: libcurl
See-also:
  - fprintf (3)
  - printf (3)
  - sprintf (3)
  - vprintf (3)
Protocol:
  - All

---

# NAME

curl_maprintf, curl_mfprintf, curl_mprintf, curl_msnprintf, curl_msprintf
curl_mvaprintf, curl_mvfprintf, curl_mvprintf, curl_mvsnprintf,
curl_mvsprintf - formatted output conversion

# SYNOPSIS

~~~c
#include <curl/mprintf.h>













>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_printf
Section: 3
Source: libcurl
See-also:
  - fprintf (3)
  - printf (3)
  - sprintf (3)
  - vprintf (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_maprintf, curl_mfprintf, curl_mprintf, curl_msnprintf, curl_msprintf,
curl_mvaprintf, curl_mvfprintf, curl_mvprintf, curl_mvsnprintf,
curl_mvsprintf - formatted output conversion

# SYNOPSIS

~~~c
#include <curl/mprintf.h>
259
260
261
262
263
264
265


266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
The number of characters written so far is stored into the integer pointed to
by the corresponding argument.

## %

A '%' symbol is written. No argument is converted.



# EXAMPLE

~~~c
const char *name = "John";

int main(void)
{
  curl_mprintf("My name is %s\n", name);
  curl_mprintf("Pi is almost %f\n", (double)25.0/8);
}
~~~

# AVAILABILITY

These functions might be removed from the public libcurl API in the future. Do
not use them in new programs or projects.

# RETURN VALUE

The **curl_maprintf** and **curl_mvaprintf** functions return a pointer to
a newly allocated string, or NULL if it failed.

All other functions return the number of characters actually printed
(excluding the null byte used to end output to strings). Note that this
sometimes differ from how the POSIX versions of these functions work.







>
>












|
<
<
<









260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281



282
283
284
285
286
287
288
289
290
The number of characters written so far is stored into the integer pointed to
by the corresponding argument.

## %

A '%' symbol is written. No argument is converted.

# %PROTOCOLS%

# EXAMPLE

~~~c
const char *name = "John";

int main(void)
{
  curl_mprintf("My name is %s\n", name);
  curl_mprintf("Pi is almost %f\n", (double)25.0/8);
}
~~~

# %AVAILABILITY%




# RETURN VALUE

The **curl_maprintf** and **curl_mvaprintf** functions return a pointer to
a newly allocated string, or NULL if it failed.

All other functions return the number of characters actually printed
(excluding the null byte used to end output to strings). Note that this
sometimes differ from how the POSIX versions of these functions work.
Changes to jni/curl/docs/libcurl/curl_multi_add_handle.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_multi_cleanup (3)
  - curl_multi_get_handles (3)
  - curl_multi_init (3)
  - curl_multi_setopt (3)
  - curl_multi_socket_action (3)
Protocol:
  - All

---

# NAME

curl_multi_add_handle - add an easy handle to a multi session

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_multi_cleanup (3)
  - curl_multi_get_handles (3)
  - curl_multi_init (3)
  - curl_multi_setopt (3)
  - curl_multi_socket_action (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

curl_multi_add_handle - add an easy handle to a multi session

# SYNOPSIS
59
60
61
62
63
64
65


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

1 - curl_multi_remove_handle(3)

2 - curl_easy_cleanup(3)

3 - curl_multi_cleanup(3)



# EXAMPLE

~~~c
int main(void)
{
  /* init a multi stack */
  CURLM *multi = curl_multi_init();

  /* create two easy handles */
  CURL *http_handle = curl_easy_init();
  CURL *http_handle2 = curl_easy_init();

  /* add individual transfers */
  curl_multi_add_handle(multi, http_handle);
  curl_multi_add_handle(multi, http_handle2);
}
~~~

# AVAILABILITY

Added in 7.9.6

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.







>
>


















|
<
<




60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87


88
89
90
91

1 - curl_multi_remove_handle(3)

2 - curl_easy_cleanup(3)

3 - curl_multi_cleanup(3)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  /* init a multi stack */
  CURLM *multi = curl_multi_init();

  /* create two easy handles */
  CURL *http_handle = curl_easy_init();
  CURL *http_handle2 = curl_easy_init();

  /* add individual transfers */
  curl_multi_add_handle(multi, http_handle);
  curl_multi_add_handle(multi, http_handle2);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.
Changes to jni/curl/docs/libcurl/curl_multi_assign.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_assign
Section: 3
Source: libcurl
See-also:
  - curl_multi_setopt (3)
  - curl_multi_socket_action (3)
Protocol:
  - All

---

# NAME

curl_multi_assign - set data to associate with an internal socket

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_assign
Section: 3
Source: libcurl
See-also:
  - curl_multi_setopt (3)
  - curl_multi_socket_action (3)
Protocol:
  - All
Added-in: 7.15.5
---

# NAME

curl_multi_assign - set data to associate with an internal socket

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83






The idea here being that this association (socket to private pointer) is
something that just about every application that uses this API needs and then
libcurl can just as well do it since it already has the necessary
functionality.

It is acceptable to call this function from your multi callback functions.



# EXAMPLE

~~~c
int main(void)
{
  CURLM *multi = curl_multi_init();
  void *ourstructp; /* pointer to our data */
  curl_socket_t fd; /* file descriptor to associate our data with */

  /* make our struct pointer associated with socket fd */
  CURLMcode mc = curl_multi_assign(multi, fd, ourstructp);
  if(mc)
    printf("error: %s\n", curl_multi_strerror(mc));
}
~~~

# AVAILABILITY

Added in 7.15.5

# RETURN VALUE

The standard CURLMcode for multi interface error codes.

# TYPICAL USAGE

In a typical application you allocate a struct or at least use some kind of
semi-dynamic data for each socket that we must wait for action on when using
the curl_multi_socket_action(3) approach.

When our socket-callback gets called by libcurl and we get to know about yet
another socket to wait for, we can use curl_multi_assign(3) to point out
the particular data so that when we get updates about this same socket again,
we do not have to find the struct associated with this socket by ourselves.













>
>
















<
<
<
<
<
<
<
<







|
|
|
>
>
>
>
>
>
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68








69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
The idea here being that this association (socket to private pointer) is
something that just about every application that uses this API needs and then
libcurl can just as well do it since it already has the necessary
functionality.

It is acceptable to call this function from your multi callback functions.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *multi = curl_multi_init();
  void *ourstructp; /* pointer to our data */
  curl_socket_t fd; /* file descriptor to associate our data with */

  /* make our struct pointer associated with socket fd */
  CURLMcode mc = curl_multi_assign(multi, fd, ourstructp);
  if(mc)
    printf("error: %s\n", curl_multi_strerror(mc));
}
~~~









# TYPICAL USAGE

In a typical application you allocate a struct or at least use some kind of
semi-dynamic data for each socket that we must wait for action on when using
the curl_multi_socket_action(3) approach.

When our socket-callback gets called by libcurl and we get to know about yet
another socket to wait for, we can use curl_multi_assign(3) to point out the
particular data so that when we get updates about this same socket again, we
do not have to find the struct associated with this socket by ourselves.

# %AVAILABILITY%

# RETURN VALUE

The standard CURLMcode for multi interface error codes.
Changes to jni/curl/docs/libcurl/curl_multi_cleanup.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44




45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_cleanup
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_init (3)
  - curl_multi_get_handles (3)
  - curl_multi_init (3)
Protocol:
  - All

---

# NAME

curl_multi_cleanup - close down a multi session

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_cleanup(CURLM *multi_handle);
~~~

# DESCRIPTION


Cleans up and removes a whole multi stack. It does not free or touch any
individual easy handles in any way - they still need to be closed
individually, using the usual curl_easy_cleanup(3) way. The order of
cleaning up should be:

1 - curl_multi_remove_handle(3) before any easy handles are cleaned up

2 - curl_easy_cleanup(3) can now be called independently since the easy
handle is no longer connected to the multi handle

3 - curl_multi_cleanup(3) should be called when all easy handles are
removed

Passing in a NULL pointer in *multi_handle* makes this function return
CURLM_BAD_HANDLE immediately with no other action.





# EXAMPLE

~~~c
int main(void)
{
  CURLM *multi = curl_multi_init();

  /* when the multi transfer is done ... */

  /* remove all easy handles, then: */
  curl_multi_cleanup(multi);
}
~~~

# AVAILABILITY

Added in 7.9.6

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code. On success,
CURLM_OK is returned.













>
















>
|
|
|
<











>
>
>
>















|
<
<





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
70
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_cleanup
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_init (3)
  - curl_multi_get_handles (3)
  - curl_multi_init (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

curl_multi_cleanup - close down a multi session

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_cleanup(CURLM *multi_handle);
~~~

# DESCRIPTION

This function is the opposite of curl_multi_init(3). Cleans up and removes a
whole multi stack. It does not free or touch any individual easy handles in
any way - they still need to be closed individually, using the usual
curl_easy_cleanup(3) way. The order of cleaning up should be:


1 - curl_multi_remove_handle(3) before any easy handles are cleaned up

2 - curl_easy_cleanup(3) can now be called independently since the easy
handle is no longer connected to the multi handle

3 - curl_multi_cleanup(3) should be called when all easy handles are
removed

Passing in a NULL pointer in *multi_handle* makes this function return
CURLM_BAD_HANDLE immediately with no other action.

Any use of the **multi_handle** after this function has been called and have
returned, is illegal.
# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *multi = curl_multi_init();

  /* when the multi transfer is done ... */

  /* remove all easy handles, then: */
  curl_multi_cleanup(multi);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLMcode type, general libcurl multi interface error code. On success,
CURLM_OK is returned.
Changes to jni/curl/docs/libcurl/curl_multi_fdset.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
  - curl_multi_perform (3)
  - curl_multi_timeout (3)
  - curl_multi_wait (3)
  - curl_multi_waitfds (3)
  - select (2)
Protocol:
  - All

---

# NAME

curl_multi_fdset - extracts file descriptor information from a multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_fdset(CURLM *multi_handle,







>




|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  - curl_multi_perform (3)
  - curl_multi_timeout (3)
  - curl_multi_wait (3)
  - curl_multi_waitfds (3)
  - select (2)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

curl_multi_fdset - extract file descriptor information from a multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_fdset(CURLM *multi_handle,
74
75
76
77
78
79
80


81
82
83
84
85
86
87
set in an **fd_set**, which on POSIX systems means that the file descriptor
is larger than **FD_SETSIZE**, then libcurl tries to not set it. Setting a
too large file descriptor in an **fd_set** implies an out of bounds write
which can cause crashes, or worse. The effect of NOT storing it might possibly
save you from the crash, but makes your program NOT wait for sockets it should
wait for...



# EXAMPLE

~~~c
int main(void)
{
  fd_set fdread;
  fd_set fdwrite;







>
>







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
set in an **fd_set**, which on POSIX systems means that the file descriptor
is larger than **FD_SETSIZE**, then libcurl tries to not set it. Setting a
too large file descriptor in an **fd_set** implies an out of bounds write
which can cause crashes, or worse. The effect of NOT storing it might possibly
save you from the crash, but makes your program NOT wait for sockets it should
wait for...

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  fd_set fdread;
  fd_set fdwrite;
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
    /* wait for activity on one of the sockets */
    rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);

  } while(!mc);
}
~~~

# AVAILABILITY

Added in 7.9.6

# RETURN VALUE

**CURLMcode** type, general libcurl multi interface error code. See
libcurl-errors(3)







|
<
<





111
112
113
114
115
116
117
118


119
120
121
122
123
    /* wait for activity on one of the sockets */
    rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);

  } while(!mc);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

**CURLMcode** type, general libcurl multi interface error code. See
libcurl-errors(3)
Changes to jni/curl/docs/libcurl/curl_multi_get_handles.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_get_handles
Section: 3
Source: libcurl
See-also:
  - curl_multi_add_handle (3)
  - curl_multi_cleanup (3)
  - curl_multi_init (3)
  - curl_multi_remove_handle (3)
Protocol:
  - All

---

# NAME

curl_multi_get_handles - returns all added easy handles

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURL **curl_multi_get_handles(CURLM *multi_handle);













>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_get_handles
Section: 3
Source: libcurl
See-also:
  - curl_multi_add_handle (3)
  - curl_multi_cleanup (3)
  - curl_multi_init (3)
  - curl_multi_remove_handle (3)
Protocol:
  - All
Added-in: 8.4.0
---

# NAME

curl_multi_get_handles - return all added easy handles

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURL **curl_multi_get_handles(CURLM *multi_handle);
37
38
39
40
41
42
43


44
45
46
47
48
49
50
the call. As soon as a handle has been removed from or a handle has been added
to the multi handle after the handle array was returned, the two data points
are out of sync.

The order of the easy handles within the array is not guaranteed.

The returned array must be freed with a call to curl_free(3) after use.



# EXAMPLE

~~~c
int main(void)
{
  /* init a multi stack */







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
the call. As soon as a handle has been removed from or a handle has been added
to the multi handle after the handle array was returned, the two data points
are out of sync.

The order of the easy handles within the array is not guaranteed.

The returned array must be freed with a call to curl_free(3) after use.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  /* init a multi stack */
66
67
68
69
70
71
72
73
74
75
76
77
78
79
      }
      curl_free(list);
    }
  }
}
~~~

# AVAILABILITY

Added in 8.4.0

# RETURN VALUE

Returns NULL on failure. Otherwise it returns a pointer to an allocated array.







|
<
<




69
70
71
72
73
74
75
76


77
78
79
80
      }
      curl_free(list);
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns NULL on failure. Otherwise it returns a pointer to an allocated array.
Changes to jni/curl/docs/libcurl/curl_multi_info_read.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_info_read
Section: 3
Source: libcurl
See-also:
  - curl_multi_cleanup (3)
  - curl_multi_init (3)
  - curl_multi_perform (3)
Protocol:
  - All

---

# NAME

curl_multi_info_read - read multi stack information

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_info_read
Section: 3
Source: libcurl
See-also:
  - curl_multi_cleanup (3)
  - curl_multi_init (3)
  - curl_multi_perform (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

curl_multi_info_read - read multi stack information

# SYNOPSIS
62
63
64
65
66
67
68


69
70
71
72
73
74
75
~~~
When **msg** is *CURLMSG_DONE*, the message identifies a transfer that
is done, and then **result** contains the return code for the easy handle
that just completed.

At this point, there are no other **msg** types defined.



# EXAMPLE

~~~c
int main(void)
{
  CURLM *multi = curl_multi_init();
  CURL *curl = curl_easy_init();







>
>







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
~~~
When **msg** is *CURLMSG_DONE*, the message identifies a transfer that
is done, and then **result** contains the return code for the easy handle
that just completed.

At this point, there are no other **msg** types defined.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *multi = curl_multi_init();
  CURL *curl = curl_easy_init();
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
        curl_easy_cleanup(e);
      }
    } while(m);
  }
}
~~~

# AVAILABILITY

Added in 7.9.6

# RETURN VALUE

A pointer to a filled-in struct, or NULL if it failed or ran out of
structs. It also writes the number of messages left in the queue (after this
read) in the integer the second argument points to.







|
<
<






92
93
94
95
96
97
98
99


100
101
102
103
104
105
        curl_easy_cleanup(e);
      }
    } while(m);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a filled-in struct, or NULL if it failed or ran out of
structs. It also writes the number of messages left in the queue (after this
read) in the integer the second argument points to.
Changes to jni/curl/docs/libcurl/curl_multi_init.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_easy_init (3)
  - curl_global_init (3)
  - curl_multi_add_handle (3)
  - curl_multi_cleanup (3)
  - curl_multi_get_handles (3)
Protocol:
  - All

---

# NAME

curl_multi_init - create a multi handle

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_easy_init (3)
  - curl_global_init (3)
  - curl_multi_add_handle (3)
  - curl_multi_cleanup (3)
  - curl_multi_get_handles (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

curl_multi_init - create a multi handle

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# DESCRIPTION

This function returns a pointer to a *CURLM* handle to be used as input to
all the other multi-functions, sometimes referred to as a multi handle in some
places in the documentation. This init call MUST have a corresponding call to
curl_multi_cleanup(3) when the operation is complete.



# EXAMPLE

~~~c
int main(void)
{
  /* init a multi stack */
  CURLM *multi = curl_multi_init();
  CURL *curl = curl_easy_init();
  CURL *curl2 = curl_easy_init();

  /* add individual transfers */
  curl_multi_add_handle(multi, curl);
  curl_multi_add_handle(multi, curl2);
}
~~~

# AVAILABILITY

Added in 7.9.6

# RETURN VALUE

If this function returns NULL, something went wrong and you cannot use the
other curl functions.







>
>
















|
<
<





30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


56
57
58
59
60
# DESCRIPTION

This function returns a pointer to a *CURLM* handle to be used as input to
all the other multi-functions, sometimes referred to as a multi handle in some
places in the documentation. This init call MUST have a corresponding call to
curl_multi_cleanup(3) when the operation is complete.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  /* init a multi stack */
  CURLM *multi = curl_multi_init();
  CURL *curl = curl_easy_init();
  CURL *curl2 = curl_easy_init();

  /* add individual transfers */
  curl_multi_add_handle(multi, curl);
  curl_multi_add_handle(multi, curl2);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

If this function returns NULL, something went wrong and you cannot use the
other curl functions.
Changes to jni/curl/docs/libcurl/curl_multi_perform.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - curl_multi_wait (3)
  - libcurl-errors (3)
Protocol:
  - All

---

# NAME

curl_multi_perform - reads/writes available data from easy handles

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles);







>




|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - curl_multi_wait (3)
  - libcurl-errors (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

curl_multi_perform - run all transfers until it would block

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles);
56
57
58
59
60
61
62


63
64
65
66
67
68
69
there is no longer any transfers in progress.

When this function returns error, the state of all transfers are uncertain and
they cannot be continued. curl_multi_perform(3) should not be called
again on the same multi handle after an error has been returned, unless first
removing all the handles and adding new ones.



# EXAMPLE

~~~c
int main(void)
{
  int still_running;
  CURL *multi = curl_multi_init();







>
>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
there is no longer any transfers in progress.

When this function returns error, the state of all transfers are uncertain and
they cannot be continued. curl_multi_perform(3) should not be called
again on the same multi handle after an error has been returned, unless first
removing all the handles and adding new ones.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  int still_running;
  CURL *multi = curl_multi_init();
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

    /* if there are still transfers, loop! */
    } while(still_running);
  }
}
~~~

# AVAILABILITY

Added in 7.9.6

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.

This function returns errors regarding the whole multi stack. Problems on
individual transfers may have occurred even when this function returns







|
<
<







87
88
89
90
91
92
93
94


95
96
97
98
99
100
101

    /* if there are still transfers, loop! */
    } while(still_running);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.

This function returns errors regarding the whole multi stack. Problems on
individual transfers may have occurred even when this function returns
Changes to jni/curl/docs/libcurl/curl_multi_poll.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_poll
Section: 3
Source: libcurl
See-also:
  - curl_multi_fdset (3)
  - curl_multi_perform (3)
  - curl_multi_wait (3)
  - curl_multi_wakeup (3)
Protocol:
  - All

---

# NAME

curl_multi_poll - polls on all easy handles in a multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_poll(CURLM *multi_handle,













>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_poll
Section: 3
Source: libcurl
See-also:
  - curl_multi_fdset (3)
  - curl_multi_perform (3)
  - curl_multi_wait (3)
  - curl_multi_wakeup (3)
Protocol:
  - All
Added-in: 7.66.0
---

# NAME

curl_multi_poll - poll on all easy handles in a multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_poll(CURLM *multi_handle,
82
83
84
85
86
87
88


89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107





108

109





110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
priority read events such as out of band data.

## CURL_WAIT_POLLOUT

Bit flag to curl_waitfd.events indicating the socket should poll on write
events such as the socket being clear to write without blocking.



# EXAMPLE

~~~c
int main(void)
{
  CURL *easy_handle;
  CURLM *multi_handle;
  int still_running = 0;


  /* add the individual easy handle */
  curl_multi_add_handle(multi_handle, easy_handle);

  do {
    CURLMcode mc;
    int numfds;

    mc = curl_multi_perform(multi_handle, &still_running);

    if(mc == CURLM_OK) {





      /* wait for activity or timeout */

      mc = curl_multi_poll(multi_handle, NULL, 0, 1000, &numfds);





    }

    if(mc != CURLM_OK) {
      fprintf(stderr, "curl_multi failed, code %d.\n", mc);
      break;
    }

  } while(still_running);

  curl_multi_remove_handle(multi_handle, easy_handle);
}
~~~

# AVAILABILITY

Added in 7.66.0.

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code. See
libcurl-errors(3)







>
>








>











>
>
>
>
>
|
>
|
>
>
>
>
>













|
<
<





83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138


139
140
141
142
143
priority read events such as out of band data.

## CURL_WAIT_POLLOUT

Bit flag to curl_waitfd.events indicating the socket should poll on write
events such as the socket being clear to write without blocking.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *easy_handle;
  CURLM *multi_handle;
  int still_running = 0;
  int myfd; /* this is our own file descriptor */

  /* add the individual easy handle */
  curl_multi_add_handle(multi_handle, easy_handle);

  do {
    CURLMcode mc;
    int numfds;

    mc = curl_multi_perform(multi_handle, &still_running);

    if(mc == CURLM_OK) {
      struct curl_waitfd myown;
      myown.fd = myfd;
      myown.events = CURL_WAIT_POLLIN; /* wait for input */
      myown.revents = 0; /* clear it */

      /* wait for activity on curl's descriptors or on our own,
         or timeout */
      mc = curl_multi_poll(multi_handle, &myown, 1, 1000, &numfds);

      if(myown.revents) {
        /* did our descriptor receive an event? */
        handle_fd(myfd);
      }
    }

    if(mc != CURLM_OK) {
      fprintf(stderr, "curl_multi failed, code %d.\n", mc);
      break;
    }

  } while(still_running);

  curl_multi_remove_handle(multi_handle, easy_handle);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLMcode type, general libcurl multi interface error code. See
libcurl-errors(3)
Changes to jni/curl/docs/libcurl/curl_multi_remove_handle.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_remove_handle
Section: 3
Source: libcurl
See-also:
  - curl_multi_add_handle (3)
  - curl_multi_cleanup (3)
  - curl_multi_init (3)
Protocol:
  - All

---

# NAME

curl_multi_remove_handle - remove an easy handle from a multi session

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_remove_handle
Section: 3
Source: libcurl
See-also:
  - curl_multi_add_handle (3)
  - curl_multi_cleanup (3)
  - curl_multi_init (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

curl_multi_remove_handle - remove an easy handle from a multi session

# SYNOPSIS
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Removing an easy handle from the multi handle before the corresponding
transfer is complete might cause libcurl to close the connection - if the
state of it and the internal protocol handler deem it necessary. Otherwise
libcurl keeps the connection alive in the connection pool associated with the
multi handle, ready to get reused for a future transfer using this multi
handle.



# EXAMPLE

~~~c
int main(void)
{
  CURLM *multi = curl_multi_init();
  int queued = 0;

  /* when an easy handle has completed, remove it */
  CURLMsg *msg = curl_multi_info_read(multi, &queued);
  if(msg) {
    if(msg->msg == CURLMSG_DONE) {
      /* a transfer ended */
      fprintf(stderr, "Transfer completed\n");
      curl_multi_remove_handle(multi, msg->easy_handle);
    }
  }
}
~~~

# AVAILABILITY

Added in 7.9.6

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.







>
>




















|
<
<




43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
Removing an easy handle from the multi handle before the corresponding
transfer is complete might cause libcurl to close the connection - if the
state of it and the internal protocol handler deem it necessary. Otherwise
libcurl keeps the connection alive in the connection pool associated with the
multi handle, ready to get reused for a future transfer using this multi
handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *multi = curl_multi_init();
  int queued = 0;

  /* when an easy handle has completed, remove it */
  CURLMsg *msg = curl_multi_info_read(multi, &queued);
  if(msg) {
    if(msg->msg == CURLMSG_DONE) {
      /* a transfer ended */
      fprintf(stderr, "Transfer completed\n");
      curl_multi_remove_handle(multi, msg->easy_handle);
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.
Changes to jni/curl/docs/libcurl/curl_multi_setopt.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47








48
49
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_setopt
Section: 3
Source: libcurl
See-also:
  - curl_multi_cleanup (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - curl_multi_socket (3)
Protocol:
  - All

---

# NAME

curl_multi_setopt - set options for a curl multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_setopt(CURLM *multi_handle, CURLMoption option, parameter);
~~~

# DESCRIPTION

curl_multi_setopt(3) is used to tell a libcurl multi handle how to
behave. By using the appropriate options to curl_multi_setopt(3), you
can change libcurl's behavior when using that multi handle. All options are
set with the *option* followed by the *parameter*. That parameter can
be a **long**, a **function pointer**, an **object pointer** or a
**curl_off_t** type, depending on what the specific option expects. Read
this manual carefully as bad input values may cause libcurl to behave
badly. You can only set one option in each function call.

# OPTIONS

## CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE

See CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3)

## CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE

See CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3)









## CURLMOPT_MAX_HOST_CONNECTIONS


See CURLMOPT_MAX_HOST_CONNECTIONS(3)

## CURLMOPT_MAX_PIPELINE_LENGTH

See CURLMOPT_MAX_PIPELINE_LENGTH(3)

## CURLMOPT_MAX_TOTAL_CONNECTIONS

See CURLMOPT_MAX_TOTAL_CONNECTIONS(3)

## CURLMOPT_MAXCONNECTS

See CURLMOPT_MAXCONNECTS(3)

## CURLMOPT_PIPELINING

See CURLMOPT_PIPELINING(3)

## CURLMOPT_PIPELINING_SITE_BL

See CURLMOPT_PIPELINING_SITE_BL(3)

## CURLMOPT_PIPELINING_SERVER_BL

See CURLMOPT_PIPELINING_SERVER_BL(3)

## CURLMOPT_PUSHFUNCTION

See CURLMOPT_PUSHFUNCTION(3)

## CURLMOPT_PUSHDATA

See CURLMOPT_PUSHDATA(3)

## CURLMOPT_SOCKETFUNCTION

See CURLMOPT_SOCKETFUNCTION(3)

## CURLMOPT_SOCKETDATA

See CURLMOPT_SOCKETDATA(3)

## CURLMOPT_TIMERFUNCTION

See CURLMOPT_TIMERFUNCTION(3)

## CURLMOPT_TIMERDATA

See CURLMOPT_TIMERDATA(3)

## CURLMOPT_MAX_CONCURRENT_STREAMS


See CURLMOPT_MAX_CONCURRENT_STREAMS(3)


# EXAMPLE

~~~c

#define MAX_PARALLEL 45

int main(void)
{
  CURLM *multi;
  /* Limit the amount of simultaneous connections curl should allow: */
  curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)MAX_PARALLEL);
}
~~~

# AVAILABILITY

Added in 7.15.4

# RETURN VALUE

The standard CURLMcode for multi interface error codes. Note that it returns a
CURLM_UNKNOWN_OPTION if you try setting an option that this version of libcurl
does not know of.













>











|




|
|
|
|
|
|
|
|





|



|
>
>
>
>
>
>
>
>



>
|



|



|
<
<
<
<



|
<
<
<
<



|

|

|



|

|

|



|

|

|



|

|

>
|
>















|
<
<






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69




70
71
72
73




74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123


124
125
126
127
128
129
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_setopt
Section: 3
Source: libcurl
See-also:
  - curl_multi_cleanup (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - curl_multi_socket (3)
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

curl_multi_setopt - set options for a curl multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_setopt(CURLM *multi, CURLMoption option, parameter);
~~~

# DESCRIPTION

curl_multi_setopt(3) is used to tell a libcurl multi handle how to behave. By
using the appropriate options to curl_multi_setopt(3), you can change
libcurl's behavior when using that multi handle. All options are set with the
*option* followed by the *parameter*. That parameter can be a **long**, a
**function pointer**, an **object pointer** or a **curl_off_t** type,
depending on what the specific option expects. Read this manual carefully as
bad input values may cause libcurl to behave badly. You can only set one
option in each function call.

# OPTIONS

## CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE

**deprecated** See CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3)

## CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE

**deprecated** See CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3)

## CURLMOPT_MAXCONNECTS

Size of connection cache. See CURLMOPT_MAXCONNECTS(3)

## CURLMOPT_MAX_CONCURRENT_STREAMS

Max concurrent streams for http2. See CURLMOPT_MAX_CONCURRENT_STREAMS(3)

## CURLMOPT_MAX_HOST_CONNECTIONS

Max number of connections to a single host. See
CURLMOPT_MAX_HOST_CONNECTIONS(3)

## CURLMOPT_MAX_PIPELINE_LENGTH

**deprecated**. See CURLMOPT_MAX_PIPELINE_LENGTH(3)

## CURLMOPT_MAX_TOTAL_CONNECTIONS

Max simultaneously open connections. See CURLMOPT_MAX_TOTAL_CONNECTIONS(3)





## CURLMOPT_PIPELINING

Enable HTTP multiplexing. See CURLMOPT_PIPELINING(3)





## CURLMOPT_PIPELINING_SERVER_BL

**deprecated**. See CURLMOPT_PIPELINING_SERVER_BL(3)

## CURLMOPT_PIPELINING_SITE_BL

**deprecated**. See CURLMOPT_PIPELINING_SITE_BL(3)

## CURLMOPT_PUSHDATA

Pointer to pass to push callback. See CURLMOPT_PUSHDATA(3)

## CURLMOPT_PUSHFUNCTION

Callback that approves or denies server pushes. See CURLMOPT_PUSHFUNCTION(3)

## CURLMOPT_SOCKETDATA

Custom pointer passed to the socket callback. See CURLMOPT_SOCKETDATA(3)

## CURLMOPT_SOCKETFUNCTION

Callback informed about what to wait for. See CURLMOPT_SOCKETFUNCTION(3)

## CURLMOPT_TIMERDATA

Custom pointer to pass to timer callback. See CURLMOPT_TIMERDATA(3)

## CURLMOPT_TIMERFUNCTION

Callback to receive timeout values. See CURLMOPT_TIMERFUNCTION(3)

# %PROTOCOLS%

# EXAMPLE

~~~c

#define MAX_PARALLEL 45

int main(void)
{
  CURLM *multi;
  /* Limit the amount of simultaneous connections curl should allow: */
  curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)MAX_PARALLEL);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

The standard CURLMcode for multi interface error codes. Note that it returns a
CURLM_UNKNOWN_OPTION if you try setting an option that this version of libcurl
does not know of.
Changes to jni/curl/docs/libcurl/curl_multi_socket.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

91
92
93
94
95
96
97
  - curl_multi_cleanup (3)
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - the hiperfifo.c example
Protocol:
  - All

---

# NAME

curl_multi_socket - reads/writes available data

# SYNOPSIS

~~~c
#include <curl/curl.h>
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t sockfd,
                            int *running_handles);

CURLMcode curl_multi_socket_all(CURLM *multi_handle,
                                int *running_handles);
~~~

# DESCRIPTION

These functions are deprecated. Do not use. See
curl_multi_socket_action(3) instead.

At return, the integer **running_handles** points to contains the number of
still running easy handles within the multi handle. When this number reaches
zero, all transfers are complete/done. Note that when you call
curl_multi_socket_action(3) on a specific socket and the counter
decreases by one, it DOES NOT necessarily mean that this exact socket/transfer
is the one that completed. Use curl_multi_info_read(3) to figure out
which easy handle that completed.

The curl_multi_socket_action(3) functions inform the application about
updates in the socket (file descriptor) status by doing none, one, or multiple
calls to the socket callback function set with the
CURLMOPT_SOCKETFUNCTION(3) option to curl_multi_setopt(3). They
update the status with changes since the previous time the callback was
called.

Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option
with curl_multi_setopt(3). Your application then gets called with
information on how long to wait for socket actions at most before doing the
timeout action: call the curl_multi_socket_action(3) function with the
**sockfd** argument set to CURL_SOCKET_TIMEOUT. You can also use the
curl_multi_timeout(3) function to poll the value at any given time, but
for an event-based system using the callback is far better than relying on
polling the timeout value.

Usage of curl_multi_socket(3) is deprecated, whereas the function is
equivalent to curl_multi_socket_action(3) with **ev_bitmask** set to
0.

Force libcurl to (re-)check all its internal sockets and transfers instead of
just a single one by calling curl_multi_socket_all(3). Note that there
should not be any reason to use this function.


# EXAMPLE

~~~c
int main(void)
{
  /* the event-library gets told when there activity on the socket 'fd',
     which we translate to a call to curl_multi_socket_action() */
  int running;
  int rc;
  int fd;
  CURLM *multi;
  rc = curl_multi_socket(multi, fd, &running);
}
~~~

# AVAILABILITY

This function was added in libcurl 7.15.4, and is deemed stable since
7.16.0.

curl_multi_socket(3) is deprecated, use
curl_multi_socket_action(3) instead!


# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.

The return code is for the whole multi stack. Problems still might have
occurred on individual transfers even when one of these functions return OK.







>




|







<
<
<




|
|




|
|
|
|

|
|
|
<
|
|

|
|
|
|
|
|
<
|


|
<

<
<
<
>
















<
|
<
<

|
|
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54

55
56
57
58

59



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

77


78
79
80
81
82
83
84
85
86
87
88
  - curl_multi_cleanup (3)
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - the hiperfifo.c example
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

curl_multi_socket - read/write available data

# SYNOPSIS

~~~c
#include <curl/curl.h>
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t sockfd,
                            int *running_handles);



~~~

# DESCRIPTION

This function is deprecated. Do not use. See curl_multi_socket_action(3)
instead.

At return, the integer **running_handles** points to contains the number of
still running easy handles within the multi handle. When this number reaches
zero, all transfers are complete/done. Note that when you call
curl_multi_socket(3) on a specific socket and the counter decreases by one, it
DOES NOT necessarily mean that this exact socket/transfer is the one that
completed. Use curl_multi_info_read(3) to figure out which easy handle that
completed.

The curl_multi_socket(3) functions inform the application about updates in the
socket (file descriptor) status by doing none, one, or multiple calls to the
socket callback function set with the CURLMOPT_SOCKETFUNCTION(3) option to

curl_multi_setopt(3). They update the status with changes since the previous
time the callback was called.

Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option with
curl_multi_setopt(3). Your application then gets called with information on
how long to wait for socket actions at most before doing the timeout action:
call the curl_multi_socket_action(3) function with the **sockfd** argument set
to CURL_SOCKET_TIMEOUT. You can also use the curl_multi_timeout(3) function to
poll the value at any given time, but for an event-based system using the

callback is far better than relying on polling the timeout value.

Usage of curl_multi_socket(3) is deprecated, whereas the function is
equivalent to curl_multi_socket_action(3) with **ev_bitmask** set to 0.





# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  /* the event-library gets told when there activity on the socket 'fd',
     which we translate to a call to curl_multi_socket_action() */
  int running;
  int rc;
  int fd;
  CURLM *multi;
  rc = curl_multi_socket(multi, fd, &running);
}
~~~


# DEPRECATED



curl_multi_socket(3) is deprecated, use curl_multi_socket_action(3) instead!

# %AVAILABILITY%

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.

The return code is for the whole multi stack. Problems still might have
occurred on individual transfers even when one of these functions return OK.
Changes to jni/curl/docs/libcurl/curl_multi_socket_action.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
  - curl_multi_cleanup (3)
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - the hiperfifo.c example
Protocol:
  - All

---

# NAME

curl_multi_socket_action - reads/writes available data given an action

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_socket_action(CURLM *multi_handle,







>




|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  - curl_multi_cleanup (3)
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - the hiperfifo.c example
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

curl_multi_socket_action - read/write available data given an action

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_socket_action(CURLM *multi_handle,
91
92
93
94
95
96
97


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
7. Wait for activity on any of libcurl's sockets, use the timeout value your
callback has been told.

8, When activity is detected, call curl_multi_socket_action() for the
socket(s) that got action. If no activity is detected and the timeout expires,
call curl_multi_socket_action(3) with *CURL_SOCKET_TIMEOUT*.



# EXAMPLE

~~~c
int main(void)
{
  /* the event-library gets told when there activity on the socket 'fd',
     which we translate to a call to curl_multi_socket_action() */
  int running;
  CURLM *multi; /* the stack we work with */
  int fd; /* the descriptor that had action */
  int bitmask; /* what activity that happened */
  CURLMcode mc = curl_multi_socket_action(multi, fd, bitmask, &running);
  if(mc)
    printf("error: %s\n", curl_multi_strerror(mc));
}
~~~

# AVAILABILITY

This function was added in libcurl 7.15.4, and is deemed stable since 7.16.0.

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code. See
libcurl-errors(3)







>
>

















|
<
<





92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118


119
120
121
122
123
7. Wait for activity on any of libcurl's sockets, use the timeout value your
callback has been told.

8, When activity is detected, call curl_multi_socket_action() for the
socket(s) that got action. If no activity is detected and the timeout expires,
call curl_multi_socket_action(3) with *CURL_SOCKET_TIMEOUT*.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  /* the event-library gets told when there activity on the socket 'fd',
     which we translate to a call to curl_multi_socket_action() */
  int running;
  CURLM *multi; /* the stack we work with */
  int fd; /* the descriptor that had action */
  int bitmask; /* what activity that happened */
  CURLMcode mc = curl_multi_socket_action(multi, fd, bitmask, &running);
  if(mc)
    printf("error: %s\n", curl_multi_strerror(mc));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLMcode type, general libcurl multi interface error code. See
libcurl-errors(3)
Changes to jni/curl/docs/libcurl/curl_multi_socket_all.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_socket
Section: 3
Source: libcurl
See-also:
  - curl_multi_cleanup (3)
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - the hiperfifo.c example
Protocol:
  - All

---

# NAME

curl_multi_socket - reads/writes available data

# SYNOPSIS

~~~c
#include <curl/curl.h>
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t sockfd,
                            int *running_handles);

CURLMcode curl_multi_socket_all(CURLM *multi_handle,
                                int *running_handles);
~~~

# DESCRIPTION

These functions are deprecated. Do not use. See
curl_multi_socket_action(3) instead.

At return, the integer **running_handles** points to contains the number of
still running easy handles within the multi handle. When this number reaches
zero, all transfers are complete/done. Note that when you call
curl_multi_socket_action(3) on a specific socket and the counter
decreases by one, it DOES NOT necessarily mean that this exact socket/transfer
is the one that completed. Use curl_multi_info_read(3) to figure out
which easy handle that completed.

The curl_multi_socket_action(3) functions inform the application about
updates in the socket (file descriptor) status by doing none, one, or multiple
calls to the socket callback function set with the
CURLMOPT_SOCKETFUNCTION(3) option to curl_multi_setopt(3). They
update the status with changes since the previous time the callback was
called.

Get the timeout time by setting the CURLMOPT_TIMERFUNCTION(3) option
with curl_multi_setopt(3). Your application then gets called with
information on how long to wait for socket actions at most before doing the
timeout action: call the curl_multi_socket_action(3) function with the
**sockfd** argument set to CURL_SOCKET_TIMEOUT. You can also use the
curl_multi_timeout(3) function to poll the value at any given time, but
for an event-based system using the callback is far better than relying on
polling the timeout value.

Usage of curl_multi_socket(3) is deprecated, whereas the function is
equivalent to curl_multi_socket_action(3) with **ev_bitmask** set to
0.

Force libcurl to (re-)check all its internal sockets and transfers instead of
just a single one by calling curl_multi_socket_all(3). Note that there
should not be any reason to use this function.



# EXAMPLE

~~~c
int main(void)
{
  /* the event-library gets told when there activity on the socket 'fd',
     which we translate to a call to curl_multi_socket_action() */
  int running;
  int rc;
  int fd;
  CURLM *multi;
  rc = curl_multi_socket(multi, fd, &running);
}
~~~

# AVAILABILITY

This function was added in libcurl 7.15.4, and is deemed stable since
7.16.0.

curl_multi_socket(3) is deprecated, use
curl_multi_socket_action(3) instead!

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.

The return code is for the whole multi stack. Problems still might have
occurred on individual transfers even when one of these functions return OK.



|










>




|





<
<







|
|



|
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

|
|
>
>






<
<


<

|



|
<
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25


26
27
28
29
30
31
32
33
34
35
36
37
38




39




















40
41
42
43
44
45
46
47
48
49
50


51
52

53
54
55
56
57
58






59
60
61
62
63
64
65
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_socket_all
Section: 3
Source: libcurl
See-also:
  - curl_multi_cleanup (3)
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_init (3)
  - the hiperfifo.c example
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

curl_multi_socket_all - reads/writes available data for all easy handles

# SYNOPSIS

~~~c
#include <curl/curl.h>



CURLMcode curl_multi_socket_all(CURLM *multi_handle,
                                int *running_handles);
~~~

# DESCRIPTION

This function is deprecated. Do not use. See curl_multi_socket_action(3)
instead.

At return, the integer **running_handles** points to contains the number of
still running easy handles within the multi handle. When this number reaches
zero, all transfers are complete/done.

























Force libcurl to (re-)check all its internal sockets and transfers instead of
just a single one by calling curl_multi_socket_all(3). Note that there should
not be any reason to use this function.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{


  int running;
  int rc;

  CURLM *multi;
  rc = curl_multi_socket_all(multi, &running);
}
~~~

# %AVAILABILITY%







# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.

The return code is for the whole multi stack. Problems still might have
occurred on individual transfers even when one of these functions return OK.
Changes to jni/curl/docs/libcurl/curl_multi_strerror.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_strerror
Section: 3
Source: libcurl
See-also:
  - curl_easy_strerror (3)
  - curl_share_strerror (3)
  - curl_url_strerror (3)
  - libcurl-errors (3)
Protocol:
  - All

---

# NAME

curl_multi_strerror - return string describing error code

# SYNOPSIS

~~~c
#include <curl/curl.h>

const char *curl_multi_strerror(CURLMcode errornum);
~~~

# DESCRIPTION

This function returns a string describing the *CURLMcode* error code
passed in the argument *errornum*.



# EXAMPLE

~~~c
int main(void)
{
  int still_running;
  CURLM *multi = curl_multi_init();

  CURLMcode mc = curl_multi_perform(multi, &still_running);
  if(mc)
    printf("error: %s\n", curl_multi_strerror(mc));
}
~~~

# AVAILABILITY

This function was added in libcurl 7.12.0

# RETURN VALUE

A pointer to a null-terminated string.













>



















>
>














|
<
<




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50


51
52
53
54
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_strerror
Section: 3
Source: libcurl
See-also:
  - curl_easy_strerror (3)
  - curl_share_strerror (3)
  - curl_url_strerror (3)
  - libcurl-errors (3)
Protocol:
  - All
Added-in: 7.12.0
---

# NAME

curl_multi_strerror - return string describing error code

# SYNOPSIS

~~~c
#include <curl/curl.h>

const char *curl_multi_strerror(CURLMcode errornum);
~~~

# DESCRIPTION

This function returns a string describing the *CURLMcode* error code
passed in the argument *errornum*.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  int still_running;
  CURLM *multi = curl_multi_init();

  CURLMcode mc = curl_multi_perform(multi, &still_running);
  if(mc)
    printf("error: %s\n", curl_multi_strerror(mc));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a null-terminated string.
Changes to jni/curl/docs/libcurl/curl_multi_timeout.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_timeout
Section: 3
Source: libcurl
See-also:
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_setopt (3)
  - curl_multi_socket (3)
Protocol:
  - All

---

# NAME

curl_multi_timeout - how long to wait for action before proceeding

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_timeout
Section: 3
Source: libcurl
See-also:
  - curl_multi_fdset (3)
  - curl_multi_info_read (3)
  - curl_multi_setopt (3)
  - curl_multi_socket (3)
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

curl_multi_timeout - how long to wait for action before proceeding

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57
It should instead use the CURLMOPT_TIMERFUNCTION(3) option for proper and
desired behavior.

Note: if libcurl returns a -1 timeout here, it just means that libcurl
currently has no stored timeout value. You must not wait too long (more than a
few seconds perhaps) before you call curl_multi_perform(3) again.



# EXAMPLE

~~~c
int main(void)
{
  struct timeval timeout;
  long timeo;







>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
It should instead use the CURLMOPT_TIMERFUNCTION(3) option for proper and
desired behavior.

Note: if libcurl returns a -1 timeout here, it just means that libcurl
currently has no stored timeout value. You must not wait too long (more than a
few seconds perhaps) before you call curl_multi_perform(3) again.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  struct timeval timeout;
  long timeo;
78
79
80
81
82
83
84
85
86
87
88
89
90
91

Call curl_multi_timeout(3), then wait for action on the sockets. Figure
out which sockets to wait for by calling curl_multi_fdset(3).

When there is activity or timeout, call curl_multi_perform(3) and then
loop - until all transfers are complete.

# AVAILABILITY

This function was added in libcurl 7.15.4.

# RETURN VALUE

The standard CURLMcode for multi interface error codes.







|
<
<




81
82
83
84
85
86
87
88


89
90
91
92

Call curl_multi_timeout(3), then wait for action on the sockets. Figure
out which sockets to wait for by calling curl_multi_fdset(3).

When there is activity or timeout, call curl_multi_perform(3) and then
loop - until all transfers are complete.

# %AVAILABILITY%



# RETURN VALUE

The standard CURLMcode for multi interface error codes.
Changes to jni/curl/docs/libcurl/curl_multi_wait.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_wait
Section: 3
Source: libcurl
See-also:
  - curl_multi_fdset (3)
  - curl_multi_perform (3)
  - curl_multi_poll (3)
Protocol:
  - All

---

# NAME

curl_multi_wait - polls on all easy handles in a multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_wait(CURLM *multi_handle,












>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_wait
Section: 3
Source: libcurl
See-also:
  - curl_multi_fdset (3)
  - curl_multi_perform (3)
  - curl_multi_poll (3)
Protocol:
  - All
Added-in: 7.28.0
---

# NAME

curl_multi_wait - poll on all easy handles in a multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_wait(CURLM *multi_handle,
75
76
77
78
79
80
81


82
83
84
85
86
87
88
priority read events such as out of band data.

## CURL_WAIT_POLLOUT

Bit flag to *curl_waitfd.events* indicating the socket should poll on
write events such as the socket being clear to write without blocking.



# EXAMPLE

~~~c
int main(void)
{
  CURL *easy;
  CURLM *multi = curl_multi_init();







>
>







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
priority read events such as out of band data.

## CURL_WAIT_POLLOUT

Bit flag to *curl_waitfd.events* indicating the socket should poll on
write events such as the socket being clear to write without blocking.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *easy;
  CURLM *multi = curl_multi_init();
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

  } while(still_running);

  curl_multi_remove_handle(multi, easy);
}
~~~

# AVAILABILITY

This function was added in libcurl 7.28.0.

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code. See
libcurl-errors(3)







|
<
<





112
113
114
115
116
117
118
119


120
121
122
123
124

  } while(still_running);

  curl_multi_remove_handle(multi, easy);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLMcode type, general libcurl multi interface error code. See
libcurl-errors(3)
Changes to jni/curl/docs/libcurl/curl_multi_waitfds.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_waitfds
Section: 3
Source: libcurl
See-also:
  - curl_multi_perform (3)
  - curl_multi_poll (3)
  - curl_multi_wait (3)
  - curl_multi_fdset (3)
Protocol:
  - All

---

# NAME

curl_multi_waitfds - extracts file descriptor information from a multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>
#include <stdlib.h>














>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_waitfds
Section: 3
Source: libcurl
See-also:
  - curl_multi_perform (3)
  - curl_multi_poll (3)
  - curl_multi_wait (3)
  - curl_multi_fdset (3)
Protocol:
  - All
Added-in: 8.8.0
---

# NAME

curl_multi_waitfds - extract file descriptor information from a multi handle

# SYNOPSIS

~~~c
#include <curl/curl.h>
#include <stdlib.h>

46
47
48
49
50
51
52


53
54
55
56
57
58
59
If the *fd_count* argument is not a null pointer, it points to a variable
that on returns specifies the number of descriptors used by the multi_handle to
be checked for being ready to read or write.

The client code can pass *size* equal to zero just to get the number of the
descriptors and allocate appropriate storage for them to be used in a
subsequent function call.



# EXAMPLE

~~~c
int main(void)
{
  CURLMcode mc;







>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
If the *fd_count* argument is not a null pointer, it points to a variable
that on returns specifies the number of descriptors used by the multi_handle to
be checked for being ready to read or write.

The client code can pass *size* equal to zero just to get the number of the
descriptors and allocate appropriate storage for them to be used in a
subsequent function call.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLMcode mc;
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    /* Do polling on descriptors in ufds */

    free(ufds);
  } while (!mc);
}
~~~

# AVAILABILITY

Added in 8.8.0

# RETURN VALUE

**CURLMcode** type, general libcurl multi interface error code. See
libcurl-errors(3)







|
<
<





98
99
100
101
102
103
104
105


106
107
108
109
110
    /* Do polling on descriptors in ufds */

    free(ufds);
  } while (!mc);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

**CURLMcode** type, general libcurl multi interface error code. See
libcurl-errors(3)
Changes to jni/curl/docs/libcurl/curl_multi_wakeup.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_wakeup
Section: 3
Source: libcurl
See-also:
  - curl_multi_poll (3)
  - curl_multi_wait (3)
Protocol:
  - All

---

# NAME

curl_multi_wakeup - wakes up a sleeping curl_multi_poll call

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_wakeup(CURLM *multi_handle);











>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_multi_wakeup
Section: 3
Source: libcurl
See-also:
  - curl_multi_poll (3)
  - curl_multi_wait (3)
Protocol:
  - All
Added-in: 7.68.0
---

# NAME

curl_multi_wakeup - wake up a sleeping curl_multi_poll call

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLMcode curl_multi_wakeup(CURLM *multi_handle);
33
34
35
36
37
38
39


40
41
42
43
44
45
46
causes the next call to return immediately.

Calling this function only guarantees to wake up the current (or the next if
there is no current) curl_multi_poll(3) call, which means it is possible
that multiple calls to this function wake up the same waiting operation.

This function has no effect on curl_multi_wait(3) calls.



# EXAMPLE

~~~c
extern int time_to_die(void);
extern int set_something_to_signal_thread_1_to_exit(void);
extern int decide_to_stop_thread1();







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
causes the next call to return immediately.

Calling this function only guarantees to wake up the current (or the next if
there is no current) curl_multi_poll(3) call, which means it is possible
that multiple calls to this function wake up the same waiting operation.

This function has no effect on curl_multi_wait(3) calls.

# %PROTOCOLS%

# EXAMPLE

~~~c
extern int time_to_die(void);
extern int set_something_to_signal_thread_1_to_exit(void);
extern int decide_to_stop_thread1();
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    set_something_to_signal_thread_1_to_exit();

    curl_multi_wakeup(multi);
  }
}
~~~

# AVAILABILITY

Added in 7.68.0

# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.







|
<
<




83
84
85
86
87
88
89
90


91
92
93
94
    set_something_to_signal_thread_1_to_exit();

    curl_multi_wakeup(multi);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLMcode type, general libcurl multi interface error code.
Changes to jni/curl/docs/libcurl/curl_pushheader_byname.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_pushheader_byname
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PUSHFUNCTION (3)
  - curl_pushheader_bynum (3)
Protocol:
  - HTTP

---

# NAME

curl_pushheader_byname - get a push header by name

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_pushheader_byname
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PUSHFUNCTION (3)
  - curl_pushheader_bynum (3)
Protocol:
  - HTTP
Added-in: 7.44.0
---

# NAME

curl_pushheader_byname - get a push header by name

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
elsewhere and it has no function then.

It returns the value for the given header field name (or NULL) for the
incoming server push request. This is a shortcut so that the application does
not have to loop through all headers to find the one it is interested in. The
data this function points to is freed when this callback returns. If more than
one header field use the same name, this returns only the first one.



# EXAMPLE

~~~c
#include <string.h> /* for strncmp */

static int push_cb(CURL *parent,







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
elsewhere and it has no function then.

It returns the value for the given header field name (or NULL) for the
incoming server push request. This is a shortcut so that the application does
not have to loop through all headers to find the one it is interested in. The
data this function points to is freed when this callback returns. If more than
one header field use the same name, this returns only the first one.

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h> /* for strncmp */

static int push_cb(CURL *parent,
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  int counter;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_cb);
  curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter);
}
~~~

# AVAILABILITY

Added in 7.44.0

# RETURN VALUE

Returns a pointer to the header field content or NULL.







|
<
<




74
75
76
77
78
79
80
81


82
83
84
85
  int counter;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_cb);
  curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns a pointer to the header field content or NULL.
Changes to jni/curl/docs/libcurl/curl_pushheader_bynum.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_pushheader_bynum
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PUSHFUNCTION (3)
  - curl_pushheader_byname (3)
Protocol:
  - HTTP

---

# NAME

curl_pushheader_bynum - get a push header by index

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_pushheader_bynum
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PUSHFUNCTION (3)
  - curl_pushheader_byname (3)
Protocol:
  - HTTP
Added-in: 7.44.0
---

# NAME

curl_pushheader_bynum - get a push header by index

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
CURLMOPT_PUSHFUNCTION(3) callback. It makes no sense to try to use it
elsewhere and it has no function then.

It returns the value for the header field at the given index **num**, for
the incoming server push request or NULL. The data pointed to is freed by
libcurl when this callback returns. The returned pointer points to a
"name:value" string that gets freed when this callback returns.



# EXAMPLE

~~~c
/* output all the incoming push request headers */
static int push_cb(CURL *parent,
                   CURL *easy,







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
CURLMOPT_PUSHFUNCTION(3) callback. It makes no sense to try to use it
elsewhere and it has no function then.

It returns the value for the header field at the given index **num**, for
the incoming server push request or NULL. The data pointed to is freed by
libcurl when this callback returns. The returned pointer points to a
"name:value" string that gets freed when this callback returns.

# %PROTOCOLS%

# EXAMPLE

~~~c
/* output all the incoming push request headers */
static int push_cb(CURL *parent,
                   CURL *easy,
58
59
60
61
62
63
64
65
66
67
68
69
70
71
int main(void)
{
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_cb);
}
~~~

# AVAILABILITY

Added in 7.44.0

# RETURN VALUE

Returns a pointer to the header field content or NULL.







|
<
<




61
62
63
64
65
66
67
68


69
70
71
72
int main(void)
{
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_cb);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns a pointer to the header field content or NULL.
Changes to jni/curl/docs/libcurl/curl_share_cleanup.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33





34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_share_cleanup
Section: 3
Source: libcurl
See-also:
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All

---

# NAME

curl_share_cleanup - Clean up a shared object

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLSHcode curl_share_cleanup(CURLSH *share_handle);
~~~

# DESCRIPTION

This function deletes a shared object. The share handle cannot be used anymore
when this function has been called.

Passing in a NULL pointer in *share_handle* makes this function return
immediately with no action.






# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  /* use the share, then ... */
  curl_share_cleanup(share);
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred as *\<curl/curl.h\>* defines. See the libcurl-errors(3) man
page for the full list with descriptions. If an error occurs, then the share
object is not deleted.











>




|

















>
>
>
>
>













|
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53


54
55
56
57
58
59
60
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_share_cleanup
Section: 3
Source: libcurl
See-also:
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All
Added-in: 7.10
---

# NAME

curl_share_cleanup - close a shared object

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLSHcode curl_share_cleanup(CURLSH *share_handle);
~~~

# DESCRIPTION

This function deletes a shared object. The share handle cannot be used anymore
when this function has been called.

Passing in a NULL pointer in *share_handle* makes this function return
immediately with no action.

Any use of the **share_handle** after this function has been called and have
returned, is illegal.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  /* use the share, then ... */
  curl_share_cleanup(share);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred as *\<curl/curl.h\>* defines. See the libcurl-errors(3) man
page for the full list with descriptions. If an error occurs, then the share
object is not deleted.
Changes to jni/curl/docs/libcurl/curl_share_init.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_share_init
Section: 3
Source: libcurl
See-also:
  - curl_share_cleanup (3)
  - curl_share_setopt (3)
Protocol:
  - All

---

# NAME

curl_share_init - Create a shared object

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLSH *curl_share_init();











>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_share_init
Section: 3
Source: libcurl
See-also:
  - curl_share_cleanup (3)
  - curl_share_setopt (3)
Protocol:
  - All
Added-in: 7.10
---

# NAME

curl_share_init - create a share object

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLSH *curl_share_init();
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
call to curl_share_cleanup(3) when all operations using the share are
complete.

This *share handle* is what you pass to curl using the
CURLOPT_SHARE(3) option with curl_easy_setopt(3), to make that
specific curl handle use the data in this share.



# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

If this function returns NULL, something went wrong (out of memory, etc.)
and therefore the share object was not created.







>
>













|
<
<





32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


55
56
57
58
59
call to curl_share_cleanup(3) when all operations using the share are
complete.

This *share handle* is what you pass to curl using the
CURLOPT_SHARE(3) option with curl_easy_setopt(3), to make that
specific curl handle use the data in this share.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

If this function returns NULL, something went wrong (out of memory, etc.)
and therefore the share object was not created.
Changes to jni/curl/docs/libcurl/curl_share_setopt.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_share_setopt
Section: 3
Source: libcurl
See-also:
  - curl_share_cleanup (3)
  - curl_share_init (3)
Protocol:
  - All

---

# NAME

curl_share_setopt - Set options for a shared object

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLSHcode curl_share_setopt(CURLSH *share, CURLSHoption option, parameter);











>




|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_share_setopt
Section: 3
Source: libcurl
See-also:
  - curl_share_cleanup (3)
  - curl_share_init (3)
Protocol:
  - All
Added-in: 7.10
---

# NAME

curl_share_setopt - set options for a shared object

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLSHcode curl_share_setopt(CURLSH *share, CURLSHoption option, parameter);
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

See CURLSHOPT_UNSHARE(3).

## CURLSHOPT_USERDATA

See CURLSHOPT_USERDATA(3).



# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred as *\<curl/curl.h\>* defines. See the libcurl-errors(3) man
page for the full list with descriptions.







>
>













|
<
<






46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
73
74

See CURLSHOPT_UNSHARE(3).

## CURLSHOPT_USERDATA

See CURLSHOPT_USERDATA(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred as *\<curl/curl.h\>* defines. See the libcurl-errors(3) man
page for the full list with descriptions.
Changes to jni/curl/docs/libcurl/curl_share_strerror.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_share_strerror
Section: 3
Source: libcurl
See-also:
  - curl_easy_strerror (3)
  - curl_multi_strerror (3)
  - curl_url_strerror (3)
  - libcurl-errors (3)
Protocol:
  - All

---

# NAME

curl_share_strerror - return string describing error code

# SYNOPSIS

~~~c
#include <curl/curl.h>

const char *curl_share_strerror(CURLSHcode errornum);
~~~

# DESCRIPTION

The curl_share_strerror(3) function returns a string describing the
*CURLSHcode* error code passed in the argument *errornum*.



# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# AVAILABILITY

This function was added in libcurl 7.12.0

# RETURN VALUE

A pointer to a null-terminated string.













>



















>
>













|
<
<




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49


50
51
52
53
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_share_strerror
Section: 3
Source: libcurl
See-also:
  - curl_easy_strerror (3)
  - curl_multi_strerror (3)
  - curl_url_strerror (3)
  - libcurl-errors (3)
Protocol:
  - All
Added-in: 7.12.0
---

# NAME

curl_share_strerror - return string describing error code

# SYNOPSIS

~~~c
#include <curl/curl.h>

const char *curl_share_strerror(CURLSHcode errornum);
~~~

# DESCRIPTION

The curl_share_strerror(3) function returns a string describing the
*CURLSHcode* error code passed in the argument *errornum*.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a null-terminated string.
Changes to jni/curl/docs/libcurl/curl_slist_append.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_slist_append
Section: 3
Source: libcurl
See-also:
  - curl_slist_free_all (3)
Protocol:
  - All

---

# NAME

curl_slist_append - add a string to an slist

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_slist_append
Section: 3
Source: libcurl
See-also:
  - curl_slist_free_all (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_slist_append - add a string to an slist

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
existing **list** should be passed as the first argument and the new list is
returned from this function. Pass in NULL in the **list** argument to create
a new list. The specified **string** has been appended when this function
returns. curl_slist_append(3) copies the string.

The list should be freed again (after usage) with
curl_slist_free_all(3).



# EXAMPLE

~~~c
int main(void)
{
  CURL *handle;







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
existing **list** should be passed as the first argument and the new list is
returned from this function. Pass in NULL in the **list** argument to create
a new list. The specified **string** has been appended when this function
returns. curl_slist_append(3) copies the string.

The list should be freed again (after usage) with
curl_slist_free_all(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *handle;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

  curl_easy_perform(handle);

  curl_slist_free_all(slist); /* free the list again */
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

A null pointer is returned if anything went wrong, otherwise the new list
pointer is returned. To avoid overwriting an existing non-empty list on
failure, the new list should be returned to a temporary variable which can
be tested for NULL before updating the original list pointer.







|
<
<







64
65
66
67
68
69
70
71


72
73
74
75
76
77
78

  curl_easy_perform(handle);

  curl_slist_free_all(slist); /* free the list again */
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A null pointer is returned if anything went wrong, otherwise the new list
pointer is returned. To avoid overwriting an existing non-empty list on
failure, the new list should be returned to a temporary variable which can
be tested for NULL before updating the original list pointer.
Changes to jni/curl/docs/libcurl/curl_slist_free_all.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_slist_free_all
Section: 3
Source: libcurl
See-also:
  - curl_slist_append (3)
Protocol:
  - All

---

# NAME

curl_slist_free_all - free an entire curl_slist list

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_slist_free_all
Section: 3
Source: libcurl
See-also:
  - curl_slist_append (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_slist_free_all - free an entire curl_slist list

# SYNOPSIS
26
27
28
29
30
31
32





33
34
35
36
37
38
39

curl_slist_free_all() removes all traces of a previously built curl_slist
linked list.

Passing in a NULL pointer in *list* makes this function return immediately
with no action.






# EXAMPLE

~~~c
int main(void)
{
  CURL *handle;
  struct curl_slist *slist = NULL;







>
>
>
>
>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

curl_slist_free_all() removes all traces of a previously built curl_slist
linked list.

Passing in a NULL pointer in *list* makes this function return immediately
with no action.

Any use of the **list** after this function has been called and have returned,
is illegal.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *handle;
  struct curl_slist *slist = NULL;
47
48
49
50
51
52
53
54
55
56
57
58
59
60

  curl_easy_perform(handle);

  curl_slist_free_all(slist); /* free the list again */
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Nothing.







|
<
<




53
54
55
56
57
58
59
60


61
62
63
64

  curl_easy_perform(handle);

  curl_slist_free_all(slist); /* free the list again */
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Nothing.
Changes to jni/curl/docs/libcurl/curl_strequal.md.
1
2
3
4
5
6
7

8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_strequal
Section: 3
Source: libcurl
See-also:

  - strcasecmp (3)
  - strcmp (3)
Protocol:
  - All

---

# NAME

curl_strequal, curl_strnequal - case insensitive string comparisons

# SYNOPSIS

~~~c
#include <curl/curl.h>

int curl_strequal(const char *str1, const char *str2);
int curl_strnequal(const char *str1, const char *str2, size_t length);
~~~

# DESCRIPTION

The curl_strequal(3) function compares the two strings *str1* and
*str2*, ignoring the case of the characters. It returns a non-zero (TRUE)
integer if the strings are identical.

The **curl_strnequal()** function is similar, except it only compares the
first *length* characters of *str1*.


These functions are provided by libcurl to enable applications to compare
strings in a truly portable manner. There are no standard portable case
insensitive string comparison functions. These two work on all platforms.



# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  const char *name = "compare";
  if(curl_strequal(name, argv[1]))
    printf("Name and input matches\n");
  if(curl_strnequal(name, argv[1], 5))
    printf("Name and input matches in the 5 first bytes\n");
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Non-zero if the strings are identical. Zero if they are not.







>




>




|







<




|
|
|

|
|
>

|
|
|
>
>









<
<



|
<
<




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51


52
53
54
55


56
57
58
59
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_strequal
Section: 3
Source: libcurl
See-also:
  - curl_strnequal (3)
  - strcasecmp (3)
  - strcmp (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_strequal - compare two strings ignoring case

# SYNOPSIS

~~~c
#include <curl/curl.h>

int curl_strequal(const char *str1, const char *str2);

~~~

# DESCRIPTION

The curl_strequal(3) function compares the two strings *str1* and *str2*,
ignoring the case of the characters. It returns a non-zero (TRUE) integer if
the strings are identical.

This function uses plain ASCII based comparisons completely disregarding the
locale - contrary to how **strcasecmp** and other system case insensitive
string comparisons usually work.

This function is provided by libcurl to enable applications to compare strings
in a truly portable manner. There are no standard portable case insensitive
string comparison functions. This function works on all platforms.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  const char *name = "compare";
  if(curl_strequal(name, argv[1]))
    printf("Name and input matches\n");


}
~~~

# %AVAILABILITY%



# RETURN VALUE

Non-zero if the strings are identical. Zero if they are not.
Changes to jni/curl/docs/libcurl/curl_strnequal.md.
1
2
3
4
5
6
7

8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

34



35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_strequal
Section: 3
Source: libcurl
See-also:

  - strcasecmp (3)
  - strcmp (3)
Protocol:
  - All

---

# NAME

curl_strequal, curl_strnequal - case insensitive string comparisons

# SYNOPSIS

~~~c
#include <curl/curl.h>

int curl_strequal(const char *str1, const char *str2);
int curl_strnequal(const char *str1, const char *str2, size_t length);
~~~

# DESCRIPTION

The curl_strequal(3) function compares the two strings *str1* and
*str2*, ignoring the case of the characters. It returns a non-zero (TRUE)
integer if the strings are identical.

The **curl_strnequal()** function is similar, except it only compares the

first *length* characters of *str1*.




These functions are provided by libcurl to enable applications to compare
strings in a truly portable manner. There are no standard portable case
insensitive string comparison functions. These two work on all platforms.



# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  const char *name = "compare";
  if(curl_strequal(name, argv[1]))
    printf("Name and input matches\n");
  if(curl_strnequal(name, argv[1], 5))
    printf("Name and input matches in the 5 first bytes\n");
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Non-zero if the strings are identical. Zero if they are not.



|



>




>




|






<





|
|
|

|
>
|
>
>
>

|
|
|
>
>







<
<





|
<
<




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52


53
54
55
56
57
58


59
60
61
62
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_strnequal
Section: 3
Source: libcurl
See-also:
  - curl_strequal (3)
  - strcasecmp (3)
  - strcmp (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_strnequal - compare two strings ignoring case

# SYNOPSIS

~~~c
#include <curl/curl.h>


int curl_strnequal(const char *str1, const char *str2, size_t length);
~~~

# DESCRIPTION

The curl_strnequal(3) function compares the two strings *str1* and *str2*,
ignoring the case of the characters. It returns a non-zero (TRUE) integer if
the strings are identical.

This function compares no more than the first *length* bytes of *str1* and
*str2*.

This function uses plain ASCII based comparisons completely disregarding the
locale - contrary to how **strcasecmp** and other system case insensitive
string comparisons usually work.

This function is provided by libcurl to enable applications to compare strings
in a truly portable manner. There are no standard portable case insensitive
string comparison functions. This function works on all platforms.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  const char *name = "compare";


  if(curl_strnequal(name, argv[1], 5))
    printf("Name and input matches in the 5 first bytes\n");
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Non-zero if the strings are identical. Zero if they are not.
Changes to jni/curl/docs/libcurl/curl_unescape.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_unescape
Section: 3
Source: libcurl
See-also:
  - RFC 2396
  - curl_easy_escape (3)
  - curl_easy_unescape (3)
  - curl_free (3)
Protocol:
  - All

---

# NAME

curl_unescape - URL decodes the given string

# SYNOPSIS

~~~c
#include <curl/curl.h>

char *curl_unescape(const char *input, int length);
~~~

# DESCRIPTION

Obsolete function. Use curl_easy_unescape(3) instead.

This function converts the URL encoded string **input** to a "plain string"
and return that as a new allocated string. All input characters that are URL
encoded (%XX where XX is a two-digit hexadecimal number) are converted to
their plain text versions.

If the **length** argument is set to 0, curl_unescape(3) calls
strlen() on **input** to find out the size.

You must curl_free(3) the returned string when you are done with it.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    char *decoded = curl_unescape("%63%75%72%6c", 12);
    if(decoded) {
      /* do not assume printf() works on the decoded data */
      printf("Decoded: ");
      /* ... */
      curl_free(decoded);
    }
  }
}
~~~

# AVAILABILITY

Since 7.15.4, curl_easy_unescape(3) should be used. This function might
be removed in a future release.



# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed.













>




|











|










>
>



















|



>
>




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_unescape
Section: 3
Source: libcurl
See-also:
  - RFC 2396
  - curl_easy_escape (3)
  - curl_easy_unescape (3)
  - curl_free (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_unescape - URL decode a string

# SYNOPSIS

~~~c
#include <curl/curl.h>

char *curl_unescape(const char *input, int length);
~~~

# DESCRIPTION

Deprecated. Use curl_easy_unescape(3) instead.

This function converts the URL encoded string **input** to a "plain string"
and return that as a new allocated string. All input characters that are URL
encoded (%XX where XX is a two-digit hexadecimal number) are converted to
their plain text versions.

If the **length** argument is set to 0, curl_unescape(3) calls
strlen() on **input** to find out the size.

You must curl_free(3) the returned string when you are done with it.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    char *decoded = curl_unescape("%63%75%72%6c", 12);
    if(decoded) {
      /* do not assume printf() works on the decoded data */
      printf("Decoded: ");
      /* ... */
      curl_free(decoded);
    }
  }
}
~~~

# DEPRECATED

Since 7.15.4, curl_easy_unescape(3) should be used. This function might
be removed in a future release.

# %AVAILABILITY%

# RETURN VALUE

A pointer to a null-terminated string or NULL if it failed.
Changes to jni/curl/docs/libcurl/curl_url.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38


39
40
41
42
43
44
45
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_set (3)
  - curl_url_strerror (3)
Protocol:
  - All

---

# NAME

curl_url - returns a new URL handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLU *curl_url();
~~~

# DESCRIPTION

This function allocates a URL object and returns a *CURLU* handle for it,
to be used as input to all other URL API functions.

This is a handle to a URL object that holds or can hold URL components for a
single URL. When the object is first created, there is of course no components
stored. They are then set in the object with the curl_url_set(3)
function.



# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;







>




|


















>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_set (3)
  - curl_url_strerror (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

curl_url - create a URL handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLU *curl_url();
~~~

# DESCRIPTION

This function allocates a URL object and returns a *CURLU* handle for it,
to be used as input to all other URL API functions.

This is a handle to a URL object that holds or can hold URL components for a
single URL. When the object is first created, there is of course no components
stored. They are then set in the object with the curl_url_set(3)
function.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
      curl_free(scheme);
    }
    curl_url_cleanup(url);
  }
}
~~~

# AVAILABILITY

Added in 7.62.0

# RETURN VALUE

Returns a **CURLU *** if successful, or NULL if out of memory.







|
<
<




56
57
58
59
60
61
62
63


64
65
66
67
      curl_free(scheme);
    }
    curl_url_cleanup(url);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns a **CURLU *** if successful, or NULL if out of memory.
Changes to jni/curl/docs/libcurl/curl_url_cleanup.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_CURLU (3)
  - curl_url (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_set (3)
Protocol:
  - All

---

# NAME

curl_url_cleanup - free the URL handle

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_CURLU (3)
  - curl_url (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_set (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

curl_url_cleanup - free the URL handle

# SYNOPSIS
29
30
31
32
33
34
35





36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# DESCRIPTION

Frees all the resources associated with the given *CURLU* handle!

Passing in a NULL pointer in *handle* makes this function return
immediately with no action.






# EXAMPLE

~~~c
int main(void)
{
  CURLU *url = curl_url();
  curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  curl_url_cleanup(url);
}
~~~

# AVAILABILITY

Added in 7.62.0

# RETURN VALUE

none







>
>
>
>
>











|
<
<




30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53


54
55
56
57
# DESCRIPTION

Frees all the resources associated with the given *CURLU* handle!

Passing in a NULL pointer in *handle* makes this function return
immediately with no action.

Any use of the **handle** after this function has been called and have
returned, is illegal.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLU *url = curl_url();
  curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  curl_url_cleanup(url);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

none
Changes to jni/curl/docs/libcurl/curl_url_dup.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  - CURLOPT_CURLU (3)
  - curl_url (3)
  - curl_url_cleanup (3)
  - curl_url_get (3)
  - curl_url_set (3)
Protocol:
  - All

---

# NAME

curl_url_dup - duplicate a URL handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLU *curl_url_dup(const CURLU *inhandle);
~~~

# DESCRIPTION

Duplicates the URL object the input *CURLU* *inhandle* identifies and
returns a pointer to the copy as a new *CURLU* handle. The new handle also
needs to be freed with curl_url_cleanup(3).



# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
  CURLU *url = curl_url();
  CURLU *url2;
  rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  if(!rc) {
    url2 = curl_url_dup(url); /* clone it! */
    curl_url_cleanup(url2);
  }
  curl_url_cleanup(url);
}
~~~

# AVAILABILITY

Added in 7.62.0

# RETURN VALUE

Returns a new handle or NULL if out of memory.







>




















>
>

















|
<
<




8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


56
57
58
59
  - CURLOPT_CURLU (3)
  - curl_url (3)
  - curl_url_cleanup (3)
  - curl_url_get (3)
  - curl_url_set (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

curl_url_dup - duplicate a URL handle

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLU *curl_url_dup(const CURLU *inhandle);
~~~

# DESCRIPTION

Duplicates the URL object the input *CURLU* *inhandle* identifies and
returns a pointer to the copy as a new *CURLU* handle. The new handle also
needs to be freed with curl_url_cleanup(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
  CURLU *url = curl_url();
  CURLU *url2;
  rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  if(!rc) {
    url2 = curl_url_dup(url); /* clone it! */
    curl_url_cleanup(url2);
  }
  curl_url_cleanup(url);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns a new handle or NULL if out of memory.
Changes to jni/curl/docs/libcurl/curl_url_get.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_url (3)
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_set (3)
  - curl_url_strerror (3)
Protocol:
  - All

---

# NAME

curl_url_get - extract a part from a URL

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_url (3)
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_set (3)
  - curl_url_strerror (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

curl_url_get - extract a part from a URL

# SYNOPSIS
121
122
123
124
125
126
127
















128
129
130
131
132
133
134

An empty query part is one where this is nothing following the question mark
(before the possible fragment). An empty fragments part is one where there is
nothing following the hash sign.

(Added in curl 8.8.0)

















# PARTS

## CURLUPART_URL

When asked to return the full URL, curl_url_get(3) returns a normalized and
possibly cleaned up version using all available URL parts.








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

An empty query part is one where this is nothing following the question mark
(before the possible fragment). An empty fragments part is one where there is
nothing following the hash sign.

(Added in curl 8.8.0)

## CURLU_NO_GUESS_SCHEME

When this flag is used in curl_url_get(), it treats the scheme as non-existing
if it was set as a result of a previous guess; when CURLU_GUESS_SCHEME was
used parsing a URL.

Using this flag when getting CURLUPART_SCHEME if the scheme was set as the
result of a guess makes curl_url_get() return CURLUE_NO_SCHEME.

Using this flag when getting CURLUPART_URL if the scheme was set as the result
of a guess makes curl_url_get() return the full URL without the scheme
component. Such a URL can then only be parsed with curl_url_set() if
CURLU_GUESS_SCHEME is used.

(Added in curl 8.9.0)

# PARTS

## CURLUPART_URL

When asked to return the full URL, curl_url_get(3) returns a normalized and
possibly cleaned up version using all available URL parts.

195
196
197
198
199
200
201


202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
The initial hash sign that denotes the beginning of the fragment is a
delimiter only. It is not part of the fragment contents.

A not-present fragment returns *part* set to NULL.

A zero-length fragment returns *part* as NULL unless CURLU_GET_EMPTY is set.



# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
  CURLU *url = curl_url();
  rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  if(!rc) {
    char *scheme;
    rc = curl_url_get(url, CURLUPART_SCHEME, &scheme, 0);
    if(!rc) {
      printf("the scheme is %s\n", scheme);
      curl_free(scheme);
    }
    curl_url_cleanup(url);
  }
}
~~~

# AVAILABILITY

Added in 7.62.0. CURLUPART_ZONEID was added in 7.65.0.

# RETURN VALUE

Returns a CURLUcode error value, which is CURLUE_OK (0) if everything went
fine. See the libcurl-errors(3) man page for the full list with
descriptions.

If this function returns an error, no URL part is returned.







>
>




















|
<
<








212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241


242
243
244
245
246
247
248
249
The initial hash sign that denotes the beginning of the fragment is a
delimiter only. It is not part of the fragment contents.

A not-present fragment returns *part* set to NULL.

A zero-length fragment returns *part* as NULL unless CURLU_GET_EMPTY is set.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
  CURLU *url = curl_url();
  rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  if(!rc) {
    char *scheme;
    rc = curl_url_get(url, CURLUPART_SCHEME, &scheme, 0);
    if(!rc) {
      printf("the scheme is %s\n", scheme);
      curl_free(scheme);
    }
    curl_url_cleanup(url);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns a CURLUcode error value, which is CURLUE_OK (0) if everything went
fine. See the libcurl-errors(3) man page for the full list with
descriptions.

If this function returns an error, no URL part is returned.
Changes to jni/curl/docs/libcurl/curl_url_set.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_url (3)
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_strerror (3)
Protocol:
  - All

---

# NAME

curl_url_set - set a URL part

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_url (3)
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_strerror (3)
Protocol:
  - All
Added-in: 7.78.0
---

# NAME

curl_url_set - set a URL part

# SYNOPSIS
71
72
73
74
75
76
77
78
79
80


81
82
83
84
85
86
87
88
89
90
91
92
93

Allows the full URL of the handle to be replaced. If the handle already is
populated with a URL, the new URL can be relative to the previous.

When successfully setting a new URL, relative or absolute, the handle contents
is replaced with the components of the newly set URL.

Pass a pointer to a null-terminated string to the *url* parameter. The
string must point to a correctly formatted "RFC 3986+" URL or be a NULL
pointer.



By default, this API only accepts setting URLs using schemes for protocols
that are supported built-in. To make libcurl parse URLs generically even for
schemes it does not know about, the **CURLU_NON_SUPPORT_SCHEME** flags bit
must be set. Otherwise, this function returns *CURLUE_UNSUPPORTED_SCHEME* for
URL schemes it does not recognize.

Unless *CURLU_NO_AUTHORITY* is set, a blank hostname is not allowed in
the URL.

## CURLUPART_SCHEME

Scheme cannot be URL decoded on set. libcurl only accepts setting schemes up







|
|
|
>
>

|
|
|
|
|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

Allows the full URL of the handle to be replaced. If the handle already is
populated with a URL, the new URL can be relative to the previous.

When successfully setting a new URL, relative or absolute, the handle contents
is replaced with the components of the newly set URL.

Pass a pointer to a null-terminated string to the *url* parameter. The string
must point to a correctly formatted "RFC 3986+" URL or be a NULL pointer. The
URL parser only understands and parses the subset of URLS that are
"hierarchical" and therefore contain a :// separator - not the ones that are
normally specified with only a colon separator.

By default this API only parses URLs using schemes for protocols that are
supported built-in. To make libcurl parse URLs generically even for schemes it
does not know about, the **CURLU_NON_SUPPORT_SCHEME** flags bit must be set.
Otherwise, this function returns *CURLUE_UNSUPPORTED_SCHEME* for URL schemes
it does not recognize.

Unless *CURLU_NO_AUTHORITY* is set, a blank hostname is not allowed in
the URL.

## CURLUPART_SCHEME

Scheme cannot be URL decoded on set. libcurl only accepts setting schemes up
163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198








199
200
201
202
203
204
205
new appended part.

When *CURLU_APPENDQUERY* is used together with *CURLU_URLENCODE*, the
first '=' symbol is not URL encoded.

## CURLU_NON_SUPPORT_SCHEME

If set, allows curl_url_set(3) to set a non-supported scheme.


## CURLU_URLENCODE

When set, curl_url_set(3) URL encodes the part on entry, except for
**scheme**, **port** and **URL**.

When setting the path component with URL encoding enabled, the slash character
is skipped.

The query part gets space-to-plus converted before the URL conversion is
applied.

This URL encoding is charset unaware and converts the input in a byte-by-byte
manner.

## CURLU_DEFAULT_SCHEME

If set, allows the URL to be set without a scheme and then sets that to the
default scheme: HTTPS. Overrides the *CURLU_GUESS_SCHEME* option if both
are set.

## CURLU_GUESS_SCHEME

If set, allows the URL to be set without a scheme and it instead "guesses"
which scheme that was intended based on the hostname. If the outermost
subdomain name matches DICT, FTP, IMAP, LDAP, POP3 or SMTP then that scheme is
used, otherwise it picks HTTP. Conflicts with the *CURLU_DEFAULT_SCHEME*
option which takes precedence if both are set.









## CURLU_NO_AUTHORITY

If set, skips authority checks. The RFC allows individual schemes to omit the
host part (normally the only mandatory part of the authority), but libcurl
cannot know whether this is permitted for custom schemes. Specifying the flag
permits empty authority sections, similar to how file scheme is handled.







|
>


















|
|








>
>
>
>
>
>
>
>







166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
new appended part.

When *CURLU_APPENDQUERY* is used together with *CURLU_URLENCODE*, the
first '=' symbol is not URL encoded.

## CURLU_NON_SUPPORT_SCHEME

If set, allows curl_url_set(3) to set a non-supported scheme. It then of
course cannot know if the provided scheme is a valid one or not.

## CURLU_URLENCODE

When set, curl_url_set(3) URL encodes the part on entry, except for
**scheme**, **port** and **URL**.

When setting the path component with URL encoding enabled, the slash character
is skipped.

The query part gets space-to-plus converted before the URL conversion is
applied.

This URL encoding is charset unaware and converts the input in a byte-by-byte
manner.

## CURLU_DEFAULT_SCHEME

If set, allows the URL to be set without a scheme and then sets that to the
default scheme: HTTPS. Overrides the *CURLU_GUESS_SCHEME* option if both are
set.

## CURLU_GUESS_SCHEME

If set, allows the URL to be set without a scheme and it instead "guesses"
which scheme that was intended based on the hostname. If the outermost
subdomain name matches DICT, FTP, IMAP, LDAP, POP3 or SMTP then that scheme is
used, otherwise it picks HTTP. Conflicts with the *CURLU_DEFAULT_SCHEME*
option which takes precedence if both are set.

If guessing is not allowed and there is no default scheme set, trying to parse
a URL without a scheme returns error.

If the scheme ends up set as a result of guessing, i.e. it is not actually
present in the parsed URL, it can later be figured out by using the
**CURLU_NO_GUESS_SCHEME** flag when subsequently getting the URL or the scheme
with curl_url_get(3).

## CURLU_NO_AUTHORITY

If set, skips authority checks. The RFC allows individual schemes to omit the
host part (normally the only mandatory part of the authority), but libcurl
cannot know whether this is permitted for custom schemes. Specifying the flag
permits empty authority sections, similar to how file scheme is handled.
224
225
226
227
228
229
230


231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

## CURLU_DISALLOW_USER

If set, the URL parser does not accept embedded credentials for the
**CURLUPART_URL**, and instead returns **CURLUE_USER_NOT_ALLOWED** for
such URLs.



# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
  CURLU *url = curl_url();
  rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  if(!rc) {
    /* change it to an FTP URL */
    rc = curl_url_set(url, CURLUPART_SCHEME, "ftp", 0);
  }
  curl_url_cleanup(url);
}
~~~

# AVAILABILITY

Added in 7.62.0. CURLUPART_ZONEID was added in 7.65.0.

# RETURN VALUE

Returns a *CURLUcode* error value, which is CURLUE_OK (0) if everything
went fine. See the libcurl-errors(3) man page for the full list with
descriptions.

The input string passed to curl_url_set(3) must be shorter than eight
million bytes. Otherwise this function returns **CURLUE_MALFORMED_INPUT**.

If this function returns an error, no URL part is set.







>
>
















|
<
<











236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261


262
263
264
265
266
267
268
269
270
271
272

## CURLU_DISALLOW_USER

If set, the URL parser does not accept embedded credentials for the
**CURLUPART_URL**, and instead returns **CURLUE_USER_NOT_ALLOWED** for
such URLs.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
  CURLU *url = curl_url();
  rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  if(!rc) {
    /* change it to an FTP URL */
    rc = curl_url_set(url, CURLUPART_SCHEME, "ftp", 0);
  }
  curl_url_cleanup(url);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns a *CURLUcode* error value, which is CURLUE_OK (0) if everything
went fine. See the libcurl-errors(3) man page for the full list with
descriptions.

The input string passed to curl_url_set(3) must be shorter than eight
million bytes. Otherwise this function returns **CURLUE_MALFORMED_INPUT**.

If this function returns an error, no URL part is set.
Changes to jni/curl/docs/libcurl/curl_url_strerror.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  - curl_multi_strerror (3)
  - curl_share_strerror (3)
  - curl_url_get (3)
  - curl_url_set (3)
  - libcurl-errors (3)
Protocol:
  - All

---

# NAME

curl_url_strerror - return string describing error code

# SYNOPSIS

~~~c
#include <curl/curl.h>

const char *curl_url_strerror(CURLUcode errornum);
~~~

# DESCRIPTION

This function returns a string describing the CURLUcode error code passed in
the argument *errornum*.



# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
  CURLU *url = curl_url();
  rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  if(rc)
    printf("URL error: %s\n", curl_url_strerror(rc));
  curl_url_cleanup(url);
}
~~~

# AVAILABILITY

Added in 7.80.0

# RETURN VALUE

A pointer to a null-terminated string.







>



















>
>














|
<
<




9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52


53
54
55
56
  - curl_multi_strerror (3)
  - curl_share_strerror (3)
  - curl_url_get (3)
  - curl_url_set (3)
  - libcurl-errors (3)
Protocol:
  - All
Added-in: 7.80.0
---

# NAME

curl_url_strerror - return string describing error code

# SYNOPSIS

~~~c
#include <curl/curl.h>

const char *curl_url_strerror(CURLUcode errornum);
~~~

# DESCRIPTION

This function returns a string describing the CURLUcode error code passed in
the argument *errornum*.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLUcode rc;
  CURLU *url = curl_url();
  rc = curl_url_set(url, CURLUPART_URL, "https://example.com", 0);
  if(rc)
    printf("URL error: %s\n", curl_url_strerror(rc));
  curl_url_cleanup(url);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a null-terminated string.
Changes to jni/curl/docs/libcurl/curl_version.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_version
Section: 3
Source: libcurl
See-also:
  - curl_version_info (3)
Protocol:
  - All

---

# NAME

curl_version - returns the libcurl version string

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_version
Section: 3
Source: libcurl
See-also:
  - curl_version_info (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

curl_version - returns the libcurl version string

# SYNOPSIS
25
26
27
28
29
30
31


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# DESCRIPTION

Returns a human readable string with the version number of libcurl and some of
its important components (like OpenSSL version).

We recommend using curl_version_info(3) instead!



# EXAMPLE

~~~c
int main(void)
{
  printf("libcurl version %s\n", curl_version());
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

A pointer to a null-terminated string. The string resides in a statically
allocated buffer and must not be freed by the caller.







>
>









|
<
<





26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44


45
46
47
48
49
# DESCRIPTION

Returns a human readable string with the version number of libcurl and some of
its important components (like OpenSSL version).

We recommend using curl_version_info(3) instead!

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  printf("libcurl version %s\n", curl_version());
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a null-terminated string. The string resides in a statically
allocated buffer and must not be freed by the caller.
Changes to jni/curl/docs/libcurl/curl_version_info.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_version_info
Section: 3
Source: libcurl
See-also:
  - curl_version (3)
Protocol:
  - All

---

# NAME

curl_version_info - returns runtime libcurl version info

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: curl_version_info
Section: 3
Source: libcurl
See-also:
  - curl_version (3)
Protocol:
  - All
Added-in: 7.10.0
---

# NAME

curl_version_info - returns runtime libcurl version info

# SYNOPSIS
365
366
367
368
369
370
371


372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391

## no name

*features* mask bit: CURL_VERSION_KERBEROS4

supports Kerberos V4 (when using FTP). Legacy bit. Deprecated since 7.33.0.



# EXAMPLE

~~~c
int main(void)
{
  curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
  printf("libcurl version %u.%u.%u\n",
         (ver->version_num >> 16) & 0xff,
         (ver->version_num >> 8) & 0xff,
         ver->version_num & 0xff);
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

A pointer to a curl_version_info_data struct.







>
>













|
<
<




366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388


389
390
391
392

## no name

*features* mask bit: CURL_VERSION_KERBEROS4

supports Kerberos V4 (when using FTP). Legacy bit. Deprecated since 7.33.0.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
  printf("libcurl version %u.%u.%u\n",
         (ver->version_num >> 16) & 0xff,
         (ver->version_num >> 8) & 0xff,
         ver->version_num & 0xff);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

A pointer to a curl_version_info_data struct.
Changes to jni/curl/docs/libcurl/curl_ws_meta.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
  - curl_ws_recv (3)
  - curl_ws_send (3)
  - libcurl-ws (3)
Protocol:
  - WS

---

# NAME

curl_ws_meta - meta data WebSocket information

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
  - curl_ws_recv (3)
  - curl_ws_send (3)
  - libcurl-ws (3)
Protocol:
  - WS
Added-in: 7.86.0
---

# NAME

curl_ws_meta - meta data WebSocket information

# SYNOPSIS
93
94
95
96
97
98
99


100
101
102
103
104
105
106

This transfer is now closed.

## CURLWS_PING

This as an incoming ping message, that expects a pong response.



# EXAMPLE

~~~c

/* we pass a pointer to this struct to the callback */
struct customdata {
  CURL *easy;







>
>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

This transfer is now closed.

## CURLWS_PING

This as an incoming ping message, that expects a pong response.

# %PROTOCOLS%

# EXAMPLE

~~~c

/* we pass a pointer to this struct to the callback */
struct customdata {
  CURL *easy;
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

    curl_easy_perform(curl);

  }
}
~~~

# AVAILABILITY

Added in 7.86.0.

# RETURN VALUE

This function returns a pointer to a *curl_ws_frame* struct with read-only
information that is valid for this specific callback invocation. If it cannot
return this information, or if the function is called in the wrong context, it
returns NULL.







|
<
<







131
132
133
134
135
136
137
138


139
140
141
142
143
144
145

    curl_easy_perform(curl);

  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

This function returns a pointer to a *curl_ws_frame* struct with read-only
information that is valid for this specific callback invocation. If it cannot
return this information, or if the function is called in the wrong context, it
returns NULL.
Changes to jni/curl/docs/libcurl/curl_ws_recv.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_easy_getinfo (3)
  - curl_easy_perform (3)
  - curl_easy_setopt (3)
  - curl_ws_send (3)
  - libcurl-ws (3)
Protocol:
  - WS

---

# NAME

curl_ws_recv - receive WebSocket data

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_easy_getinfo (3)
  - curl_easy_perform (3)
  - curl_easy_setopt (3)
  - curl_ws_send (3)
  - libcurl-ws (3)
Protocol:
  - WS
Added-in: 7.86.0
---

# NAME

curl_ws_recv - receive WebSocket data

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
*buffer*, libcurl returns a full buffer and the application needs to call
this function again to continue draining the buffer.

The *meta* pointer gets set to point to a *const struct curl_ws_frame*
that contains information about the received data. See the
curl_ws_meta(3) for details on that struct.



# EXAMPLE

~~~c
int main(void)
{
  size_t rlen;
  const struct curl_ws_frame *meta;
  char buffer[256];
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta);
    if(res)
      printf("error: %s\n", curl_easy_strerror(res));
  }
}
~~~

# AVAILABILITY

Added in 7.86.0.

# RETURN VALUE

Returns **CURLE_OK** if everything is okay, and a non-zero number for
errors. Returns **CURLE_GOT_NOTHING** if the associated connection is
closed.

Instead of blocking, the function returns **CURLE_AGAIN**. The correct
behavior is then to wait for the socket to signal readability before calling
this function again.







>
>

















|
<
<










40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
71
72
73
74
75
76
*buffer*, libcurl returns a full buffer and the application needs to call
this function again to continue draining the buffer.

The *meta* pointer gets set to point to a *const struct curl_ws_frame*
that contains information about the received data. See the
curl_ws_meta(3) for details on that struct.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  size_t rlen;
  const struct curl_ws_frame *meta;
  char buffer[256];
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta);
    if(res)
      printf("error: %s\n", curl_easy_strerror(res));
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns **CURLE_OK** if everything is okay, and a non-zero number for
errors. Returns **CURLE_GOT_NOTHING** if the associated connection is
closed.

Instead of blocking, the function returns **CURLE_AGAIN**. The correct
behavior is then to wait for the socket to signal readability before calling
this function again.
Changes to jni/curl/docs/libcurl/curl_ws_send.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - curl_easy_getinfo (3)
  - curl_easy_perform (3)
  - curl_easy_setopt (3)
  - curl_ws_recv (3)
  - libcurl-ws (3)
Protocol:
  - WS

---

# NAME

curl_ws_send - send WebSocket data

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - curl_easy_getinfo (3)
  - curl_easy_perform (3)
  - curl_easy_setopt (3)
  - curl_ws_recv (3)
  - libcurl-ws (3)
Protocol:
  - WS
Added-in: 7.86.0
---

# NAME

curl_ws_send - send WebSocket data

# SYNOPSIS
85
86
87
88
89
90
91


92
93
94
95
96
97
98

The provided data is only a partial fragment and there is more coming in a
following call to *curl_ws_send()*. When sending only a piece of the
fragment like this, the *fragsize* must be provided with the total
expected fragment size in the first call and it needs to be zero in subsequent
calls.



# EXAMPLE

~~~c
#include <string.h> /* for strlen */

const char *send_payload = "magic";








>
>







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

The provided data is only a partial fragment and there is more coming in a
following call to *curl_ws_send()*. When sending only a piece of the
fragment like this, the *fragsize* must be provided with the total
expected fragment size in the first call and it needs to be zero in subsequent
calls.

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h> /* for strlen */

const char *send_payload = "magic";

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  res = curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0,
                     CURLWS_PING);
  curl_easy_cleanup(curl);
  return (int)res;
}
~~~

# AVAILABILITY

Added in 7.86.0.

# RETURN VALUE

*CURLE_OK* (zero) means that the data was sent properly, non-zero means an
error occurred as *\<curl/curl.h\>* defines. See the libcurl-errors(3) man
page for the full list with descriptions.







|
<
<






110
111
112
113
114
115
116
117


118
119
120
121
122
123
  res = curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0,
                     CURLWS_PING);
  curl_easy_cleanup(curl);
  return (int)res;
}
~~~

# %AVAILABILITY%



# RETURN VALUE

*CURLE_OK* (zero) means that the data was sent properly, non-zero means an
error occurred as *\<curl/curl.h\>* defines. See the libcurl-errors(3) man
page for the full list with descriptions.
Changes to jni/curl/docs/libcurl/libcurl-easy.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_init (3)
  - curl_easy_setopt (3)
  - libcurl (3)
  - libcurl-errors (3)
  - libcurl-multi (3)
Protocol:
  - All

---

# NAME

libcurl-easy - easy interface overview

# DESCRIPTION

When using libcurl's "easy" interface you init your session and get a handle
(often referred to as an "easy handle"), which you use as input to the easy
interface functions you use. Use curl_easy_init(3) to get the handle.

You continue by setting all the options you want in the upcoming transfer, the
most important among them is the URL itself (you cannot transfer anything
without a specified URL as you may have figured out yourself). You might want
to set some callbacks as well that are called from the library when data is
available etc. curl_easy_setopt(3) is used for all this.

CURLOPT_URL(3) is the only option you really must set, as otherwise
there can be no transfer. Another commonly used option is
CURLOPT_VERBOSE(3) that helps you see what libcurl is doing under the
hood, which is useful when debugging for example. The
curl_easy_setopt(3) man page has a full index of the almost 300
available options.

If you at any point would like to blank all previously set options for a
single easy handle, you can call curl_easy_reset(3) and you can also
make a clone of an easy handle (with all its set options) using
curl_easy_duphandle(3).

When all is setup, you tell libcurl to perform the transfer using
curl_easy_perform(3). It performs the entire transfer operation and does
not return until it is done (successfully or not).

After the transfer has been made, you can set new options and make another
transfer, or if you are done, cleanup the session by calling
curl_easy_cleanup(3). If you want persistent connections, you do not
cleanup immediately, but instead run ahead and perform other transfers using
the same easy handle.



|











>














|
|
|

|
|
<
|
|



|
|



|
|



|
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-easy
Section: 3
Source: libcurl
See-also:
  - curl_easy_cleanup (3)
  - curl_easy_init (3)
  - curl_easy_setopt (3)
  - libcurl (3)
  - libcurl-errors (3)
  - libcurl-multi (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

libcurl-easy - easy interface overview

# DESCRIPTION

When using libcurl's "easy" interface you init your session and get a handle
(often referred to as an "easy handle"), which you use as input to the easy
interface functions you use. Use curl_easy_init(3) to get the handle.

You continue by setting all the options you want in the upcoming transfer, the
most important among them is the URL itself (you cannot transfer anything
without a specified URL). You might want to set some callbacks as well that
are called from the library when data is available etc. For example
CURLOPT_WRITEFUNCTION(3). curl_easy_setopt(3) is used for all this.

CURLOPT_URL(3) is the only option you really must set, as otherwise there can
be no transfer. Another commonly used option is CURLOPT_VERBOSE(3) that helps

you see what libcurl is doing under the hood, which is useful when debugging
for example. The curl_easy_setopt(3) man page has a full index of the over 300
available options.

If you at any point would like to blank all previously set options for a
single easy handle, you can call curl_easy_reset(3) and you can also make a
clone of an easy handle (with all its set options) using
curl_easy_duphandle(3).

When all is setup, you tell libcurl to perform the transfer using
curl_easy_perform(3). It performs the entire transfer operation and does not
return until it is done (successfully or not).

After the transfer has been made, you can set new options and make another
transfer, or if you are done, cleanup the session by calling
curl_easy_cleanup(3). If you want persistent connections, you do not cleanup
immediately, but instead run ahead and perform other transfers using the same
easy handle.
Changes to jni/curl/docs/libcurl/libcurl-env-dbg.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-env-dbg
Section: 3
Source: libcurl
See-also:
  - libcurl-env (3)
Protocol:
  - All

---

# NAME

libcurl-env-dbg - environment variables libcurl DEBUGBUILD understands

# DESCRIPTION










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-env-dbg
Section: 3
Source: libcurl
See-also:
  - libcurl-env (3)
Protocol:
  - All
Added-in: n/a
---

# NAME

libcurl-env-dbg - environment variables libcurl DEBUGBUILD understands

# DESCRIPTION
119
120
121
122
123
124
125













OpenLDAP tracing is enabled if this variable exists and its value is 1 or
greater. There is a number of debug levels, refer to *openldap.c* comments.

## CURL_WS_CHUNK_SIZE

Used to influence the buffer chunk size used for WebSocket encoding and
decoding.




















>
>
>
>
>
>
>
>
>
>
>
>
>
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
OpenLDAP tracing is enabled if this variable exists and its value is 1 or
greater. There is a number of debug levels, refer to *openldap.c* comments.

## CURL_WS_CHUNK_SIZE

Used to influence the buffer chunk size used for WebSocket encoding and
decoding.

## CURL_FORBID_REUSE

Used to set the CURLOPT_FORBID_REUSE flag on each transfer initiated
by the curl command line tool. The value of the environment variable
does not matter.

## CURL_GRACEFUL_SHUTDOWN

Make a blocking, graceful shutdown of all remaining connections when
a multi handle is destroyed. This implicitly triggers for easy handles
that are run via easy_perform. The value of the environment variable
gives the shutdown timeout in milliseconds.
Changes to jni/curl/docs/libcurl/libcurl-env.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-env
Section: 3
Source: libcurl
See-also:
  - libcurl-env-dbg (3)
Protocol:
  - All

---

# NAME

libcurl-env - environment variables libcurl understands

# DESCRIPTION










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-env
Section: 3
Source: libcurl
See-also:
  - libcurl-env-dbg (3)
Protocol:
  - All
Added-in: n/a
---

# NAME

libcurl-env - environment variables libcurl understands

# DESCRIPTION
Changes to jni/curl/docs/libcurl/libcurl-errors.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_VERBOSE (3)
  - curl_easy_strerror (3)
  - curl_multi_strerror (3)
  - curl_share_strerror (3)
  - curl_url_strerror (3)
Protocol:
  - All

---

# NAME

libcurl-errors - error codes in libcurl

# DESCRIPTION







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_VERBOSE (3)
  - curl_easy_strerror (3)
  - curl_multi_strerror (3)
  - curl_share_strerror (3)
  - curl_url_strerror (3)
Protocol:
  - All
Added-in: n/a
---

# NAME

libcurl-errors - error codes in libcurl

# DESCRIPTION
Changes to jni/curl/docs/libcurl/libcurl-multi.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-multi
Section: 3
Source: libcurl
See-also:
  - libcurl (3)
  - libcurl-easy (3)
  - libcurl-errors (3)
Protocol:
  - All

---

# NAME

libcurl-multi - how to use the multi interface

# DESCRIPTION












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-multi
Section: 3
Source: libcurl
See-also:
  - libcurl (3)
  - libcurl-easy (3)
  - libcurl-errors (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

libcurl-multi - how to use the multi interface

# DESCRIPTION
Changes to jni/curl/docs/libcurl/libcurl-security.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-security
Section: 3
Source: libcurl
See-also:
  - libcurl-thread (3)
Protocol:
  - All

---
<!-- markdown-link-check-disable -->
# NAME

libcurl-security - security considerations when using libcurl

# Security










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-security
Section: 3
Source: libcurl
See-also:
  - libcurl-thread (3)
Protocol:
  - All
Added-in: n/a
---
<!-- markdown-link-check-disable -->
# NAME

libcurl-security - security considerations when using libcurl

# Security
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
then return data even when the server is password protected.

In the same way, if an unencrypted SSH private key has been configured for the
user running the libcurl application, SCP: or SFTP: URLs could access password
or private-key protected resources,
e.g. **sftp://user@some-internal-server/etc/passwd**

The CURLOPT_REDIR_PROTOCOLS(3) and CURLOPT_NETRC(3) options can be
used to mitigate against this kind of attack.

A redirect can also specify a location available only on the machine running
libcurl, including servers hidden behind a firewall from the attacker.
E.g. **http://127.0.0.1/** or **http://intranet/delete-stuff.cgi?delete=all** or
**tftp://bootp-server/pc-config-data**

Applications can mitigate against this by disabling
CURLOPT_FOLLOWLOCATION(3) and handling redirects itself, sanitizing URLs
as necessary. Alternately, an app could leave CURLOPT_FOLLOWLOCATION(3)
enabled but set CURLOPT_REDIR_PROTOCOLS(3) and install a
CURLOPT_OPENSOCKETFUNCTION(3) or CURLOPT_PREREQFUNCTION(3) callback
function in which addresses are sanitized before use.

# CRLF in Headers

For all options in libcurl which specify headers, including but not limited to
CURLOPT_HTTPHEADER(3), CURLOPT_PROXYHEADER(3),







|










|







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
then return data even when the server is password protected.

In the same way, if an unencrypted SSH private key has been configured for the
user running the libcurl application, SCP: or SFTP: URLs could access password
or private-key protected resources,
e.g. **sftp://user@some-internal-server/etc/passwd**

The CURLOPT_REDIR_PROTOCOLS_STR(3) and CURLOPT_NETRC(3) options can be
used to mitigate against this kind of attack.

A redirect can also specify a location available only on the machine running
libcurl, including servers hidden behind a firewall from the attacker.
E.g. **http://127.0.0.1/** or **http://intranet/delete-stuff.cgi?delete=all** or
**tftp://bootp-server/pc-config-data**

Applications can mitigate against this by disabling
CURLOPT_FOLLOWLOCATION(3) and handling redirects itself, sanitizing URLs
as necessary. Alternately, an app could leave CURLOPT_FOLLOWLOCATION(3)
enabled but set CURLOPT_REDIR_PROTOCOLS_STR(3) and install a
CURLOPT_OPENSOCKETFUNCTION(3) or CURLOPT_PREREQFUNCTION(3) callback
function in which addresses are sanitized before use.

# CRLF in Headers

For all options in libcurl which specify headers, including but not limited to
CURLOPT_HTTPHEADER(3), CURLOPT_PROXYHEADER(3),
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
checking the address before a connection.

All the malicious scenarios regarding redirected URLs apply just as well to
non-redirected URLs, if the user is allowed to specify an arbitrary URL that
could point to a private resource. For example, a web app providing a
translation service might happily translate **file://localhost/etc/passwd**
and display the result. Applications can mitigate against this with the
CURLOPT_PROTOCOLS(3) option as well as by similar mitigation techniques
for redirections.

A malicious FTP server could in response to the PASV command return an IP
address and port number for a server local to the app running libcurl but
behind a firewall. Applications can mitigate against this by using the
CURLOPT_FTP_SKIP_PASV_IP(3) option or CURLOPT_FTPPORT(3).








|







161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
checking the address before a connection.

All the malicious scenarios regarding redirected URLs apply just as well to
non-redirected URLs, if the user is allowed to specify an arbitrary URL that
could point to a private resource. For example, a web app providing a
translation service might happily translate **file://localhost/etc/passwd**
and display the result. Applications can mitigate against this with the
CURLOPT_PROTOCOLS_STR(3) option as well as by similar mitigation techniques
for redirections.

A malicious FTP server could in response to the PASV command return an IP
address and port number for a server local to the app running libcurl but
behind a firewall. Applications can mitigate against this by using the
CURLOPT_FTP_SKIP_PASV_IP(3) option or CURLOPT_FTPPORT(3).

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

Remedies:

## Use --proto

curl command lines can use *--proto* to limit what URL schemes it accepts

## Use CURLOPT_PROTOCOLS

libcurl programs can use CURLOPT_PROTOCOLS(3) to limit what URL schemes it accepts

## consider not allowing the user to set the full URL

Maybe just let the user provide data for parts of it? Or maybe filter input to
only allow specific choices?

# RFC 3986 vs WHATWG URL







|

|







305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321

Remedies:

## Use --proto

curl command lines can use *--proto* to limit what URL schemes it accepts

## Use CURLOPT_PROTOCOLS_STR

libcurl programs can use CURLOPT_PROTOCOLS_STR(3) to limit what URL schemes it accepts

## consider not allowing the user to set the full URL

Maybe just let the user provide data for parts of it? Or maybe filter input to
only allow specific choices?

# RFC 3986 vs WHATWG URL
Changes to jni/curl/docs/libcurl/libcurl-share.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_share_init (3)
  - curl_share_setopt (3)
  - libcurl-easy (3)
  - libcurl-errors (3)
  - libcurl-multi (3)
Protocol:
  - All

---

# NAME

libcurl-share - how to use the share interface

# DESCRIPTION







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_share_init (3)
  - curl_share_setopt (3)
  - libcurl-easy (3)
  - libcurl-errors (3)
  - libcurl-multi (3)
Protocol:
  - All
Added-in: n/a
---

# NAME

libcurl-share - how to use the share interface

# DESCRIPTION
Changes to jni/curl/docs/libcurl/libcurl-symbols.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  - All
See-also:
  - libcurl (3)
  - libcurl-easy (3)
  - libcurl-multi (3)
  - libcurl-security (3)
  - libcurl-thread (3)

---
# libcurl symbols

This man page details version information for public symbols provided in the
libcurl header files. This lists the first version in which the symbol was
introduced and for some symbols two additional information pieces:

The first version in which the symbol is marked "deprecated" - meaning that
since that version no new code should be written to use the symbol as it is
marked for getting removed in a future.

The last version that featured the specific symbol. Using the symbol in source
code will make it no longer compile error-free after that specified version.

This man page is automatically generated from the symbols-in-versions file.

## CURL_AT_LEAST_VERSION
Introduced in 7.43.0.

## CURL_BLOB_COPY







>












|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  - All
See-also:
  - libcurl (3)
  - libcurl-easy (3)
  - libcurl-multi (3)
  - libcurl-security (3)
  - libcurl-thread (3)
Added-in: n/a
---
# libcurl symbols

This man page details version information for public symbols provided in the
libcurl header files. This lists the first version in which the symbol was
introduced and for some symbols two additional information pieces:

The first version in which the symbol is marked "deprecated" - meaning that
since that version no new code should be written to use the symbol as it is
marked for getting removed in a future.

The last version that featured the specific symbol. Using the symbol in source
code makes it no longer compile error-free after that specified version.

This man page is automatically generated from the symbols-in-versions file.

## CURL_AT_LEAST_VERSION
Introduced in 7.43.0.

## CURL_BLOB_COPY
2580
2581
2582
2583
2584
2585
2586



2587
2588
2589
2590
2591
2592
2593

## CURLOPT_TCP_KEEPIDLE
Introduced in 7.25.0. See CURLOPT_TCP_KEEPIDLE(3).

## CURLOPT_TCP_KEEPINTVL
Introduced in 7.25.0. See CURLOPT_TCP_KEEPINTVL(3).




## CURLOPT_TCP_NODELAY
Introduced in 7.11.2. See CURLOPT_TCP_NODELAY(3).

## CURLOPT_TELNETOPTIONS
Introduced in 7.7. See CURLOPT_TELNETOPTIONS(3).

## CURLOPT_TFTP_BLKSIZE







>
>
>







2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597

## CURLOPT_TCP_KEEPIDLE
Introduced in 7.25.0. See CURLOPT_TCP_KEEPIDLE(3).

## CURLOPT_TCP_KEEPINTVL
Introduced in 7.25.0. See CURLOPT_TCP_KEEPINTVL(3).

## CURLOPT_TCP_KEEPCNT
Introduced in 8.9.0. See CURLOPT_TCP_KEEPCNT(3).

## CURLOPT_TCP_NODELAY
Introduced in 7.11.2. See CURLOPT_TCP_NODELAY(3).

## CURLOPT_TELNETOPTIONS
Introduced in 7.7. See CURLOPT_TELNETOPTIONS(3).

## CURLOPT_TFTP_BLKSIZE
3192
3193
3194
3195
3196
3197
3198



3199
3200
3201
3202
3203
3204
3205

## CURLU_NO_AUTHORITY
Introduced in 7.67.0. See curl_url_get(3).

## CURLU_NO_DEFAULT_PORT
Introduced in 7.62.0. See curl_url_get(3).




## CURLU_NON_SUPPORT_SCHEME
Introduced in 7.62.0. See curl_url_get(3).

## CURLU_PATH_AS_IS
Introduced in 7.62.0. See curl_url_get(3).

## CURLU_PUNY2IDN







>
>
>







3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212

## CURLU_NO_AUTHORITY
Introduced in 7.67.0. See curl_url_get(3).

## CURLU_NO_DEFAULT_PORT
Introduced in 7.62.0. See curl_url_get(3).

## CURLU_NO_GUESS_SCHEME
Introduced in 8.9.0. See curl_url_get(3).

## CURLU_NON_SUPPORT_SCHEME
Introduced in 7.62.0. See curl_url_get(3).

## CURLU_PATH_AS_IS
Introduced in 7.62.0. See curl_url_get(3).

## CURLU_PUNY2IDN
Changes to jni/curl/docs/libcurl/libcurl-thread.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-thread
Section: 3
Source: libcurl
See-also:
  - libcurl-security (3)
Protocol:
  - All

---

# NAME

libcurl-thread - libcurl thread safety

# Multi-threading with libcurl










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-thread
Section: 3
Source: libcurl
See-also:
  - libcurl-security (3)
Protocol:
  - All
Added-in: n/a
---

# NAME

libcurl-thread - libcurl thread safety

# Multi-threading with libcurl
Changes to jni/curl/docs/libcurl/libcurl-tutorial.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-tutorial
Section: 3
Source: libcurl
See-also:
  - libcurl-easy (3)
  - libcurl-errors (3)
  - libcurl-multi (3)
  - libcurl-url (3)
Protocol:
  - All

---

# NAME

libcurl-tutorial - libcurl programming tutorial

# Objective













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-tutorial
Section: 3
Source: libcurl
See-also:
  - libcurl-easy (3)
  - libcurl-errors (3)
  - libcurl-multi (3)
  - libcurl-url (3)
Protocol:
  - All
Added-in: n/a
---

# NAME

libcurl-tutorial - libcurl programming tutorial

# Objective
Changes to jni/curl/docs/libcurl/libcurl-url.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl
Section: 3
Source: libcurl
See-also:
  - CURLOPT_URL (3)
  - curl_url (3)
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_set (3)
  - curl_url_strerror (3)
Protocol:
  - All

---

# NAME

libcurl-url - URL interface overview

# DESCRIPTION



|












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-url
Section: 3
Source: libcurl
See-also:
  - CURLOPT_URL (3)
  - curl_url (3)
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_set (3)
  - curl_url_strerror (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

libcurl-url - URL interface overview

# DESCRIPTION
152
153
154
155
156
157
158
159
160
161
162
163
164

Now the URL looks like

~~~c
  https://example.com/?shoes=2&hat=1&candy=N%26N
~~~

# AVAILABILITY

The URL API was introduced in libcurl 7.62.0.

A URL with a literal IPv6 address can be parsed even when IPv6 support is not
enabled.







<
|
<



153
154
155
156
157
158
159

160

161
162
163

Now the URL looks like

~~~c
  https://example.com/?shoes=2&hat=1&candy=N%26N
~~~


# NOTES


A URL with a literal IPv6 address can be parsed even when IPv6 support is not
enabled.
Changes to jni/curl/docs/libcurl/libcurl-ws.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECT_ONLY (3)
  - CURLOPT_WRITEFUNCTION (3)
  - CURLOPT_WS_OPTIONS (3)
  - curl_easy_init (3)
  - curl_ws_meta (3)
  - curl_ws_recv (3)
  - curl_ws_send (3)
Protocol:
  - All

---

# NAME

libcurl-ws - WebSocket interface overview

# DESCRIPTION



|












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl-ws
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECT_ONLY (3)
  - CURLOPT_WRITEFUNCTION (3)
  - CURLOPT_WS_OPTIONS (3)
  - curl_easy_init (3)
  - curl_ws_meta (3)
  - curl_ws_recv (3)
  - curl_ws_send (3)
Protocol:
  - All
Added-in: 7.86.0
---

# NAME

libcurl-ws - WebSocket interface overview

# DESCRIPTION
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
establishes and setups the WebSocket communication and then returns control
back to the application.

Once such a setup has been successfully performed, the application can proceed
and use curl_ws_recv(3) and curl_ws_send(3) freely to exchange
WebSocket messages with the server.

# AVAILABILITY

The WebSocket API was introduced as experimental in 7.86.0 and is still
experimental today.

It is only built-in if explicitly opted in at build time. We discourage use of
the WebSocket API in production because of its experimental state. We might
change API, ABI and behavior before this "goes live".







|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
establishes and setups the WebSocket communication and then returns control
back to the application.

Once such a setup has been successfully performed, the application can proceed
and use curl_ws_recv(3) and curl_ws_send(3) freely to exchange
WebSocket messages with the server.

# EXPERIMENTAL

The WebSocket API was introduced as experimental in 7.86.0 and is still
experimental today.

It is only built-in if explicitly opted in at build time. We discourage use of
the WebSocket API in production because of its experimental state. We might
change API, ABI and behavior before this "goes live".
Changes to jni/curl/docs/libcurl/libcurl.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl
Section: 3
Source: libcurl
See-also:
  - libcurl-easy (3)
  - libcurl-multi (3)
  - libcurl-security (3)
  - libcurl-thread (3)
Protocol:
  - All

---

# NAME

libcurl - client-side URL transfers

# DESCRIPTION













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: libcurl
Section: 3
Source: libcurl
See-also:
  - libcurl-easy (3)
  - libcurl-multi (3)
  - libcurl-security (3)
  - libcurl-thread (3)
Protocol:
  - All
Added-in: n/a
---

# NAME

libcurl - client-side URL transfers

# DESCRIPTION
Changes to jni/curl/docs/libcurl/mksymbolsmanpage.pl.
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  - All
See-also:
  - libcurl (3)
  - libcurl-easy (3)
  - libcurl-multi (3)
  - libcurl-security (3)
  - libcurl-thread (3)

---
# libcurl symbols

This man page details version information for public symbols provided in the
libcurl header files. This lists the first version in which the symbol was
introduced and for some symbols two additional information pieces:

The first version in which the symbol is marked "deprecated" - meaning that
since that version no new code should be written to use the symbol as it is
marked for getting removed in a future.

The last version that featured the specific symbol. Using the symbol in source
code will make it no longer compile error-free after that specified version.

This man page is automatically generated from the symbols-in-versions file.
HEADER
    ;

sub nameref {
    my ($n)=@_;







>












|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  - All
See-also:
  - libcurl (3)
  - libcurl-easy (3)
  - libcurl-multi (3)
  - libcurl-security (3)
  - libcurl-thread (3)
Added-in: n/a
---
# libcurl symbols

This man page details version information for public symbols provided in the
libcurl header files. This lists the first version in which the symbol was
introduced and for some symbols two additional information pieces:

The first version in which the symbol is marked "deprecated" - meaning that
since that version no new code should be written to use the symbol as it is
marked for getting removed in a future.

The last version that featured the specific symbol. Using the symbol in source
code makes it no longer compile error-free after that specified version.

This man page is automatically generated from the symbols-in-versions file.
HEADER
    ;

sub nameref {
    my ($n)=@_;
Changes to jni/curl/docs/libcurl/opts/CURLINFO_ACTIVESOCKET.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_ACTIVESOCKET
Section: 3
Source: libcurl
See-also:
  - CURLINFO_LASTSOCKET (3)
  - CURLOPT_CONNECT_ONLY (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_ACTIVESOCKET - get the active socket

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_ACTIVESOCKET
Section: 3
Source: libcurl
See-also:
  - CURLINFO_LASTSOCKET (3)
  - CURLOPT_CONNECT_ONLY (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.45.0
---

# NAME

CURLINFO_ACTIVESOCKET - get the active socket

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
handle and let libcurl close the socket and cleanup other resources associated
with the handle. This option returns the active socket only after the transfer
is complete, and is typically used in combination with
CURLOPT_CONNECT_ONLY(3), which skips the transfer phase.

CURLINFO_ACTIVESOCKET(3) was added as a replacement for
CURLINFO_LASTSOCKET(3) since that one is not working on all platforms.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
handle and let libcurl close the socket and cleanup other resources associated
with the handle. This option returns the active socket only after the transfer
is complete, and is typically used in combination with
CURLOPT_CONNECT_ONLY(3), which skips the transfer phase.

CURLINFO_ACTIVESOCKET(3) was added as a replacement for
CURLINFO_LASTSOCKET(3) since that one is not working on all platforms.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    }

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.45.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




70
71
72
73
74
75
76
77


78
79
80
81
    }

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_APPCONNECT_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_APPCONNECT_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_APPCONNECT_TIME - get the time until the SSL/SSH handshake is completed

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_APPCONNECT_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_APPCONNECT_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.19.0
---

# NAME

CURLINFO_APPCONNECT_TIME - get the time until the SSL/SSH handshake is completed

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
for cases such as HTTP multiplexing where the pretransfer time can be delayed
due to waits in line for the stream and more.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
for cases such as HTTP multiplexing where the pretransfer time can be delayed
due to waits in line for the stream and more.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




59
60
61
62
63
64
65
66


67
68
69
70
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_APPCONNECT_TIME_T.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_APPCONNECT_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_APPCONNECT_TIME (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_APPCONNECT_TIME_T - time until the SSL/SSH handshake completed

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_APPCONNECT_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_APPCONNECT_TIME (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.61.0
---

# NAME

CURLINFO_APPCONNECT_TIME_T - time until the SSL/SSH handshake completed

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
time, except for cases such as HTTP multiplexing where the pretransfer time
can be delayed due to waits in line for the stream and more.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
time, except for cases such as HTTP multiplexing where the pretransfer time
can be delayed due to waits in line for the stream and more.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CAINFO.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_CAPATH (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLINFO_CAINFO - get the default built-in CA certificate path

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_CAPATH (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.84.0
---

# NAME

CURLINFO_CAINFO - get the default built-in CA certificate path

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
libraries, this option might return a string even if the specific TLS library
currently set to be used does not support CURLOPT_CAINFO(3).

This is a path identifying a single file containing CA certificates.

The **path** pointer is set to NULL if there is no default path.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    char *cainfo = NULL;
    curl_easy_getinfo(curl, CURLINFO_CAINFO, &cainfo);
    if(cainfo) {
      printf("default ca info path: %s\n", cainfo);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.84.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
libraries, this option might return a string even if the specific TLS library
currently set to be used does not support CURLOPT_CAINFO(3).

This is a path identifying a single file containing CA certificates.

The **path** pointer is set to NULL if there is no default path.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    char *cainfo = NULL;
    curl_easy_getinfo(curl, CURLINFO_CAINFO, &cainfo);
    if(cainfo) {
      printf("default ca info path: %s\n", cainfo);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CAPATH.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - wolfSSL

---

# NAME

CURLINFO_CAPATH - get the default built-in CA path string

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - wolfSSL
Added-in: 7.84.0
---

# NAME

CURLINFO_CAPATH - get the default built-in CA path string

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
libraries, this option might return a string even if the specific TLS library
currently set to be used does not support CURLOPT_CAPATH(3).

This is a path identifying a directory.

The **path** pointer is set to NULL if there is no default path.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    char *capath = NULL;
    curl_easy_getinfo(curl, CURLINFO_CAPATH, &capath);
    if(capath) {
      printf("default ca path: %s\n", capath);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.84.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
libraries, this option might return a string even if the specific TLS library
currently set to be used does not support CURLOPT_CAPATH(3).

This is a path identifying a directory.

The **path** pointer is set to NULL if there is no default path.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    char *capath = NULL;
    curl_easy_getinfo(curl, CURLINFO_CAPATH, &capath);
    if(capath) {
      printf("default ca path: %s\n", capath);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CERTINFO.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - Schannel
  - Secure Transport

---

# NAME

CURLINFO_CERTINFO - get the TLS certificate chain

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - Schannel
  - Secure Transport
Added-in: 7.19.1
---

# NAME

CURLINFO_CERTINFO - get the TLS certificate chain

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58

The *certinfo* struct member is an array of linked lists of certificate
information. The *num_of_certs* struct member is the number of certificates
which is the number of elements in the array. Each certificate's list has
items with textual information in the format "name:content" such as
"Subject:Foo", "Issuer:Bar", etc. The items in each list varies depending on
the SSL backend and the certificate.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

The *certinfo* struct member is an array of linked lists of certificate
information. The *num_of_certs* struct member is the number of certificates
which is the number of elements in the array. Each certificate's list has
items with textual information in the format "name:content" such as
"Subject:Foo", "Issuer:Bar", etc. The items in each list varies depending on
the SSL backend and the certificate.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
87
88
89
90
91
92
93
94
95
96
97
98
99
100

101
102
103
104
    curl_easy_cleanup(curl);
  }
}
~~~

See also the *certinfo.c* example.

# AVAILABILITY

This option is only working in libcurl built with OpenSSL, GnuTLS, Schannel or
Secure Transport. GnuTLS support added in 7.42.0. Schannel support added in
7.50.0. Secure Transport support added in 7.79.0.

Added in 7.19.1


# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

<
|
|

<
>




90
91
92
93
94
95
96
97
98

99
100
101

102
103
104
105
106
    curl_easy_cleanup(curl);
  }
}
~~~

See also the *certinfo.c* example.

# HISTORY


GnuTLS support added in 7.42.0. Schannel support added in 7.50.0. Secure
Transport support added in 7.79.0. mbedTLS support added in 8.9.0.


# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONDITION_UNMET.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONDITION_UNMET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TIMECONDITION (3)
  - CURLOPT_TIMEVALUE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_CONDITION_UNMET - get info on unmet time conditional or 304 HTTP response.

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONDITION_UNMET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TIMECONDITION (3)
  - CURLOPT_TIMEVALUE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.19.4
---

# NAME

CURLINFO_CONDITION_UNMET - get info on unmet time conditional or 304 HTTP response.

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
Pass a pointer to a long to receive the number 1 if the condition provided in
the previous request did not match (see CURLOPT_TIMECONDITION(3)). Alas,
if this returns a 1 you know that the reason you did not get data in return is
because it did not fulfill the condition. The long this argument points to
gets a zero stored if the condition instead was met. This can also return 1 if
the server responded with a 304 HTTP status code, for example after sending a
custom "If-Match-*" header.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Pass a pointer to a long to receive the number 1 if the condition provided in
the previous request did not match (see CURLOPT_TIMECONDITION(3)). Alas,
if this returns a 1 you know that the reason you did not get data in return is
because it did not fulfill the condition. The long this argument points to
gets a zero stored if the condition instead was met. This can also return 1 if
the server responded with a 304 HTTP status code, for example after sending a
custom "If-Match-*" header.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
65
66
67
68
69
70
71
72
73
74
75
76
77
78
        printf("The time condition was %sfulfilled\n", unmet?"NOT":"");
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.19.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




68
69
70
71
72
73
74
75


76
77
78
79
        printf("The time condition was %sfulfilled\n", unmet?"NOT":"");
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONNECT_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONNECT_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_CONNECT_TIME - get the time until connect

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONNECT_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONNECT_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_CONNECT_TIME - get the time until connect

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41

Pass a pointer to a double to receive the total time in seconds from the start
until the connection to the remote host (or proxy) was completed.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Pass a pointer to a double to receive the total time in seconds from the start
until the connection to the remote host (or proxy) was completed.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.4.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




55
56
57
58
59
60
61
62


63
64
65
66
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONNECT_TIME_T.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONNECT_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONNECT_TIME (3)
  - CURLOPT_CONNECTTIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_CONNECT_TIME_T - get the time until connect

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONNECT_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONNECT_TIME (3)
  - CURLOPT_CONNECTTIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.61.0
---

# NAME

CURLINFO_CONNECT_TIME_T - get the time until connect

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43

Pass a pointer to a curl_off_t to receive the total time in microseconds from
the start until the connection to the remote host (or proxy) was completed.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

Pass a pointer to a curl_off_t to receive the total time in microseconds from
the start until the connection to the remote host (or proxy) was completed.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONN_ID.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONN_ID
Section: 3
Source: libcurl
See-also:
  - CURLINFO_XFER_ID (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_CONN_ID - get the ID of the last connection used by the handle

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONN_ID
Section: 3
Source: libcurl
See-also:
  - CURLINFO_XFER_ID (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 8.2.0
---

# NAME

CURLINFO_CONN_ID - get the ID of the last connection used by the handle

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42

Pass a pointer to a *curl_off_t* to receive the connection identifier last
used by the handle. Stores -1 if there was no connection used.

The connection id is unique among all connections using the same
connection cache. This is implicitly the case for all connections in the
same multi handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Pass a pointer to a *curl_off_t* to receive the connection identifier last
used by the handle. Stores -1 if there was no connection used.

The connection id is unique among all connections using the same
connection cache. This is implicitly the case for all connections in the
same multi handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
        printf("Connection used: %" CURL_FORMAT_CURL_OFF_T "\n", conn_id);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 8.2.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
        printf("Connection used: %" CURL_FORMAT_CURL_OFF_T "\n", conn_id);
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_LENGTH_DOWNLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_UPLOAD (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_CONTENT_LENGTH_DOWNLOAD - get content-length of download

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_LENGTH_DOWNLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_UPLOAD (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.6.1
---

# NAME

CURLINFO_CONTENT_LENGTH_DOWNLOAD - get content-length of download

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42

Pass a pointer to a double to receive the content-length of the download. This
is the value read from the Content-Length: field. Since 7.19.4, this returns
-1 if the size is not known.

CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) is a newer replacement that returns a more
sensible variable type.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Pass a pointer to a double to receive the content-length of the download. This
is the value read from the Content-Length: field. Since 7.19.4, this returns
-1 if the size is not known.

CURLINFO_CONTENT_LENGTH_DOWNLOAD_T(3) is a newer replacement that returns a more
sensible variable type.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64


65
66
67
68
        printf("Size: %.0f\n", cl);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.6.1. Deprecated since 7.55.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
        printf("Size: %.0f\n", cl);
      }
    }
  }
}
~~~

# DEPRECATED

Deprecated since 7.55.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_DOWNLOAD_T.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_CONTENT_LENGTH_DOWNLOAD_T - get content-length of download

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,
                           curl_off_t *content_length);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the content-length of the
download. This is the value read from the Content-Length: field. Stores -1 if
the size is not known.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();












>




















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.55.0
---

# NAME

CURLINFO_CONTENT_LENGTH_DOWNLOAD_T - get content-length of download

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,
                           curl_off_t *content_length);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the content-length of the
download. This is the value read from the Content-Length: field. Stores -1 if
the size is not known.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
52
53
54
55
56
57
58
59
60
61
62
63
64
65
        printf("Download size: %" CURL_FORMAT_CURL_OFF_T "\n", cl);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.55.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




55
56
57
58
59
60
61
62


63
64
65
66
        printf("Download size: %" CURL_FORMAT_CURL_OFF_T "\n", cl);
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_LENGTH_UPLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_CONTENT_LENGTH_UPLOAD - get the specified size of the upload

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_LENGTH_UPLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.6.1
---

# NAME

CURLINFO_CONTENT_LENGTH_UPLOAD - get the specified size of the upload

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41
# DESCRIPTION

Pass a pointer to a double to receive the specified size of the upload. Since
7.19.4, this returns -1 if the size is not known.

CURLINFO_CONTENT_LENGTH_UPLOAD_T(3) is a newer replacement that returns a
more sensible variable type.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# DESCRIPTION

Pass a pointer to a double to receive the specified size of the upload. Since
7.19.4, this returns -1 if the size is not known.

CURLINFO_CONTENT_LENGTH_UPLOAD_T(3) is a newer replacement that returns a
more sensible variable type.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
54
55
56
57
58
59
60
61
62
63


64
65
66
67
        printf("Size: %.0f\n", cl);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.6.1. Deprecated since 7.55.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
        printf("Size: %.0f\n", cl);
      }
    }
  }
}
~~~

# DEPRECATED

Deprecated since 7.55.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONTENT_LENGTH_UPLOAD_T.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


32
33
34
35
36
37
38
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_LENGTH_UPLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_CONTENT_LENGTH_UPLOAD_T - get the specified size of the upload

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_UPLOAD_T,
                           curl_off_t *content_length);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the specified size of the
upload. Stores -1 if the size is not known.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();












>



















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_LENGTH_UPLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.55.0
---

# NAME

CURLINFO_CONTENT_LENGTH_UPLOAD_T - get the specified size of the upload

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_CONTENT_LENGTH_UPLOAD_T,
                           curl_off_t *content_length);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the specified size of the
upload. Stores -1 if the size is not known.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
51
52
53
54
55
56
57
58
59
60
61
62
63
64
        printf("Upload size: %" CURL_FORMAT_CURL_OFF_T "\n", cl);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.55.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




54
55
56
57
58
59
60
61


62
63
64
65
        printf("Upload size: %" CURL_FORMAT_CURL_OFF_T "\n", cl);
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_CONTENT_TYPE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_TYPE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - curl_easy_getinfo (3)
  - curl_easy_header (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_CONTENT_TYPE - get Content-Type

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_CONTENT_TYPE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - curl_easy_getinfo (3)
  - curl_easy_header (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.9.4
---

# NAME

CURLINFO_CONTENT_TYPE - get Content-Type

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
The **ct** pointer is set to NULL or pointing to private memory. You MUST
NOT free it - it gets freed when you call curl_easy_cleanup(3) on the
corresponding CURL handle.

The modern way to get this header from a response is to instead use the
curl_easy_header(3) function.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
The **ct** pointer is set to NULL or pointing to private memory. You MUST
NOT free it - it gets freed when you call curl_easy_cleanup(3) on the
corresponding CURL handle.

The modern way to get this header from a response is to instead use the
curl_easy_header(3) function.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
60
61
62
63
64
65
66
67
68
69
70
71
72
73
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.9.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




63
64
65
66
67
68
69
70


71
72
73
74
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_COOKIELIST.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_COOKIELIST
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIELIST (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_COOKIELIST - get all known cookies

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_COOKIELIST
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIELIST (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.14.1
---

# NAME

CURLINFO_COOKIELIST - get all known cookies

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
cookies curl knows (expired ones, too). Do not forget to call
curl_slist_free_all(3) on the list after it has been used. If there are no
cookies (cookies for the handle have not been enabled or simply none have been
received) the 'struct curl_slist *' is made a NULL pointer.

Since 7.43.0 cookies that were imported in the Set-Cookie format without a
domain name are not exported by this option.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
cookies curl knows (expired ones, too). Do not forget to call
curl_slist_free_all(3) on the list after it has been used. If there are no
cookies (cookies for the handle have not been enabled or simply none have been
received) the 'struct curl_slist *' is made a NULL pointer.

Since 7.43.0 cookies that were imported in the Set-Cookie format without a
domain name are not exported by this option.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
67
68
69
70
71
72
73
74
75
76
77
78
79
80
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.14.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




70
71
72
73
74
75
76
77


78
79
80
81
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_EFFECTIVE_METHOD.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_EFFECTIVE_METHOD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_EFFECTIVE_METHOD - get the last used HTTP method

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_EFFECTIVE_METHOD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.72.0
---

# NAME

CURLINFO_EFFECTIVE_METHOD - get the last used HTTP method

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
In cases when you have asked libcurl to follow redirects, the method may not be
the same method the first request would use.

The **methodp** pointer is NULL or points to private memory. You MUST NOT
free - it gets freed when you call curl_easy_cleanup(3) on the
corresponding CURL handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
In cases when you have asked libcurl to follow redirects, the method may not be
the same method the first request would use.

The **methodp** pointer is NULL or points to private memory. You MUST NOT
free - it gets freed when you call curl_easy_cleanup(3) on the
corresponding CURL handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
57
58
59
60
61
62
63
64
65
66
67
68
69
70
        printf("Redirected to method: %s\n", method);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.72.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71
        printf("Redirected to method: %s\n", method);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_EFFECTIVE_URL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FOLLOWLOCATION (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_EFFECTIVE_URL - get the last used URL

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_EFFECTIVE_URL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FOLLOWLOCATION (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.4
---

# NAME

CURLINFO_EFFECTIVE_URL - get the last used URL

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
In cases when you have asked libcurl to follow redirects, it may not be the same
value you set with CURLOPT_URL(3).

The **urlp** pointer is NULL or points to private memory. You MUST NOT free
- it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
In cases when you have asked libcurl to follow redirects, it may not be the same
value you set with CURLOPT_URL(3).

The **urlp** pointer is NULL or points to private memory. You MUST NOT free
- it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
53
54
55
56
57
58
59
60
61
62
63
64
65
66
        printf("Redirect to: %s\n", url);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




56
57
58
59
60
61
62
63


64
65
66
67
        printf("Redirect to: %s\n", url);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_FILETIME.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_FILETIME (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
  - FTP
  - SFTP

---

# NAME

CURLINFO_FILETIME - get the remote time of the retrieved document

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_FILETIME (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
  - FTP
  - SFTP
Added-in: 7.5
---

# NAME

CURLINFO_FILETIME - get the remote time of the retrieved document

# SYNOPSIS
30
31
32
33
34
35
36
37
38
39
40
41
42


43
44
45
46
47
48
49

Pass a pointer to a long to receive the remote time of the retrieved document
in number of seconds since January 1 1970 in the GMT/UTC time zone. If you get
-1, it can be because of many reasons (it might be unknown, the server might
hide it or the server does not support the command that tells document time
etc) and the time of the document is unknown.

You must tell libcurl to collect this information before the transfer is made,
by using the CURLOPT_FILETIME(3) option to curl_easy_setopt(3) or
you this unconditionally gets a -1 back.

Consider using CURLINFO_FILETIME_T(3) to be able to extract dates beyond
the year 2038 on systems using 32 bit longs (Windows).



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







|
|
<

|
|
>
>







31
32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
48
49
50
51

Pass a pointer to a long to receive the remote time of the retrieved document
in number of seconds since January 1 1970 in the GMT/UTC time zone. If you get
-1, it can be because of many reasons (it might be unknown, the server might
hide it or the server does not support the command that tells document time
etc) and the time of the document is unknown.

You must ask libcurl to collect this information before the transfer is made,
by using the CURLOPT_FILETIME(3) option or you unconditionally get a -1 back.


Consider CURLINFO_FILETIME_T(3) instead to be able to extract dates beyond the
year 2038 on systems using 32-bit longs (Windows).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.5

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




65
66
67
68
69
70
71
72


73
74
75
76
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_FILETIME_T.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

45
46
47
48
49
50
51
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_FILETIME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FILETIME (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
  - FTP
  - SFTP

---

# NAME

CURLINFO_FILETIME_T - get the remote time of the retrieved document

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FILETIME_T,
                           curl_off_t *timep);
~~~

# DESCRIPTION

Pass a pointer to a curl_off_t to receive the remote time of the retrieved
document in number of seconds since January 1 1970 in the GMT/UTC time
zone. If you get -1, it can be because of many reasons (it might be unknown,
the server might hide it or the server does not support the command that tells
document time etc) and the time of the document is unknown.

You must ask libcurl to collect this information before the transfer is made,
by using the CURLOPT_FILETIME(3) option to curl_easy_setopt(3) or
you unconditionally get a -1 back.

This option is an alternative to CURLINFO_FILETIME(3) to allow systems
with 32 bit long variables to extract dates outside of the 32bit timestamp
range.


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();



|










>


















|
|
|



|
<

|
|
|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48
49
50
51
52
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_FILETIME_T
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FILETIME (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
  - FTP
  - SFTP
Added-in: 7.59.0
---

# NAME

CURLINFO_FILETIME_T - get the remote time of the retrieved document

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FILETIME_T,
                           curl_off_t *timep);
~~~

# DESCRIPTION

Pass a pointer to a curl_off_t to receive the remote time of the retrieved
document in number of seconds since January 1 1970 in the GMT/UTC time zone.
If you get -1, it can be because of many reasons (it might be unknown, the
server might hide it or the server does not support the command that tells
document time etc) and the time of the document is unknown.

You must ask libcurl to collect this information before the transfer is made,
by using the CURLOPT_FILETIME(3) option or you unconditionally get a -1 back.


This option is an alternative to CURLINFO_FILETIME(3) to allow systems with 32
bit long variables to extract dates outside of the 32-bit timestamp range.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.59.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




66
67
68
69
70
71
72
73


74
75
76
77
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_FTP_ENTRY_PATH.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_FTP_ENTRY_PATH
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - FTP

---

# NAME

CURLINFO_FTP_ENTRY_PATH - get entry path in FTP server

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_FTP_ENTRY_PATH
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - FTP
Added-in: 7.15.4
---

# NAME

CURLINFO_FTP_ENTRY_PATH - get entry path in FTP server

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
path of the entry path. That is the initial path libcurl ended up in when
logging on to the remote FTP server. This stores a NULL as pointer if
something is wrong.

The **path** pointer is NULL or points to private memory. You MUST NOT free
- it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
path of the entry path. That is the initial path libcurl ended up in when
logging on to the remote FTP server. This stores a NULL as pointer if
something is wrong.

The **path** pointer is NULL or points to private memory. You MUST NOT free
- it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64


65
66
67
68
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.4. Works for SFTP since 7.21.4



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Works for SFTP since 7.21.4

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_HEADER_SIZE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_HEADER_SIZE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REQUEST_SIZE (3)
  - CURLINFO_SIZE_DOWNLOAD (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_HEADER_SIZE - get size of retrieved headers

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_HEADER_SIZE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REQUEST_SIZE (3)
  - CURLINFO_SIZE_DOWNLOAD (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_HEADER_SIZE - get size of retrieved headers

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41
# DESCRIPTION

Pass a pointer to a long to receive the total size of all the headers
received. Measured in number of bytes.

The total includes the size of any received headers suppressed by
CURLOPT_SUPPRESS_CONNECT_HEADERS(3).



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# DESCRIPTION

Pass a pointer to a long to receive the total size of all the headers
received. Measured in number of bytes.

The total includes the size of any received headers suppressed by
CURLOPT_SUPPRESS_CONNECT_HEADERS(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
50
51
52
53
54
55
56
57
58
59
60
61
62
63
        printf("Header size: %ld bytes\n", size);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.4.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




53
54
55
56
57
58
59
60


61
62
63
64
        printf("Header size: %ld bytes\n", size);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_HTTPAUTH_AVAIL.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_HTTPAUTH_AVAIL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PROXYAUTH_AVAIL (3)
  - CURLOPT_HTTPAUTH (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_HTTPAUTH_AVAIL - get available HTTP authentication methods

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HTTPAUTH_AVAIL, long *authp);
~~~

# DESCRIPTION

Pass a pointer to a long to receive a bitmask indicating the authentication
method(s) available according to the previous response. The meaning of the
bits is explained in the CURLOPT_HTTPAUTH(3) option for
curl_easy_setopt(3).


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();













>


















|
|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_HTTPAUTH_AVAIL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PROXYAUTH_AVAIL (3)
  - CURLOPT_HTTPAUTH (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.10.8
---

# NAME

CURLINFO_HTTPAUTH_AVAIL - get available HTTP authentication methods

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HTTPAUTH_AVAIL, long *authp);
~~~

# DESCRIPTION

Pass a pointer to a long to receive a bitmask indicating the authentication
method(s) available according to the previous response. The meaning of the
bits is explained in the CURLOPT_HTTPAUTH(3) option for curl_easy_setopt(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added RFC 2617 in 7.10.8
Added RFC 7616 in 7.57.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<
<




63
64
65
66
67
68
69
70



71
72
73
74
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_HTTP_CONNECTCODE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


32
33
34
35
36
37
38
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_HTTP_CONNECTCODE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_HTTP_CONNECTCODE - get the CONNECT response code

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HTTP_CONNECTCODE, long *p);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the last received HTTP proxy response code
to a CONNECT request. The returned value is zero if no such response code was
available.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();












>



















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_HTTP_CONNECTCODE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.10.7
---

# NAME

CURLINFO_HTTP_CONNECTCODE - get the CONNECT response code

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_HTTP_CONNECTCODE, long *p);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the last received HTTP proxy response code
to a CONNECT request. The returned value is zero if no such response code was
available.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
50
51
52
53
54
55
56
57
58
59
60
61
62
63
        printf("The CONNECT response code: %03ld\n", code);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10.7

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




53
54
55
56
57
58
59
60


61
62
63
64
        printf("The CONNECT response code: %03ld\n", code);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_HTTP_VERSION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_HTTP_VERSION
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_HTTP_VERSION - get the http version used in the connection

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_HTTP_VERSION
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.50.0
---

# NAME

CURLINFO_HTTP_VERSION - get the http version used in the connection

# SYNOPSIS
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# DESCRIPTION

Pass a pointer to a long to receive the version used in the last http
connection done using this handle. The returned value is
CURL_HTTP_VERSION_1_0, CURL_HTTP_VERSION_1_1, CURL_HTTP_VERSION_2_0,
CURL_HTTP_VERSION_3 or 0 if the version cannot be determined.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long http_version;
      curl_easy_getinfo(curl, CURLINFO_HTTP_VERSION, &http_version);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.50.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
# DESCRIPTION

Pass a pointer to a long to receive the version used in the last http
connection done using this handle. The returned value is
CURL_HTTP_VERSION_1_0, CURL_HTTP_VERSION_1_1, CURL_HTTP_VERSION_2_0,
CURL_HTTP_VERSION_3 or 0 if the version cannot be determined.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long http_version;
      curl_easy_getinfo(curl, CURLINFO_HTTP_VERSION, &http_version);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_LASTSOCKET.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_LASTSOCKET
Section: 3
Source: libcurl
See-also:
  - CURLINFO_ACTIVESOCKET (3)
  - CURLOPT_CONNECT_ONLY (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_LASTSOCKET - get the last socket used

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_LASTSOCKET
Section: 3
Source: libcurl
See-also:
  - CURLINFO_ACTIVESOCKET (3)
  - CURLOPT_CONNECT_ONLY (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.15.2
---

# NAME

CURLINFO_LASTSOCKET - get the last socket used

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
let libcurl close the socket and cleanup other resources associated with the
handle. This is typically used in combination with
CURLOPT_CONNECT_ONLY(3).

NOTE: this API is deprecated since it is not working on win64 where the SOCKET
type is 64 bits large while its 'long' is 32 bits. Use the
CURLINFO_ACTIVESOCKET(3) instead, if possible.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
let libcurl close the socket and cleanup other resources associated with the
handle. This is typically used in combination with
CURLOPT_CONNECT_ONLY(3).

NOTE: this API is deprecated since it is not working on win64 where the SOCKET
type is 64 bits large while its 'long' is 32 bits. Use the
CURLINFO_ACTIVESOCKET(3) instead, if possible.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    }

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.2

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




70
71
72
73
74
75
76
77


78
79
80
81
    }

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_LOCAL_IP.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_LOCAL_IP
Section: 3
Source: libcurl
See-also:
  - CURLINFO_LOCAL_PORT (3)
  - CURLINFO_PRIMARY_IP (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_LOCAL_IP - get local IP address of last connection

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_LOCAL_IP
Section: 3
Source: libcurl
See-also:
  - CURLINFO_LOCAL_PORT (3)
  - CURLINFO_PRIMARY_IP (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.21.0
---

# NAME

CURLINFO_LOCAL_IP - get local IP address of last connection

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
enabled. Note that you get a pointer to a memory area that is reused at next
request so you need to copy the string if you want to keep the information.

The **ip** pointer is NULL or points to private memory. You MUST NOT free -
it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.



# EXAMPLE

~~~c
int main(void)
{
  char *ip;
  CURLcode res;







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
enabled. Note that you get a pointer to a memory area that is reused at next
request so you need to copy the string if you want to keep the information.

The **ip** pointer is NULL or points to private memory. You MUST NOT free -
it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  char *ip;
  CURLcode res;
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  }

  /* always cleanup */
  curl_easy_cleanup(curl);
}
~~~

# AVAILABILITY

Added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71
  }

  /* always cleanup */
  curl_easy_cleanup(curl);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_LOCAL_PORT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


32
33
34
35
36
37
38
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_LOCAL_PORT
Section: 3
Source: libcurl
Protocol:
  - TCP
See-also:
  - CURLINFO_LOCAL_IP (3)
  - CURLINFO_PRIMARY_PORT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)

---

# NAME

CURLINFO_LOCAL_PORT - get the latest local port number

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_LOCAL_PORT, long *portp);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the local port number of the most recent
connection done with this **curl** handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl;













>


















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_LOCAL_PORT
Section: 3
Source: libcurl
Protocol:
  - TCP
See-also:
  - CURLINFO_LOCAL_IP (3)
  - CURLINFO_PRIMARY_PORT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Added-in: 7.21.0
---

# NAME

CURLINFO_LOCAL_PORT - get the latest local port number

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_LOCAL_PORT, long *portp);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the local port number of the most recent
connection done with this **curl** handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    }
    curl_easy_cleanup(curl);
  }
  return 0;
}
~~~

# AVAILABILITY

Added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




56
57
58
59
60
61
62
63


64
65
66
67
    }
    curl_easy_cleanup(curl);
  }
  return 0;
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_NAMELOOKUP_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_NAMELOOKUP_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_NAMELOOKUP_TIME - get the name lookup time

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_NAMELOOKUP_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_NAMELOOKUP_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_NAMELOOKUP_TIME - get the name lookup time

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42

Pass a pointer to a double to receive the total time in seconds from the start
until the name resolving was completed.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Pass a pointer to a double to receive the total time in seconds from the start
until the name resolving was completed.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
53
54
55
56
57
58
59
60
61
62
63
64
65
66
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.4.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




56
57
58
59
60
61
62
63


64
65
66
67
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_NAMELOOKUP_TIME_T.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_NAMELOOKUP_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_NAMELOOKUP_TIME (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_NAMELOOKUP_TIME_T - get the name lookup time in microseconds

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_NAMELOOKUP_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_NAMELOOKUP_TIME (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.61.0
---

# NAME

CURLINFO_NAMELOOKUP_TIME_T - get the name lookup time in microseconds

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42

Pass a pointer to a curl_off_t to receive the total time in microseconds
from the start until the name resolving was completed.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Pass a pointer to a curl_off_t to receive the total time in microseconds
from the start until the name resolving was completed.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




57
58
59
60
61
62
63
64


65
66
67
68
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_NUM_CONNECTS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_NUM_CONNECTS
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_NUM_CONNECTS - get number of created connections

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_NUM_CONNECTS
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.12.3
---

# NAME

CURLINFO_NUM_CONNECTS - get number of created connections

# SYNOPSIS
27
28
29
30
31
32
33


34
35
36
37
38
39
40

Pass a pointer to a long to receive how many new connections libcurl had to
create to achieve the previous transfer (only the successful connects are
counted). Combined with CURLINFO_REDIRECT_COUNT(3) you are able to know how
many times libcurl successfully reused existing connection(s) or not. See the
connection options of curl_easy_setopt(3) to see how libcurl tries to make
persistent connections to save time.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

Pass a pointer to a long to receive how many new connections libcurl had to
create to achieve the previous transfer (only the successful connects are
counted). Combined with CURLINFO_REDIRECT_COUNT(3) you are able to know how
many times libcurl successfully reused existing connection(s) or not. See the
connection options of curl_easy_setopt(3) to see how libcurl tries to make
persistent connections to save time.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
50
51
52
53
54
55
56
57
58
59
60
61
62
63
        printf("It needed %ld connects\n", connects);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.12.3

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




53
54
55
56
57
58
59
60


61
62
63
64
        printf("It needed %ld connects\n", connects);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_OS_ERRNO.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_OS_ERRNO
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_OS_ERRNO - get errno number from last connect failure

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_OS_ERRNO
Section: 3
Source: libcurl
See-also:
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.12.2
---

# NAME

CURLINFO_OS_ERRNO - get errno number from last connect failure

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
CURLE_COULDNT_CONNECT, CURLE_FAILED_INIT, CURLE_INTERFACE_FAILED,
CURLE_OPERATION_TIMEDOUT, CURLE_RECV_ERROR, CURLE_SEND_ERROR.

Since 8.8.0 libcurl clears the easy handle's saved errno before performing the
transfer. Prior versions did not clear the saved errno, which means if a saved
errno is retrieved it could be from a previous transfer on the same handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
CURLE_COULDNT_CONNECT, CURLE_FAILED_INIT, CURLE_INTERFACE_FAILED,
CURLE_OPERATION_TIMEDOUT, CURLE_RECV_ERROR, CURLE_SEND_ERROR.

Since 8.8.0 libcurl clears the easy handle's saved errno before performing the
transfer. Prior versions did not clear the saved errno, which means if a saved
errno is retrieved it could be from a previous transfer on the same handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
55
56
57
58
59
60
61
62
63
64
65
66
67
68
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.12.2

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PRETRANSFER_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONNECT_TIME_T (3)
  - CURLINFO_PRETRANSFER_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_PRETRANSFER_TIME - get the time until the file transfer start

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PRETRANSFER_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONNECT_TIME_T (3)
  - CURLINFO_PRETRANSFER_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_PRETRANSFER_TIME - get the time until the file transfer start

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
specific to the particular protocol(s) involved. It includes the sending of
the protocol-specific instructions that trigger a transfer.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
specific to the particular protocol(s) involved. It includes the sending of
the protocol-specific instructions that trigger a transfer.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.4.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




61
62
63
64
65
66
67
68


69
70
71
72
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PRETRANSFER_TIME_T.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PRETRANSFER_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONNECT_TIME (3)
  - CURLINFO_PRETRANSFER_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_PRETRANSFER_TIME_T - get the time until the file transfer start

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PRETRANSFER_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONNECT_TIME (3)
  - CURLINFO_PRETRANSFER_TIME_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.61.0
---

# NAME

CURLINFO_PRETRANSFER_TIME_T - get the time until the file transfer start

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
specific to the particular protocol(s) involved. It includes the sending of
the protocol-specific instructions that trigger a transfer.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
specific to the particular protocol(s) involved. It includes the sending of
the protocol-specific instructions that trigger a transfer.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




63
64
65
66
67
68
69
70


71
72
73
74
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PRIMARY_IP.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_LOCAL_IP (3)
  - CURLINFO_LOCAL_PORT (3)
  - CURLINFO_PRIMARY_PORT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_PRIMARY_IP - get IP address of last connection

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_LOCAL_IP (3)
  - CURLINFO_LOCAL_PORT (3)
  - CURLINFO_PRIMARY_PORT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.19.0
---

# NAME

CURLINFO_PRIMARY_IP - get IP address of last connection

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
get a pointer to a memory area that is reused at next request so you need to
copy the string if you want to keep the information.

The **ip** pointer is NULL or points to private memory. You MUST NOT free -
it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.



# EXAMPLE

~~~c
int main(void)
{
  char *ip;
  CURLcode res;







>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
get a pointer to a memory area that is reused at next request so you need to
copy the string if you want to keep the information.

The **ip** pointer is NULL or points to private memory. You MUST NOT free -
it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  char *ip;
  CURLcode res;
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  }

  /* always cleanup */
  curl_easy_cleanup(curl);
}
~~~

# AVAILABILITY

Added in 7.19.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




61
62
63
64
65
66
67
68


69
70
71
72
  }

  /* always cleanup */
  curl_easy_cleanup(curl);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PRIMARY_PORT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PRIMARY_PORT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_LOCAL_PORT (3)
  - CURLINFO_PRIMARY_IP (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_PRIMARY_PORT - get the latest destination port number

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PRIMARY_PORT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_LOCAL_PORT (3)
  - CURLINFO_PRIMARY_IP (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.21.0
---

# NAME

CURLINFO_PRIMARY_PORT - get the latest destination port number

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
connection done with this **curl** handle.

This is the destination port of the actual TCP or UDP connection libcurl used.
If a proxy was used for the most recent transfer, this is the port number of
the proxy, if no proxy was used it is the port number of the most recently
accessed URL.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
connection done with this **curl** handle.

This is the destination port of the actual TCP or UDP connection libcurl used.
If a proxy was used for the most recent transfer, this is the port number of
the proxy, if no proxy was used it is the port number of the most recently
accessed URL.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
52
53
54
55
56
57
58
59
60
61
62
63
64
65
        printf("Connected to remote port: %ld\n", port);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




55
56
57
58
59
60
61
62


63
64
65
66
        printf("Connected to remote port: %ld\n", port);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PRIVATE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PRIVATE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PRIVATE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_PRIVATE - get the private pointer

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRIVATE, char **private);
~~~

# DESCRIPTION

Pass a pointer to a char pointer to receive the pointer to the private data
associated with the curl handle (set with the CURLOPT_PRIVATE(3)).
Please note that for internal reasons, the value is returned as a char
pointer, although effectively being a 'void *'.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();












>




















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PRIVATE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PRIVATE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.10.3
---

# NAME

CURLINFO_PRIVATE - get the private pointer

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PRIVATE, char **private);
~~~

# DESCRIPTION

Pass a pointer to a char pointer to receive the pointer to the private data
associated with the curl handle (set with the CURLOPT_PRIVATE(3)).
Please note that for internal reasons, the value is returned as a char
pointer, although effectively being a 'void *'.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
53
54
55
56
57
58
59
60
61
62
63
64
65
66
      printf("error: %s\n", curl_easy_strerror(res));

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10.3

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




56
57
58
59
60
61
62
63


64
65
66
67
      printf("error: %s\n", curl_easy_strerror(res));

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PROTOCOL.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PROTOCOL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_PROTOCOL - get the protocol used in the connection

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PROTOCOL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.52.0
---

# NAME

CURLINFO_PROTOCOL - get the protocol used in the connection

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71
CURLPROTO_IMAPS, CURLPROTO_LDAP, CURLPROTO_LDAPS, CURLPROTO_POP3,
CURLPROTO_POP3S, CURLPROTO_RTMP, CURLPROTO_RTMPE, CURLPROTO_RTMPS,
CURLPROTO_RTMPT, CURLPROTO_RTMPTE, CURLPROTO_RTMPTS, CURLPROTO_RTSP,
CURLPROTO_SCP, CURLPROTO_SFTP, CURLPROTO_SMB, CURLPROTO_SMBS, CURLPROTO_SMTP,
CURLPROTO_SMTPS, CURLPROTO_TELNET, CURLPROTO_TFTP, CURLPROTO_MQTT
~~~



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long protocol;
      curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0. Deprecated since 7.85.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|

|
>
>




40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
CURLPROTO_IMAPS, CURLPROTO_LDAP, CURLPROTO_LDAPS, CURLPROTO_POP3,
CURLPROTO_POP3S, CURLPROTO_RTMP, CURLPROTO_RTMPE, CURLPROTO_RTMPS,
CURLPROTO_RTMPT, CURLPROTO_RTMPTE, CURLPROTO_RTMPTS, CURLPROTO_RTSP,
CURLPROTO_SCP, CURLPROTO_SFTP, CURLPROTO_SMB, CURLPROTO_SMBS, CURLPROTO_SMTP,
CURLPROTO_SMTPS, CURLPROTO_TELNET, CURLPROTO_TFTP, CURLPROTO_MQTT
~~~

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long protocol;
      curl_easy_getinfo(curl, CURLINFO_PROTOCOL, &protocol);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# DEPRECATED

Deprecated since 7.85.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PROXYAUTH_AVAIL.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PROXYAUTH_AVAIL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_HTTPAUTH_AVAIL (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_PROXYAUTH_AVAIL - get available HTTP proxy authentication methods

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROXYAUTH_AVAIL,
                           long *authp);
~~~

# DESCRIPTION

Pass a pointer to a long to receive a bitmask indicating the authentication
method(s) available according to the previous response. The meaning of the
bits is explained in the CURLOPT_PROXYAUTH(3) option for
curl_easy_setopt(3).


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();












>



















|
|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PROXYAUTH_AVAIL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_HTTPAUTH_AVAIL (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.10.8
---

# NAME

CURLINFO_PROXYAUTH_AVAIL - get available HTTP proxy authentication methods

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PROXYAUTH_AVAIL,
                           long *authp);
~~~

# DESCRIPTION

Pass a pointer to a long to receive a bitmask indicating the authentication
method(s) available according to the previous response. The meaning of the
bits is explained in the CURLOPT_PROXYAUTH(3) option for curl_easy_setopt(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added RFC 2617 in 7.10.8
Added RFC 7616 in 7.57.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<
<




64
65
66
67
68
69
70
71



72
73
74
75
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PROXY_ERROR.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PROXY_ERROR
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
  - libcurl-errors (3)
Protocol:
  - All

---

# NAME

CURLINFO_PROXY_ERROR - get the detailed (SOCKS) proxy error

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PROXY_ERROR
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
  - libcurl-errors (3)
Protocol:
  - All
Added-in: 7.73.0
---

# NAME

CURLINFO_PROXY_ERROR - get the detailed (SOCKS) proxy error

# SYNOPSIS
67
68
69
70
71
72
73


74
75
76
77
78
79
80

Pass a pointer to a long to receive a detailed error code when the most recent
transfer returned a **CURLE_PROXY** error. That error code matches the
**CURLproxycode** set.

The error code is zero (**CURLPX_OK**) if no response code was available.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

Pass a pointer to a long to receive a detailed error code when the most recent
transfer returned a **CURLE_PROXY** error. That error code matches the
**CURLproxycode** set.

The error code is zero (**CURLPX_OK**) if no response code was available.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
90
91
92
93
94
95
96
97
98
99
100
101
102
103
        printf("The detailed proxy error: %ld\n", proxycode);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.73.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




93
94
95
96
97
98
99
100


101
102
103
104
        printf("The detailed proxy error: %ld\n", proxycode);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_PROXY_SSL_VERIFYRESULT.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLINFO_PROXY_SSL_VERIFYRESULT - get the result of the proxy certificate verification

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.52.0
---

# NAME

CURLINFO_PROXY_SSL_VERIFYRESULT - get the result of the proxy certificate verification

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
# DESCRIPTION

Pass a pointer to a long to receive the result of the certificate verification
that was requested (using the CURLOPT_PROXY_SSL_VERIFYPEER(3)
option. This is only used for HTTPS proxies.

0 is a positive result. Non-zero is an error.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# DESCRIPTION

Pass a pointer to a long to receive the result of the certificate verification
that was requested (using the CURLOPT_PROXY_SSL_VERIFYPEER(3)
option. This is only used for HTTPS proxies.

0 is a positive result. Non-zero is an error.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
63
64
65
66
67
68
69
70
71
72
73
74
75
76
             (verifyresult ? "bad" : "fine"));
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




66
67
68
69
70
71
72
73


74
75
76
77
             (verifyresult ? "bad" : "fine"));
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_QUEUE_TIME_T.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_QUEUE_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_STARTTRANSFER_TIME_T (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_QUEUE_TIME_T - time this transfer was queued

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_QUEUE_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_STARTTRANSFER_TIME_T (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 8.6.0
---

# NAME

CURLINFO_QUEUE_TIME_T - time this transfer was queued

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43

Pass a pointer to a curl_off_t to receive the time, in microseconds, this
transfer was held in a waiting queue before it started "for real". A transfer
might be put in a queue if after getting started, it cannot create a new
connection etc due to set conditions and limits imposed by the application.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

Pass a pointer to a curl_off_t to receive the time, in microseconds, this
transfer was held in a waiting queue before it started "for real". A transfer
might be put in a queue if after getting started, it cannot create a new
connection etc due to set conditions and limits imposed by the application.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 8.6.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_REDIRECT_COUNT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_REDIRECT_COUNT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_URL (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_REDIRECT_COUNT - get the number of redirects

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_COUNT,
                           long *countp);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the total number of redirections that were
actually followed.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();













>



















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_REDIRECT_COUNT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_URL (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.9.7
---

# NAME

CURLINFO_REDIRECT_COUNT - get the number of redirects

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_COUNT,
                           long *countp);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the total number of redirections that were
actually followed.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
47
48
49
50
51
52
53
54
55
56
57
58
59
60
      curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redirects);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.9.7

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




50
51
52
53
54
55
56
57


58
59
60
61
      curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redirects);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_TIME_T (3)
  - CURLINFO_REDIRECT_URL (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_REDIRECT_TIME - get the time for all redirection steps

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_TIME_T (3)
  - CURLINFO_REDIRECT_URL (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.9.7
---

# NAME

CURLINFO_REDIRECT_TIME - get the time for all redirection steps

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44

Pass a pointer to a double to receive the total time, in seconds, it took for
all redirection steps include name lookup, connect, pretransfer and transfer
before final transaction was started. CURLINFO_REDIRECT_TIME(3) contains
the complete execution time for multiple redirections.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

Pass a pointer to a double to receive the total time, in seconds, it took for
all redirection steps include name lookup, connect, pretransfer and transfer
before final transaction was started. CURLINFO_REDIRECT_TIME(3) contains
the complete execution time for multiple redirections.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.9.7

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_REDIRECT_TIME_T.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_TIME (3)
  - CURLINFO_REDIRECT_URL (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_REDIRECT_TIME_T - get the time for all redirection steps

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_TIME (3)
  - CURLINFO_REDIRECT_URL (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.61.0
---

# NAME

CURLINFO_REDIRECT_TIME_T - get the time for all redirection steps

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
Pass a pointer to a curl_off_t to receive the total time, in microseconds, it
took for all redirection steps include name lookup, connect, pretransfer and
transfer before final transaction was started.
CURLINFO_REDIRECT_TIME_T(3) holds the complete execution time for
multiple redirections.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Pass a pointer to a curl_off_t to receive the total time, in microseconds, it
took for all redirection steps include name lookup, connect, pretransfer and
transfer before final transaction was started.
CURLINFO_REDIRECT_TIME_T(3) holds the complete execution time for
multiple redirections.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_REDIRECT_URL.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38


39
40
41
42
43
44
45
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_TIME_T (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_REDIRECT_URL - get the URL a redirect would go to

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_URL, char **urlp);
~~~

# DESCRIPTION

Pass a pointer to a char pointer to receive the URL a redirect *would*
take you to if you would enable CURLOPT_FOLLOWLOCATION(3). This can come
handy if you think using the built-in libcurl redirect logic is not good enough
for you but you would still prefer to avoid implementing all the magic of
figuring out the new URL.

This URL is also set if the CURLOPT_MAXREDIRS(3) limit prevented a
redirect to happen (since 7.54.1).



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
















|
|
|
|
|

|
|
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_TIME_T (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.18.2
---

# NAME

CURLINFO_REDIRECT_URL - get the URL a redirect would go to

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REDIRECT_URL, char **urlp);
~~~

# DESCRIPTION

Pass a pointer to a char pointer to receive the URL a redirect *would* take
you to if you would enable CURLOPT_FOLLOWLOCATION(3). This can come handy if
you think using the built-in libcurl redirect logic is not good enough for you
but you would still prefer to avoid implementing all the magic of figuring out
the new URL.

This URL is also set if the CURLOPT_MAXREDIRS(3) limit prevented a redirect to
happen (since 7.54.1).

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
54
55
56
57
58
59
60
61
62
63
64
65
66
67
        printf("Redirect to: %s\n", url);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.18.2

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




57
58
59
60
61
62
63
64


65
66
67
68
        printf("Redirect to: %s\n", url);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_REFERER.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_REFERER
Section: 3
Source: libcurl
See-also:
  - CURLOPT_REFERER (3)
  - curl_easy_getinfo (3)
  - curl_easy_header (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP

---

# NAME

CURLINFO_REFERER - get the used referrer request header

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_REFERER
Section: 3
Source: libcurl
See-also:
  - CURLOPT_REFERER (3)
  - curl_easy_getinfo (3)
  - curl_easy_header (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
Added-in: 7.76.0
---

# NAME

CURLINFO_REFERER - get the used referrer request header

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42

Pass in a pointer to a char pointer and get the referrer header used in the
most recent request.

The **hdrp** pointer is NULL or points to private memory you MUST NOT free -
it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Pass in a pointer to a char pointer and get the referrer header used in the
most recent request.

The **hdrp** pointer is NULL or points to private memory you MUST NOT free -
it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
52
53
54
55
56
57
58
59
60
61
62
63
64
65
        printf("Referrer header: %s\n", hdr);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.76.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




55
56
57
58
59
60
61
62


63
64
65
66
        printf("Referrer header: %s\n", hdr);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_REQUEST_SIZE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_REQUEST_SIZE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_HEADER_SIZE (3)
  - CURLINFO_SIZE_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_REQUEST_SIZE - get size of sent request

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REQUEST_SIZE, long *sizep);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the total size of the issued
requests. This is so far only for HTTP requests. Note that this may be more
than one request if CURLOPT_FOLLOWLOCATION(3) is enabled.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();













>



















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_REQUEST_SIZE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_HEADER_SIZE (3)
  - CURLINFO_SIZE_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_REQUEST_SIZE - get size of sent request

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_REQUEST_SIZE, long *sizep);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the total size of the issued
requests. This is so far only for HTTP requests. Note that this may be more
than one request if CURLOPT_FOLLOWLOCATION(3) is enabled.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
48
49
50
51
52
53
54
55
56
57
58
59
60
61
        printf("Request size: %ld bytes\n", req);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.4.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




51
52
53
54
55
56
57
58


59
60
61
62
        printf("Request size: %ld bytes\n", req);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
  - FTP
  - SMTP
  - LDAP

---

# NAME

CURLINFO_RESPONSE_CODE - get the last response code

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - HTTP
  - FTP
  - SMTP
  - LDAP
Added-in: 7.10.8
---

# NAME

CURLINFO_RESPONSE_CODE - get the last response code

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62


63
64
65
66
(OpenLDAP only) response code. This option was previously known as
CURLINFO_HTTP_CODE in libcurl 7.10.7 and earlier. The stored value is zero if
no server response code has been received.

Note that a proxy's CONNECT response should be read with
CURLINFO_HTTP_CONNECTCODE(3) and not this.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long response_code;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10.8. CURLINFO_HTTP_CODE was added in 7.4.1.
Support for SMTP responses added in 7.25.0, for OpenLDAP in 7.81.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|

|
|
>
>




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
(OpenLDAP only) response code. This option was previously known as
CURLINFO_HTTP_CODE in libcurl 7.10.7 and earlier. The stored value is zero if
no server response code has been received.

Note that a proxy's CONNECT response should be read with
CURLINFO_HTTP_CONNECTCODE(3) and not this.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long response_code;
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# NOTES

The former name, CURLINFO_HTTP_CODE, was added in 7.4.1. Support for SMTP
responses added in 7.25.0, for OpenLDAP in 7.81.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_RETRY_AFTER.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RETRY_AFTER
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - CURLOPT_STDERR (3)
  - curl_easy_header (3)
Protocol:
  - All

---

# NAME

CURLINFO_RETRY_AFTER - returns the Retry-After retry delay

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RETRY_AFTER
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - CURLOPT_STDERR (3)
  - curl_easy_header (3)
Protocol:
  - All
Added-in: 7.66.0
---

# NAME

CURLINFO_RETRY_AFTER - returns the Retry-After retry delay

# SYNOPSIS
33
34
35
36
37
38
39
40


41
42
43
44
45
46
47

While the HTTP header might contain a fixed date string, the
CURLINFO_RETRY_AFTER(3) always returns the number of seconds to wait -
or zero if there was no header or the header could not be parsed.

# DEFAULT

Returns zero delay if there was no header.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







|
>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

While the HTTP header might contain a fixed date string, the
CURLINFO_RETRY_AFTER(3) always returns the number of seconds to wait -
or zero if there was no header or the header could not be parsed.

# DEFAULT

Zero if there was no header.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
56
57
58
59
60
61
62
63
64
65
66
67
68
69
        printf("Wait for %" CURL_FORMAT_CURL_OFF_T " seconds\n", wait);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.66.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




59
60
61
62
63
64
65
66


67
68
69
70
        printf("Wait for %" CURL_FORMAT_CURL_OFF_T " seconds\n", wait);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_RTSP_CLIENT_CSEQ.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RTSP_CLIENT_CSEQ
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_CSEQ_RECV (3)
  - CURLINFO_RTSP_SERVER_CSEQ (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - RTSP

---

# NAME

CURLINFO_RTSP_CLIENT_CSEQ - get the next RTSP client CSeq

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RTSP_CLIENT_CSEQ,
                           long *cseq);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the next CSeq that is expected to be used
by the application.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long cseq;
      curl_easy_getinfo(curl, CURLINFO_RTSP_CLIENT_CSEQ, &cseq);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.













>



















>
>




















|
<
<




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RTSP_CLIENT_CSEQ
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_CSEQ_RECV (3)
  - CURLINFO_RTSP_SERVER_CSEQ (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLINFO_RTSP_CLIENT_CSEQ - get the next RTSP client CSeq

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RTSP_CLIENT_CSEQ,
                           long *cseq);
~~~

# DESCRIPTION

Pass a pointer to a long to receive the next CSeq that is expected to be used
by the application.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long cseq;
      curl_easy_getinfo(curl, CURLINFO_RTSP_CLIENT_CSEQ, &cseq);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_RTSP_CSEQ_RECV.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RTSP_CSEQ_RECV
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_SERVER_CSEQ (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - RTSP

---

# NAME

CURLINFO_RTSP_CSEQ_RECV - get the recently received CSeq

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RTSP_CSEQ_RECV
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_SERVER_CSEQ (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLINFO_RTSP_CSEQ_RECV - get the recently received CSeq

# SYNOPSIS
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# DESCRIPTION

Pass a pointer to a long to receive the most recently received CSeq from the
server. If your application encounters a *CURLE_RTSP_CSEQ_ERROR* then you
may wish to troubleshoot and/or fix the CSeq mismatch by peeking at this
value.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long cseq;
      curl_easy_getinfo(curl, CURLINFO_RTSP_CSEQ_RECV, &cseq);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
# DESCRIPTION

Pass a pointer to a long to receive the most recently received CSeq from the
server. If your application encounters a *CURLE_RTSP_CSEQ_ERROR* then you
may wish to troubleshoot and/or fix the CSeq mismatch by peeking at this
value.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long cseq;
      curl_easy_getinfo(curl, CURLINFO_RTSP_CSEQ_RECV, &cseq);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_RTSP_SERVER_CSEQ.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RTSP_SERVER_CSEQ
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_CSEQ_RECV (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - RTSP

---

# NAME

CURLINFO_RTSP_SERVER_CSEQ - get the next RTSP server CSeq

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RTSP_SERVER_CSEQ
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_CSEQ_RECV (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLINFO_RTSP_SERVER_CSEQ - get the next RTSP server CSeq

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
by the application.

Listening for server initiated requests is not implemented!

Applications wishing to resume an RTSP session on another connection should
retrieve this info before closing the active connection.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long cseq;
      curl_easy_getinfo(curl, CURLINFO_RTSP_SERVER_CSEQ, &cseq);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
by the application.

Listening for server initiated requests is not implemented!

Applications wishing to resume an RTSP session on another connection should
retrieve this info before closing the active connection.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      long cseq;
      curl_easy_getinfo(curl, CURLINFO_RTSP_SERVER_CSEQ, &cseq);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_RTSP_SESSION_ID.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RTSP_SESSION_ID
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_CSEQ_RECV (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - RTSP

---

# NAME

CURLINFO_RTSP_SESSION_ID - get RTSP session ID

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_RTSP_SESSION_ID
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_CSEQ_RECV (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLINFO_RTSP_SESSION_ID - get RTSP session ID

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
Applications wishing to resume an RTSP session on another connection should
retrieve this info before closing the active connection.

The **id** pointer is NULL or points to private memory. You MUST NOT free -
it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      char *id;
      curl_easy_getinfo(curl, CURLINFO_RTSP_SESSION_ID, &id);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
Applications wishing to resume an RTSP session on another connection should
retrieve this info before closing the active connection.

The **id** pointer is NULL or points to private memory. You MUST NOT free -
it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://rtsp.example.com");
    res = curl_easy_perform(curl);
    if(res == CURLE_OK) {
      char *id;
      curl_easy_getinfo(curl, CURLINFO_RTSP_SESSION_ID, &id);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SCHEME.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_EFFECTIVE_URL (3)
  - CURLINFO_PROTOCOL (3)
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SCHEME - get the URL scheme (sometimes called protocol) used in the connection

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_EFFECTIVE_URL (3)
  - CURLINFO_PROTOCOL (3)
  - CURLINFO_RESPONSE_CODE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.52.0
---

# NAME

CURLINFO_SCHEME - get the URL scheme (sometimes called protocol) used in the connection

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
The **scheme** pointer is NULL or points to private memory. You MUST NOT
free - it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.

The returned scheme might be upper or lowercase. Do comparisons case
insensitively.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
The **scheme** pointer is NULL or points to private memory. You MUST NOT
free - it gets freed when you call curl_easy_cleanup(3) on the corresponding
CURL handle.

The returned scheme might be upper or lowercase. Do comparisons case
insensitively.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
56
57
58
59
60
61
62
63
64
65
66
67
68
69
        printf("scheme: %s\n", scheme); /* scheme: HTTP */
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




59
60
61
62
63
64
65
66


67
68
69
70
        printf("scheme: %s\n", scheme); /* scheme: HTTP */
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_SIZE_DOWNLOAD_T (3)
  - CURLINFO_SIZE_UPLOAD_T (3)
  - CURLOPT_MAXFILESIZE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SIZE_DOWNLOAD - get the number of downloaded bytes

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_SIZE_DOWNLOAD_T (3)
  - CURLINFO_SIZE_UPLOAD_T (3)
  - CURLOPT_MAXFILESIZE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_SIZE_DOWNLOAD - get the number of downloaded bytes

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
downloaded. The amount is only for the latest transfer and gets reset again
for each new transfer. This counts actual payload data, what's also commonly
called body. All meta and header data is excluded and not included in this
number.

CURLINFO_SIZE_DOWNLOAD_T(3) is a newer replacement that returns a more
sensible variable type.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
downloaded. The amount is only for the latest transfer and gets reset again
for each new transfer. This counts actual payload data, what's also commonly
called body. All meta and header data is excluded and not included in this
number.

CURLINFO_SIZE_DOWNLOAD_T(3) is a newer replacement that returns a more
sensible variable type.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
58
59
60
61
62
63
64
65
66
67


68
69
70
71
        printf("Downloaded %.0f bytes\n", dl);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.4.1. Deprecated since 7.55.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
        printf("Downloaded %.0f bytes\n", dl);
      }
    }
  }
}
~~~

# DEPRECATED

Deprecated since 7.55.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SIZE_DOWNLOAD_T.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_SIZE_DOWNLOAD (3)
  - CURLINFO_SIZE_UPLOAD_T (3)
  - CURLOPT_MAXFILESIZE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SIZE_DOWNLOAD_T - get the number of downloaded bytes

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_SIZE_DOWNLOAD (3)
  - CURLINFO_SIZE_UPLOAD_T (3)
  - CURLOPT_MAXFILESIZE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.55.0
---

# NAME

CURLINFO_SIZE_DOWNLOAD_T - get the number of downloaded bytes

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the total amount of bytes that
were downloaded. The amount is only for the latest transfer and gets reset
again for each new transfer. This counts actual payload data, what's also
commonly called body. All meta and header data is excluded from this amount.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the total amount of bytes that
were downloaded. The amount is only for the latest transfer and gets reset
again for each new transfer. This counts actual payload data, what's also
commonly called body. All meta and header data is excluded from this amount.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
        printf("Downloaded %" CURL_FORMAT_CURL_OFF_T " bytes\n", dl);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.55.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
        printf("Downloaded %" CURL_FORMAT_CURL_OFF_T " bytes\n", dl);
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SIZE_UPLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SIZE_DOWNLOAD_T (3)
  - CURLINFO_SIZE_UPLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SIZE_UPLOAD - get the number of uploaded bytes

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SIZE_UPLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SIZE_DOWNLOAD_T (3)
  - CURLINFO_SIZE_UPLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_SIZE_UPLOAD - get the number of uploaded bytes

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
# DESCRIPTION

Pass a pointer to a double to receive the total amount of bytes that were
uploaded.

CURLINFO_SIZE_UPLOAD_T(3) is a newer replacement that returns a more
sensible variable type.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# DESCRIPTION

Pass a pointer to a double to receive the total amount of bytes that were
uploaded.

CURLINFO_SIZE_UPLOAD_T(3) is a newer replacement that returns a more
sensible variable type.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
54
55
56
57
58
59
60
61
62
63


64
65
66
67
        printf("Uploaded %.0f bytes\n", ul);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.4.1. Deprecated since 7.55.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
        printf("Uploaded %.0f bytes\n", ul);
      }
    }
  }
}
~~~

# DEPRECATED

Deprecated since 7.55.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SIZE_UPLOAD_T.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SIZE_UPLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SIZE_DOWNLOAD_T (3)
  - CURLINFO_SIZE_UPLOAD (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SIZE_UPLOAD_T - get the number of uploaded bytes

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SIZE_UPLOAD_T,
                           curl_off_t *uploadp);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the total amount of bytes that
were uploaded.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();













>



















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SIZE_UPLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SIZE_DOWNLOAD_T (3)
  - CURLINFO_SIZE_UPLOAD (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.55.0
---

# NAME

CURLINFO_SIZE_UPLOAD_T - get the number of uploaded bytes

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SIZE_UPLOAD_T,
                           curl_off_t *uploadp);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the total amount of bytes that
were uploaded.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
51
52
53
54
55
56
57
58
59
60
61
62
63
64
        printf("Uploaded %" CURL_FORMAT_CURL_OFF_T " bytes\n", ul);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.55.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




54
55
56
57
58
59
60
61


62
63
64
65
        printf("Uploaded %" CURL_FORMAT_CURL_OFF_T " bytes\n", ul);
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SPEED_DOWNLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SIZE_UPLOAD_T (3)
  - CURLINFO_SPEED_UPLOAD (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SPEED_DOWNLOAD - get download speed

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SPEED_DOWNLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SIZE_UPLOAD_T (3)
  - CURLINFO_SPEED_UPLOAD (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_SPEED_DOWNLOAD - get download speed

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
# DESCRIPTION

Pass a pointer to a double to receive the average download speed that curl
measured for the complete download. Measured in bytes/second.

CURLINFO_SPEED_DOWNLOAD_T(3) is a newer replacement that returns a more
sensible variable type.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# DESCRIPTION

Pass a pointer to a double to receive the average download speed that curl
measured for the complete download. Measured in bytes/second.

CURLINFO_SPEED_DOWNLOAD_T(3) is a newer replacement that returns a more
sensible variable type.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
54
55
56
57
58
59
60
61
62
63


64
65
66
67
        printf("Download speed %.0f bytes/sec\n", speed);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.4.1. Deprecated since 7.55.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
        printf("Download speed %.0f bytes/sec\n", speed);
      }
    }
  }
}
~~~

# DEPRECATED

Deprecated since 7.55.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SPEED_DOWNLOAD_T.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SPEED_DOWNLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SIZE_UPLOAD_T (3)
  - CURLINFO_SPEED_UPLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SPEED_DOWNLOAD_T - get download speed

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_DOWNLOAD_T,
                           curl_off_t *speed);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the average download speed
that curl measured for the complete download. Measured in bytes/second.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();













>



















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SPEED_DOWNLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SIZE_UPLOAD_T (3)
  - CURLINFO_SPEED_UPLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.55.0
---

# NAME

CURLINFO_SPEED_DOWNLOAD_T - get download speed

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_DOWNLOAD_T,
                           curl_off_t *speed);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the average download speed
that curl measured for the complete download. Measured in bytes/second.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
52
53
54
55
56
57
58
59
60
61
62
63
64
65
               speed);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.55.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




55
56
57
58
59
60
61
62


63
64
65
66
               speed);
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SPEED_UPLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SPEED_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SPEED_UPLOAD - get upload speed

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SPEED_UPLOAD
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SPEED_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_SPEED_UPLOAD - get upload speed

# SYNOPSIS
27
28
29
30
31
32
33


34
35
36
37
38
39
40
# DESCRIPTION

Pass a pointer to a double to receive the average upload speed that curl
measured for the complete upload. Measured in bytes/second.

CURLINFO_SPEED_UPLOAD_T(3) is a newer replacement that returns a more
sensible variable type.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# DESCRIPTION

Pass a pointer to a double to receive the average upload speed that curl
measured for the complete upload. Measured in bytes/second.

CURLINFO_SPEED_UPLOAD_T(3) is a newer replacement that returns a more
sensible variable type.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
52
53
54
55
56
57
58
59
60
61


62
63
64
65
        printf("Upload speed %.0f bytes/sec\n", speed);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.4.1. Deprecated since 7.55.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
        printf("Upload speed %.0f bytes/sec\n", speed);
      }
    }
  }
}
~~~

# DEPRECATED

Deprecated since 7.55.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SPEED_UPLOAD_T.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


32
33
34
35
36
37
38
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SPEED_UPLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SPEED_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_SPEED_UPLOAD_T - get upload speed

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_UPLOAD_T,
                           curl_off_t *speed);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the average upload speed that
curl measured for the complete upload. Measured in bytes/second.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();












>



















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_SPEED_UPLOAD_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SPEED_DOWNLOAD_T (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.55.0
---

# NAME

CURLINFO_SPEED_UPLOAD_T - get upload speed

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_SPEED_UPLOAD_T,
                           curl_off_t *speed);
~~~

# DESCRIPTION

Pass a pointer to a *curl_off_t* to receive the average upload speed that
curl measured for the complete upload. Measured in bytes/second.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
50
51
52
53
54
55
56
57
58
59
60
61
62
63
        printf("Upload speed %" CURL_FORMAT_CURL_OFF_T " bytes/sec\n", speed);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 7.55.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




53
54
55
56
57
58
59
60


61
62
63
64
        printf("Upload speed %" CURL_FORMAT_CURL_OFF_T " bytes/sec\n", speed);
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SSL_ENGINES.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_SSLENGINE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLINFO_SSL_ENGINES - get an slist of OpenSSL crypto-engines

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_SSLENGINE (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.12.3
---

# NAME

CURLINFO_SSL_ENGINES - get an slist of OpenSSL crypto-engines

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
Pass the address of a 'struct curl_slist *' to receive a linked-list of
OpenSSL crypto-engines supported. Note that engines are normally implemented
in separate dynamic libraries. Hence not all the returned engines may be
available at runtime. **NOTE:** you must call curl_slist_free_all(3)
on the list pointer once you are done with it, as libcurl does not free this
data for you.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    struct curl_slist *engines;
    res = curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
    if((res == CURLE_OK) && engines) {
      /* we have a list, free it when done using it */
      curl_slist_free_all(engines);
    }

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.12.3. Available in OpenSSL builds with "engine" support.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62


63
64
65
66
Pass the address of a 'struct curl_slist *' to receive a linked-list of
OpenSSL crypto-engines supported. Note that engines are normally implemented
in separate dynamic libraries. Hence not all the returned engines may be
available at runtime. **NOTE:** you must call curl_slist_free_all(3)
on the list pointer once you are done with it, as libcurl does not free this
data for you.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    struct curl_slist *engines;
    res = curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
    if((res == CURLE_OK) && engines) {
      /* we have a list, free it when done using it */
      curl_slist_free_all(engines);
    }

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_SSL_VERIFYRESULT.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLINFO_SSL_VERIFYRESULT - get the result of the certificate verification

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.5
---

# NAME

CURLINFO_SSL_VERIFYRESULT - get the result of the certificate verification

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
# DESCRIPTION

Pass a pointer to a long to receive the result of the server SSL certificate
verification that was requested (using the CURLOPT_SSL_VERIFYPEER(3)
option).

0 is a positive result. Non-zero is an error.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# DESCRIPTION

Pass a pointer to a long to receive the result of the server SSL certificate
verification that was requested (using the CURLOPT_SSL_VERIFYPEER(3)
option).

0 is a positive result. Non-zero is an error.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
62
63
64
65
66
67
68
69
70
71
72
73
74
75
             (verifyresult ? "bad" : "fine"));
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.5. Only set by the OpenSSL/libressl/boringssl and GnuTLS backends.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




65
66
67
68
69
70
71
72


73
74
75
76
             (verifyresult ? "bad" : "fine"));
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_STARTTRANSFER_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_STARTTRANSFER_TIME_T (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_STARTTRANSFER_TIME - get the time until the first byte is received

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_STARTTRANSFER_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_STARTTRANSFER_TIME_T (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.9.2
---

# NAME

CURLINFO_STARTTRANSFER_TIME - get the time until the first byte is received

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
CURLINFO_PRETRANSFER_TIME(3) and also the time the server needs to
calculate the result.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
CURLINFO_PRETRANSFER_TIME(3) and also the time the server needs to
calculate the result.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.9.2

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




59
60
61
62
63
64
65
66


67
68
69
70
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_STARTTRANSFER_TIME_T.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_STARTTRANSFER_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_STARTTRANSFER_TIME (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_STARTTRANSFER_TIME_T - get the time until the first byte is received

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_STARTTRANSFER_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_STARTTRANSFER_TIME (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.61.0
---

# NAME

CURLINFO_STARTTRANSFER_TIME_T - get the time until the first byte is received

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
CURLINFO_PRETRANSFER_TIME_T(3) and also the time the server needs to
calculate the result.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
CURLINFO_PRETRANSFER_TIME_T(3) and also the time the server needs to
calculate the result.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




61
62
63
64
65
66
67
68


69
70
71
72
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_TLS_SESSION.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLINFO_TLS_SESSION - get TLS session info

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.34.0
---

# NAME

CURLINFO_TLS_SESSION - get TLS session info

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

73
74
75
76
CURLINFO_TLS_SSL_PTR(3) OpenSSL session *internals* is **SSL ***.

You can obtain an **SSL_CTX** pointer from an SSL pointer using OpenSSL
function *SSL_get_SSL_CTX(3)*. Therefore unless you need compatibility
with older versions of libcurl use CURLINFO_TLS_SSL_PTR(3). Refer to
that document for more information.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    struct curl_tlssessioninfo *tls;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res)
      printf("error: %s\n", curl_easy_strerror(res));
    curl_easy_getinfo(curl, CURLINFO_TLS_SESSION, &tls);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.34.0. Deprecated since 7.48.0 and supported by OpenSSL and GnuTLS
only up until this version was released.


# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|

|
|
>




44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
CURLINFO_TLS_SSL_PTR(3) OpenSSL session *internals* is **SSL ***.

You can obtain an **SSL_CTX** pointer from an SSL pointer using OpenSSL
function *SSL_get_SSL_CTX(3)*. Therefore unless you need compatibility
with older versions of libcurl use CURLINFO_TLS_SSL_PTR(3). Refer to
that document for more information.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    struct curl_tlssessioninfo *tls;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    res = curl_easy_perform(curl);
    if(res)
      printf("error: %s\n", curl_easy_strerror(res));
    curl_easy_getinfo(curl, CURLINFO_TLS_SESSION, &tls);
    curl_easy_cleanup(curl);
  }
}
~~~

# DEPRECATED

Deprecated since 7.48.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_TLS_SSL_PTR.md.
14
15
16
17
18
19
20

21
22
23
24
25
26
27
  - BearSSL
  - GnuTLS
  - mbedTLS
  - OpenSSL
  - Schannel
  - Secure Transport
  - wolfSSL

---

# NAME

CURLINFO_TLS_SESSION, CURLINFO_TLS_SSL_PTR - get TLS session info

# SYNOPSIS







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  - BearSSL
  - GnuTLS
  - mbedTLS
  - OpenSSL
  - Schannel
  - Secure Transport
  - wolfSSL
Added-in: 7.48.0
---

# NAME

CURLINFO_TLS_SESSION, CURLINFO_TLS_SSL_PTR - get TLS session info

# SYNOPSIS
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  void *internals;
};
~~~

The *backend* struct member is one of the defines in the CURLSSLBACKEND_*
series: CURLSSLBACKEND_NONE (when built without TLS support),
CURLSSLBACKEND_WOLFSSL, CURLSSLBACKEND_SECURETRANSPORT, CURLSSLBACKEND_GNUTLS,
CURLSSLBACKEND_MBEDTLS, CURLSSLBACKEND_NSS, CURLSSLBACKEND_OPENSSL,
CURLSSLBACKEND_SCHANNEL or CURLSSLBACKEND_MESALINK. (Note that the OpenSSL
forks are all reported as just OpenSSL here.)

The *internals* struct member points to a TLS library specific pointer for
the active ("in use") SSL connection, with the following underlying types:

## GnuTLS








|
|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  void *internals;
};
~~~

The *backend* struct member is one of the defines in the CURLSSLBACKEND_*
series: CURLSSLBACKEND_NONE (when built without TLS support),
CURLSSLBACKEND_WOLFSSL, CURLSSLBACKEND_SECURETRANSPORT, CURLSSLBACKEND_GNUTLS,
CURLSSLBACKEND_MBEDTLS, CURLSSLBACKEND_NSS, CURLSSLBACKEND_OPENSSL or
CURLSSLBACKEND_SCHANNEL. (Note that the OpenSSL
forks are all reported as just OpenSSL here.)

The *internals* struct member points to a TLS library specific pointer for
the active ("in use") SSL connection, with the following underlying types:

## GnuTLS

90
91
92
93
94
95
96


97
98
99
100
101
102
103
## Secure Transport

**SSLContext ***

## wolfSSL

**SSL ***



If the *internals* pointer is NULL then either the SSL backend is not
supported, an SSL session has not yet been established or the connection is no
longer associated with the easy handle (e.g. curl_easy_perform(3) has
returned).

# LIMITATIONS







>
>







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
## Secure Transport

**SSLContext ***

## wolfSSL

**SSL ***

##

If the *internals* pointer is NULL then either the SSL backend is not
supported, an SSL session has not yet been established or the connection is no
longer associated with the easy handle (e.g. curl_easy_perform(3) has
returned).

# LIMITATIONS
127
128
129
130
131
132
133


134
135
136
137
138
139
140
CURLOPT_SSL_CTX_FUNCTION(3) to set a verification callback, if supported.
That is safer and does not suffer from any of the problems above.

How are you using this option? Are you affected by any of these limitations?
Please let us know by making a comment at
https://github.com/curl/curl/issues/685



# EXAMPLE

~~~c
#include <curl/curl.h>
#include <openssl/ssl.h>

CURL *curl;







>
>







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
CURLOPT_SSL_CTX_FUNCTION(3) to set a verification callback, if supported.
That is safer and does not suffer from any of the problems above.

How are you using this option? Are you affected by any of these limitations?
Please let us know by making a comment at
https://github.com/curl/curl/issues/685

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <curl/curl.h>
#include <openssl/ssl.h>

CURL *curl;
160
161
162
163
164
165
166
167
168
169
170
171
172


173
174
175
176
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
  return res;
}
~~~

# AVAILABILITY

Added in 7.48.0.

This option supersedes CURLINFO_TLS_SESSION(3) which was added in 7.34.0.
This option is exactly the same as that option except in the case of OpenSSL.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







<
|
<



>
>




165
166
167
168
169
170
171

172

173
174
175
176
177
178
179
180
181
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
  return res;
}
~~~


# HISTORY


This option supersedes CURLINFO_TLS_SESSION(3) which was added in 7.34.0.
This option is exactly the same as that option except in the case of OpenSSL.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_TOTAL_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_TOTAL_TIME_T (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_TOTAL_TIME - get total time of previous transfer

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_TOTAL_TIME
Section: 3
Source: libcurl
See-also:
  - CURLINFO_TOTAL_TIME_T (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.4.1
---

# NAME

CURLINFO_TOTAL_TIME - get total time of previous transfer

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
Pass a pointer to a double to receive the total time in seconds for the
previous transfer, including name resolving, TCP connect etc. The double
represents the time in seconds, including fractions.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Pass a pointer to a double to receive the total time in seconds for the
previous transfer, including name resolving, TCP connect etc. The double
represents the time in seconds, including fractions.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
54
55
56
57
58
59
60
61
62
63
64
65
66
67
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.4.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




57
58
59
60
61
62
63
64


65
66
67
68
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_TOTAL_TIME_T.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_TOTAL_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_TOTAL_TIME (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---
# NAME

CURLINFO_TOTAL_TIME_T - get total time of previous transfer in microseconds

# SYNOPSIS














>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_TOTAL_TIME_T
Section: 3
Source: libcurl
See-also:
  - CURLINFO_TOTAL_TIME (3)
  - CURLOPT_TIMEOUT (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 7.61.0
---
# NAME

CURLINFO_TOTAL_TIME_T - get total time of previous transfer in microseconds

# SYNOPSIS

30
31
32
33
34
35
36


37
38
39
40
41
42
43
Pass a pointer to a curl_off_t to receive the total time in microseconds
for the previous transfer, including name resolving, TCP connect etc.
The curl_off_t represents the time in microseconds.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Pass a pointer to a curl_off_t to receive the total time in microseconds
for the previous transfer, including name resolving, TCP connect etc.
The curl_off_t represents the time in microseconds.

When a redirect is followed, the time from each request is added together.

See also the TIMES overview in the curl_easy_getinfo(3) man page.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_USED_PROXY.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32


33
34
35
36
37
38
39
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_USED_PROXY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NOPROXY (3)
  - CURLOPT_PROXY (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_USED_PROXY - whether the transfer used a proxy

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_USED_PROXY,
                           long *authp);
~~~

# DESCRIPTION

Pass a pointer to a long. It gets set to zero set if no proxy was used in the
previous transfer or a non-zero value if a proxy was used.



# EXAMPLE

~~~c
int main(int argc, char *argv[])
{
  CURL *curl = curl_easy_init();













>



















>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_USED_PROXY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NOPROXY (3)
  - CURLOPT_PROXY (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 8.7.0
---

# NAME

CURLINFO_USED_PROXY - whether the transfer used a proxy

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_USED_PROXY,
                           long *authp);
~~~

# DESCRIPTION

Pass a pointer to a long. It gets set to zero set if no proxy was used in the
previous transfer or a non-zero value if a proxy was used.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(int argc, char *argv[])
{
  CURL *curl = curl_easy_init();
54
55
56
57
58
59
60
61
62
63
64
65
66
67
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 8.7.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




57
58
59
60
61
62
63
64


65
66
67
68
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLINFO_XFER_ID.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_XFER_ID
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONN_ID (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All

---

# NAME

CURLINFO_XFER_ID - get the ID of a transfer

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_XFER_ID
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONN_ID (3)
  - curl_easy_getinfo (3)
  - curl_easy_setopt (3)
Protocol:
  - All
Added-in: 8.2.0
---

# NAME

CURLINFO_XFER_ID - get the ID of a transfer

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
Pass a pointer to a *curl_off_t* to receive the identifier of the
current/last transfer done with the handle. Stores -1 if no transfer
has been started yet for the handle.

The transfer id is unique among all transfers performed using the same
connection cache. This is implicitly the case for all transfers in the
same multi handle.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Pass a pointer to a *curl_off_t* to receive the identifier of the
current/last transfer done with the handle. Stores -1 if no transfer
has been started yet for the handle.

The transfer id is unique among all transfers performed using the same
connection cache. This is implicitly the case for all transfers in the
same multi handle.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
        printf("Transfer ID: %" CURL_FORMAT_CURL_OFF_T "\n", xfer_id);
      }
    }
  }
}
~~~

# AVAILABILITY

Added in 8.2.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
        printf("Transfer ID: %" CURL_FORMAT_CURL_OFF_T "\n", xfer_id);
      }
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE (3)
  - CURLMOPT_MAX_PIPELINE_LENGTH (3)
  - CURLMOPT_PIPELINING (3)
Protocol:
  - HTTP

---

# NAME

CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE - chunk length threshold for pipelining

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE (3)
  - CURLMOPT_MAX_PIPELINE_LENGTH (3)
  - CURLMOPT_PIPELINING (3)
Protocol:
  - HTTP
Added-in: 7.30.0
---

# NAME

CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE - chunk length threshold for pipelining

# SYNOPSIS
33
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
currently processing a chunked (Transfer-encoding: chunked) request with a
current chunk length larger than CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3),
that pipeline is not considered for additional requests, even if it is shorter
than CURLMOPT_MAX_PIPELINE_LENGTH(3).

# DEFAULT

The default value is 0, which means that the penalization is inactive.



# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  long maxchunk = 10000;
  curl_multi_setopt(m, CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, maxchunk);
}
~~~

# AVAILABILITY

Added in 7.30.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
>
>












|
<
<




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
currently processing a chunked (Transfer-encoding: chunked) request with a
current chunk length larger than CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE(3),
that pipeline is not considered for additional requests, even if it is shorter
than CURLMOPT_MAX_PIPELINE_LENGTH(3).

# DEFAULT

0, which means that penalization is inactive.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  long maxchunk = 10000;
  curl_multi_setopt(m, CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, maxchunk);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE (3)
  - CURLMOPT_PIPELINING (3)
Protocol:
  - HTTP

---

# NAME

CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE - size threshold for pipelining penalty

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE (3)
  - CURLMOPT_PIPELINING (3)
Protocol:
  - HTTP
Added-in: 7.30.0
---

# NAME

CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE - size threshold for pipelining penalty

# SYNOPSIS
32
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
currently processing a request with a Content-Length larger than this
CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3), that pipeline is not considered
for additional requests, even if it is shorter than
CURLMOPT_MAX_PIPELINE_LENGTH(3).

# DEFAULT

The default value is 0, which means that the size penalization is inactive.



# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  long maxlength = 10000;
  curl_multi_setopt(m, CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, maxlength);
}
~~~

# AVAILABILITY

Added in 7.30.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
>
>












|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


56
57
58
59
currently processing a request with a Content-Length larger than this
CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE(3), that pipeline is not considered
for additional requests, even if it is shorter than
CURLMOPT_MAX_PIPELINE_LENGTH(3).

# DEFAULT

0, which means that the size penalization is inactive.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  long maxlength = 10000;
  curl_multi_setopt(m, CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, maxlength);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_MAXCONNECTS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAXCONNECTS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLOPT_MAXCONNECTS (3)
Protocol:
  - All

---

# NAME

CURLMOPT_MAXCONNECTS - size of connection cache

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAXCONNECTS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLOPT_MAXCONNECTS (3)
Protocol:
  - All
Added-in: 7.16.3
---

# NAME

CURLMOPT_MAXCONNECTS - size of connection cache

# SYNOPSIS
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
does however not close down any active transfers, it simply does not allow new
ones to get made.

# DEFAULT

See DESCRIPTION



# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* only keep 10 connections in the cache */
  curl_multi_setopt(m, CURLMOPT_MAXCONNECTS, 10L);
}
~~~

# AVAILABILITY

Added in 7.16.3

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







>
>











|
<
<




49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69


70
71
72
73
does however not close down any active transfers, it simply does not allow new
ones to get made.

# DEFAULT

See DESCRIPTION

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* only keep 10 connections in the cache */
  curl_multi_setopt(m, CURLMOPT_MAXCONNECTS, 10L);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_MAX_CONCURRENT_STREAMS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAX_CONCURRENT_STREAMS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAXCONNECTS (3)
  - CURLOPT_MAXCONNECTS (3)
Protocol:
  - HTTP

---

# NAME

CURLMOPT_MAX_CONCURRENT_STREAMS - max concurrent streams for http2

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAX_CONCURRENT_STREAMS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAXCONNECTS (3)
  - CURLOPT_MAXCONNECTS (3)
Protocol:
  - HTTP
Added-in: 7.67.0
---

# NAME

CURLMOPT_MAX_CONCURRENT_STREAMS - max concurrent streams for http2

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Valid values range from 1 to 2147483647 (2^31 - 1) and defaults to 100. The
value passed here would be honored based on other system resources properties.

# DEFAULT

100



# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* max concurrent streams 200 */
  curl_multi_setopt(m, CURLMOPT_MAX_CONCURRENT_STREAMS, 200L);
}
~~~

# AVAILABILITY

Added in 7.67.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







>
>











|
<
<




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


55
56
57
58
Valid values range from 1 to 2147483647 (2^31 - 1) and defaults to 100. The
value passed here would be honored based on other system resources properties.

# DEFAULT

100

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* max concurrent streams 200 */
  curl_multi_setopt(m, CURLMOPT_MAX_CONCURRENT_STREAMS, 200L);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_MAX_HOST_CONNECTIONS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAX_HOST_CONNECTIONS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAXCONNECTS (3)
  - CURLMOPT_MAX_TOTAL_CONNECTIONS (3)
Protocol:
  - All

---

# NAME

CURLMOPT_MAX_HOST_CONNECTIONS - max number of connections to a single host

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAX_HOST_CONNECTIONS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAXCONNECTS (3)
  - CURLMOPT_MAX_TOTAL_CONNECTIONS (3)
Protocol:
  - All
Added-in: 7.30.0
---

# NAME

CURLMOPT_MAX_HOST_CONNECTIONS - max number of connections to a single host

# SYNOPSIS
51
52
53
54
55
56
57


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
does however not close down any active transfers, it simply does not allow new
ones to get made.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* do no more than 2 connections per host */
  curl_multi_setopt(m, CURLMOPT_MAX_HOST_CONNECTIONS, 2L);
}
~~~

# AVAILABILITY

Added in 7.30.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







>
>











|
<
<




52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
does however not close down any active transfers, it simply does not allow new
ones to get made.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* do no more than 2 connections per host */
  curl_multi_setopt(m, CURLMOPT_MAX_HOST_CONNECTIONS, 2L);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_MAX_PIPELINE_LENGTH.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAX_PIPELINE_LENGTH
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLMOPT_PIPELINING (3)
Protocol:
  - All

---

# NAME

CURLMOPT_MAX_PIPELINE_LENGTH - maximum number of requests in a pipeline

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAX_PIPELINE_LENGTH
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLMOPT_PIPELINING (3)
Protocol:
  - All
Added-in: 7.30.0
---

# NAME

CURLMOPT_MAX_PIPELINE_LENGTH - maximum number of requests in a pipeline

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
number of requests in-flight is CURLMOPT_MAX_HOST_CONNECTIONS(3) *
CURLMOPT_MAX_PIPELINE_LENGTH(3).

# DEFAULT

5



# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* set a more conservative pipe length */
  curl_multi_setopt(m, CURLMOPT_MAX_PIPELINE_LENGTH, 3L);
}
~~~

# AVAILABILITY

Added in 7.30.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







>
>











|
<
<




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
number of requests in-flight is CURLMOPT_MAX_HOST_CONNECTIONS(3) *
CURLMOPT_MAX_PIPELINE_LENGTH(3).

# DEFAULT

5

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* set a more conservative pipe length */
  curl_multi_setopt(m, CURLMOPT_MAX_PIPELINE_LENGTH, 3L);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_MAX_TOTAL_CONNECTIONS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAX_TOTAL_CONNECTIONS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAXCONNECTS (3)
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
Protocol:
  - All

---

# NAME

CURLMOPT_MAX_TOTAL_CONNECTIONS - max simultaneously open connections

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_MAX_TOTAL_CONNECTIONS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAXCONNECTS (3)
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
Protocol:
  - All
Added-in: 7.30.0
---

# NAME

CURLMOPT_MAX_TOTAL_CONNECTIONS - max simultaneously open connections

# SYNOPSIS
41
42
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
transfer might never even start before it times out.

Even in the queued up situation, the CURLOPT_CONNECTTIMEOUT_MS(3)
timeout is however treated as a per-connect timeout.

# DEFAULT

The default value is 0, which means that there is no limit. It is then simply
controlled by the number of easy handles added.



# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* never do more than 15 connections */
  curl_multi_setopt(m, CURLMOPT_MAX_TOTAL_CONNECTIONS, 15L);
}
~~~

# AVAILABILITY

Added in 7.30.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
|
>
>












|
<
<




42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
transfer might never even start before it times out.

Even in the queued up situation, the CURLOPT_CONNECTTIMEOUT_MS(3)
timeout is however treated as a per-connect timeout.

# DEFAULT

0, which means that there is no limit. It is then simply controlled by the
number of easy handles added.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* never do more than 15 connections */
  curl_multi_setopt(m, CURLMOPT_MAX_TOTAL_CONNECTIONS, 15L);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_PIPELINING.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE (3)
  - CURLMOPT_MAXCONNECTS (3)
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLMOPT_MAX_PIPELINE_LENGTH (3)
  - CURLMOPT_PIPELINING_SITE_BL (3)
Protocol:
  - HTTP

---

# NAME

CURLMOPT_PIPELINING - enable HTTP multiplexing

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE (3)
  - CURLMOPT_MAXCONNECTS (3)
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLMOPT_MAX_PIPELINE_LENGTH (3)
  - CURLMOPT_PIPELINING_SITE_BL (3)
Protocol:
  - HTTP
Added-in: 7.16.0
---

# NAME

CURLMOPT_PIPELINING - enable HTTP multiplexing

# SYNOPSIS
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71






72
73
74
75
## CURLPIPE_MULTIPLEX (2)

If this bit is set, libcurl tries to multiplex the new transfer over an
existing connection if possible. This requires HTTP/2 or HTTP/3.

# DEFAULT

Since 7.62.0, **CURLPIPE_MULTIPLEX** is enabled by default.

Before that, default was **CURLPIPE_NOTHING**.

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* try HTTP/2 multiplexing */
  curl_multi_setopt(m, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
}
~~~

# AVAILABILITY

Added in 7.16.0. Multiplex support bit added in 7.43.0. HTTP/1 Pipelining
support was disabled in 7.62.0.







# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|

|












|

|
|
>
>
>
>
>
>




47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
## CURLPIPE_MULTIPLEX (2)

If this bit is set, libcurl tries to multiplex the new transfer over an
existing connection if possible. This requires HTTP/2 or HTTP/3.

# DEFAULT

**CURLPIPE_MULTIPLEX**

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLM *m = curl_multi_init();
  /* try HTTP/2 multiplexing */
  curl_multi_setopt(m, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
}
~~~

# HISTORY

The multiplex support bit was added in 7.43.0. HTTP/1 Pipelining support was
disabled in 7.62.0.

Since 7.62.0, **CURLPIPE_MULTIPLEX** is enabled by default.

Before that, default was **CURLPIPE_NOTHING**.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SERVER_BL.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_PIPELINING_SERVER_BL
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLMOPT_PIPELINING_SITE_BL (3)
Protocol:
  - HTTP

---

# NAME

CURLMOPT_PIPELINING_SERVER_BL - pipelining server block list

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_PIPELINING_SERVER_BL
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLMOPT_PIPELINING_SITE_BL (3)
Protocol:
  - HTTP
Added-in: 7.30.0
---

# NAME

CURLMOPT_PIPELINING_SERVER_BL - pipelining server block list

# SYNOPSIS
37
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
in the block list, i.e "Server: Ninja 1.2.3" and "Server: Ninja 1.4.0" can
both be blocked by having "Ninja" in the list.

Pass a NULL pointer to clear the block list.

# DEFAULT

The default value is NULL, which means that there is no block list.



# EXAMPLE

~~~c
static char *server_block_list[] =
{
  "Microsoft-IIS/6.0",
  "nginx/0.8.54",
  NULL
};
int main(void)
{
  CURLM *m = curl_multi_init();
  curl_multi_setopt(m, CURLMOPT_PIPELINING_SERVER_BL, server_block_list);
}
~~~

# AVAILABILITY

Added in 7.30.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
>
>

















|
<
<




38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
in the block list, i.e "Server: Ninja 1.2.3" and "Server: Ninja 1.4.0" can
both be blocked by having "Ninja" in the list.

Pass a NULL pointer to clear the block list.

# DEFAULT

NULL, which means that there is no block list.

# %PROTOCOLS%

# EXAMPLE

~~~c
static char *server_block_list[] =
{
  "Microsoft-IIS/6.0",
  "nginx/0.8.54",
  NULL
};
int main(void)
{
  CURLM *m = curl_multi_init();
  curl_multi_setopt(m, CURLMOPT_PIPELINING_SERVER_BL, server_block_list);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_PIPELINING_SITE_BL.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_PIPELINING_SITE_BL
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLMOPT_PIPELINING_SERVER_BL (3)
Protocol:
  - HTTP

---

# NAME

CURLMOPT_PIPELINING_SITE_BL - pipelining host block list

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_PIPELINING_SITE_BL
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLMOPT_PIPELINING_SERVER_BL (3)
Protocol:
  - HTTP
Added-in: 7.30.0
---

# NAME

CURLMOPT_PIPELINING_SITE_BL - pipelining host block list

# SYNOPSIS
32
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
of sites that are blocked from pipelining, i.e sites that are known to not
support HTTP pipelining. The array is copied by libcurl.

Pass a NULL pointer to clear the block list.

# DEFAULT

The default value is NULL, which means that there is no block list.



# EXAMPLE

~~~c
static char *site_block_list[] =
{
  "www.haxx.se",
  "www.example.com:1234",
  NULL
};

int main(void)
{
  CURLM *m = curl_multi_init();
  curl_multi_setopt(m, CURLMOPT_PIPELINING_SITE_BL, site_block_list);
}
~~~

# AVAILABILITY

Added in 7.30.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
>
>


















|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
of sites that are blocked from pipelining, i.e sites that are known to not
support HTTP pipelining. The array is copied by libcurl.

Pass a NULL pointer to clear the block list.

# DEFAULT

NULL, which means that there is no block list.

# %PROTOCOLS%

# EXAMPLE

~~~c
static char *site_block_list[] =
{
  "www.haxx.se",
  "www.example.com:1234",
  NULL
};

int main(void)
{
  CURLM *m = curl_multi_init();
  curl_multi_setopt(m, CURLMOPT_PIPELINING_SITE_BL, site_block_list);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_PUSHDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_PUSHDATA
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLMOPT_PUSHFUNCTION (3)
  - CURLOPT_PIPEWAIT (3)
  - RFC 7540
Protocol:
  - HTTP

---

# NAME

CURLMOPT_PUSHDATA - pointer to pass to push callback

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_PUSHDATA
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLMOPT_PUSHFUNCTION (3)
  - CURLOPT_PIPEWAIT (3)
  - RFC 7540
Protocol:
  - HTTP
Added-in: 7.44.0
---

# NAME

CURLMOPT_PUSHDATA - pointer to pass to push callback

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
Set a *pointer* to pass as the last argument to the
CURLMOPT_PUSHFUNCTION(3) callback. The pointer is not touched or used by
libcurl itself, only passed on to the callback function.

# DEFAULT

NULL



# EXAMPLE

~~~c
#include <string.h>

/* only allow pushes for filenames starting with "push-" */







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Set a *pointer* to pass as the last argument to the
CURLMOPT_PUSHFUNCTION(3) callback. The pointer is not touched or used by
libcurl itself, only passed on to the callback function.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h>

/* only allow pushes for filenames starting with "push-" */
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  int counter;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_callback);
  curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter);
}
~~~

# AVAILABILITY

Added in 7.44.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
<
<




75
76
77
78
79
80
81
82


83
84
85
86
  int counter;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_callback);
  curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_PUSHFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLMOPT_PUSHDATA (3)
  - CURLOPT_PIPEWAIT (3)
  - RFC 7540
Protocol:
  - HTTP

---

# NAME

CURLMOPT_PUSHFUNCTION - callback that approves or denies server pushes

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_PUSHFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLMOPT_PUSHDATA (3)
  - CURLOPT_PIPEWAIT (3)
  - RFC 7540
Protocol:
  - HTTP
Added-in: 7.44.0
---

# NAME

CURLMOPT_PUSHFUNCTION - callback that approves or denies server pushes

# SYNOPSIS
92
93
94
95
96
97
98


99
100
101
102
103
104
105

All other return codes are reserved for future use.

# DEFAULT

NULL, no callback



# EXAMPLE

~~~c
#include <string.h>

/* only allow pushes for filenames starting with "push-" */
int push_callback(CURL *parent,







>
>







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

All other return codes are reserved for future use.

# DEFAULT

NULL, no callback

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h>

/* only allow pushes for filenames starting with "push-" */
int push_callback(CURL *parent,
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  int counter;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_callback);
  curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter);
}
~~~

# AVAILABILITY

Added in 7.44.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
<
<




136
137
138
139
140
141
142
143


144
145
146
147
  int counter;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_PUSHFUNCTION, push_callback);
  curl_multi_setopt(multi, CURLMOPT_PUSHDATA, &counter);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_SOCKETDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_SOCKETDATA
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_SOCKETFUNCTION (3)
  - CURLMOPT_TIMERFUNCTION (3)
  - curl_multi_socket_action (3)
Protocol:
  - All

---

# NAME

CURLMOPT_SOCKETDATA - custom pointer passed to the socket callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_SOCKETDATA
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_SOCKETFUNCTION (3)
  - CURLMOPT_TIMERFUNCTION (3)
  - curl_multi_socket_action (3)
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

CURLMOPT_SOCKETDATA - custom pointer passed to the socket callback

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44

This pointer is not touched by libcurl but is only passed in as the socket
callback's **clientp** argument.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct priv {
  void *ours;
};







>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

This pointer is not touched by libcurl but is only passed in as the socket
callback's **clientp** argument.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *ours;
};
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  CURLM *multi = curl_multi_init();
  /* ... use socket callback and custom pointer */
  curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
  curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, &setup);
}
~~~

# AVAILABILITY

Added in 7.15.4

# RETURN VALUE

Returns CURLM_OK.







|
<
<




70
71
72
73
74
75
76
77


78
79
80
81
  CURLM *multi = curl_multi_init();
  /* ... use socket callback and custom pointer */
  curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
  curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, &setup);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_SOCKETFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_SOCKETFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_SOCKETDATA (3)
  - CURLMOPT_TIMERFUNCTION (3)
  - curl_multi_socket_action (3)
Protocol:
  - All

---

# NAME

CURLMOPT_SOCKETFUNCTION - callback informed about what to wait for

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_SOCKETFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_SOCKETDATA (3)
  - CURLMOPT_TIMERFUNCTION (3)
  - curl_multi_socket_action (3)
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

CURLMOPT_SOCKETFUNCTION - callback informed about what to wait for

# SYNOPSIS
85
86
87
88
89
90
91


92
93
94
95
96
97
98
The specified socket/file descriptor is no longer used by libcurl for any
active transfer. It might soon be added again.

# DEFAULT

NULL (no callback)



# EXAMPLE

~~~c
struct priv {
  void *ours;
};








>
>







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
The specified socket/file descriptor is no longer used by libcurl for any
active transfer. It might soon be added again.

# DEFAULT

NULL (no callback)

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *ours;
};

120
121
122
123
124
125
126
127
128
129
130
131
132
133
  CURLM *multi = curl_multi_init();
  /* ... use socket callback and custom pointer */
  curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
  curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, &setup);
}
~~~

# AVAILABILITY

Added in 7.15.4

# RETURN VALUE

Returns CURLM_OK.







|
<
<




123
124
125
126
127
128
129
130


131
132
133
134
  CURLM *multi = curl_multi_init();
  /* ... use socket callback and custom pointer */
  curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
  curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, &setup);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_TIMERDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_TIMERDATA
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_SOCKETFUNCTION (3)
  - CURLMOPT_TIMERFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLMOPT_TIMERDATA - custom pointer to pass to timer callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_TIMERDATA
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_SOCKETFUNCTION (3)
  - CURLMOPT_TIMERFUNCTION (3)
Protocol:
  - All
Added-in: 7.16.0
---

# NAME

CURLMOPT_TIMERDATA - custom pointer to pass to timer callback

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43

This pointer is not touched by libcurl but is only be passed in to the timer
callback's **clientp** argument.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct priv {
  void *custom;
};







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

This pointer is not touched by libcurl but is only be passed in to the timer
callback's **clientp** argument.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *custom;
};
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  struct priv mydata;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timerfunc);
  curl_multi_setopt(multi, CURLMOPT_TIMERDATA, &mydata);
}
~~~

# AVAILABILITY

Added in 7.16.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
<
<




63
64
65
66
67
68
69
70


71
72
73
74
  struct priv mydata;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timerfunc);
  curl_multi_setopt(multi, CURLMOPT_TIMERDATA, &mydata);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLMOPT_TIMERFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_TIMERFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_SOCKETFUNCTION (3)
  - CURLMOPT_TIMERDATA (3)
Protocol:
  - All

---

# NAME

CURLMOPT_TIMERFUNCTION - callback to receive timeout values

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLMOPT_TIMERFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_SOCKETFUNCTION (3)
  - CURLMOPT_TIMERDATA (3)
Protocol:
  - All
Added-in: 7.16.0
---

# NAME

CURLMOPT_TIMERFUNCTION - callback to receive timeout values

# SYNOPSIS
59
60
61
62
63
64
65


66
67
68
69
70
71
72
unpleasant recursive behavior that immediately calls another call to the
callback with a zero timeout...

# DEFAULT

NULL



# EXAMPLE

~~~c
struct priv {
  void *custom;
};








>
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
unpleasant recursive behavior that immediately calls another call to the
callback with a zero timeout...

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *custom;
};

88
89
90
91
92
93
94
95
96
97
98
99
100
101
  struct priv mydata;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timerfunc);
  curl_multi_setopt(multi, CURLMOPT_TIMERDATA, &mydata);
}
~~~

# AVAILABILITY

Added in 7.16.0

# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.







|
<
<




91
92
93
94
95
96
97
98


99
100
101
102
  struct priv mydata;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timerfunc);
  curl_multi_setopt(multi, CURLMOPT_TIMERDATA, &mydata);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLM_OK if the option is supported, and CURLM_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ABSTRACT_UNIX_SOCKET.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ABSTRACT_UNIX_SOCKET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_UNIX_SOCKET_PATH (3)
  - unix (7)
Protocol:
  - All

---

# NAME

CURLOPT_ABSTRACT_UNIX_SOCKET - abstract Unix domain socket

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ABSTRACT_UNIX_SOCKET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_UNIX_SOCKET_PATH (3)
  - unix (7)
Protocol:
  - All
Added-in: 7.53.0
---

# NAME

CURLOPT_ABSTRACT_UNIX_SOCKET - abstract Unix domain socket

# SYNOPSIS
38
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

This option shares the same semantics as CURLOPT_UNIX_SOCKET_PATH(3) in
which documentation more details can be found. Internally, these two options
share the same storage and therefore only one of them can be set per handle.

# DEFAULT

Default is NULL.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_ABSTRACT_UNIX_SOCKET, "/tmp/foo.sock");
    curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.53.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
>
>

















|
<
<




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70

This option shares the same semantics as CURLOPT_UNIX_SOCKET_PATH(3) in
which documentation more details can be found. Internally, these two options
share the same storage and therefore only one of them can be set per handle.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_ABSTRACT_UNIX_SOCKET, "/tmp/foo.sock");
    curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ACCEPTTIMEOUT_MS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ACCEPTTIMEOUT_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECTTIMEOUT_MS (3)
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_ACCEPTTIMEOUT_MS - timeout waiting for FTP server to connect back

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ACCEPTTIMEOUT_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECTTIMEOUT_MS (3)
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
Protocol:
  - FTP
Added-in: 7.24.0
---

# NAME

CURLOPT_ACCEPTTIMEOUT_MS - timeout waiting for FTP server to connect back

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Pass a long telling libcurl the maximum number of milliseconds to wait for a
server to connect back to libcurl when an active FTP connection is used.

# DEFAULT

60000 milliseconds



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/path/file");

    /* wait no more than 5 seconds for FTP server responses */
    curl_easy_setopt(curl, CURLOPT_ACCEPTTIMEOUT_MS, 5000L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.24.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
Pass a long telling libcurl the maximum number of milliseconds to wait for a
server to connect back to libcurl when an active FTP connection is used.

# DEFAULT

60000 milliseconds

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/path/file");

    /* wait no more than 5 seconds for FTP server responses */
    curl_easy_setopt(curl, CURLOPT_ACCEPTTIMEOUT_MS, 5000L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ACCEPT_ENCODING.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ACCEPT_ENCODING
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_HTTP_CONTENT_DECODING (3)
  - CURLOPT_TRANSFER_ENCODING (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_ACCEPT_ENCODING - automatic decompression of HTTP downloads

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ACCEPT_ENCODING
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_HTTP_CONTENT_DECODING (3)
  - CURLOPT_TRANSFER_ENCODING (3)
Protocol:
  - HTTP
Added-in: 7.21.6
---

# NAME

CURLOPT_ACCEPT_ENCODING - automatic decompression of HTTP downloads

# SYNOPSIS
67
68
69
70
71
72
73











74
75
76


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
indicate the length of the compressed content so when auto decoding is enabled
it may not match the sum of bytes reported by the write callbacks (although,
sending the length of the non-compressed content is a common server mistake).

The application does not have to keep the string around after setting this
option.












# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable all supported built-in compressions */
    curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

This option was called CURLOPT_ENCODING before 7.21.6

The specific libcurl you are using must have been built with zlib to be able to
decompress gzip and deflate responses, with the brotli library to
decompress brotli responses and with the zstd library to decompress zstd
responses.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
>
>
>
>
>
>
>
>
>



>
>



















|
<
<
<
<
<
<
<





68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110







111
112
113
114
115
indicate the length of the compressed content so when auto decoding is enabled
it may not match the sum of bytes reported by the write callbacks (although,
sending the length of the non-compressed content is a common server mistake).

The application does not have to keep the string around after setting this
option.

# HISTORY

This option was called CURLOPT_ENCODING before 7.21.6

# NOTES

The specific libcurl you are using must have been built with zlib to be able to
decompress gzip and deflate responses, with the brotli library to
decompress brotli responses and with the zstd library to decompress zstd
responses.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable all supported built-in compressions */
    curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%








# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ADDRESS_SCOPE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ADDRESS_SCOPE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
Protocol:
  - All

---

# NAME

CURLOPT_ADDRESS_SCOPE - scope id for IPv6 addresses

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ADDRESS_SCOPE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
Protocol:
  - All
Added-in: 7.19.0
---

# NAME

CURLOPT_ADDRESS_SCOPE - scope id for IPv6 addresses

# SYNOPSIS
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

Pass a long specifying the scope id value to use when connecting to IPv6 addresses.

# DEFAULT

0



# EXAMPLE

~~~c
#include <net/if.h> /* for if_nametoindex() */

int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    long my_scope_id;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    my_scope_id = if_nametoindex("eth0");
    curl_easy_setopt(curl, CURLOPT_ADDRESS_SCOPE, my_scope_id);
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value.







>
>




















|
<
<





28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61
62

Pass a long specifying the scope id value to use when connecting to IPv6 addresses.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <net/if.h> /* for if_nametoindex() */

int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    long my_scope_id;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    my_scope_id = if_nametoindex("eth0");
    curl_easy_setopt(curl, CURLOPT_ADDRESS_SCOPE, my_scope_id);
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ALTSVC.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ALTSVC
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ALTSVC_CTRL (3)
  - CURLOPT_CONNECT_TO (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_RESOLVE (3)
Protocol:
  - HTTP

---
<!-- markdown-link-check-disable -->
# NAME

CURLOPT_ALTSVC - alt-svc cache filename

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ALTSVC
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ALTSVC_CTRL (3)
  - CURLOPT_CONNECT_TO (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_RESOLVE (3)
Protocol:
  - HTTP
Added-in: 7.64.1
---
<!-- markdown-link-check-disable -->
# NAME

CURLOPT_ALTSVC - alt-svc cache filename

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
CURLOPT_ALTSVC_CTRL(3).

Specify a blank filename ("") to make libcurl not load from a file at all.

# DEFAULT

NULL. The alt-svc cache is not read nor written to file.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
CURLOPT_ALTSVC_CTRL(3).

Specify a blank filename ("") to make libcurl not load from a file at all.

# DEFAULT

NULL. The alt-svc cache is not read nor written to file.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
96
97
98
99
100
101
102
103
104
105
106
107
108
109

Boolean (1 or 0) if "persist" was set for this entry

## 0

Integer priority value (not currently used)

# AVAILABILITY

Added in 7.64.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




99
100
101
102
103
104
105
106


107
108
109
110

Boolean (1 or 0) if "persist" was set for this entry

## 0

Integer priority value (not currently used)

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ALTSVC_CTRL.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ALTSVC_CTRL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ALTSVC (3)
  - CURLOPT_CONNECT_TO (3)
  - CURLOPT_RESOLVE (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_ALTSVC_CTRL - control alt-svc behavior

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ALTSVC_CTRL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ALTSVC (3)
  - CURLOPT_CONNECT_TO (3)
  - CURLOPT_RESOLVE (3)
Protocol:
  - HTTP
Added-in: 7.64.1
---

# NAME

CURLOPT_ALTSVC_CTRL - control alt-svc behavior

# SYNOPSIS
38
39
40
41
42
43
44





45
46
47
48
49
50
51
HTTPS. It also only completes a request to an alternative origin if that
origin is properly hosted over HTTPS. These requirements are there to make
sure both the source and the destination are legitimate.

Alternative services are only used when setting up new connections. If there
exists an existing connection to the host in the connection pool, then that is
preferred.






Setting any bit enables the alt-svc engine.

## CURLALTSVC_READONLYFILE

Do not write the alt-svc cache back to the file specified with
CURLOPT_ALTSVC(3) even if it gets updated. By default a file specified







>
>
>
>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
HTTPS. It also only completes a request to an alternative origin if that
origin is properly hosted over HTTPS. These requirements are there to make
sure both the source and the destination are legitimate.

Alternative services are only used when setting up new connections. If there
exists an existing connection to the host in the connection pool, then that is
preferred.

If CURLOPT_ALTSVC(3) is set, CURLOPT_ALTSVC_CTRL(3) gets a default value
corresponding to CURLALTSVC_H1 | CURLALTSVC_H2 | CURLALTSVC_H3 - the HTTP/2
and HTTP/3 bits are only set if libcurl was built with support for those
versions.

Setting any bit enables the alt-svc engine.

## CURLALTSVC_READONLYFILE

Do not write the alt-svc cache back to the file specified with
CURLOPT_ALTSVC(3) even if it gets updated. By default a file specified
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
## CURLALTSVC_H3

Accept alternative services offered over HTTP/3. This is only used if libcurl
was also built to actually support HTTP/3, otherwise this bit is ignored.

# DEFAULT

Alt-Svc handling is disabled by default. If CURLOPT_ALTSVC(3) is set,
CURLOPT_ALTSVC_CTRL(3) has a default value corresponding to
CURLALTSVC_H1 | CURLALTSVC_H2 | CURLALTSVC_H3 - the HTTP/2 and HTTP/3 bits are
only set if libcurl was built with support for those versions.

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_ALTSVC_CTRL, (long)CURLALTSVC_H1);
    curl_easy_setopt(curl, CURLOPT_ALTSVC, "altsvc-cache.txt");
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.64.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
|
|
<















|
<
<




69
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94


95
96
97
98
## CURLALTSVC_H3

Accept alternative services offered over HTTP/3. This is only used if libcurl
was also built to actually support HTTP/3, otherwise this bit is ignored.

# DEFAULT

0 - Alt-Svc handling is disabled

# %PROTOCOLS%


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_ALTSVC_CTRL, (long)CURLALTSVC_H1);
    curl_easy_setopt(curl, CURLOPT_ALTSVC, "altsvc-cache.txt");
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_APPEND.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_APPEND
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DIRLISTONLY (3)
  - CURLOPT_RESUME_FROM (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_APPEND - append to the remote file

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_APPEND
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DIRLISTONLY (3)
  - CURLOPT_RESUME_FROM (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - FTP
Added-in: 7.17.0
---

# NAME

CURLOPT_APPEND - append to the remote file

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


56
57
58
59
A long parameter set to 1 tells the library to append to the remote file
instead of overwrite it. This is only useful when uploading to an FTP site.

# DEFAULT

0 (disabled)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {

    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/to/newfile");
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curl, CURLOPT_APPEND, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

This option was known as CURLOPT_FTPAPPEND up to 7.16.4



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|


>
>




30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
A long parameter set to 1 tells the library to append to the remote file
instead of overwrite it. This is only useful when uploading to an FTP site.

# DEFAULT

0 (disabled)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {

    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/to/newfile");
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curl, CURLOPT_APPEND, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

This option was known as CURLOPT_FTPAPPEND up to 7.16.4

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_AUTOREFERER.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_EFFECTIVE_URL (3)
  - CURLINFO_REDIRECT_URL (3)
  - CURLINFO_REFERER (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - CURLOPT_REFERER (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_AUTOREFERER - automatically update the referer header

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_EFFECTIVE_URL (3)
  - CURLINFO_REDIRECT_URL (3)
  - CURLINFO_REFERER (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - CURLOPT_REFERER (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_AUTOREFERER - automatically update the referer header

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
With CURLINFO_REFERER(3), applications can extract the actually used
referer header after the transfer.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
With CURLINFO_REFERER(3), applications can extract the actually used
referer header after the transfer.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




65
66
67
68
69
70
71
72


73
74
75
76
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_AWS_SIGV4.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_AWS_SIGV4
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADEROPT (3)
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_PROXYAUTH (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_AWS_SIGV4 - V4 signature

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_AWS_SIGV4
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADEROPT (3)
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_PROXYAUTH (3)
Protocol:
  - HTTP
Added-in: 7.75.0
---

# NAME

CURLOPT_AWS_SIGV4 - V4 signature

# SYNOPSIS
46
47
48
49
50
51
52


53
54
55
56
57
58
59
60
61
62
63
64



65
66
67
68
69

70
71
72
73
74
75
76
It is extracted from the hostname specified in the URL if omitted.

## service

The argument is a function provided by a cloud. It is extracted from the
hostname specified in the URL if omitted.



NOTE: This call set CURLOPT_HTTPAUTH(3) to CURLAUTH_AWS_SIGV4.
Calling CURLOPT_HTTPAUTH(3) with CURLAUTH_AWS_SIGV4 is the same
as calling this with **"aws:amz"** in parameter.

Example with "Test:Try", when curl uses the algorithm, it generates
**"TEST-HMAC-SHA256"** for "Algorithm", **"x-try-date"** and
**"X-Try-Date"** for "date", **"test4_request"** for "request type",
**"SignedHeaders=content-type;host;x-try-date"** for "signed headers"

If you use just "test", instead of "test:try", test is used for every
generated string.




# DEFAULT

By default, the value of this parameter is NULL.
Calling CURLOPT_HTTPAUTH(3) with CURLAUTH_AWS_SIGV4 is the same
as calling this with **"aws:amz"** in parameter.


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>
|
|
|


|
|





>
>
>


|
|
<
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80
81
82
It is extracted from the hostname specified in the URL if omitted.

## service

The argument is a function provided by a cloud. It is extracted from the
hostname specified in the URL if omitted.

##

NOTE: This call set CURLOPT_HTTPAUTH(3) to CURLAUTH_AWS_SIGV4. Calling
CURLOPT_HTTPAUTH(3) with CURLAUTH_AWS_SIGV4 is the same as calling this with
**"aws:amz"** in parameter.

Example with "Test:Try", when curl uses the algorithm, it generates
**"TEST-HMAC-SHA256"** for "Algorithm", **"x-try-date"** and **"X-Try-Date"**
for "date", **"test4_request"** for "request type",
**"SignedHeaders=content-type;host;x-try-date"** for "signed headers"

If you use just "test", instead of "test:try", test is used for every
generated string.

Setting CURLOPT_HTTPAUTH(3) with the CURLAUTH_AWS_SIGV4 bit set is the same as
setting this option with a **"aws:amz"** parameter.

# DEFAULT

NULL


# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116







    curl_easy_setopt(curl, CURLOPT_USERPWD, "MY_ACCESS_KEY:MY_SECRET_KEY");
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.75.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.

# NOTES

This option overrides the other auth types you might have set in
CURLOPT_HTTPAUTH(3) which should be highlighted as this makes this auth
method special. This method cannot be combined with other auth types.

A sha256 checksum of the request payload is used as input to the signature
calculation. For POST requests, this is a checksum of the provided
CURLOPT_POSTFIELDS(3). Otherwise, it is the checksum of an empty buffer. For
requests like PUT, you can provide your own checksum in an HTTP header named
**x-provider2-content-sha256**.

For **aws:s3**, a **x-amz-content-sha256** header is added to every request
if not already present. For s3 requests with unknown payload, this header takes
the special value "UNSIGNED-PAYLOAD".













<
<
<
<
<
<
<
<



|
|







|
|

>
>
>
>
>
>
93
94
95
96
97
98
99








100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

    curl_easy_setopt(curl, CURLOPT_USERPWD, "MY_ACCESS_KEY:MY_SECRET_KEY");
    curl_easy_perform(curl);
  }
}
~~~









# NOTES

This option overrides the other auth types you might have set in
CURLOPT_HTTPAUTH(3) which should be highlighted as this makes this auth method
special. This method cannot be combined with other auth types.

A sha256 checksum of the request payload is used as input to the signature
calculation. For POST requests, this is a checksum of the provided
CURLOPT_POSTFIELDS(3). Otherwise, it is the checksum of an empty buffer. For
requests like PUT, you can provide your own checksum in an HTTP header named
**x-provider2-content-sha256**.

For **aws:s3**, a **x-amz-content-sha256** header is added to every request if
not already present. For s3 requests with unknown payload, this header takes
the special value "UNSIGNED-PAYLOAD".

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_BUFFERSIZE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_BUFFERSIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAXFILESIZE (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_UPLOAD_BUFFERSIZE (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_BUFFERSIZE - receive buffer size

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_BUFFERSIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAXFILESIZE (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_UPLOAD_BUFFERSIZE (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - All
Added-in: 7.10
---

# NAME

CURLOPT_BUFFERSIZE - receive buffer size

# SYNOPSIS
49
50
51
52
53
54
55


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
handle no matter how many parallel transfers there are. The buffer remains
allocated as long as there are active transfers.

# DEFAULT

CURL_MAX_WRITE_SIZE (16kB)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/foo.bin");

    /* ask libcurl to allocate a larger receive buffer */
    curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 120000L);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10. Growing the buffer was added in 7.53.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<




50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79


80
81
82
83
handle no matter how many parallel transfers there are. The buffer remains
allocated as long as there are active transfers.

# DEFAULT

CURL_MAX_WRITE_SIZE (16kB)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/foo.bin");

    /* ask libcurl to allocate a larger receive buffer */
    curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, 120000L);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CAINFO.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - CURLOPT_CA_CACHE_TIMEOUT (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_CAINFO - path to Certificate Authority (CA) bundle

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - CURLOPT_CA_CACHE_TIMEOUT (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.4.2
---

# NAME

CURLOPT_CAINFO - path to Certificate Authority (CA) bundle

# SYNOPSIS
56
57
58
59
60
61
62


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80


81
82
83
84
85
The default value for this can be figured out with CURLINFO_CAINFO(3).

# DEFAULT

Built-in system specific. When curl is built with Secure Transport or
Schannel, this option is not set by default.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/certs/cabundle.pem");
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Schannel support added in libcurl 7.60.



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>















|


>
>





57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
The default value for this can be figured out with CURLINFO_CAINFO(3).

# DEFAULT

Built-in system specific. When curl is built with Secure Transport or
Schannel, this option is not set by default.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_CAINFO, "/etc/certs/cabundle.pem");
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Schannel support added in libcurl 7.60.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CAINFO_BLOB.md.
15
16
17
18
19
20
21

22
23
24
25
26
27
28
  - BearSSL
  - OpenSSL
  - mbedTLS
  - rustls
  - wolfSSL
  - Secure Transport
  - Schannel

---

# NAME

CURLOPT_CAINFO_BLOB - Certificate Authority (CA) bundle in PEM format

# SYNOPSIS







>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  - BearSSL
  - OpenSSL
  - mbedTLS
  - rustls
  - wolfSSL
  - Secure Transport
  - Schannel
Added-in: 7.77.0
---

# NAME

CURLOPT_CAINFO_BLOB - Certificate Authority (CA) bundle in PEM format

# SYNOPSIS
49
50
51
52
53
54
55


56
57
58
59
60
61
62

This option overrides CURLOPT_CAINFO(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
#include <string.h>

int main(void)
{







>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

This option overrides CURLOPT_CAINFO(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h>

int main(void)
{
72
73
74
75
76
77
78
79
80
81
82
83
84
85


86
87
88
89
90
    curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.77.0.

This option is supported by the BearSSL (since 7.79.0), mbedTLS (since
7.81.0), rustls (since 7.82.0), wolfSSL (since 8.2.0), OpenSSL, Secure
Transport and Schannel backends.



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







<
|
<




>
>





75
76
77
78
79
80
81

82

83
84
85
86
87
88
89
90
91
92
93
    curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~


# HISTORY


This option is supported by the BearSSL (since 7.79.0), mbedTLS (since
7.81.0), rustls (since 7.82.0), wolfSSL (since 8.2.0), OpenSSL, Secure
Transport and Schannel backends.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CAPATH.md.
12
13
14
15
16
17
18

19
20
21
22
23
24
25
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - wolfSSL

---

# NAME

CURLOPT_CAPATH - directory holding CA certificates

# SYNOPSIS







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - wolfSSL
Added-in: 7.9.8
---

# NAME

CURLOPT_CAPATH - directory holding CA certificates

# SYNOPSIS
44
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
The application does not have to keep the string around after setting this
option.

The default value for this can be figured out with CURLINFO_CAPATH(3).

# DEFAULT

A default path detected at build time.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_CAPATH, "/etc/cert-dir");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option is supported by the OpenSSL, GnuTLS, mbedTLS and wolfSSL backends.

# RETURN VALUE

CURLE_OK if supported; or an error such as:

CURLE_NOT_BUILT_IN - Not supported by the SSL backend

CURLE_UNKNOWN_OPTION

CURLE_OUT_OF_MEMORY







|
>
>

















|
<
<










45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
77
78
79
80
81
82
The application does not have to keep the string around after setting this
option.

The default value for this can be figured out with CURLINFO_CAPATH(3).

# DEFAULT

A path detected at build time.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_CAPATH, "/etc/cert-dir");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK if supported; or an error such as:

CURLE_NOT_BUILT_IN - Not supported by the SSL backend

CURLE_UNKNOWN_OPTION

CURLE_OUT_OF_MEMORY
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CA_CACHE_TIMEOUT.md.
9
10
11
12
13
14
15

16



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

44
45
46
47


48
49
50
51
52
53
54
  - CURLOPT_CAINFO_BLOB (3)
  - CURLOPT_CAPATH (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:

  - OpenSSL



---

# NAME

CURLOPT_CA_CACHE_TIMEOUT - life-time for cached certificate stores

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CA_CACHE_TIMEOUT, long age);
~~~

# DESCRIPTION

Pass a long, this sets the timeout in seconds. This tells libcurl the maximum
time any cached certificate store it has in memory may be kept and reused for
new connections. Once the timeout has expired, a subsequent fetch requiring a
certificate has to reload it.

Building a certificate store from a CURLOPT_CAINFO(3) file is a slow
operation so curl may cache the generated certificate store internally to speed
up future connections.

Set to zero to completely disable caching, or set to -1 to retain the cached
store remain forever. By default, libcurl caches this info for 24 hours.


# DEFAULT

86400 (24 hours)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>

>
>
>

















|
|
|

|
|
|

|
|
>




>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  - CURLOPT_CAINFO_BLOB (3)
  - CURLOPT_CAPATH (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - GnuTLS
  - OpenSSL
  - Schannel
  - wolfSSL
Added-in: 7.87.0
---

# NAME

CURLOPT_CA_CACHE_TIMEOUT - life-time for cached certificate stores

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CA_CACHE_TIMEOUT, long age);
~~~

# DESCRIPTION

Pass a long, this sets the timeout in seconds. This tells libcurl the maximum
time any cached CA certificate store it has in memory may be kept and reused
for new connections. Once the timeout has expired, a subsequent fetch
requiring a CA certificate has to reload it.

Building a CA certificate store from a CURLOPT_CAINFO(3) file is a slow
operation so curl may cache the generated certificate store internally to
speed up future connections.

Set the timeout to zero to completely disable caching, or set to -1 to retain
the cached store remain forever. By default, libcurl caches this info for 24
hours.

# DEFAULT

86400 (24 hours)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
66
67
68
69
70
71
72
73
74
75
76
77
78


79
80
81
82
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option was added in curl 7.87.0.

This option is supported by OpenSSL and its forks (since 7.87.0) and Schannel
(since 8.5.0).



# RETURN VALUE

Returns CURLE_OK







<
|
<

|
|
>
>




73
74
75
76
77
78
79

80

81
82
83
84
85
86
87
88
89
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~


# HISTORY


This option is supported by OpenSSL and its forks (since 7.87.0), Schannel
(since 8.5.0), wolfSSL (since 8.9.0) and GnuTLS (since 8.9.0).

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CERTINFO.md.
13
14
15
16
17
18
19

20
21
22
23
24
25
26
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - Schannel
  - Secure Transport

---

# NAME

CURLOPT_CERTINFO - request SSL certificate information

# SYNOPSIS







>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - Schannel
  - Secure Transport
Added-in: 7.19.1
---

# NAME

CURLOPT_CERTINFO - request SSL certificate information

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
certificates in the certificate chain used in the SSL connection. This data
may then be retrieved after a transfer using curl_easy_getinfo(3) and
its option CURLINFO_CERTINFO(3).

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
certificates in the certificate chain used in the SSL connection. This data
may then be retrieved after a transfer using curl_easy_getinfo(3) and
its option CURLINFO_CERTINFO(3).

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
78
79
80
81
82
83
84
85
86
87



88
89
90
91
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Schannel support added in 7.50.0. Secure Transport support added in 7.79.0.




# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|


>
>
>




81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
      }
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Schannel support added in 7.50.0. Secure Transport support added in 7.79.0.
mbedTLS support added in 8.9.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CHUNK_BGN_FUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CHUNK_BGN_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CHUNK_END_FUNCTION (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_CHUNK_BGN_FUNCTION - callback before a transfer with FTP wildcard match

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CHUNK_BGN_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CHUNK_END_FUNCTION (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP
Added-in: 7.21.0
---

# NAME

CURLOPT_CHUNK_BGN_FUNCTION - callback before a transfer with FTP wildcard match

# SYNOPSIS
79
80
81
82
83
84
85


86
87
88
89
90
91
92
*CURL_CHUNK_BGN_FUNC_SKIP* if you want to skip the concrete chunk or
*CURL_CHUNK_BGN_FUNC_FAIL* to tell libcurl to stop if some error occurred.

# DEFAULT

NULL



# EXAMPLE

~~~c
#include <stdio.h>

struct callback_data {
   FILE *output;







>
>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
*CURL_CHUNK_BGN_FUNC_SKIP* if you want to skip the concrete chunk or
*CURL_CHUNK_BGN_FUNC_FAIL* to tell libcurl to stop if some error occurred.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <stdio.h>

struct callback_data {
   FILE *output;
137
138
139
140
141
142
143
144
145
146
147
148
149
150

  /* callback is called before download of concrete file started */
  curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming);
  curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info);
}
~~~

# AVAILABILITY

This was added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




140
141
142
143
144
145
146
147


148
149
150
151

  /* callback is called before download of concrete file started */
  curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming);
  curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CHUNK_DATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CHUNK_DATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CHUNK_BGN_FUNCTION (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_CHUNK_DATA - pointer passed to the FTP chunk callbacks

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CHUNK_DATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CHUNK_BGN_FUNCTION (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP
Added-in: 7.21.0
---

# NAME

CURLOPT_CHUNK_DATA - pointer passed to the FTP chunk callbacks

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41
Pass a *pointer* that is untouched by libcurl and passed as the ptr
argument to the CURLOPT_CHUNK_BGN_FUNCTION(3) and
CURLOPT_CHUNK_END_FUNCTION(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
#include <stdio.h>

struct callback_data {







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Pass a *pointer* that is untouched by libcurl and passed as the ptr
argument to the CURLOPT_CHUNK_BGN_FUNCTION(3) and
CURLOPT_CHUNK_END_FUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <stdio.h>

struct callback_data {
87
88
89
90
91
92
93
94
95
96
97
98
99
100

  /* callback is called before download of concrete file started */
  curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming);
  curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info);
}
~~~

# AVAILABILITY

Added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




90
91
92
93
94
95
96
97


98
99
100
101

  /* callback is called before download of concrete file started */
  curl_easy_setopt(curl, CURLOPT_CHUNK_BGN_FUNCTION, file_is_coming);
  curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CHUNK_END_FUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CHUNK_END_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CHUNK_BGN_FUNCTION (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_CHUNK_END_FUNCTION - callback after a transfer with FTP wildcard match

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CHUNK_END_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CHUNK_BGN_FUNCTION (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP
Added-in: 7.21.0
---

# NAME

CURLOPT_CHUNK_END_FUNCTION - callback after a transfer with FTP wildcard match

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
Return *CURL_CHUNK_END_FUNC_OK* if everything is fine or
**CURL_CHUNK_END_FUNC_FAIL** to tell the lib to stop if some error occurred.

# DEFAULT

NULL



# EXAMPLE

~~~c
#include <stdio.h>

struct callback_data {
   FILE *output;







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Return *CURL_CHUNK_END_FUNC_OK* if everything is fine or
**CURL_CHUNK_END_FUNC_FAIL** to tell the lib to stop if some error occurred.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <stdio.h>

struct callback_data {
   FILE *output;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  CURL *curl = curl_easy_init();

  curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded);
  curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info);
}
~~~

# AVAILABILITY

Added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




70
71
72
73
74
75
76
77


78
79
80
81
  CURL *curl = curl_easy_init();

  curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, file_is_downloaded);
  curl_easy_setopt(curl, CURLOPT_CHUNK_DATA, &callback_info);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CLOSESOCKETDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CLOSESOCKETFUNCTION (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_CLOSESOCKETDATA - pointer passed to the socket close callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CLOSESOCKETDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CLOSESOCKETFUNCTION (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
Protocol:
  - All
Added-in: 7.21.7
---

# NAME

CURLOPT_CLOSESOCKETDATA - pointer passed to the socket close callback

# SYNOPSIS
28
29
30
31
32
33
34

35

36
37
38
39
40
41
42

Pass a *pointer* that remains untouched by libcurl and passed as the first
argument in the closesocket callback set with
CURLOPT_CLOSESOCKETFUNCTION(3).

# DEFAULT


The default value of this parameter is NULL.


# EXAMPLE

~~~c
struct priv {
  void *custom;
};







>
|
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Pass a *pointer* that remains untouched by libcurl and passed as the first
argument in the closesocket callback set with
CURLOPT_CLOSESOCKETFUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *custom;
};
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &myown);

  curl_easy_perform(curl);
  curl_easy_cleanup(curl);
}
~~~

# AVAILABILITY

Added in 7.21.7

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




63
64
65
66
67
68
69
70


71
72
73
74
  curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &myown);

  curl_easy_perform(curl);
  curl_easy_cleanup(curl);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CLOSESOCKETFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CLOSESOCKETFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CLOSESOCKETDATA (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_CLOSESOCKETFUNCTION - callback to socket close replacement

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CLOSESOCKETFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CLOSESOCKETDATA (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
Protocol:
  - All
Added-in: 7.21.7
---

# NAME

CURLOPT_CLOSESOCKETFUNCTION - callback to socket close replacement

# SYNOPSIS
39
40
41
42
43
44
45
46


47
48
49
50
51
52
53

The *clientp* pointer is set with
CURLOPT_CLOSESOCKETDATA(3). *item* is the socket libcurl wants to be
closed.

# DEFAULT

By default libcurl uses the standard socket close function.



# EXAMPLE

~~~c
struct priv {
  void *custom;
};







|
>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

The *clientp* pointer is set with
CURLOPT_CLOSESOCKETDATA(3). *item* is the socket libcurl wants to be
closed.

# DEFAULT

Use the standard socket close function.

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *custom;
};
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &myown);

  curl_easy_perform(curl);
  curl_easy_cleanup(curl);
}
~~~

# AVAILABILITY

Added in 7.21.7

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




74
75
76
77
78
79
80
81


82
83
84
85
  curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &myown);

  curl_easy_perform(curl);
  curl_easy_cleanup(curl);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONNECTTIMEOUT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECTTIMEOUT_MS (3)
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_CONNECTTIMEOUT - timeout for the connect phase

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT, long timeout);
~~~

# DESCRIPTION

Pass a long. It should contain the maximum time in seconds that you allow the
connection phase to the server to take. This timeout only limits the



connection phase, it has no impact once it has connected. Set to zero to
switch to the default built-in connection timeout - 300 seconds. See also the
CURLOPT_TIMEOUT(3) option.

CURLOPT_CONNECTTIMEOUT_MS(3) is the same function but set in milliseconds.

If both CURLOPT_CONNECTTIMEOUT(3) and CURLOPT_CONNECTTIMEOUT_MS(3)
are set, the value set last is used.

The "connection phase" is considered complete when the requested TCP, TLS or
QUIC handshakes are done.

The connection timeout set with CURLOPT_CONNECTTIMEOUT(3) is included in
the general all-covering CURLOPT_TIMEOUT(3).

With CURLOPT_CONNECTTIMEOUT(3) set to 3 and CURLOPT_TIMEOUT(3) set
to 5, the operation can never last longer than 5 seconds, and the connection
phase cannot last longer than 3 seconds.

With CURLOPT_CONNECTTIMEOUT(3) set to 4 and CURLOPT_TIMEOUT(3) set
to 2, the operation can never last longer than 2 seconds. Including the
connection phase.

This option may cause libcurl to use the SIGALRM signal to timeout system
calls on builds not using asynch DNS. In unix-like systems, this might cause
signals to be used unless CURLOPT_NOSIGNAL(3) is set.

# DEFAULT

300



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* complete connection within 10 seconds */
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK. Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative
value or a value that when converted to milliseconds is too large.







<





>
















|
|
>
>
>
|
|
|






<
<
<
|
|
















>
>


















|
<
<





1
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82


83
84
85
86
87
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONNECTTIMEOUT
Section: 3
Source: libcurl
See-also:

  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All
Added-in: 7.7
---

# NAME

CURLOPT_CONNECTTIMEOUT - timeout for the connect phase

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT, long timeout);
~~~

# DESCRIPTION

Pass a long. It sets the maximum time in seconds that you allow the connection
phase to take. This timeout only limits the connection phase, it has no impact
once libcurl has connected. The connection phase includes the name resolve
(DNS) and all protocol handshakes and negotiations until there is an
established connection with the remote side.

Set this option to zero to switch to the default built-in connection timeout -
300 seconds. See also the CURLOPT_TIMEOUT(3) option.

CURLOPT_CONNECTTIMEOUT_MS(3) is the same function but set in milliseconds.

If both CURLOPT_CONNECTTIMEOUT(3) and CURLOPT_CONNECTTIMEOUT_MS(3)
are set, the value set last is used.




The connection timeout is included in the general all-covering
CURLOPT_TIMEOUT(3):

With CURLOPT_CONNECTTIMEOUT(3) set to 3 and CURLOPT_TIMEOUT(3) set
to 5, the operation can never last longer than 5 seconds, and the connection
phase cannot last longer than 3 seconds.

With CURLOPT_CONNECTTIMEOUT(3) set to 4 and CURLOPT_TIMEOUT(3) set
to 2, the operation can never last longer than 2 seconds. Including the
connection phase.

This option may cause libcurl to use the SIGALRM signal to timeout system
calls on builds not using asynch DNS. In unix-like systems, this might cause
signals to be used unless CURLOPT_NOSIGNAL(3) is set.

# DEFAULT

300

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* complete connection within 10 seconds */
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK. Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative
value or a value that when converted to milliseconds is too large.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CONNECTTIMEOUT_MS.md.
1
2
3
4
5
6
7
8
9

10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30






















31
32


33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONNECTTIMEOUT_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECTTIMEOUT (3)
  - CURLOPT_LOW_SPEED_LIMIT (3)

  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_CONNECTTIMEOUT_MS - timeout for the connect phase

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT_MS,
                          long timeout);
~~~

# DESCRIPTION

Pass a long. It should contain the maximum time in milliseconds that you allow






















the connection phase to the server to take.



See CURLOPT_CONNECTTIMEOUT(3) for details.

# DEFAULT

300000



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* complete connection within 10000 milliseconds */
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 10000L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







<

>
|


>

















|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

>
>
|




>
>


















|
<
<




1
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83


84
85
86
87
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONNECTTIMEOUT_MS
Section: 3
Source: libcurl
See-also:

  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_TIMEOUT_MS (3)
Protocol:
  - All
Added-in: 7.16.2
---

# NAME

CURLOPT_CONNECTTIMEOUT_MS - timeout for the connect phase

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CONNECTTIMEOUT_MS,
                          long timeout);
~~~

# DESCRIPTION

Pass a long. It sets the maximum time in milliseconds that you allow the
connection phase to take. This timeout only limits the connection phase, it
has no impact once libcurl has connected. The connection phase includes the
name resolve (DNS) and all protocol handshakes and negotiations until there is
an established connection with the remote side.

Set this option to zero to switch to the default built-in connection timeout -
300 seconds. See also the CURLOPT_TIMEOUT_MS(3) option.

CURLOPT_CONNECTTIMEOUT(3) is the same function but set in seconds.

If both CURLOPT_CONNECTTIMEOUT(3) and CURLOPT_CONNECTTIMEOUT_MS(3) are set,
the value set last is used.

The connection timeout is included in the general all-covering
CURLOPT_TIMEOUT_MS(3):

With CURLOPT_CONNECTTIMEOUT_MS(3) set to 3000 and CURLOPT_TIMEOUT_MS(3) set to
5000, the operation can never last longer than 5000 milliseconds, and the
connection phase cannot last longer than 3000 milliseconds.

With CURLOPT_CONNECTTIMEOUT_MS(3) set to 4000 and CURLOPT_TIMEOUT_MS(3) set to
2000, the operation can never last longer than 2000 milliseconds. Including
the connection phase.

This option may cause libcurl to use the SIGALRM signal to timeout system
calls on builds not using asynch DNS. In unix-like systems, this might cause
signals to be used unless CURLOPT_NOSIGNAL(3) is set.

# DEFAULT

300000

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* complete connection within 10000 milliseconds */
    curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, 10000L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CONNECT_ONLY.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONNECT_ONLY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_VERBOSE (3)
  - curl_easy_recv (3)
  - curl_easy_send (3)
Protocol:
  - All

---

# NAME

CURLOPT_CONNECT_ONLY - stop when connected to target server

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONNECT_ONLY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_VERBOSE (3)
  - curl_easy_recv (3)
  - curl_easy_send (3)
Protocol:
  - All
Added-in: 7.15.2
---

# NAME

CURLOPT_CONNECT_ONLY - stop when connected to target server

# SYNOPSIS
50
51
52
53
54
55
56


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77


78
79
80
81
curl_multi_remove_handle(3), curl_easy_send(3) and
curl_easy_recv(3) do not function.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
    ret = curl_easy_perform(curl);
    if(ret == CURLE_OK) {
      /* only connected! */
    }
  }
}
~~~

# AVAILABILITY

Added in 7.15.2. WS and WSS support added in 7.86.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|

|
>
>




51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
curl_multi_remove_handle(3), curl_easy_send(3) and
curl_easy_recv(3) do not function.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
    ret = curl_easy_perform(curl);
    if(ret == CURLE_OK) {
      /* only connected! */
    }
  }
}
~~~

# HISTORY

WS and WSS support added in 7.86.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CONNECT_TO.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONNECT_TO
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FOLLOWLOCATION (3)
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_RESOLVE (3)
  - CURLOPT_URL (3)
Protocol:
  - All

---

# NAME

CURLOPT_CONNECT_TO - connect to another host and port instead

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONNECT_TO
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FOLLOWLOCATION (3)
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_RESOLVE (3)
  - CURLOPT_URL (3)
Protocol:
  - All
Added-in: 7.49.0
---

# NAME

CURLOPT_CONNECT_TO - connect to another host and port instead

# SYNOPSIS
75
76
77
78
79
80
81


82
83
84
85
86
87
88
list so you **must** keep it around until you no longer use this *handle* for
a transfer before you call curl_slist_free_all(3) on the list.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl;
  struct curl_slist *connect_to = NULL;







>
>







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
list so you **must** keep it around until you no longer use this *handle* for
a transfer before you call curl_slist_free_all(3) on the list.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl;
  struct curl_slist *connect_to = NULL;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    curl_easy_cleanup(curl);
  }

  curl_slist_free_all(connect_to);
}
~~~

# AVAILABILITY

Added in 7.49.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




102
103
104
105
106
107
108
109


110
111
112
113
    curl_easy_cleanup(curl);
  }

  curl_slist_free_all(connect_to);
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_NETWORK_FUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONV_FROM_NETWORK_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONV_FROM_UTF8_FUNCTION (3)
  - CURLOPT_CONV_TO_NETWORK_FUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_CONV_FROM_NETWORK_FUNCTION - convert data from network to host encoding

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONV_FROM_NETWORK_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONV_FROM_UTF8_FUNCTION (3)
  - CURLOPT_CONV_TO_NETWORK_FUNCTION (3)
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

CURLOPT_CONV_FROM_NETWORK_FUNCTION - convert data from network to host encoding

# SYNOPSIS
68
69
70
71
72
73
74


75
76
77
78
79
80
81

You need to override these definitions if they are different on your system.

# DEFAULT

NULL



# EXAMPLE

~~~c
static CURLcode my_conv_from_ascii_to_ebcdic(char *buffer, size_t length)
{
  int rc = 0;








>
>







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

You need to override these definitions if they are different on your system.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
static CURLcode my_conv_from_ascii_to_ebcdic(char *buffer, size_t length)
{
  int rc = 0;

96
97
98
99
100
101
102
103
104
105
106
107
108


109
110
111
112

  /* use platform-specific functions for codeset conversions */
  curl_easy_setopt(curl, CURLOPT_CONV_FROM_NETWORK_FUNCTION,
                   my_conv_from_ascii_to_ebcdic);
}
~~~

# AVAILABILITY

Not available and deprecated since 7.82.0.

Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was
built.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|





>
>




99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

  /* use platform-specific functions for codeset conversions */
  curl_easy_setopt(curl, CURLOPT_CONV_FROM_NETWORK_FUNCTION,
                   my_conv_from_ascii_to_ebcdic);
}
~~~

# DEPRECATED

Not available and deprecated since 7.82.0.

Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was
built.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CONV_FROM_UTF8_FUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONV_FROM_UTF8_FUNCTION
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3)
  - CURLOPT_CONV_TO_NETWORK_FUNCTION (3)

---

# NAME

CURLOPT_CONV_FROM_UTF8_FUNCTION - convert data from UTF8 to host encoding

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONV_FROM_UTF8_FUNCTION
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3)
  - CURLOPT_CONV_TO_NETWORK_FUNCTION (3)
Added-in: 7.15.4
---

# NAME

CURLOPT_CONV_FROM_UTF8_FUNCTION - convert data from UTF8 to host encoding

# SYNOPSIS
65
66
67
68
69
70
71


72
73
74
75
76
77
78

You need to override these definitions if they are different on your system.

# DEFAULT

NULL



# EXAMPLE

~~~c
static CURLcode my_conv_from_utf8_to_ebcdic(char *buffer, size_t length)
{
  int rc = 0;
  /* in-place convert 'buffer' from UTF-8 to EBCDIC */







>
>







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

You need to override these definitions if they are different on your system.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
static CURLcode my_conv_from_utf8_to_ebcdic(char *buffer, size_t length)
{
  int rc = 0;
  /* in-place convert 'buffer' from UTF-8 to EBCDIC */
89
90
91
92
93
94
95
96
97
98
99
100
101


102
103
104
105
{
  CURL *curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_CONV_FROM_UTF8_FUNCTION,
                   my_conv_from_utf8_to_ebcdic);
}
~~~

# AVAILABILITY

Not available and deprecated since 7.82.0.

Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was
built.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|





>
>




92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
{
  CURL *curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_CONV_FROM_UTF8_FUNCTION,
                   my_conv_from_utf8_to_ebcdic);
}
~~~

# DEPRECATED

Not available and deprecated since 7.82.0.

Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was
built.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CONV_TO_NETWORK_FUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONV_TO_NETWORK_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3)
  - CURLOPT_CONV_FROM_UTF8_FUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_CONV_TO_NETWORK_FUNCTION - convert data to network from host encoding

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CONV_TO_NETWORK_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3)
  - CURLOPT_CONV_FROM_UTF8_FUNCTION (3)
Protocol:
  - All
Added-in: 7.15.4
---

# NAME

CURLOPT_CONV_TO_NETWORK_FUNCTION - convert data to network from host encoding

# SYNOPSIS
67
68
69
70
71
72
73


74
75
76
77
78
79
80

You need to override these definitions if they are different on your system.

# DEFAULT

NULL



# EXAMPLE

~~~c
static CURLcode my_conv_from_ebcdic_to_ascii(char *buffer, size_t length)
{
  int rc = 0;
  /* in-place convert 'buffer' from EBCDIC to ASCII */







>
>







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

You need to override these definitions if they are different on your system.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
static CURLcode my_conv_from_ebcdic_to_ascii(char *buffer, size_t length)
{
  int rc = 0;
  /* in-place convert 'buffer' from EBCDIC to ASCII */
92
93
94
95
96
97
98
99
100
101
102
103
104


105
106
107
108
  CURL *curl = curl_easy_init();

  curl_easy_setopt(curl, CURLOPT_CONV_TO_NETWORK_FUNCTION,
                   my_conv_from_ebcdic_to_ascii);
}
~~~

# AVAILABILITY

Not available and deprecated since 7.82.0.

Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was
built.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|





>
>




95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  CURL *curl = curl_easy_init();

  curl_easy_setopt(curl, CURLOPT_CONV_TO_NETWORK_FUNCTION,
                   my_conv_from_ebcdic_to_ascii);
}
~~~

# DEPRECATED

Not available and deprecated since 7.82.0.

Available only if **CURL_DOES_CONVERSIONS** was defined when libcurl was
built.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_COOKIE.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_COOKIELIST (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_COOKIEJAR (3)
  - CURLOPT_COOKIELIST (3)
  - CURLOPT_HTTPHEADER (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_COOKIE - HTTP Cookie header

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_COOKIELIST (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_COOKIEJAR (3)
  - CURLOPT_COOKIELIST (3)
  - CURLOPT_HTTPHEADER (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_COOKIE - HTTP Cookie header

# SYNOPSIS
65
66
67
68
69
70
71


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
ability to stop super cookies. PSL support is identified by the
**CURL_VERSION_PSL** feature bit returned by curl_version_info(3).

# DEFAULT

NULL, no cookies



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_COOKIE, "tool=curl; fun=yes;");

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

If HTTP is enabled

# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|
<
<





66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91


92
93
94
95
96
ability to stop super cookies. PSL support is identified by the
**CURL_VERSION_PSL** feature bit returned by curl_version_info(3).

# DEFAULT

NULL, no cookies

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_COOKIE, "tool=curl; fun=yes;");

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_COOKIEFILE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COOKIEFILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIE (3)
  - CURLOPT_COOKIEJAR (3)
  - CURLOPT_COOKIESESSION (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_COOKIEFILE - filename to read cookies from

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COOKIEFILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIE (3)
  - CURLOPT_COOKIEJAR (3)
  - CURLOPT_COOKIESESSION (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_COOKIEFILE - filename to read cookies from

# SYNOPSIS
63
64
65
66
67
68
69


70
71
72
73
74
75
76
method as it is too hard to be sure that files that stay that way in the long
run.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
method as it is too hard to be sure that files that stay that way in the long
run.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
88
89
90
91
92
93
94
95
96
97
98
99
100
101
~~~

# Cookie file format

The cookie file format and general cookie concepts in curl are described
online here: https://curl.se/docs/http-cookies.html

# AVAILABILITY

As long as HTTP is supported

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




91
92
93
94
95
96
97
98


99
100
101
102
~~~

# Cookie file format

The cookie file format and general cookie concepts in curl are described
online here: https://curl.se/docs/http-cookies.html

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_COOKIEJAR.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COOKIEJAR
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIE (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_COOKIELIST (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_COOKIEJAR - filename to store cookies to

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COOKIEJAR
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIE (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_COOKIELIST (3)
Protocol:
  - HTTP
Added-in: 7.9
---

# NAME

CURLOPT_COOKIEJAR - filename to store cookies to

# SYNOPSIS
49
50
51
52
53
54
55


56
57
58
59
60
61
62
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

    /* close the handle, write the cookies! */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<





73
74
75
76
77
78
79
80


81
82
83
84
85

    /* close the handle, write the cookies! */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_COOKIELIST.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COOKIELIST
Section: 3
Source: libcurl
See-also:
  - CURLINFO_COOKIELIST (3)
  - CURLOPT_COOKIE (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_COOKIEJAR (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_COOKIELIST - add to or manipulate cookies held in memory

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COOKIELIST
Section: 3
Source: libcurl
See-also:
  - CURLINFO_COOKIELIST (3)
  - CURLOPT_COOKIE (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_COOKIEJAR (3)
Protocol:
  - HTTP
Added-in: 7.14.1
---

# NAME

CURLOPT_COOKIELIST - add to or manipulate cookies held in memory

# SYNOPSIS
65
66
67
68
69
70
71


72
73
74
75
76
77
78

loads all cookies from the files specified by CURLOPT_COOKIEFILE(3)

# DEFAULT

NULL



# EXAMPLE

~~~c
/* an inline import of a cookie in Netscape format. */

#define SEP  "\t"  /* Tab separates the fields */








>
>







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

loads all cookies from the files specified by CURLOPT_COOKIEFILE(3)

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
/* an inline import of a cookie in Netscape format. */

#define SEP  "\t"  /* Tab separates the fields */

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129


130
131
132
133
134
~~~

# Cookie file format

The cookie file format and general cookie concepts in curl are described
online here: https://curl.se/docs/http-cookies.html

# AVAILABILITY

**ALL** was added in 7.14.1

**SESS** was added in 7.15.4

**FLUSH** was added in 7.17.1

**RELOAD** was added in 7.39.0



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|








>
>





117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
~~~

# Cookie file format

The cookie file format and general cookie concepts in curl are described
online here: https://curl.se/docs/http-cookies.html

# HISTORY

**ALL** was added in 7.14.1

**SESS** was added in 7.15.4

**FLUSH** was added in 7.17.1

**RELOAD** was added in 7.39.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_COOKIESESSION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COOKIESESSION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIE (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_COOKIEJAR (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_COOKIESESSION - start a new cookie session

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COOKIESESSION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIE (3)
  - CURLOPT_COOKIEFILE (3)
  - CURLOPT_COOKIEJAR (3)
Protocol:
  - HTTP
Added-in: 7.9.7
---

# NAME

CURLOPT_COOKIESESSION - start a new cookie session

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
tell it when a new session starts, otherwise it assumes everything is still in
the same session.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
tell it when a new session starts, otherwise it assumes everything is still in
the same session.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK







|
<
<




63
64
65
66
67
68
69
70


71
72
73
74
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_COPYPOSTFIELDS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COPYPOSTFIELDS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_POSTFIELDSIZE (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_COPYPOSTFIELDS - have libcurl copy data to POST

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_COPYPOSTFIELDS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_POSTFIELDSIZE (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - HTTP
Added-in: 7.17.1
---

# NAME

CURLOPT_COPYPOSTFIELDS - have libcurl copy data to POST

# SYNOPSIS
41
42
43
44
45
46
47


48
49
50
51
52
53
54
CURLOPT_COPYPOSTFIELDS(3), unless another CURLOPT_POSTFIELDS(3) or
CURLOPT_COPYPOSTFIELDS(3) option is issued.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
CURLOPT_COPYPOSTFIELDS(3), unless another CURLOPT_POSTFIELDS(3) or
CURLOPT_COPYPOSTFIELDS(3) option is issued.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, local_buffer);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.17.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<





65
66
67
68
69
70
71
72


73
74
75
76
77
    curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, local_buffer);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CRLF.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CRLF
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3)
  - CURLOPT_CONV_TO_NETWORK_FUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_CRLF - CRLF conversion

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_CRLF
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONV_FROM_NETWORK_FUNCTION (3)
  - CURLOPT_CONV_TO_NETWORK_FUNCTION (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_CRLF - CRLF conversion

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

This is a legacy option of questionable use.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/");
    curl_easy_setopt(curl, CURLOPT_CRLF, 1L);
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

SMTP since 7.40.0, other protocols since they were introduced

# RETURN VALUE

Returns CURLE_OK







>
>
















|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61

This is a legacy option of questionable use.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/");
    curl_easy_setopt(curl, CURLOPT_CRLF, 1L);
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CRLFILE.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - GnuTLS
  - mbedTLS
  - OpenSSL

---

# NAME

CURLOPT_CRLFILE - Certificate Revocation List file

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - GnuTLS
  - mbedTLS
  - OpenSSL
Added-in: 7.19.0
---

# NAME

CURLOPT_CRLFILE - Certificate Revocation List file

# SYNOPSIS
54
55
56
57
58
59
60


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_CRLFILE, "/etc/certs/crl.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|
<
<





55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80


81
82
83
84
85
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_CRLFILE, "/etc/certs/crl.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CURLU.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_set (3)
  - curl_url_strerror (3)
Protocol:
  - All

---

# NAME

CURLOPT_CURLU - URL in URL handle format

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - curl_url_cleanup (3)
  - curl_url_dup (3)
  - curl_url_get (3)
  - curl_url_set (3)
  - curl_url_strerror (3)
Protocol:
  - All
Added-in: 7.63.0
---

# NAME

CURLOPT_CURLU - URL in URL handle format

# SYNOPSIS
40
41
42
43
44
45
46

47

48
49
50
51
52
53
54
libcurl uses this handle and its contents read-only and does not change its
contents. An application can update the contents of the URL handle after a
transfer is done and if the same handle is used in a subsequent request the
updated contents is used.

# DEFAULT


The default value of this parameter is NULL.


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
|
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
libcurl uses this handle and its contents read-only and does not change its
contents. An application can update the contents of the URL handle after a
transfer is done and if the same handle is used in a subsequent request the
updated contents is used.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
64
65
66
67
68
69
70
71
72
73
74
75
76
77

    curl_url_cleanup(urlp);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.63.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




67
68
69
70
71
72
73
74


75
76
77
78

    curl_url_cleanup(urlp);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_CUSTOMREQUEST.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - CURLOPT_REQUEST_TARGET (3)
Protocol:
  - HTTP
  - FTP
  - IMAP
  - POP3
  - SMTP

---

# NAME

CURLOPT_CUSTOMREQUEST - custom request method

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - CURLOPT_REQUEST_TARGET (3)
Protocol:
  - HTTP
  - FTP
  - IMAP
  - POP3
  - SMTP
Added-in: 7.1
---

# NAME

CURLOPT_CUSTOMREQUEST - custom request method

# SYNOPSIS
91
92
93
94
95
96
97
98
99
100
101
102
103


104
105
106
107
108
109
110
For example:

Normally a multi line response is returned which can be used, in conjunction
with CURLOPT_MAIL_RCPT(3), to specify an EXPN request. If the
CURLOPT_NOBODY(3) option is specified then the request can be used to
issue **NOOP** and **RSET** commands.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







<
<
<



>
>







92
93
94
95
96
97
98



99
100
101
102
103
104
105
106
107
108
109
110
For example:

Normally a multi line response is returned which can be used, in conjunction
with CURLOPT_MAIL_RCPT(3), to specify an EXPN request. If the
CURLOPT_NOBODY(3) option is specified then the request can be used to
issue **NOOP** and **RSET** commands.




# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

IMAP is supported since 7.30.0, POP3 since 7.26.0 and SMTP since 7.34.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<





118
119
120
121
122
123
124
125


126
127
128
129
130
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DEBUGDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DEBUGDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
Protocol:
  - All

---

# NAME

CURLOPT_DEBUGDATA - pointer passed to the debug callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DEBUGDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

CURLOPT_DEBUGDATA - pointer passed to the debug callback

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41
Pass a *pointer* to whatever you want passed in to your
CURLOPT_DEBUGFUNCTION(3) in the last void * argument. This pointer is
not used by libcurl, it is only passed to the callback.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct data {
  void *custom;
};







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Pass a *pointer* to whatever you want passed in to your
CURLOPT_DEBUGFUNCTION(3) in the last void * argument. This pointer is
not used by libcurl, it is only passed to the callback.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct data {
  void *custom;
};
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




74
75
76
77
78
79
80
81


82
83
84
85
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DEBUGFUNCTION.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_CONN_ID (3)
  - CURLINFO_XFER_ID (3)
  - CURLOPT_DEBUGDATA (3)
  - CURLOPT_VERBOSE (3)
  - curl_global_trace (3)
Protocol:
  - All

---

# NAME

CURLOPT_DEBUGFUNCTION - debug callback

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_CONN_ID (3)
  - CURLINFO_XFER_ID (3)
  - CURLOPT_DEBUGDATA (3)
  - CURLOPT_VERBOSE (3)
  - curl_global_trace (3)
Protocol:
  - All
Added-in: 7.9.6
---

# NAME

CURLOPT_DEBUGFUNCTION - debug callback

# SYNOPSIS
87
88
89
90
91
92
93


94
95
96
97
98
99
100
101
102


103
104
105
106
107
108
109

The data is SSL/TLS (binary) data sent to the peer.

## CURLINFO_SSL_DATA_IN

The data is SSL/TLS (binary) data received from the peer.



WARNING: This callback may be called with the curl *handle* set to an
internal handle. (Added in 8.4.0)

If you need to distinguish your curl *handle* from internal handles then
set CURLOPT_PRIVATE(3) on your handle.

# DEFAULT

NULL



# EXAMPLE

~~~c
static
void dump(const char *text,
          FILE *stream, unsigned char *ptr, size_t size)







>
>
|
|

|
|




>
>







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

The data is SSL/TLS (binary) data sent to the peer.

## CURLINFO_SSL_DATA_IN

The data is SSL/TLS (binary) data received from the peer.

##

WARNING: This callback may be called with the curl *handle* set to an internal
handle. (Added in 8.4.0)

If you need to distinguish your curl *handle* from internal handles then set
CURLOPT_PRIVATE(3) on your handle.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
static
void dump(const char *text,
          FILE *stream, unsigned char *ptr, size_t size)
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




206
207
208
209
210
211
212
213


214
215
216
217
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
  return 0;
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DEFAULT_PROTOCOL.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DEFAULT_PROTOCOL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PROTOCOL (3)
  - CURLINFO_SCHEME (3)
  - CURLOPT_URL (3)
Protocol:
  - All

---

# NAME

CURLOPT_DEFAULT_PROTOCOL - default protocol to use if the URL is missing a
scheme name













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DEFAULT_PROTOCOL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PROTOCOL (3)
  - CURLINFO_SCHEME (3)
  - CURLOPT_URL (3)
Protocol:
  - All
Added-in: 7.45.0
---

# NAME

CURLOPT_DEFAULT_PROTOCOL - default protocol to use if the URL is missing a
scheme name

51
52
53
54
55
56
57


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL (make a guess based on the host)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* set a URL without a scheme */
    curl_easy_setopt(curl, CURLOPT_URL, "example.com");

    /* set the default protocol (scheme) for schemeless URLs */
    curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.45.0

# RETURN VALUE

CURLE_OK if the option is supported.

CURLE_OUT_OF_MEMORY if there was insufficient heap space.

CURLE_UNKNOWN_OPTION if the option is not supported.







>
>



















|
<
<








52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80


81
82
83
84
85
86
87
88
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL (make a guess based on the host)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* set a URL without a scheme */
    curl_easy_setopt(curl, CURLOPT_URL, "example.com");

    /* set the default protocol (scheme) for schemeless URLs */
    curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK if the option is supported.

CURLE_OUT_OF_MEMORY if there was insufficient heap space.

CURLE_UNKNOWN_OPTION if the option is not supported.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DIRLISTONLY.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DIRLISTONLY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP
  - SFTP
  - POP3

---

# NAME

CURLOPT_DIRLISTONLY - ask for names only in a directory listing

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DIRLISTONLY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP
  - SFTP
  - POP3
Added-in: 7.17.0
---

# NAME

CURLOPT_DIRLISTONLY - ask for names only in a directory listing

# SYNOPSIS
49
50
51
52
53
54
55


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79


80
81
82
83
Do not use this option if you also use CURLOPT_WILDCARDMATCH(3) as it
effectively breaks that feature.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/");

    /* list only */
    curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option was known as CURLOPT_FTPLISTONLY up to 7.16.4. POP3 is supported
since 7.21.5.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|



>
>




50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
Do not use this option if you also use CURLOPT_WILDCARDMATCH(3) as it
effectively breaks that feature.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/");

    /* list only */
    curl_easy_setopt(curl, CURLOPT_DIRLISTONLY, 1L);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

This option was known as CURLOPT_FTPLISTONLY up to 7.16.4. POP3 is supported
since 7.21.5.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DISALLOW_USERNAME_IN_URL.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DISALLOW_USERNAME_IN_URL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROTOCOLS (3)
  - CURLOPT_URL (3)
  - curl_url_set (3)
  - libcurl-security (3)
Protocol:
  - All

---

# NAME

CURLOPT_DISALLOW_USERNAME_IN_URL - disallow specifying username in the URL

# SYNOPSIS







|





>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DISALLOW_USERNAME_IN_URL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROTOCOLS_STR (3)
  - CURLOPT_URL (3)
  - curl_url_set (3)
  - libcurl-security (3)
Protocol:
  - All
Added-in: 7.61.0
---

# NAME

CURLOPT_DISALLOW_USERNAME_IN_URL - disallow specifying username in the URL

# SYNOPSIS
32
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
username.

This is the equivalent to the *CURLU_DISALLOW_USER* flag for the
curl_url_set(3) function.

# DEFAULT

0 (disabled) - usernames are allowed by default.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {

    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.

curl_easy_perform(3) returns CURLE_LOGIN_DENIED if this option is
enabled and a URL containing a username is specified.







|
>
>

















|
<
<







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
65
66
67
username.

This is the equivalent to the *CURLU_DISALLOW_USER* flag for the
curl_url_set(3) function.

# DEFAULT

0 (disabled)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {

    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_DISALLOW_USERNAME_IN_URL, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.

curl_easy_perform(3) returns CURLE_LOGIN_DENIED if this option is
enabled and a URL containing a username is specified.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DNS_CACHE_TIMEOUT.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_CONNECTTIMEOUT_MS (3)
  - CURLOPT_DNS_SERVERS (3)
  - CURLOPT_DNS_USE_GLOBAL_CACHE (3)
  - CURLOPT_MAXAGE_CONN (3)
  - CURLOPT_RESOLVE (3)
Protocol:
  - All

---

# NAME

CURLOPT_DNS_CACHE_TIMEOUT - life-time for DNS cache entries

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_CONNECTTIMEOUT_MS (3)
  - CURLOPT_DNS_SERVERS (3)
  - CURLOPT_DNS_USE_GLOBAL_CACHE (3)
  - CURLOPT_MAXAGE_CONN (3)
  - CURLOPT_RESOLVE (3)
Protocol:
  - All
Added-in: 7.9.3
---

# NAME

CURLOPT_DNS_CACHE_TIMEOUT - life-time for DNS cache entries

# SYNOPSIS
50
51
52
53
54
55
56


57
58
59
60
61
62
63
Since version 8.1.0, libcurl prunes entries from the DNS cache if it exceeds
30,000 entries no matter which timeout value is used.

# DEFAULT

60



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
Since version 8.1.0, libcurl prunes entries from the DNS cache if it exceeds
30,000 entries no matter which timeout value is used.

# DEFAULT

60

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
74
75
76
77
78
79
80
81
82
83
84
85
86
87
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




77
78
79
80
81
82
83
84


85
86
87
88
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DNS_INTERFACE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_INTERFACE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_LOCAL_IP4 (3)
  - CURLOPT_DNS_LOCAL_IP6 (3)
  - CURLOPT_DNS_SERVERS (3)
  - CURLOPT_INTERFACE (3)
Protocol:
  - All

---

# NAME

CURLOPT_DNS_INTERFACE - interface to speak DNS over

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_INTERFACE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_LOCAL_IP4 (3)
  - CURLOPT_DNS_LOCAL_IP6 (3)
  - CURLOPT_DNS_SERVERS (3)
  - CURLOPT_INTERFACE (3)
Protocol:
  - All
Added-in: 7.33.0
---

# NAME

CURLOPT_DNS_INTERFACE - interface to speak DNS over

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

63
64
65
66
67
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_DNS_INTERFACE, "eth0");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.33.0. This option also requires that libcurl was built with a
resolver backend that supports this operation. The c-ares backend is the only
such one.


# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not,
or CURLE_NOT_BUILT_IN if support was disabled at compile-time.







>
>
















|

|
|
|
>





36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_DNS_INTERFACE, "eth0");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# NOTES

This option requires that libcurl was built with a resolver backend that
supports this operation. The c-ares backend is the only such one.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not,
or CURLE_NOT_BUILT_IN if support was disabled at compile-time.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP4.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_LOCAL_IP4
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_INTERFACE (3)
  - CURLOPT_DNS_LOCAL_IP6 (3)
  - CURLOPT_DNS_SERVERS (3)
Protocol:
  - All

---

# NAME

CURLOPT_DNS_LOCAL_IP4 - IPv4 address to bind DNS resolves to

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_LOCAL_IP4
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_INTERFACE (3)
  - CURLOPT_DNS_LOCAL_IP6 (3)
  - CURLOPT_DNS_SERVERS (3)
Protocol:
  - All
Added-in: 7.33.0
---

# NAME

CURLOPT_DNS_LOCAL_IP4 - IPv4 address to bind DNS resolves to

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_DNS_LOCAL_IP4, "192.168.0.14");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option requires that libcurl was built with a resolver backend that
supports this operation. The c-ares backend is the only such one.

Added in 7.33.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not,
CURLE_NOT_BUILT_IN if support was disabled at compile-time, or
CURLE_BAD_FUNCTION_ARGUMENT when given a bad address.







>
>
















|




|






35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_DNS_LOCAL_IP4, "192.168.0.14");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# NOTES

This option requires that libcurl was built with a resolver backend that
supports this operation. The c-ares backend is the only such one.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not,
CURLE_NOT_BUILT_IN if support was disabled at compile-time, or
CURLE_BAD_FUNCTION_ARGUMENT when given a bad address.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DNS_LOCAL_IP6.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_LOCAL_IP6
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_INTERFACE (3)
  - CURLOPT_DNS_LOCAL_IP4 (3)
  - CURLOPT_DNS_SERVERS (3)
Protocol:
  - All

---

# NAME

CURLOPT_DNS_LOCAL_IP6 - IPv6 address to bind DNS resolves to

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_LOCAL_IP6
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_INTERFACE (3)
  - CURLOPT_DNS_LOCAL_IP4 (3)
  - CURLOPT_DNS_SERVERS (3)
Protocol:
  - All
Added-in: 7.33.0
---

# NAME

CURLOPT_DNS_LOCAL_IP6 - IPv6 address to bind DNS resolves to

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_DNS_LOCAL_IP6, "fe80::a9ff:fe46:b619");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option requires that libcurl was built with a resolver backend that
supports this operation. The c-ares backend is the only such one.

Added in 7.33.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not,
CURLE_NOT_BUILT_IN if support was disabled at compile-time, or
CURLE_BAD_FUNCTION_ARGUMENT when given a bad address.







>
>
















|




|






35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_DNS_LOCAL_IP6, "fe80::a9ff:fe46:b619");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# NOTES

This option requires that libcurl was built with a resolver backend that
supports this operation. The c-ares backend is the only such one.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not,
CURLE_NOT_BUILT_IN if support was disabled at compile-time, or
CURLE_BAD_FUNCTION_ARGUMENT when given a bad address.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DNS_SERVERS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_SERVERS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_DNS_LOCAL_IP4 (3)
  - CURLOPT_DNS_LOCAL_IP6 (3)
Protocol:
  - All

---

# NAME

CURLOPT_DNS_SERVERS - DNS servers to use

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_SERVERS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_DNS_LOCAL_IP4 (3)
  - CURLOPT_DNS_LOCAL_IP6 (3)
Protocol:
  - All
Added-in: 7.24.0
---

# NAME

CURLOPT_DNS_SERVERS - DNS servers to use

# SYNOPSIS
36
37
38
39
40
41
42

43

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
192.168.1.100,192.168.1.101,3.4.5.6

The application does not have to keep the string around after setting this
option.

# DEFAULT


NULL - use system default


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_DNS_SERVERS,
                     "192.168.1.100:53,192.168.1.101");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option requires that libcurl was built with a resolver backend that
supports this operation. The c-ares backend is the only such one.

Added in 7.24.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not,
CURLE_NOT_BUILT_IN if support was disabled at compile-time,
CURLE_BAD_FUNCTION_ARGUMENT when given an invalid server list, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
|
>


















|




|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
192.168.1.100,192.168.1.101,3.4.5.6

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_DNS_SERVERS,
                     "192.168.1.100:53,192.168.1.101");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# NOTES

This option requires that libcurl was built with a resolver backend that
supports this operation. The c-ares backend is the only such one.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not,
CURLE_NOT_BUILT_IN if support was disabled at compile-time,
CURLE_BAD_FUNCTION_ARGUMENT when given an invalid server list, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DNS_SHUFFLE_ADDRESSES.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_SHUFFLE_ADDRESSES
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_IPRESOLVE (3)
Protocol:
  - All

---

# NAME

CURLOPT_DNS_SHUFFLE_ADDRESSES - shuffle IP addresses for hostname

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_SHUFFLE_ADDRESSES
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_IPRESOLVE (3)
Protocol:
  - All
Added-in: 7.60.0
---

# NAME

CURLOPT_DNS_SHUFFLE_ADDRESSES - shuffle IP addresses for hostname

# SYNOPSIS
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
generated by the system's name resolution implementation. This may have
performance impacts and may cause IPv4 to be used before IPv6 or vice versa.

# DEFAULT

0 (disabled)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_DNS_SHUFFLE_ADDRESSES, 1L);

    curl_easy_perform(curl);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.60.0

# RETURN VALUE

CURLE_OK or an error such as CURLE_UNKNOWN_OPTION.







>
>


















|
<
<




43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
generated by the system's name resolution implementation. This may have
performance impacts and may cause IPv4 to be used before IPv6 or vice versa.

# DEFAULT

0 (disabled)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_DNS_SHUFFLE_ADDRESSES, 1L);

    curl_easy_perform(curl);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or an error such as CURLE_UNKNOWN_OPTION.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DNS_USE_GLOBAL_CACHE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_USE_GLOBAL_CACHE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_SHARE (3)
Protocol:
  - All

---

# NAME

CURLOPT_DNS_USE_GLOBAL_CACHE - global DNS cache

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DNS_USE_GLOBAL_CACHE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_SHARE (3)
Protocol:
  - All
Added-in: 7.9.3
---

# NAME

CURLOPT_DNS_USE_GLOBAL_CACHE - global DNS cache

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62


63
64
65
66
See CURLOPT_SHARE(3) and curl_share_init(3) for the correct way to share DNS
cache between transfers.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* switch off the use of a global, thread unsafe, cache */
    curl_easy_setopt(curl, CURLOPT_DNS_USE_GLOBAL_CACHE, 0L);
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}

~~~

# AVAILABILITY

Deprecated since 7.11.1. Function removed in 7.62.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|

|
>
>




36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
See CURLOPT_SHARE(3) and curl_share_init(3) for the correct way to share DNS
cache between transfers.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* switch off the use of a global, thread unsafe, cache */
    curl_easy_setopt(curl, CURLOPT_DNS_USE_GLOBAL_CACHE, 0L);
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}

~~~

# DEPRECATED

Deprecated since 7.11.1. Functionality removed in 7.62.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYHOST.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_DOH_SSL_VERIFYHOST - verify the hostname in the DoH SSL certificate

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.76.0
---

# NAME

CURLOPT_DOH_SSL_VERIFYHOST - verify the hostname in the DoH SSL certificate

# SYNOPSIS
55
56
57
58
59
60
61


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
See also CURLOPT_DOH_SSL_VERIFYPEER(3) to verify the digital signature
of the DoH server certificate.

# DEFAULT

2



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_DOH_URL,
                     "https://cloudflare-dns.com/dns-query");

    /* Disable host name verification of the DoH server */
    curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.76.0

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<
<
<




56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85




86
87
88
89
See also CURLOPT_DOH_SSL_VERIFYPEER(3) to verify the digital signature
of the DoH server certificate.

# DEFAULT

2

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_DOH_URL,
                     "https://cloudflare-dns.com/dns-query");

    /* Disable host name verification of the DoH server */
    curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%





# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYPEER.md.
12
13
14
15
16
17
18

19
20
21
22
23
24
25
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_DOH_SSL_VERIFYPEER - verify the DoH SSL certificate

# SYNOPSIS







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.76.0
---

# NAME

CURLOPT_DOH_SSL_VERIFYPEER - verify the DoH SSL certificate

# SYNOPSIS
67
68
69
70
71
72
73


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
transfer is not enough as you cannot be sure that you are communicating with
the correct end-point.

# DEFAULT

1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_DOH_URL,
                     "https://cloudflare-dns.com/dns-query");

    /* Disable certificate verification of the DoH server */
    curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.76.0

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<
<
<




68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97




98
99
100
101
transfer is not enough as you cannot be sure that you are communicating with
the correct end-point.

# DEFAULT

1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_DOH_URL,
                     "https://cloudflare-dns.com/dns-query");

    /* Disable certificate verification of the DoH server */
    curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%





# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DOH_SSL_VERIFYSTATUS.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_DOH_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYSTATUS (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_DOH_SSL_VERIFYSTATUS - verify the DoH SSL certificate's status

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_DOH_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYSTATUS (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.76.0
---

# NAME

CURLOPT_DOH_SSL_VERIFYSTATUS - verify the DoH SSL certificate's status

# SYNOPSIS
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
If this option is enabled and the server does not support the TLS extension,
the verification fails.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_DOH_URL,
                     "https://cloudflare-dns.com/dns-query");

    /* Ask for OCSP stapling when verifying the DoH server */
    curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.76.0.

# RETURN VALUE

Returns CURLE_OK if OCSP stapling is supported by the SSL backend, otherwise
returns CURLE_NOT_BUILT_IN.







>
>




















|
<
<





43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
77
If this option is enabled and the server does not support the TLS extension,
the verification fails.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_DOH_URL,
                     "https://cloudflare-dns.com/dns-query");

    /* Ask for OCSP stapling when verifying the DoH server */
    curl_easy_setopt(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if OCSP stapling is supported by the SSL backend, otherwise
returns CURLE_NOT_BUILT_IN.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_DOH_URL.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DOH_URL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_RESOLVE (3)
  - CURLOPT_VERBOSE (3)
Protocol:
  - All

---

# NAME

CURLOPT_DOH_URL - provide the DNS-over-HTTPS URL

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_DOH_URL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_RESOLVE (3)
  - CURLOPT_VERBOSE (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

CURLOPT_DOH_URL - provide the DNS-over-HTTPS URL

# SYNOPSIS
59
60
61
62
63
64
65
66
67

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
resolves that are performed without it, using the default name resolver
mechanism. This includes name resolves done for CURLOPT_INTERFACE(3),
CURLOPT_FTPPORT(3), a proxy type set to **CURLPROXY_SOCKS4** or
**CURLPROXY_SOCKS5** and probably some more.

# DEFAULT

NULL - there is no default DoH URL. If this option is not set, libcurl uses
the default name resolver.


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_DOH_URL, "https://dns.example.com");
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.62.0

# RETURN VALUE

Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient
heap space.

Note that curl_easy_setopt(3) does immediately parse the given string so
when given a bad DoH URL, libcurl might not detect the problem until it later
tries to resolve a name with it.







|
|
>















|
<
<









60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85


86
87
88
89
90
91
92
93
94
resolves that are performed without it, using the default name resolver
mechanism. This includes name resolves done for CURLOPT_INTERFACE(3),
CURLOPT_FTPPORT(3), a proxy type set to **CURLPROXY_SOCKS4** or
**CURLPROXY_SOCKS5** and probably some more.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_DOH_URL, "https://dns.example.com");
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient
heap space.

Note that curl_easy_setopt(3) does immediately parse the given string so
when given a bad DoH URL, libcurl might not detect the problem until it later
tries to resolve a name with it.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ECH.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ECH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DOH_URL (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - wolfSSL

---

# NAME

CURLOPT_ECH - configuration for Encrypted Client Hello

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_ECH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DOH_URL (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - wolfSSL
Added-in: 8.8.0
---

# NAME

CURLOPT_ECH - configuration for Encrypted Client Hello

# SYNOPSIS
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
## true

Instructs client to attempt ECH, if possible, but to not fail if attempting
ECH is not possible.

## hard

Instructs client to attempt ECH and fail if if attempting ECH is not possible.

## ecl:\<base64-value\>

If the string starts with `ecl:` then the remainder of the string should be a
base64-encoded ECHConfigList that is used for ECH rather than attempting to
download such a value from the DNS.

## pn:\<name\>

If the string starts with `pn:` then the remainder of the string should be a
DNS/hostname that is used to over-ride the public_name field of the
ECHConfigList that is used for ECH.

# DEFAULT

NULL, meaning ECH is disabled.



# EXAMPLE

~~~c
CURL *curl = curl_easy_init();

const char *config ="ecl:AED+DQA87wAgACB/RuzUCsW3uBbSFI7mzD63TUXpI8sGDTnFTbFCDpa+CAAEAAEAAQANY292ZXIuZGVmby5pZQAA";
if(curl) {
  curl_easy_setopt(curl, CURLOPT_ECH, config);
  curl_easy_perform(curl);
}
~~~
# AVAILABILITY

Added in 8.8.0

# RETURN VALUE

Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient
heap space.







|

















>
>











|
<
<





52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90


91
92
93
94
95
## true

Instructs client to attempt ECH, if possible, but to not fail if attempting
ECH is not possible.

## hard

Instructs client to attempt ECH and fail if attempting ECH is not possible.

## ecl:\<base64-value\>

If the string starts with `ecl:` then the remainder of the string should be a
base64-encoded ECHConfigList that is used for ECH rather than attempting to
download such a value from the DNS.

## pn:\<name\>

If the string starts with `pn:` then the remainder of the string should be a
DNS/hostname that is used to over-ride the public_name field of the
ECHConfigList that is used for ECH.

# DEFAULT

NULL, meaning ECH is disabled.

# %PROTOCOLS%

# EXAMPLE

~~~c
CURL *curl = curl_easy_init();

const char *config ="ecl:AED+DQA87wAgACB/RuzUCsW3uBbSFI7mzD63TUXpI8sGDTnFTbFCDpa+CAAEAAEAAQANY292ZXIuZGVmby5pZQAA";
if(curl) {
  curl_easy_setopt(curl, CURLOPT_ECH, config);
  curl_easy_perform(curl);
}
~~~
# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient
heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_EGDSOCKET.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_EGDSOCKET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RANDOM_FILE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLOPT_EGDSOCKET - EGD socket path

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_EGDSOCKET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RANDOM_FILE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.7
---

# NAME

CURLOPT_EGDSOCKET - EGD socket path

# SYNOPSIS
28
29
30
31
32
33
34
35
36
37


38
39
40
41

Deprecated option. It serves no purpose anymore.

# DEFAULT

NULL

# AVAILABILITY

This option was deprecated in 7.84.0.



# RETURN VALUE

Returns CURLE_OK.







|


>
>




29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Deprecated option. It serves no purpose anymore.

# DEFAULT

NULL

# DEPRECATED

This option was deprecated in 7.84.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ERRORBUFFER.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_VERBOSE (3)
  - curl_easy_strerror (3)
  - curl_multi_strerror (3)
  - curl_share_strerror (3)
  - curl_url_strerror (3)
Protocol:
  - All

---

# NAME

CURLOPT_ERRORBUFFER - error buffer for error messages

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_VERBOSE (3)
  - curl_easy_strerror (3)
  - curl_multi_strerror (3)
  - curl_share_strerror (3)
  - curl_url_strerror (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_ERRORBUFFER - error buffer for error messages

# SYNOPSIS
46
47
48
49
50
51
52


53
54
55
56
57
58
59

Consider CURLOPT_VERBOSE(3) and CURLOPT_DEBUGFUNCTION(3) to better
debug and trace why errors happen.

# DEFAULT

NULL



# EXAMPLE

~~~c
#include <string.h> /* for strlen() */
int main(void)
{







>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

Consider CURLOPT_VERBOSE(3) and CURLOPT_DEBUGFUNCTION(3) to better
debug and trace why errors happen.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h> /* for strlen() */
int main(void)
{
86
87
88
89
90
91
92
93
94
95
96
97
98
99
      else
        fprintf(stderr, "%s\n", curl_easy_strerror(res));
    }
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




89
90
91
92
93
94
95
96


97
98
99
100
      else
        fprintf(stderr, "%s\n", curl_easy_strerror(res));
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_EXPECT_100_TIMEOUT_MS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_EXPECT_100_TIMEOUT_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPOST (3)
  - CURLOPT_POST (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_EXPECT_100_TIMEOUT_MS - timeout for Expect: 100-continue response

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_EXPECT_100_TIMEOUT_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPOST (3)
  - CURLOPT_POST (3)
Protocol:
  - HTTP
Added-in: 7.36.0
---

# NAME

CURLOPT_EXPECT_100_TIMEOUT_MS - timeout for Expect: 100-continue response

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
header. If this times out before a response is received, the request body is
sent anyway.

# DEFAULT

1000 milliseconds



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* wait 3 seconds for 100-continue */
    curl_easy_setopt(curl, CURLOPT_EXPECT_100_TIMEOUT_MS, 3000L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.36.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
header. If this times out before a response is received, the request body is
sent anyway.

# DEFAULT

1000 milliseconds

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* wait 3 seconds for 100-continue */
    curl_easy_setopt(curl, CURLOPT_EXPECT_100_TIMEOUT_MS, 3000L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FAILONERROR.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FAILONERROR
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - CURLOPT_HTTP200ALIASES (3)
  - CURLOPT_KEEP_SENDING_ON_ERROR (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_FAILONERROR - request failure on HTTP response \>= 400

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FAILONERROR
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - CURLOPT_HTTP200ALIASES (3)
  - CURLOPT_KEEP_SENDING_ON_ERROR (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_FAILONERROR - request failure on HTTP response \>= 400

# SYNOPSIS
41
42
43
44
45
46
47


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
When this option is used and an error is detected, it causes the connection to
get closed and *CURLE_HTTP_RETURNED_ERROR* is returned.

# DEFAULT

0, do not fail on error



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
    ret = curl_easy_perform(curl);
    if(ret == CURLE_HTTP_RETURNED_ERROR) {
      /* an HTTP response error problem */
    }
  }
}
~~~

# AVAILABILITY

Along with HTTP.

# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.







>
>


















|
<
<




42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69


70
71
72
73
When this option is used and an error is detected, it causes the connection to
get closed and *CURLE_HTTP_RETURNED_ERROR* is returned.

# DEFAULT

0, do not fail on error

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
    ret = curl_easy_perform(curl);
    if(ret == CURLE_HTTP_RETURNED_ERROR) {
      /* an HTTP response error problem */
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FILETIME.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - curl_easy_getinfo (3)
Protocol:
  - HTTP
  - FTP
  - SFTP
  - FILE
  - SMB

---

# NAME

CURLOPT_FILETIME - get the modification time of the remote resource

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - curl_easy_getinfo (3)
Protocol:
  - HTTP
  - FTP
  - SFTP
  - FILE
  - SMB
Added-in: 7.5
---

# NAME

CURLOPT_FILETIME - get the modification time of the remote resource

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
the time or replies to a time querying command. The curl_easy_getinfo(3)
function with the CURLINFO_FILETIME(3) argument can be used after a
transfer to extract the received time (if any).

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
the time or replies to a time querying command. The curl_easy_getinfo(3)
function with the CURLINFO_FILETIME(3) argument can be used after a
transfer to extract the received time (if any).

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always, for SFTP since 7.49.0

# RETURN VALUE

Returns CURLE_OK







|
<
<




64
65
66
67
68
69
70
71


72
73
74
75
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FNMATCH_DATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FNMATCH_DATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FNMATCH_FUNCTION (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_FNMATCH_DATA - pointer passed to the fnmatch callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FNMATCH_DATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FNMATCH_FUNCTION (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP
Added-in: 7.21.0
---

# NAME

CURLOPT_FNMATCH_DATA - pointer passed to the fnmatch callback

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41

Pass a pointer that is untouched by libcurl and passed as the ptr argument to
the CURLOPT_FNMATCH_FUNCTION(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
extern int string_match(const char *s1, const char *s2);

struct local_stuff {







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Pass a pointer that is untouched by libcurl and passed as the ptr argument to
the CURLOPT_FNMATCH_FUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
extern int string_match(const char *s1, const char *s2);

struct local_stuff {
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    curl_easy_setopt(curl, CURLOPT_FNMATCH_DATA, &local_data);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




68
69
70
71
72
73
74
75


76
77
78
79
    curl_easy_setopt(curl, CURLOPT_FNMATCH_DATA, &local_data);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FNMATCH_FUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FNMATCH_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_FNMATCH_DATA (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_FNMATCH_FUNCTION - wildcard match callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FNMATCH_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_FNMATCH_DATA (3)
  - CURLOPT_WILDCARDMATCH (3)
Protocol:
  - FTP
Added-in: 7.21.0
---

# NAME

CURLOPT_FNMATCH_FUNCTION - wildcard match callback

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
Return *CURL_FNMATCHFUNC_MATCH* if pattern matches the string,
*CURL_FNMATCHFUNC_NOMATCH* if not or *CURL_FNMATCHFUNC_FAIL* if an
error occurred.

# DEFAULT

NULL == an internal function for wildcard matching.



# EXAMPLE

~~~c
extern int string_match(const char *s1, const char *s2);

struct local_stuff {







>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Return *CURL_FNMATCHFUNC_MATCH* if pattern matches the string,
*CURL_FNMATCHFUNC_NOMATCH* if not or *CURL_FNMATCHFUNC_FAIL* if an
error occurred.

# DEFAULT

NULL == an internal function for wildcard matching.

# %PROTOCOLS%

# EXAMPLE

~~~c
extern int string_match(const char *s1, const char *s2);

struct local_stuff {
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    curl_easy_setopt(curl, CURLOPT_FNMATCH_FUNCTION, my_fnmatch);
    curl_easy_setopt(curl, CURLOPT_FNMATCH_DATA, &local_data);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




76
77
78
79
80
81
82
83


84
85
86
87
    curl_easy_setopt(curl, CURLOPT_FNMATCH_FUNCTION, my_fnmatch);
    curl_easy_setopt(curl, CURLOPT_FNMATCH_DATA, &local_data);
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FOLLOWLOCATION.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FOLLOWLOCATION
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_URL (3)
  - CURLOPT_POSTREDIR (3)
  - CURLOPT_PROTOCOLS (3)
  - CURLOPT_REDIR_PROTOCOLS (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_FOLLOWLOCATION - follow HTTP 3xx redirects

# SYNOPSIS










|
|


>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FOLLOWLOCATION
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_URL (3)
  - CURLOPT_POSTREDIR (3)
  - CURLOPT_PROTOCOLS_STR (3)
  - CURLOPT_REDIR_PROTOCOLS_STR (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_FOLLOWLOCATION - follow HTTP 3xx redirects

# SYNOPSIS
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

libcurl issues another request for the new URL and follows subsequent new
Location: redirects all the way until no more such headers are returned or the
maximum limit is reached. CURLOPT_MAXREDIRS(3) is used to limit the
number of redirects libcurl follows.

libcurl restricts what protocols it automatically follow redirects to. The
accepted target protocols are set with CURLOPT_REDIR_PROTOCOLS(3). By
default libcurl allows HTTP, HTTPS, FTP and FTPS on redirects.

When following a redirect, the specific 30x response code also dictates which
request method libcurl uses in the subsequent request: For 301, 302 and 303
responses libcurl switches method from POST to GET unless
CURLOPT_POSTREDIR(3) instructs libcurl otherwise. All other redirect
response codes make libcurl use the same method again.







|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

libcurl issues another request for the new URL and follows subsequent new
Location: redirects all the way until no more such headers are returned or the
maximum limit is reached. CURLOPT_MAXREDIRS(3) is used to limit the
number of redirects libcurl follows.

libcurl restricts what protocols it automatically follow redirects to. The
accepted target protocols are set with CURLOPT_REDIR_PROTOCOLS_STR(3). By
default libcurl allows HTTP, HTTPS, FTP and FTPS on redirects.

When following a redirect, the specific 30x response code also dictates which
request method libcurl uses in the subsequent request: For 301, 302 and 303
responses libcurl switches method from POST to GET unless
CURLOPT_POSTREDIR(3) instructs libcurl otherwise. All other redirect
response codes make libcurl use the same method again.
61
62
63
64
65
66
67


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
misbehave since CURLOPT_CUSTOMREQUEST(3) overrides the method libcurl
would otherwise select internally.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* example.com is redirected, so we tell libcurl to follow redirection */
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88


89
90
91
92
misbehave since CURLOPT_CUSTOMREQUEST(3) overrides the method libcurl
would otherwise select internally.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* example.com is redirected, so we tell libcurl to follow redirection */
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FORBID_REUSE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FORBID_REUSE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FRESH_CONNECT (3)
  - CURLOPT_MAXCONNECTS (3)
  - CURLOPT_MAXLIFETIME_CONN (3)
Protocol:
  - All

---

# NAME

CURLOPT_FORBID_REUSE - make connection get closed at once after use

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FORBID_REUSE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FRESH_CONNECT (3)
  - CURLOPT_MAXCONNECTS (3)
  - CURLOPT_MAXLIFETIME_CONN (3)
Protocol:
  - All
Added-in: 7.7
---

# NAME

CURLOPT_FORBID_REUSE - make connection get closed at once after use

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
Set to 0 to have libcurl keep the connection open for possible later reuse
(default behavior).

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L);
    curl_easy_perform(curl);

    /* this second transfer may not reuse the same connection */
    curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>



















|
<
<




36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64


65
66
67
68
Set to 0 to have libcurl keep the connection open for possible later reuse
(default behavior).

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L);
    curl_easy_perform(curl);

    /* this second transfer may not reuse the same connection */
    curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FRESH_CONNECT.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FRESH_CONNECT
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_MAXAGE_CONN (3)
  - CURLOPT_MAXLIFETIME_CONN (3)

---

# NAME

CURLOPT_FRESH_CONNECT - force a new connection to be used

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FRESH_CONNECT
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_MAXAGE_CONN (3)
  - CURLOPT_MAXLIFETIME_CONN (3)
Added-in: 7.7
---

# NAME

CURLOPT_FRESH_CONNECT - force a new connection to be used

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
Set *fresh* to 0 to have libcurl attempt reusing an existing connection
(default behavior).

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1L);
    /* this transfer must use a new connection, not reuse an existing */
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>
















|
<
<




38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
Set *fresh* to 0 to have libcurl attempt reusing an existing connection
(default behavior).

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1L);
    /* this transfer must use a new connection, not reuse an existing */
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTPPORT.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTPPORT
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTP_USE_EPRT (3)
  - CURLOPT_FTP_USE_EPSV (3)

---

# NAME

CURLOPT_FTPPORT - make FTP transfer active

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTPPORT
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTP_USE_EPRT (3)
  - CURLOPT_FTP_USE_EPSV (3)
Added-in: 7.1
---

# NAME

CURLOPT_FTPPORT - make FTP transfer active

# SYNOPSIS
66
67
68
69
70
71
72


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL,
                     "ftp://example.com/old-server/file.txt");
    curl_easy_setopt(curl, CURLOPT_FTPPORT, "-");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Port range support was added in 7.19.5

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|
<
<





67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93


94
95
96
97
98
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL,
                     "ftp://example.com/old-server/file.txt");
    curl_easy_setopt(curl, CURLOPT_FTPPORT, "-");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTPSSLAUTH.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTPSSLAUTH
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTP_SSL_CCC (3)
  - CURLOPT_USE_SSL (3)

---

# NAME

CURLOPT_FTPSSLAUTH - order in which to attempt TLS vs SSL

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTPSSLAUTH
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTP_SSL_CCC (3)
  - CURLOPT_USE_SSL (3)
Added-in: 7.12.2
---

# NAME

CURLOPT_FTPSSLAUTH - order in which to attempt TLS vs SSL

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

Try "AUTH TLS" first, and only if that fails try "AUTH SSL".

# DEFAULT

CURLFTPAUTH_DEFAULT



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
    /* funny server, ask for SSL before TLS */
    curl_easy_setopt(curl, CURLOPT_FTPSSLAUTH, (long)CURLFTPAUTH_SSL);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.12.2

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|
<
<




44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71


72
73
74
75

Try "AUTH TLS" first, and only if that fails try "AUTH SSL".

# DEFAULT

CURLFTPAUTH_DEFAULT

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
    /* funny server, ask for SSL before TLS */
    curl_easy_setopt(curl, CURLOPT_FTPSSLAUTH, (long)CURLFTPAUTH_SSL);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_ACCOUNT.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_ACCOUNT
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_PASSWORD (3)
  - CURLOPT_USERNAME (3)

---

# NAME

CURLOPT_FTP_ACCOUNT - account info for FTP

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_ACCOUNT
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_PASSWORD (3)
  - CURLOPT_USERNAME (3)
Added-in: 7.13.0
---

# NAME

CURLOPT_FTP_ACCOUNT - account info for FTP

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_FTP_ACCOUNT, "human-resources");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.13.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
66
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_FTP_ACCOUNT, "human-resources");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_ALTERNATIVE_TO_USER.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_ALTERNATIVE_TO_USER
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTP_ACCOUNT (3)
  - CURLOPT_FTP_SKIP_PASV_IP (3)
  - CURLOPT_SERVER_RESPONSE_TIMEOUT (3)
  - CURLOPT_USERNAME (3)

---

# NAME

CURLOPT_FTP_ALTERNATIVE_TO_USER - command to use instead of USER with FTP

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_ALTERNATIVE_TO_USER
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTP_ACCOUNT (3)
  - CURLOPT_FTP_SKIP_PASV_IP (3)
  - CURLOPT_SERVER_RESPONSE_TIMEOUT (3)
  - CURLOPT_USERNAME (3)
Added-in: 7.15.5
---

# NAME

CURLOPT_FTP_ALTERNATIVE_TO_USER - command to use instead of USER with FTP

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, "two users");
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.5

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|
<
<





38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64


65
66
67
68
69
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, "two users");
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_CREATE_MISSING_DIRS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_CREATE_MISSING_DIRS
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTP_FILEMETHOD (3)
  - CURLOPT_FTP_USE_EPSV (3)

---

# NAME

CURLOPT_FTP_CREATE_MISSING_DIRS - create missing directories for FTP and SFTP

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_CREATE_MISSING_DIRS
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTP_FILEMETHOD (3)
  - CURLOPT_FTP_USE_EPSV (3)
Added-in: 7.10.7
---

# NAME

CURLOPT_FTP_CREATE_MISSING_DIRS - create missing directories for FTP and SFTP

# SYNOPSIS
51
52
53
54
55
56
57


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
but then another connection does **MKD** before this connection and thus
**MKD** fails but trying CWD works!

# DEFAULT

CURLFTP_CREATE_DIR_NONE (0)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL,
                     "ftp://example.com/non-existing/new.txt");
    curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
                     (long)CURLFTP_CREATE_DIR_RETRY);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10.7. SFTP support added in 7.16.3. The retry option was added in
7.19.4.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if the
create value is not.







>
>




















|
<
<
<





52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81



82
83
84
85
86
but then another connection does **MKD** before this connection and thus
**MKD** fails but trying CWD works!

# DEFAULT

CURLFTP_CREATE_DIR_NONE (0)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL,
                     "ftp://example.com/non-existing/new.txt");
    curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
                     (long)CURLFTP_CREATE_DIR_RETRY);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if the
create value is not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_FILEMETHOD.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_FILEMETHOD
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_DIRLISTONLY (3)
  - CURLOPT_FTP_SKIP_PASV_IP (3)

---

# NAME

CURLOPT_FTP_FILEMETHOD - select directory traversing method for FTP

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_FILEMETHOD
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_DIRLISTONLY (3)
  - CURLOPT_FTP_SKIP_PASV_IP (3)
Added-in: 7.15.1
---

# NAME

CURLOPT_FTP_FILEMETHOD - select directory traversing method for FTP

# SYNOPSIS
52
53
54
55
56
57
58


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
file &"normally" (like in the multicwd case). This is somewhat more standards
compliant than 'nocwd' but without the full penalty of 'multicwd'.

# DEFAULT

CURLFTPMETHOD_MULTICWD



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/1/2/3/4/new.txt");
    curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD,
                     (long)CURLFTPMETHOD_SINGLECWD);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81


82
83
84
85
file &"normally" (like in the multicwd case). This is somewhat more standards
compliant than 'nocwd' but without the full penalty of 'multicwd'.

# DEFAULT

CURLFTPMETHOD_MULTICWD

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/1/2/3/4/new.txt");
    curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD,
                     (long)CURLFTPMETHOD_SINGLECWD);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_SKIP_PASV_IP.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_SKIP_PASV_IP
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTPPORT (3)
  - CURLOPT_FTP_USE_EPRT (3)

---

# NAME

CURLOPT_FTP_SKIP_PASV_IP - ignore the IP address in the PASV response

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_SKIP_PASV_IP
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTPPORT (3)
  - CURLOPT_FTP_USE_EPRT (3)
Added-in: 7.15.0
---

# NAME

CURLOPT_FTP_SKIP_PASV_IP - ignore the IP address in the PASV response

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

This option has no effect if PORT, EPRT or EPSV is used instead of PASV.

# DEFAULT

1 since 7.74.0, was 0 before then.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");

    /* please ignore the IP in the PASV response */
    curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, 1L);
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.14.2

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71

This option has no effect if PORT, EPRT or EPSV is used instead of PASV.

# DEFAULT

1 since 7.74.0, was 0 before then.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");

    /* please ignore the IP in the PASV response */
    curl_easy_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, 1L);
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_SSL_CCC.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_SSL_CCC
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTPSSLAUTH (3)
  - CURLOPT_PROTOCOLS_STR (3)
  - CURLOPT_USE_SSL (3)

---

# NAME

CURLOPT_FTP_SSL_CCC - switch off SSL again with FTP after auth

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_SSL_CCC
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTPSSLAUTH (3)
  - CURLOPT_PROTOCOLS_STR (3)
  - CURLOPT_USE_SSL (3)
Added-in: 7.16.1
---

# NAME

CURLOPT_FTP_SSL_CCC - switch off SSL again with FTP after auth

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

Initiate the shutdown and wait for a reply.

# DEFAULT

CURLFTPSSL_CCC_NONE



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
    /* go back to clear-text FTP after authenticating */
    curl_easy_setopt(curl, CURLOPT_FTP_SSL_CCC, (long)CURLFTPSSL_CCC_ACTIVE);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|
<
<




46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73


74
75
76
77

Initiate the shutdown and wait for a reply.

# DEFAULT

CURLFTPSSL_CCC_NONE

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
    /* go back to clear-text FTP after authenticating */
    curl_easy_setopt(curl, CURLOPT_FTP_SSL_CCC, (long)CURLFTPSSL_CCC_ACTIVE);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPRT.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_USE_EPRT
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTPPORT (3)
  - CURLOPT_FTP_USE_EPSV (3)

---

# NAME

CURLOPT_FTP_USE_EPRT - use EPRT for FTP

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_USE_EPRT
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTPPORT (3)
  - CURLOPT_FTP_USE_EPSV (3)
Added-in: 7.10.5
---

# NAME

CURLOPT_FTP_USE_EPRT - use EPRT for FTP

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
Sometimes that fallback is not enough and then this option might come handy.

If the server is an IPv6 host, this option has no effect as EPRT is necessary
then.

# DEFAULT



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Sometimes that fallback is not enough and then this option might come handy.

If the server is an IPv6 host, this option has no effect as EPRT is necessary
then.

# DEFAULT

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10.5

# RETURN VALUE

Returns CURLE_OK







|
<
<




63
64
65
66
67
68
69
70


71
72
73
74
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_USE_EPSV.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_USE_EPSV
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTPPORT (3)
  - CURLOPT_FTP_USE_EPRT (3)

---

# NAME

CURLOPT_FTP_USE_EPSV - use EPSV for FTP

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_USE_EPSV
Section: 3
Source: libcurl
Protocol:
  - FTP
See-also:
  - CURLOPT_FTPPORT (3)
  - CURLOPT_FTP_USE_EPRT (3)
Added-in: 7.9.2
---

# NAME

CURLOPT_FTP_USE_EPSV - use EPSV for FTP

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50

If the server is an IPv6 host, this option has no effect.

# DEFAULT

1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

If the server is an IPv6 host, this option has no effect.

# DEFAULT

1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Along with FTP

# RETURN VALUE

Returns CURLE_OK if FTP is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




61
62
63
64
65
66
67
68


69
70
71
72
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if FTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_FTP_USE_PRET.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_USE_PRET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FTP_USE_EPRT (3)
  - CURLOPT_FTP_USE_EPSV (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_FTP_USE_PRET - use PRET for FTP

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_FTP_USE_PRET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FTP_USE_EPRT (3)
  - CURLOPT_FTP_USE_EPSV (3)
Protocol:
  - FTP
Added-in: 7.20.0
---

# NAME

CURLOPT_FTP_USE_PRET - use PRET for FTP

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
command for directory listings as well as up and downloads in PASV mode. Has
no effect when using the active FTP transfers mode.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
command for directory listings as well as up and downloads in PASV mode. Has
no effect when using the active FTP transfers mode.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
51
52
53
54
55
56
57
58
59
60
61
62
63
64
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




54
55
56
57
58
59
60
61


62
63
64
65
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_GSSAPI_DELEGATION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_GSSAPI_DELEGATION
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PROXYAUTH (3)

---

# NAME

CURLOPT_GSSAPI_DELEGATION - allowed GSS-API delegation

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_GSSAPI_DELEGATION
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PROXYAUTH (3)
Added-in: 7.22.0
---

# NAME

CURLOPT_GSSAPI_DELEGATION - allowed GSS-API delegation

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
GSS-API implementation and the definition of *GSS_C_DELEG_POLICY_FLAG* was
available at compile-time.

# DEFAULT

CURLGSSAPI_DELEGATION_NONE



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* delegate if okayed by policy */
    curl_easy_setopt(curl, CURLOPT_GSSAPI_DELEGATION,
                     (long)CURLGSSAPI_DELEGATION_POLICY_FLAG);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.22.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
GSS-API implementation and the definition of *GSS_C_DELEG_POLICY_FLAG* was
available at compile-time.

# DEFAULT

CURLGSSAPI_DELEGATION_NONE

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* delegate if okayed by policy */
    curl_easy_setopt(curl, CURLOPT_GSSAPI_DELEGATION,
                     (long)CURLGSSAPI_DELEGATION_POLICY_FLAG);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_CONNECTTIMEOUT_MS (3)
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_TIMEOUT (3)

---

# NAME

CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS - head start for IPv6 for happy eyeballs

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_CONNECTTIMEOUT_MS (3)
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_TIMEOUT (3)
Added-in: 7.59.0
---

# NAME

CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS - head start for IPv6 for happy eyeballs

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
150-250 ms apart to balance human factors against network load." libcurl
currently defaults to 200 ms. Firefox and Chrome currently default to 300 ms.

# DEFAULT

CURL_HET_DEFAULT (currently defined as 200L)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, 300L);

    curl_easy_perform(curl);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.59.0

# RETURN VALUE

Returns CURLE_OK







>
>


















|
<
<




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
150-250 ms apart to balance human factors against network load." libcurl
currently defaults to 200 ms. Firefox and Chrome currently default to 300 ms.

# DEFAULT

CURL_HET_DEFAULT (currently defined as 200L)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, 300L);

    curl_easy_perform(curl);

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HAPROXYPROTOCOL.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HAPROXYPROTOCOL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
Protocol:
  - All

---

# NAME

CURLOPT_HAPROXYPROTOCOL - send HAProxy PROXY protocol v1 header

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HAPROXYPROTOCOL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
Protocol:
  - All
Added-in: 7.60.0
---

# NAME

CURLOPT_HAPROXYPROTOCOL - send HAProxy PROXY protocol v1 header

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

Most applications do not need this option.

# DEFAULT

0, do not send any HAProxy PROXY protocol header



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP. Added in 7.60.0.

# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.







>
>















|
<
<




35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63

Most applications do not need this option.

# DEFAULT

0, do not send any HAProxy PROXY protocol header

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HAPROXY_CLIENT_IP.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HAPROXY_CLIENT_IP
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_HAPROXYPROTOCOL (3)
  - CURLOPT_PROXY (3)

---

# NAME

CURLOPT_HAPROXY_CLIENT_IP - set HAProxy PROXY protocol client IP

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HAPROXY_CLIENT_IP
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_HAPROXYPROTOCOL (3)
  - CURLOPT_PROXY (3)
Added-in: 8.2.0
---

# NAME

CURLOPT_HAPROXY_CLIENT_IP - set HAProxy PROXY protocol client IP

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
This option is an alternative to CURLOPT_HAPROXYPROTOCOL(3) as that one
cannot use a specified address.

# DEFAULT

NULL, no HAProxy header is sent



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HAPROXY_CLIENT_IP, "1.1.1.1");
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP. Added in 8.2.0.

# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.







>
>















|
<
<




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


59
60
61
62
This option is an alternative to CURLOPT_HAPROXYPROTOCOL(3) as that one
cannot use a specified address.

# DEFAULT

NULL, no HAProxy header is sent

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HAPROXY_CLIENT_IP, "1.1.1.1");
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HEADER.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - FTP
  - IMAP
  - POP3
  - SMTP
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - CURLOPT_HTTPHEADER (3)

---

# NAME

CURLOPT_HEADER - pass headers to the data stream

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - FTP
  - IMAP
  - POP3
  - SMTP
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - CURLOPT_HTTPHEADER (3)
Added-in: 7.1
---

# NAME

CURLOPT_HEADER - pass headers to the data stream

# SYNOPSIS
49
50
51
52
53
54
55


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
While named confusingly similar, CURLOPT_HTTPHEADER(3) is used to set
custom HTTP headers!

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_HEADER, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Provided in all libcurl versions.

# RETURN VALUE

Returns CURLE_OK.







>
>
















|
<
<




50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75


76
77
78
79
While named confusingly similar, CURLOPT_HTTPHEADER(3) is used to set
custom HTTP headers!

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_HEADER, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HEADERDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HEADERDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - CURLOPT_WRITEFUNCTION (3)
  - curl_easy_header (3)
Protocol:
  - All

---

# NAME

CURLOPT_HEADERDATA - pointer to pass to header callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HEADERDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - CURLOPT_WRITEFUNCTION (3)
  - curl_easy_header (3)
Protocol:
  - All
Added-in: 7.10
---

# NAME

CURLOPT_HEADERDATA - pointer to pass to header callback

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
If you are using libcurl as a win32 DLL, you **MUST** use a
CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) if you set
this option or you might experience crashes.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct my_info {
  int shoesize;
  char *secret;







>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
If you are using libcurl as a win32 DLL, you **MUST** use a
CURLOPT_WRITEFUNCTION(3) or CURLOPT_HEADERFUNCTION(3) if you set
this option or you might experience crashes.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct my_info {
  int shoesize;
  char *secret;
74
75
76
77
78
79
80
81
82
83
84
85
86
87
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &my);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




77
78
79
80
81
82
83
84


85
86
87
88
    curl_easy_setopt(curl, CURLOPT_HEADERDATA, &my);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HEADERFUNCTION.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - curl_easy_header (3)
Protocol:
  - HTTP
  - FTP
  - POP3
  - IMAP
  - SMTP

---

# NAME

CURLOPT_HEADERFUNCTION - callback that receives header data

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - curl_easy_header (3)
Protocol:
  - HTTP
  - FTP
  - POP3
  - IMAP
  - SMTP
Added-in: 7.7.2
---

# NAME

CURLOPT_HEADERFUNCTION - callback that receives header data

# SYNOPSIS
96
97
98
99
100
101
102


103
104
105
106
107
108
109
a whitespace. Such folds are passed to the header callback as separate ones,
although strictly they are just continuations of the previous lines.

# DEFAULT

Nothing.



# EXAMPLE

~~~c
static size_t header_callback(char *buffer, size_t size,
                              size_t nitems, void *userdata)
{
  /* received header is nitems * size long in 'buffer' NOT ZERO TERMINATED */







>
>







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
a whitespace. Such folds are passed to the header callback as separate ones,
although strictly they are just continuations of the previous lines.

# DEFAULT

Nothing.

# %PROTOCOLS%

# EXAMPLE

~~~c
static size_t header_callback(char *buffer, size_t size,
                              size_t nitems, void *userdata)
{
  /* received header is nitems * size long in 'buffer' NOT ZERO TERMINATED */
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




123
124
125
126
127
128
129
130


131
132
133
134
    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HEADEROPT.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HEADEROPT
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_PROXYHEADER (3)

---

# NAME

CURLOPT_HEADEROPT - send HTTP headers to both proxy and host or separately

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HEADEROPT
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_PROXYHEADER (3)
Added-in: 7.37.0
---

# NAME

CURLOPT_HEADEROPT - send HTTP headers to both proxy and host or separately

# SYNOPSIS
40
41
42
43
44
45
46


47
48
49
50
51
52
53
doing CONNECT, libcurl sends CURLOPT_PROXYHEADER(3) headers only to the
proxy and then CURLOPT_HTTPHEADER(3) headers only to the server.

# DEFAULT

CURLHEADER_SEPARATE (changed in 7.42.1, used CURLHEADER_UNIFIED before then)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
doing CONNECT, libcurl sends CURLOPT_PROXYHEADER(3) headers only to the
proxy and then CURLOPT_HTTPHEADER(3) headers only to the server.

# DEFAULT

CURLHEADER_SEPARATE (changed in 7.42.1, used CURLHEADER_UNIFIED before then)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    ret = curl_easy_perform(curl);
    curl_slist_free_all(list);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.37.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




69
70
71
72
73
74
75
76


77
78
79
80
    ret = curl_easy_perform(curl);
    curl_slist_free_all(list);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HSTS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTS
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ALTSVC (3)
  - CURLOPT_HSTS_CTRL (3)
  - CURLOPT_RESOLVE (3)

---

# NAME

CURLOPT_HSTS - HSTS cache filename

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTS
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ALTSVC (3)
  - CURLOPT_HSTS_CTRL (3)
  - CURLOPT_RESOLVE (3)
Added-in: 7.74.0
---

# NAME

CURLOPT_HSTS - HSTS cache filename

# SYNOPSIS
55
56
57
58
59
60
61


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
Lines starting with "#" are treated as comments and are ignored. There is
currently no length or size limit.

# DEFAULT

NULL, no filename



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_HSTS, "/home/user/.hsts-cache");
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.74.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>













|
<
<




56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78


79
80
81
82
Lines starting with "#" are treated as comments and are ignored. There is
currently no length or size limit.

# DEFAULT

NULL, no filename

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_HSTS, "/home/user/.hsts-cache");
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HSTSREADDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTSREADDATA
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HSTS (3)
  - CURLOPT_HSTSREADFUNCTION (3)
  - CURLOPT_HSTSWRITEDATA (3)
  - CURLOPT_HSTSWRITEFUNCTION (3)

---

# NAME

CURLOPT_HSTSREADDATA - pointer passed to the HSTS read callback

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTSREADDATA
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HSTS (3)
  - CURLOPT_HSTSREADFUNCTION (3)
  - CURLOPT_HSTSWRITEDATA (3)
  - CURLOPT_HSTSWRITEFUNCTION (3)
Added-in: 7.74.0
---

# NAME

CURLOPT_HSTSREADDATA - pointer passed to the HSTS read callback

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct MyData {
  void *custom;
};








>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct MyData {
  void *custom;
};

57
58
59
60
61
62
63
64
65
66
67
68
69
70
    curl_easy_setopt(curl, CURLOPT_HSTSREADDATA, &this);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.74.0

# RETURN VALUE

This returns CURLE_OK.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71
    curl_easy_setopt(curl, CURLOPT_HSTSREADDATA, &this);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HSTSREADFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTSREADFUNCTION
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HSTS (3)
  - CURLOPT_HSTSREADDATA (3)
  - CURLOPT_HSTSWRITEFUNCTION (3)
  - CURLOPT_HSTS_CTRL (3)

---

# NAME

CURLOPT_HSTSREADFUNCTION - read callback for HSTS hosts

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTSREADFUNCTION
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HSTS (3)
  - CURLOPT_HSTSREADDATA (3)
  - CURLOPT_HSTSWRITEFUNCTION (3)
  - CURLOPT_HSTS_CTRL (3)
Added-in: 7.74.0
---

# NAME

CURLOPT_HSTSREADFUNCTION - read callback for HSTS hosts

# SYNOPSIS
59
60
61
62
63
64
65


66
67
68
69
70
71
72
This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

NULL - no callback.



# EXAMPLE

~~~c
struct priv {
  void *custom;
};








>
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

NULL - no callback.

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *custom;
};

91
92
93
94
95
96
97
98
99
100
101
102
103
104
    curl_easy_setopt(curl, CURLOPT_HSTSREADDATA, &my_stuff);

    res = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.74.0

# RETURN VALUE

This returns CURLE_OK.







|
<
<




94
95
96
97
98
99
100
101


102
103
104
105
    curl_easy_setopt(curl, CURLOPT_HSTSREADDATA, &my_stuff);

    res = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HSTSWRITEDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTSWRITEDATA
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HSTS (3)
  - CURLOPT_HSTSREADDATA (3)
  - CURLOPT_HSTSREADFUNCTION (3)
  - CURLOPT_HSTSWRITEFUNCTION (3)

---

# NAME

CURLOPT_HSTSWRITEDATA - pointer passed to the HSTS write callback

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTSWRITEDATA
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HSTS (3)
  - CURLOPT_HSTSREADDATA (3)
  - CURLOPT_HSTSREADFUNCTION (3)
  - CURLOPT_HSTSWRITEFUNCTION (3)
Added-in: 7.74.0
---

# NAME

CURLOPT_HSTSWRITEDATA - pointer passed to the HSTS write callback

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct MyData {
  void *custom;
};








>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct MyData {
  void *custom;
};

57
58
59
60
61
62
63
64
65
66
67
68
69
70
    curl_easy_setopt(curl, CURLOPT_HSTSWRITEDATA, &this);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.74.0

# RETURN VALUE

This returns CURLE_OK.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71
    curl_easy_setopt(curl, CURLOPT_HSTSWRITEDATA, &this);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HSTSWRITEFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTSWRITEFUNCTION
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HSTS (3)
  - CURLOPT_HSTSWRITEDATA (3)
  - CURLOPT_HSTSWRITEFUNCTION (3)
  - CURLOPT_HSTS_CTRL (3)

---

# NAME

CURLOPT_HSTSWRITEFUNCTION - write callback for HSTS hosts

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTSWRITEFUNCTION
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HSTS (3)
  - CURLOPT_HSTSWRITEDATA (3)
  - CURLOPT_HSTSWRITEFUNCTION (3)
  - CURLOPT_HSTS_CTRL (3)
Added-in: 7.74.0
---

# NAME

CURLOPT_HSTSWRITEFUNCTION - write callback for HSTS hosts

# SYNOPSIS
63
64
65
66
67
68
69


70
71
72
73
74
75
76
This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

NULL - no callback.



# EXAMPLE

~~~c
struct priv {
  void *custom;
};








>
>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

NULL - no callback.

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *custom;
};

95
96
97
98
99
100
101
102
103
104
105
106
107
108
    curl_easy_setopt(curl, CURLOPT_HSTSWRITEDATA, &my_stuff);

    res = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.74.0

# RETURN VALUE

This returns CURLE_OK.







|
<
<




98
99
100
101
102
103
104
105


106
107
108
109
    curl_easy_setopt(curl, CURLOPT_HSTSWRITEDATA, &my_stuff);

    res = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HSTS_CTRL.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTS_CTRL
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ALTSVC (3)
  - CURLOPT_CONNECT_TO (3)
  - CURLOPT_HSTS (3)
  - CURLOPT_RESOLVE (3)

---

# NAME

CURLOPT_HSTS_CTRL - control HSTS behavior

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HSTS_CTRL
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ALTSVC (3)
  - CURLOPT_CONNECT_TO (3)
  - CURLOPT_HSTS (3)
  - CURLOPT_RESOLVE (3)
Added-in: 7.74.0
---

# NAME

CURLOPT_HSTS_CTRL - control HSTS behavior

# SYNOPSIS
48
49
50
51
52
53
54

55

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
## CURLHSTS_READONLYFILE

Make the HSTS file (if specified) read-only - makes libcurl not save the cache
to the file when closing the handle.

# DEFAULT


0. HSTS is disabled by default.


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_HSTS_CTRL, (long)CURLHSTS_ENABLE);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.74.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
|
>














|
<
<




49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73


74
75
76
77
## CURLHSTS_READONLYFILE

Make the HSTS file (if specified) read-only - makes libcurl not save the cache
to the file when closing the handle.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_HSTS_CTRL, (long)CURLHSTS_ENABLE);
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTP09_ALLOWED.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP09_ALLOWED
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_SSLVERSION (3)

---

# NAME

CURLOPT_HTTP09_ALLOWED - allow HTTP/0.9 response

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP09_ALLOWED
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_SSLVERSION (3)
Added-in: 7.64.0
---

# NAME

CURLOPT_HTTP09_ALLOWED - allow HTTP/0.9 response

# SYNOPSIS
29
30
31
32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

56

57


58

59
60
61
62

An HTTP/0.9 response is a server response entirely without headers and only a
body. You can connect to lots of random TCP services and still get a response
that curl might consider to be HTTP/0.9!

# DEFAULT

curl allowed HTTP/0.9 responses by default before 7.66.0

Since 7.66.0, libcurl requires this option set to 1L to allow HTTP/0.9
responses.


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HTTP09_ALLOWED, 1L);
    ret = curl_easy_perform(curl);
  }
}
~~~


# AVAILABILITY




Option added in 7.64.0, present along with HTTP.


# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







<
|
|
<
>
















>
|
>

>
>
|
>




30
31
32
33
34
35
36

37
38

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

An HTTP/0.9 response is a server response entirely without headers and only a
body. You can connect to lots of random TCP services and still get a response
that curl might consider to be HTTP/0.9!

# DEFAULT


0


# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HTTP09_ALLOWED, 1L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# HISTORY

curl allowed HTTP/0.9 responses by default before 7.66.0

Since 7.66.0, libcurl requires this option set to 1L to allow HTTP/0.9
responses.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTP200ALIASES.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP200ALIASES
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTP09_ALLOWED (3)
  - CURLOPT_HTTP_VERSION (3)

---

# NAME

CURLOPT_HTTP200ALIASES - alternative matches for HTTP 200 OK

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP200ALIASES
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTP09_ALLOWED (3)
  - CURLOPT_HTTP_VERSION (3)
Added-in: 7.10.3
---

# NAME

CURLOPT_HTTP200ALIASES - alternative matches for HTTP 200 OK

# SYNOPSIS
40
41
42
43
44
45
46


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
The alias itself is not parsed for any version strings. The protocol is
assumed to match HTTP 1.0 when an alias match.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    struct curl_slist *list;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    list = curl_slist_append(NULL, "ICY 200 OK");
    list = curl_slist_append(list, "WEIRDO 99 FINE");

    curl_easy_setopt(curl, CURLOPT_HTTP200ALIASES, list);
    curl_easy_perform(curl);
    curl_slist_free_all(list); /* free the list again */
  }
}
~~~

# AVAILABILITY

Added in 7.10.3

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<




41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
The alias itself is not parsed for any version strings. The protocol is
assumed to match HTTP 1.0 when an alias match.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    struct curl_slist *list;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    list = curl_slist_append(NULL, "ICY 200 OK");
    list = curl_slist_append(list, "WEIRDO 99 FINE");

    curl_easy_setopt(curl, CURLOPT_HTTP200ALIASES, list);
    curl_easy_perform(curl);
    curl_slist_free_all(list); /* free the list again */
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTPAUTH.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTPAUTH
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_PASSWORD (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_USERNAME (3)

---

# NAME

CURLOPT_HTTPAUTH - HTTP server authentication methods to try

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTPAUTH
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_PASSWORD (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_USERNAME (3)
Added-in: 7.10.6
---

# NAME

CURLOPT_HTTPAUTH - HTTP server authentication methods to try

# SYNOPSIS
121
122
123
124
125
126
127


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157


158
159
160
161
162
163
provides AWS V4 signature authentication on HTTPS header
see CURLOPT_AWS_SIGV4(3).

# DEFAULT

CURLAUTH_BASIC



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* allow whatever auth the server speaks */
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
    curl_easy_setopt(curl, CURLOPT_USERPWD, "james:bond");
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Option Added in 7.10.6.

CURLAUTH_DIGEST_IE was added in 7.19.3

CURLAUTH_ONLY was added in 7.21.3

CURLAUTH_NTLM_WB was added in 7.22.0

CURLAUTH_BEARER was added in 7.61.0

CURLAUTH_AWS_SIGV4 was added in 7.74.0



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_NOT_BUILT_IN if the bitmask specified no supported authentication
methods.







>
>

















<
|
<










>
>






122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
provides AWS V4 signature authentication on HTTPS header
see CURLOPT_AWS_SIGV4(3).

# DEFAULT

CURLAUTH_BASIC

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* allow whatever auth the server speaks */
    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
    curl_easy_setopt(curl, CURLOPT_USERPWD, "james:bond");
    ret = curl_easy_perform(curl);
  }
}
~~~


# HISTORY


CURLAUTH_DIGEST_IE was added in 7.19.3

CURLAUTH_ONLY was added in 7.21.3

CURLAUTH_NTLM_WB was added in 7.22.0

CURLAUTH_BEARER was added in 7.61.0

CURLAUTH_AWS_SIGV4 was added in 7.74.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_NOT_BUILT_IN if the bitmask specified no supported authentication
methods.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTPGET.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTPGET
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_NOBODY (3)
  - CURLOPT_POST (3)
  - CURLOPT_UPLOAD (3)
  - curl_easy_reset (3)

---

# NAME

CURLOPT_HTTPGET - ask for an HTTP GET request

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTPGET
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_NOBODY (3)
  - CURLOPT_POST (3)
  - CURLOPT_UPLOAD (3)
  - curl_easy_reset (3)
Added-in: 7.8.1
---

# NAME

CURLOPT_HTTPGET - ask for an HTTP GET request

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
select which HTTP request method to use, they cannot deselect a method. To
reset a handle to default method, consider curl_easy_reset(3).

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* use a GET to fetch this */
    curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|
<
<




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
select which HTTP request method to use, they cannot deselect a method. To
reset a handle to default method, consider curl_easy_reset(3).

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* use a GET to fetch this */
    curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTPHEADER.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_HEADER (3)
  - CURLOPT_HEADEROPT (3)
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_PROXYHEADER (3)
  - curl_mime_init (3)

---

# NAME

CURLOPT_HTTPHEADER - set of HTTP headers

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_HEADER (3)
  - CURLOPT_HEADEROPT (3)
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_PROXYHEADER (3)
  - curl_mime_init (3)
Added-in: 7.1
---

# NAME

CURLOPT_HTTPHEADER - set of HTTP headers

# SYNOPSIS
109
110
111
112
113
114
115


116
117
118
119
120
121
122
123
124
125
126

Indicates the document's global structure type. By default, libcurl sets it
to "multipart/mixed", describing a document made of independent parts. When a
MIME mail is only composed of alternative representations of the same data
(i.e.: HTML and plain text), this header must be set to "multipart/alternative".
In all cases the value must be of the form "multipart/*" to respect the
document structure and may not include the "boundary=" parameter.



Other specific headers that do not have a libcurl default value but are
strongly desired by mail delivery and user agents should also be included.
These are "From:", "To:", "Date:" and "Subject:" among others and their
presence and value is generally checked by anti-spam utilities.

# SECURITY CONCERNS

By default, this option makes libcurl send the given headers in all HTTP
requests done by this handle. You should therefore use this option with
caution if you for example connect to the remote site using a proxy and a







>
>



|







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

Indicates the document's global structure type. By default, libcurl sets it
to "multipart/mixed", describing a document made of independent parts. When a
MIME mail is only composed of alternative representations of the same data
(i.e.: HTML and plain text), this header must be set to "multipart/alternative".
In all cases the value must be of the form "multipart/*" to respect the
document structure and may not include the "boundary=" parameter.

##

Other specific headers that do not have a libcurl default value but are
strongly desired by mail delivery and user agents should also be included.
These are `From:`, `To:`, `Date:` and `Subject:` among others and their
presence and value is generally checked by anti-spam utilities.

# SECURITY CONCERNS

By default, this option makes libcurl send the given headers in all HTTP
requests done by this handle. You should therefore use this option with
caution if you for example connect to the remote site using a proxy and a
144
145
146
147
148
149
150


151
152
153
154
155
156
157
sent to other hosts than the first used one, unless specifically permitted
with the CURLOPT_UNRESTRICTED_AUTH(3) option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();








>
>







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
sent to other hosts than the first used one, unless specifically permitted
with the CURLOPT_UNRESTRICTED_AUTH(3) option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();

168
169
170
171
172
173
174
175
176
177


178
179
180
181
    curl_easy_perform(curl);

    curl_slist_free_all(list); /* free the list */
  }
}
~~~

# AVAILABILITY

As long as HTTP is enabled. Use in MIME mail added in 7.56.0.



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
    curl_easy_perform(curl);

    curl_slist_free_all(list); /* free the list */
  }
}
~~~

# HISTORY

Use for MIME mail added in 7.56.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTPPOST.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
See-also:
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POST (3)
  - CURLOPT_POSTFIELDS (3)
  - curl_formadd (3)
  - curl_formfree (3)
  - curl_mime_init (3)

---

# NAME

CURLOPT_HTTPPOST - multipart formpost content

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
See-also:
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POST (3)
  - CURLOPT_POSTFIELDS (3)
  - curl_formadd (3)
  - curl_formfree (3)
  - curl_mime_init (3)
Added-in: 7.1
---

# NAME

CURLOPT_HTTPPOST - multipart formpost content

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57

When setting CURLOPT_HTTPPOST(3), libcurl automatically sets
CURLOPT_NOBODY(3) to 0.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  struct curl_httppost *formpost;







>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

When setting CURLOPT_HTTPPOST(3), libcurl automatically sets
CURLOPT_NOBODY(3) to 0.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  struct curl_httppost *formpost;
85
86
87
88
89
90
91
92
93
94


95
96
97
98
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
  curl_formfree(formpost);
}
~~~

# AVAILABILITY

As long as HTTP is enabled. Deprecated in 7.56.0.



# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
  curl_formfree(formpost);
}
~~~

# DEPRECATED

Deprecated in 7.56.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTPPROXYTUNNEL.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTPPROXYTUNNEL
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYPORT (3)
  - CURLOPT_PROXYTYPE (3)

---

# NAME

CURLOPT_HTTPPROXYTUNNEL - tunnel through HTTP proxy

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTPPROXYTUNNEL
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYPORT (3)
  - CURLOPT_PROXYTYPE (3)
Added-in: 7.3
---

# NAME

CURLOPT_HTTPPROXYTUNNEL - tunnel through HTTP proxy

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
proxy. By instead tunneling through the proxy, you avoid that conversion (that
rarely works through the proxy anyway).

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://127.0.0.1:80");
    curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>















|
<
<




46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
proxy. By instead tunneling through the proxy, you avoid that conversion (that
rarely works through the proxy anyway).

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://127.0.0.1:80");
    curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTP_CONTENT_DECODING.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP_CONTENT_DECODING
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ACCEPT_ENCODING (3)
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)

---

# NAME

CURLOPT_HTTP_CONTENT_DECODING - HTTP content decoding control

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP_CONTENT_DECODING
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ACCEPT_ENCODING (3)
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
Added-in: 7.16.2
---

# NAME

CURLOPT_HTTP_CONTENT_DECODING - HTTP content decoding control

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
default content decoding but requires you to use
CURLOPT_ACCEPT_ENCODING(3) for that.

# DEFAULT

1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.2

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>















|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61
default content decoding but requires you to use
CURLOPT_ACCEPT_ENCODING(3) for that.

# DEFAULT

1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, 0L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTP_TRANSFER_DECODING.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP_TRANSFER_DECODING
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ACCEPT_ENCODING (3)
  - CURLOPT_HTTP_CONTENT_DECODING (3)

---

# NAME

CURLOPT_HTTP_TRANSFER_DECODING - HTTP transfer decoding control

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP_TRANSFER_DECODING
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ACCEPT_ENCODING (3)
  - CURLOPT_HTTP_CONTENT_DECODING (3)
Added-in: 7.16.2
---

# NAME

CURLOPT_HTTP_TRANSFER_DECODING - HTTP transfer decoding control

# SYNOPSIS
26
27
28
29
30
31
32





33
34
35


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

# DESCRIPTION

Pass a long to tell libcurl how to act on transfer decoding. If set to zero,
transfer decoding is disabled, if set to 1 it is enabled (default). libcurl
does chunked transfer decoding by default unless this option is set to zero.






# DEFAULT

1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.2 Does not work with the hyper backend (it always has transfer
decoding enabled).

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>
>
>
>



>
>
















|
<
<
<




27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60



61
62
63
64

# DESCRIPTION

Pass a long to tell libcurl how to act on transfer decoding. If set to zero,
transfer decoding is disabled, if set to 1 it is enabled (default). libcurl
does chunked transfer decoding by default unless this option is set to zero.

# NOTES

This option does not work with the hyper backend as that always has transfer
decoding enabled.

# DEFAULT

1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, 0L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_HTTP_VERSION.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP_VERSION
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ALTSVC (3)
  - CURLOPT_HTTP09_ALLOWED (3)
  - CURLOPT_HTTP200ALIASES (3)
  - CURLOPT_SSLVERSION (3)

---

# NAME

CURLOPT_HTTP_VERSION - HTTP protocol version to use

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_HTTP_VERSION
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_ALTSVC (3)
  - CURLOPT_HTTP09_ALLOWED (3)
  - CURLOPT_HTTP200ALIASES (3)
  - CURLOPT_SSLVERSION (3)
Added-in: 7.9.1
---

# NAME

CURLOPT_HTTP_VERSION - HTTP protocol version to use

# SYNOPSIS
85
86
87
88
89
90
91


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

# DEFAULT

Since curl 7.62.0: CURL_HTTP_VERSION_2TLS

Before that: CURL_HTTP_VERSION_1_1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HTTP_VERSION,
                     (long)CURL_HTTP_VERSION_2TLS);
    ret = curl_easy_perform(curl);
    if(ret == CURLE_HTTP_RETURNED_ERROR) {
      /* an HTTP response error problem */
    }
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114


115
116
117
118

# DEFAULT

Since curl 7.62.0: CURL_HTTP_VERSION_2TLS

Before that: CURL_HTTP_VERSION_1_1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_HTTP_VERSION,
                     (long)CURL_HTTP_VERSION_2TLS);
    ret = curl_easy_perform(curl);
    if(ret == CURLE_HTTP_RETURNED_ERROR) {
      /* an HTTP response error problem */
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_IGNORE_CONTENT_LENGTH.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_IGNORE_CONTENT_LENGTH
Section: 3
Source: libcurl
Protocol:
  - HTTP
  - FTP
See-also:
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_MAXFILESIZE_LARGE (3)

---

# NAME

CURLOPT_IGNORE_CONTENT_LENGTH - ignore content length

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_IGNORE_CONTENT_LENGTH
Section: 3
Source: libcurl
Protocol:
  - HTTP
  - FTP
See-also:
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_MAXFILESIZE_LARGE (3)
Added-in: 7.14.1
---

# NAME

CURLOPT_IGNORE_CONTENT_LENGTH - ignore content length

# SYNOPSIS
41
42
43
44
45
46
47


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67



68



69
70
71
72

Only use this option if strictly necessary.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* we know the server is silly, ignore content-length */
    curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.14.1. Support for FTP added in 7.46.0. This option is not working



for HTTP when libcurl is built to use the hyper backend.




# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|

|
>
>
>
|
>
>
>




42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

Only use this option if strictly necessary.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* we know the server is silly, ignore content-length */
    curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

Support for FTP added in 7.46.0.

# NOTES

This option is not working for HTTP when libcurl is built to use the hyper
backend.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_INFILESIZE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INFILESIZE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3)
  - CURLOPT_INFILESIZE_LARGE (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - All

---

# NAME

CURLOPT_INFILESIZE - size of the input file to send off

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INFILESIZE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3)
  - CURLOPT_INFILESIZE_LARGE (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_INFILESIZE - size of the input file to send off

# SYNOPSIS
46
47
48
49
50
51
52


53
54
55
56
57
58
59
controlled entirely by what the read callback returns, but telling one value
and sending a different amount may lead to errors.

# DEFAULT

Unset



# EXAMPLE

~~~c

#define FILE_SIZE 12345L

int main(void)







>
>







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
controlled entirely by what the read callback returns, but telling one value
and sending a different amount may lead to errors.

# DEFAULT

Unset

# %PROTOCOLS%

# EXAMPLE

~~~c

#define FILE_SIZE 12345L

int main(void)
70
71
72
73
74
75
76
77
78
79


80
81
82
83
    curl_easy_setopt(curl, CURLOPT_INFILESIZE, uploadsize);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

SMTP support added in 7.23.0



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|


>
>




73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    curl_easy_setopt(curl, CURLOPT_INFILESIZE, uploadsize);

    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

SMTP support added in 7.23.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_INFILESIZE_LARGE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INFILESIZE_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3)
  - CURLOPT_INFILESIZE (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - All

---

# NAME

CURLOPT_INFILESIZE_LARGE - size of the input file to send off

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INFILESIZE_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_CONTENT_LENGTH_UPLOAD_T (3)
  - CURLOPT_INFILESIZE (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - All
Added-in: 7.11.0
---

# NAME

CURLOPT_INFILESIZE_LARGE - size of the input file to send off

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
controlled entirely by what the read callback returns, but telling one value
and sending a different amount may lead to errors.

# DEFAULT

Unset



# EXAMPLE

~~~c
#define FILE_SIZE 123456

int main(void)
{







>
>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
controlled entirely by what the read callback returns, but telling one value
and sending a different amount may lead to errors.

# DEFAULT

Unset

# %PROTOCOLS%

# EXAMPLE

~~~c
#define FILE_SIZE 123456

int main(void)
{
66
67
68
69
70
71
72
73
74
75


76
77
78
79
    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadsize);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

SMTP support added in 7.23.0



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|


>
>




69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadsize);

    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

SMTP support added in 7.23.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_INTERFACE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

75

76
77


78
79
80
81
82
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INTERFACE
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_SOCKOPTFUNCTION (3)
  - CURLOPT_TCP_NODELAY (3)
  - CURLOPT_LOCALPORT (3)

---

# NAME

CURLOPT_INTERFACE - source interface for outgoing traffic

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_INTERFACE, char *interface);
~~~

# DESCRIPTION

Pass a char pointer as parameter. This sets the *interface* name to use as
outgoing network interface. The name can be an interface name, an IP address,
or a hostname.


If the parameter starts with "if!" then it is treated only as an interface
name. If the parameter starts with "host!" it is treated as either an IP
address or a hostname.


If "if!" is specified but the parameter does not match an existing interface,
*CURLE_INTERFACE_FAILED* is returned from the libcurl function used to perform
the transfer.

libcurl does not support using network interface names for this option on
Windows.

We strongly advise against specifying the interface with a hostname, as it
causes libcurl to do a blocking name resolve call to retrieve the IP
address. That name resolve operation does **not** use DNS-over-HTTPS even if
CURLOPT_DOH_URL(3) is set.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use whatever the TCP stack finds suitable



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_INTERFACE, "eth0");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~


# AVAILABILITY


The "if!" and "host!" syntax was added in 7.24.0.



# RETURN VALUE

Returns CURLE_OK on success or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.












>


















|
>

|
<
|
>

|
|
|















>
>




















>
|
>

|
>
>





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INTERFACE
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_SOCKOPTFUNCTION (3)
  - CURLOPT_TCP_NODELAY (3)
  - CURLOPT_LOCALPORT (3)
Added-in: 7.3
---

# NAME

CURLOPT_INTERFACE - source interface for outgoing traffic

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_INTERFACE, char *interface);
~~~

# DESCRIPTION

Pass a char pointer as parameter. This sets the *interface* name to use as
outgoing network interface. The name can be an interface name, an IP address,
or a hostname. If you prefer one of these, you can use the following special
prefixes:

* `if!\<name\>` - Interface name

* `host!\<name\>` - IP address or hostname
* `ifhost!\<interface\>!\<host\>` - Interface name and IP address or hostname

If `if!` or `ifhost!` is specified but the parameter does not match an existing
interface, *CURLE_INTERFACE_FAILED* is returned from the libcurl function used
to perform the transfer.

libcurl does not support using network interface names for this option on
Windows.

We strongly advise against specifying the interface with a hostname, as it
causes libcurl to do a blocking name resolve call to retrieve the IP
address. That name resolve operation does **not** use DNS-over-HTTPS even if
CURLOPT_DOH_URL(3) is set.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use whatever the TCP stack finds suitable

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_INTERFACE, "eth0");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

The `if!` and `host!` syntax was added in 7.24.0.

The `ifhost!` syntax was added in 8.9.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK on success or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INTERLEAVEDATA
Section: 3
Source: libcurl
Protocol:
  - RTSP
See-also:
  - CURLOPT_INTERLEAVEFUNCTION (3)
  - CURLOPT_RTSP_REQUEST (3)

---

# NAME

CURLOPT_INTERLEAVEDATA - pointer passed to RTSP interleave callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INTERLEAVEDATA
Section: 3
Source: libcurl
Protocol:
  - RTSP
See-also:
  - CURLOPT_INTERLEAVEFUNCTION (3)
  - CURLOPT_RTSP_REQUEST (3)
Added-in: 7.20.0
---

# NAME

CURLOPT_INTERLEAVEDATA - pointer passed to RTSP interleave callback

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
CURLOPT_INTERLEAVEFUNCTION(3) when interleaved RTP data is received. If
the interleave function callback is not set, this pointer is not used
anywhere.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct local {
  void *custom;
};







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
CURLOPT_INTERLEAVEFUNCTION(3) when interleaved RTP data is received. If
the interleave function callback is not set, this pointer is not used
anywhere.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct local {
  void *custom;
};
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    curl_easy_setopt(curl, CURLOPT_INTERLEAVEDATA, &rtp_data);

    curl_easy_perform(curl);
 }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71
    curl_easy_setopt(curl, CURLOPT_INTERLEAVEDATA, &rtp_data);

    curl_easy_perform(curl);
 }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_INTERLEAVEFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INTERLEAVEFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INTERLEAVEDATA (3)
  - CURLOPT_RTSP_REQUEST (3)
Protocol:
  - RTSP

---

# NAME

CURLOPT_INTERLEAVEFUNCTION - callback for RTSP interleaved data

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_INTERLEAVEFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INTERLEAVEDATA (3)
  - CURLOPT_RTSP_REQUEST (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLOPT_INTERLEAVEFUNCTION - callback for RTSP interleaved data

# SYNOPSIS
61
62
63
64
65
66
67


68
69
70
71
72
73
74
You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. (7.87.0)

# DEFAULT

NULL, the interleave data is then passed to the regular write function:
CURLOPT_WRITEFUNCTION(3).



# EXAMPLE

~~~c
struct local {
  void *custom;
};








>
>







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
You can also abort the transfer by returning CURL_WRITEFUNC_ERROR. (7.87.0)

# DEFAULT

NULL, the interleave data is then passed to the regular write function:
CURLOPT_WRITEFUNCTION(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
struct local {
  void *custom;
};

87
88
89
90
91
92
93
94
95
96
97
98
99
100
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_INTERLEAVEFUNCTION, rtp_write);
    curl_easy_setopt(curl, CURLOPT_INTERLEAVEDATA, &rtp_data);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




90
91
92
93
94
95
96
97


98
99
100
101
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_INTERLEAVEFUNCTION, rtp_write);
    curl_easy_setopt(curl, CURLOPT_INTERLEAVEDATA, &rtp_data);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_IOCTLDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_IOCTLDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_IOCTLFUNCTION (3)
  - CURLOPT_SEEKFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_IOCTLDATA - pointer passed to I/O callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_IOCTLDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_IOCTLFUNCTION (3)
  - CURLOPT_SEEKFUNCTION (3)
Protocol:
  - All
Added-in: 7.12.3
---

# NAME

CURLOPT_IOCTLDATA - pointer passed to I/O callback

# SYNOPSIS
26
27
28
29
30
31
32

33

34
35
36
37
38
39
40
# DESCRIPTION

Pass the *pointer* that is untouched by libcurl and passed as the 3rd
argument in the ioctl callback set with CURLOPT_IOCTLFUNCTION(3).

# DEFAULT


By default, the value of this parameter is NULL.


# EXAMPLE

~~~c
#include <unistd.h> /* for lseek */

struct data {







>
|
>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# DESCRIPTION

Pass the *pointer* that is untouched by libcurl and passed as the 3rd
argument in the ioctl callback set with CURLOPT_IOCTLFUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <unistd.h> /* for lseek */

struct data {
57
58
59
60
61
62
63
64
65
66


67
68
69
70
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_callback);
    curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &ioctl_data);
  }
}
~~~

# AVAILABILITY

Added in 7.12.3. Deprecated since 7.18.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_callback);
    curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &ioctl_data);
  }
}
~~~

# DEPRECATED

Deprecated since 7.18.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_IOCTLFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_IOCTLFUNCTION
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_IOCTLDATA (3)
  - CURLOPT_SEEKFUNCTION (3)

---

# NAME

CURLOPT_IOCTLFUNCTION - callback for I/O operations

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_IOCTLFUNCTION
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_IOCTLDATA (3)
  - CURLOPT_SEEKFUNCTION (3)
Added-in: 7.12.3
---

# NAME

CURLOPT_IOCTLFUNCTION - callback for I/O operations

# SYNOPSIS
57
58
59
60
61
62
63

64

65
66
67
68
69
70
71

**This option is deprecated**. Do not use it. Use CURLOPT_SEEKFUNCTION(3)
instead to provide seeking! If CURLOPT_SEEKFUNCTION(3) is set, this
parameter is ignored when seeking.

# DEFAULT


By default, this parameter is set to NULL. Not used.


# EXAMPLE

~~~c
#include <unistd.h> /* for lseek */

struct data {







>
|
>







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

**This option is deprecated**. Do not use it. Use CURLOPT_SEEKFUNCTION(3)
instead to provide seeking! If CURLOPT_SEEKFUNCTION(3) is set, this
parameter is ignored when seeking.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <unistd.h> /* for lseek */

struct data {
88
89
90
91
92
93
94
95
96
97


98
99
100
101
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_callback);
    curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &ioctl_data);
  }
}
~~~

# AVAILABILITY

Added in 7.12.3. Deprecated since 7.18.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_callback);
    curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &ioctl_data);
  }
}
~~~

# DEPRECATED

Deprecated since 7.18.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_IPRESOLVE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_IPRESOLVE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_RESOLVE (3)
  - CURLOPT_SSLVERSION (3)
Protocol:
  - All

---

# NAME

CURLOPT_IPRESOLVE - IP protocol version to use

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_IPRESOLVE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_RESOLVE (3)
  - CURLOPT_SSLVERSION (3)
Protocol:
  - All
Added-in: 7.10.8
---

# NAME

CURLOPT_IPRESOLVE - IP protocol version to use

# SYNOPSIS
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

Uses only IPv6 addresses.

# DEFAULT

CURL_IPRESOLVE_WHATEVER



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    /* of all addresses example.com resolves to, only IPv6 ones are used */
    curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>




















|
<
<




49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78


79
80
81
82

Uses only IPv6 addresses.

# DEFAULT

CURL_IPRESOLVE_WHATEVER

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    /* of all addresses example.com resolves to, only IPv6 ones are used */
    curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ISSUERCERT.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_ISSUERCERT - issuer SSL certificate filename

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.19.0
---

# NAME

CURLOPT_ISSUERCERT - issuer SSL certificate filename

# SYNOPSIS
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_ISSUERCERT, "/etc/certs/cacert.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

If built TLS enabled

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|
<
<





49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74


75
76
77
78
79
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_ISSUERCERT, "/etc/certs/cacert.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_ISSUERCERT_BLOB.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_ISSUERCERT (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLOPT_ISSUERCERT_BLOB - issuer SSL certificate from memory blob

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_ISSUERCERT (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.71.0
---

# NAME

CURLOPT_ISSUERCERT_BLOB - issuer SSL certificate from memory blob

# SYNOPSIS
54
55
56
57
58
59
60


61
62
63
64
65
66
67
This option is an alternative to CURLOPT_ISSUERCERT(3) which instead
expects a filename as input.

# DEFAULT

NULL



# EXAMPLE

~~~c

extern char *certificateData;
extern size_t filesize;








>
>







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
This option is an alternative to CURLOPT_ISSUERCERT(3) which instead
expects a filename as input.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c

extern char *certificateData;
extern size_t filesize;

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    curl_easy_setopt(curl, CURLOPT_ISSUERCERT_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.71.0. This option is supported by the OpenSSL backends.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<





81
82
83
84
85
86
87
88


89
90
91
92
93
    curl_easy_setopt(curl, CURLOPT_ISSUERCERT_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_KEEP_SENDING_ON_ERROR.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_KEEP_SENDING_ON_ERROR
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - CURLOPT_FAILONERROR (3)
  - CURLOPT_HTTPHEADER (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_KEEP_SENDING_ON_ERROR - keep sending on early HTTP response \>= 300

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_KEEP_SENDING_ON_ERROR
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RESPONSE_CODE (3)
  - CURLOPT_FAILONERROR (3)
  - CURLOPT_HTTPHEADER (3)
Protocol:
  - HTTP
Added-in: 7.51.0
---

# NAME

CURLOPT_KEEP_SENDING_ON_ERROR - keep sending on early HTTP response \>= 300

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

Most applications do not need this option.

# DEFAULT

0, stop sending on error



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "sending data");
    curl_easy_setopt(curl, CURLOPT_KEEP_SENDING_ON_ERROR, 1L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP. Added in 7.51.0.

# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.







>
>
















|
<
<




38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67

Most applications do not need this option.

# DEFAULT

0, stop sending on error

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "sending data");
    curl_easy_setopt(curl, CURLOPT_KEEP_SENDING_ON_ERROR, 1L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is enabled, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_KEYPASSWD.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
71
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - mbedTLS
  - Schannel
  - wolfSSL

---

# NAME

CURLOPT_KEYPASSWD - passphrase to private key

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KEYPASSWD, char *pwd);
~~~

# DESCRIPTION

Pass a pointer to a null-terminated string as parameter. It is used as the
password required to use the CURLOPT_SSLKEY(3) or
CURLOPT_SSH_PRIVATE_KEYFILE(3) private key. You never need a pass phrase to
load a certificate but you need one to load your private key.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "superman");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option was known as CURLOPT_SSLKEYPASSWD up to 7.16.4 and
CURLOPT_SSLCERTPASSWD up to 7.9.2.



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>


















|








>
>



















|



>
>





10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - mbedTLS
  - Schannel
  - wolfSSL
Added-in: 7.17.0
---

# NAME

CURLOPT_KEYPASSWD - passphrase to private key

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_KEYPASSWD, char *pwd);
~~~

# DESCRIPTION

Pass a pointer to a null-terminated string as parameter. It is used as the
password required to use the CURLOPT_SSLKEY(3) or
CURLOPT_SSH_PRIVATE_KEYFILE(3) private key. You never need a passphrase to
load a certificate but you need one to load your private key.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "superman");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

This option was known as CURLOPT_SSLKEYPASSWD up to 7.16.4 and
CURLOPT_SSLCERTPASSWD up to 7.9.2.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_KRBLEVEL.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_KRBLEVEL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_KRBLEVEL (3)
  - CURLOPT_USE_SSL (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_KRBLEVEL - FTP kerberos security level

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_KRBLEVEL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_KRBLEVEL (3)
  - CURLOPT_USE_SSL (3)
Protocol:
  - FTP
Added-in: 7.16.4
---

# NAME

CURLOPT_KRBLEVEL - FTP kerberos security level

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
64
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_KRBLEVEL, "private");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option was known as CURLOPT_KRB4LEVEL up to 7.16.3



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|


>
>





35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_KRBLEVEL, "private");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

This option was known as CURLOPT_KRB4LEVEL up to 7.16.3

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_LOCALPORT.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_LOCALPORT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_LOCAL_PORT (3)
  - CURLOPT_INTERFACE (3)
  - CURLOPT_LOCALPORTRANGE (3)
Protocol:
  - All

---

# NAME

CURLOPT_LOCALPORT - local port number to use for socket

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_LOCALPORT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_LOCAL_PORT (3)
  - CURLOPT_INTERFACE (3)
  - CURLOPT_LOCALPORTRANGE (3)
Protocol:
  - All
Added-in: 7.15.2
---

# NAME

CURLOPT_LOCALPORT - local port number to use for socket

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
and you are recommended to use CURLOPT_LOCALPORTRANGE(3) as well when
this option is set. Valid port numbers are 1 - 65535.

# DEFAULT

0, disabled - use whatever the system thinks is fine



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_LOCALPORT, 49152L);
    /* and try 20 more ports following that */
    curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, 20L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.2

# RETURN VALUE

Returns CURLE_OK







>
>


















|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
and you are recommended to use CURLOPT_LOCALPORTRANGE(3) as well when
this option is set. Valid port numbers are 1 - 65535.

# DEFAULT

0, disabled - use whatever the system thinks is fine

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_LOCALPORT, 49152L);
    /* and try 20 more ports following that */
    curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, 20L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_LOCALPORTRANGE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_LOCALPORTRANGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INTERFACE (3)
  - CURLOPT_LOCALPORT (3)
Protocol:
  - All

---

# NAME

CURLOPT_LOCALPORTRANGE - number of additional local ports to try

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_LOCALPORTRANGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INTERFACE (3)
  - CURLOPT_LOCALPORT (3)
Protocol:
  - All
Added-in: 7.15.2
---

# NAME

CURLOPT_LOCALPORTRANGE - number of additional local ports to try

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
setting this value to something too low might cause unnecessary connection
setup failures.

# DEFAULT

1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_LOCALPORT, 49152L);
    /* and try 20 more ports following that */
    curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, 20L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.2

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|
<
<




35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62


63
64
65
66
setting this value to something too low might cause unnecessary connection
setup failures.

# DEFAULT

1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_LOCALPORT, 49152L);
    /* and try 20 more ports following that */
    curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, 20L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_LOGIN_OPTIONS.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_PASSWORD (3)
  - CURLOPT_USERNAME (3)
Protocol:
  - IMAP
  - LDAP
  - POP3
  - SMTP

---

# NAME

CURLOPT_LOGIN_OPTIONS - login options

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_PASSWORD (3)
  - CURLOPT_USERNAME (3)
Protocol:
  - IMAP
  - LDAP
  - POP3
  - SMTP
Added-in: 7.34.0
---

# NAME

CURLOPT_LOGIN_OPTIONS - login options

# SYNOPSIS
47
48
49
50
51
52
53


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
77
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, "AUTH=*");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.34.0. Support for OpenLDAP added in 7.82.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|

|
>
>





48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, "AUTH=*");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Support for OpenLDAP added in 7.82.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_LIMIT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_LOW_SPEED_LIMIT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_TIME (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_MAX_SEND_SPEED_LARGE (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_LOW_SPEED_LIMIT - low speed limit in bytes per second

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_LOW_SPEED_LIMIT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_TIME (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_MAX_SEND_SPEED_LARGE (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_LOW_SPEED_LIMIT - low speed limit in bytes per second

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
CURLOPT_LOW_SPEED_TIME(3) seconds for libcurl to consider it to be too
slow and abort.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
CURLOPT_LOW_SPEED_TIME(3) seconds for libcurl to consider it to be too
slow and abort.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_LOW_SPEED_TIME.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_LOW_SPEED_TIME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_LOW_SPEED_TIME - low speed limit time period

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_LOW_SPEED_TIME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_LOW_SPEED_TIME - low speed limit time period

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
transfer speed should be below the CURLOPT_LOW_SPEED_LIMIT(3) for the
library to consider it too slow and abort.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
transfer speed should be below the CURLOPT_LOW_SPEED_LIMIT(3) for the
library to consider it too slow and abort.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




55
56
57
58
59
60
61
62


63
64
65
66
    }
    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAIL_AUTH.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAIL_AUTH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_FROM (3)
  - CURLOPT_MAIL_RCPT (3)
Protocol:
  - SMTP

---

# NAME

CURLOPT_MAIL_AUTH - SMTP authentication address

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAIL_AUTH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_FROM (3)
  - CURLOPT_MAIL_RCPT (3)
Protocol:
  - SMTP
Added-in: 7.25.0
---

# NAME

CURLOPT_MAIL_AUTH - SMTP authentication address

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_MAIL_AUTH, "<secret@cave>");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.25.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|
<
<





45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
75
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_MAIL_AUTH, "<secret@cave>");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAIL_FROM.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAIL_FROM
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_AUTH (3)
  - CURLOPT_MAIL_RCPT (3)
Protocol:
  - SMTP

---

# NAME

CURLOPT_MAIL_FROM - SMTP sender address

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAIL_FROM
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_AUTH (3)
  - CURLOPT_MAIL_RCPT (3)
Protocol:
  - SMTP
Added-in: 7.20.0
---

# NAME

CURLOPT_MAIL_FROM - SMTP sender address

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "president@example.com");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|
<
<





38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
68
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "president@example.com");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAIL_RCPT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_AUTH (3)
  - CURLOPT_MAIL_FROM (3)
Protocol:
  - SMTP

---

# NAME

CURLOPT_MAIL_RCPT - list of SMTP mail recipients

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAIL_RCPT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_AUTH (3)
  - CURLOPT_MAIL_FROM (3)
Protocol:
  - SMTP
Added-in: 7.20.0
---

# NAME

CURLOPT_MAIL_RCPT - list of SMTP mail recipients

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
should be specified using the mailing list name, such as `Friends` or
`London-Office`.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    struct curl_slist *list;
    list = curl_slist_append(NULL, "root@localhost");
    list = curl_slist_append(list, "person@example.com");
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, list);
    res = curl_easy_perform(curl);
    curl_slist_free_all(list);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0. The **VRFY** and **EXPN** logic was added in 7.34.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<




45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74


75
76
77
78
should be specified using the mailing list name, such as `Friends` or
`London-Office`.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    struct curl_slist *list;
    list = curl_slist_append(NULL, "root@localhost");
    list = curl_slist_append(list, "person@example.com");
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, list);
    res = curl_easy_perform(curl);
    curl_slist_free_all(list);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLOWFAILS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAIL_RCPT_ALLOWFAILS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_FROM (3)
  - CURLOPT_MAIL_RCPT (3)
Protocol:
  - SMTP

---

# NAME

CURLOPT_MAIL_RCPT_ALLOWFAILS - allow RCPT TO command to fail for some recipients

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAIL_RCPT_ALLOWFAILS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_FROM (3)
  - CURLOPT_MAIL_RCPT (3)
Protocol:
  - SMTP
Added-in: 8.2.0
---

# NAME

CURLOPT_MAIL_RCPT_ALLOWFAILS - allow RCPT TO command to fail for some recipients

# SYNOPSIS
40
41
42
43
44
45
46


47
48
49
50
51
52
53
aborts the SMTP conversation and returns the error received from to the last
RCPT TO command.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
aborts the SMTP conversation and returns the error received from to the last
RCPT TO command.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
64
65
66
67
68
69
70
71
72
73

74
75

76
77
78
79
    res = curl_easy_perform(curl);
    curl_slist_free_all(list);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

This option was called CURLOPT_MAIL_RCPT_ALLLOWFAILS before 8.2.0


Added in 7.69.0.


# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>

<
>




67
68
69
70
71
72
73
74
75
76
77
78

79
80
81
82
83
    res = curl_easy_perform(curl);
    curl_slist_free_all(list);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

This option was called CURLOPT_MAIL_RCPT_ALLLOWFAILS (with three instead of
two letter L) before 8.2.0


# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAXAGE_CONN.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXAGE_CONN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_FRESH_CONNECT (3)
  - CURLOPT_MAXLIFETIME_CONN (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_MAXAGE_CONN - max idle time allowed for reusing a connection

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXAGE_CONN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_FRESH_CONNECT (3)
  - CURLOPT_MAXLIFETIME_CONN (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All
Added-in: 7.65.0
---

# NAME

CURLOPT_MAXAGE_CONN - max idle time allowed for reusing a connection

# SYNOPSIS
37
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
connections for reuse, since old connections have a higher risk of not working
and thus trying them is a performance loss and sometimes service loss due to
the difficulties to figure out the situation. If a connection is found in the
cache that is older than this set *age*, it is closed instead.

# DEFAULT

Default maximum age is set to 118 seconds.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* only allow 30 seconds idle time */
    curl_easy_setopt(curl, CURLOPT_MAXAGE_CONN, 30L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.65.0

# RETURN VALUE

Returns CURLE_OK.







|
>
>


















|
<
<




38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
connections for reuse, since old connections have a higher risk of not working
and thus trying them is a performance loss and sometimes service loss due to
the difficulties to figure out the situation. If a connection is found in the
cache that is older than this set *age*, it is closed instead.

# DEFAULT

118 seconds

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* only allow 30 seconds idle time */
    curl_easy_setopt(curl, CURLOPT_MAXAGE_CONN, 30L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAXCONNECTS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXCONNECTS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAXCONNECTS (3)
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLMOPT_MAX_TOTAL_CONNECTIONS (3)
  - CURLOPT_MAXREDIRS (3)
Protocol:
  - All

---

# NAME

CURLOPT_MAXCONNECTS - maximum connection cache size

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXCONNECTS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAXCONNECTS (3)
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLMOPT_MAX_TOTAL_CONNECTIONS (3)
  - CURLOPT_MAXREDIRS (3)
Protocol:
  - All
Added-in: 7.7
---

# NAME

CURLOPT_MAXCONNECTS - maximum connection cache size

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
acknowledged, and you must instead use curl_multi_setopt(3) and the
CURLMOPT_MAXCONNECTS(3) option.

# DEFAULT

5



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* limit the connection cache for this handle to no more than 3 */
    curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 3L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>
















|
<
<




45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
acknowledged, and you must instead use curl_multi_setopt(3) and the
CURLMOPT_MAXCONNECTS(3) option.

# DEFAULT

5

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* limit the connection cache for this handle to no more than 3 */
    curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 3L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXFILESIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAXFILESIZE_LARGE (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
Protocol:
  - All

---

# NAME

CURLOPT_MAXFILESIZE - maximum file size allowed to download

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXFILESIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAXFILESIZE_LARGE (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
Protocol:
  - All
Added-in: 7.10.8
---

# NAME

CURLOPT_MAXFILESIZE - maximum file size allowed to download

# SYNOPSIS
40
41
42
43
44
45
46


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Since 8.4.0, this option also stops ongoing transfers if they reach this
threshold.

# DEFAULT

0, meaning disabled.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* refuse to download if larger than 1000 bytes! */
    curl_easy_setopt(curl, CURLOPT_MAXFILESIZE, 1000L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK if the size passed is valid or CURLE_BAD_FUNCTION_ARGUMENT if
not.







>
>
















|
<
<





41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
71
Since 8.4.0, this option also stops ongoing transfers if they reach this
threshold.

# DEFAULT

0, meaning disabled.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* refuse to download if larger than 1000 bytes! */
    curl_easy_setopt(curl, CURLOPT_MAXFILESIZE, 1000L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the size passed is valid or CURLE_BAD_FUNCTION_ARGUMENT if
not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAXFILESIZE_LARGE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXFILESIZE_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAXFILESIZE (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
Protocol:
  - FTP
  - HTTP
  - MQTT

---

# NAME

CURLOPT_MAXFILESIZE_LARGE - maximum file size allowed to download

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXFILESIZE_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAXFILESIZE (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
Protocol:
  - FTP
  - HTTP
  - MQTT
Added-in: 7.11.0
---

# NAME

CURLOPT_MAXFILESIZE_LARGE - maximum file size allowed to download

# SYNOPSIS
41
42
43
44
45
46
47


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Since 8.4.0, this option also stops ongoing transfers if they reach this
threshold.

# DEFAULT

0, meaning disabled.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_off_t ridiculous = (curl_off_t)1 << 48;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* refuse to download if larger than ridiculous */
    curl_easy_setopt(curl, CURLOPT_MAXFILESIZE_LARGE, ridiculous);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.11.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_BAD_FUNCTION_ARGUMENT if the size passed is invalid.







>
>

















|
<
<





42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
73
Since 8.4.0, this option also stops ongoing transfers if they reach this
threshold.

# DEFAULT

0, meaning disabled.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_off_t ridiculous = (curl_off_t)1 << 48;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* refuse to download if larger than ridiculous */
    curl_easy_setopt(curl, CURLOPT_MAXFILESIZE_LARGE, ridiculous);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_BAD_FUNCTION_ARGUMENT if the size passed is invalid.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAXLIFETIME_CONN.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXLIFETIME_CONN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_FRESH_CONNECT (3)
  - CURLOPT_MAXAGE_CONN (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_MAXLIFETIME_CONN - max lifetime (since creation) allowed for reusing a connection

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXLIFETIME_CONN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_FRESH_CONNECT (3)
  - CURLOPT_MAXAGE_CONN (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All
Added-in: 7.80.0
---

# NAME

CURLOPT_MAXLIFETIME_CONN - max lifetime (since creation) allowed for reusing a connection

# SYNOPSIS
39
40
41
42
43
44
45
46


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
client-side load balancing. If a connection is found in the cache that is
older than this set *maxlifetime*, it is instead marked for closure.

If set to 0, this behavior is disabled: all connections are eligible for reuse.

# DEFAULT

Default *maxlifetime* is 0 seconds (i.e., disabled).



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* only allow each connection to be reused for 30 seconds */
    curl_easy_setopt(curl, CURLOPT_MAXLIFETIME_CONN, 30L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.80.0

# RETURN VALUE

Returns CURLE_OK.







|
>
>


















|
<
<




40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
client-side load balancing. If a connection is found in the cache that is
older than this set *maxlifetime*, it is instead marked for closure.

If set to 0, this behavior is disabled: all connections are eligible for reuse.

# DEFAULT

0 seconds (i.e., disabled)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* only allow each connection to be reused for 30 seconds */
    curl_easy_setopt(curl, CURLOPT_MAXLIFETIME_CONN, 30L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAXREDIRS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXREDIRS
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_URL (3)
  - CURLOPT_FOLLOWLOCATION (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_MAXREDIRS - maximum number of redirects allowed

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAXREDIRS
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLINFO_REDIRECT_URL (3)
  - CURLOPT_FOLLOWLOCATION (3)
Protocol:
  - HTTP
Added-in: 7.5
---

# NAME

CURLOPT_MAXREDIRS - maximum number of redirects allowed

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
Set it to -1 for an infinite number of redirects. This allows your application
to get stuck in never-ending redirect loops.

# DEFAULT

30 (since 8.3.0), it was previously unlimited.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Set it to -1 for an infinite number of redirects. This allows your application
to get stuck in never-ending redirect loops.

# DEFAULT

30 (since 8.3.0), it was previously unlimited.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
57
58
59
60
61
62
63
64
65
66
67
68
69
70

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAX_RECV_SPEED_LARGE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAX_RECV_SPEED_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_SEND_SPEED_LARGE (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_MAX_RECV_SPEED_LARGE - rate limit data download speed

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAX_RECV_SPEED_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_SEND_SPEED_LARGE (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All
Added-in: 7.15.5
---

# NAME

CURLOPT_MAX_RECV_SPEED_LARGE - rate limit data download speed

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

This option does not affect transfer speeds done with FILE:// URLs.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* cap the download speed to 31415 bytes/sec */
    curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)31415);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.5

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>
















|
<
<




40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69

This option does not affect transfer speeds done with FILE:// URLs.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* cap the download speed to 31415 bytes/sec */
    curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)31415);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MAX_SEND_SPEED_LARGE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAX_SEND_SPEED_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
Protocol:
  - All

---

# NAME

CURLOPT_MAX_SEND_SPEED_LARGE - rate limit data upload speed

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MAX_SEND_SPEED_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
Protocol:
  - All
Added-in: 7.15.5
---

# NAME

CURLOPT_MAX_SEND_SPEED_LARGE - rate limit data upload speed

# SYNOPSIS
40
41
42
43
44
45
46


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

This option does not affect transfer speeds done with FILE:// URLs.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* cap the upload speed to 1000 bytes/sec */
    curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t)1000);
    /* (set some upload options as well!) */
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.15.5

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71

This option does not affect transfer speeds done with FILE:// URLs.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* cap the upload speed to 1000 bytes/sec */
    curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t)1000);
    /* (set some upload options as well!) */
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MIMEPOST.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_PUT (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
  - SMTP
  - IMAP

---

# NAME

CURLOPT_MIMEPOST - send data from mime structure

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_PUT (3)
  - curl_mime_init (3)
Protocol:
  - HTTP
  - SMTP
  - IMAP
Added-in: 7.56.0
---

# NAME

CURLOPT_MIMEPOST - send data from mime structure

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51

This option is the preferred way of posting an HTTP form, replacing and
extending the CURLOPT_HTTPPOST(3) option.

When setting CURLOPT_MIMEPOST(3) to NULL, libcurl resets the request
type for HTTP to the default to disable the POST. Typically that would mean it
is reset to GET. Instead you should set a desired request method explicitly.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

This option is the preferred way of posting an HTTP form, replacing and
extending the CURLOPT_HTTPPOST(3) option.

When setting CURLOPT_MIMEPOST(3) to NULL, libcurl resets the request
type for HTTP to the default to disable the POST. Typically that would mean it
is reset to GET. Instead you should set a desired request method explicitly.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
68
69
70
71
72
73
74
75
76
77
78
79
80
81
      curl_easy_perform(curl); /* post away! */
      curl_mime_free(multipart); /* free the post data */
    }
  }
}
~~~

# AVAILABILITY

Added in 7.56.0

# RETURN VALUE

This returns CURLE_OK.







|
<
<




71
72
73
74
75
76
77
78


79
80
81
82
      curl_easy_perform(curl); /* post away! */
      curl_mime_free(multipart); /* free the post data */
    }
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_MIME_OPTIONS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MIME_OPTIONS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPOST (3)
  - CURLOPT_MIMEPOST (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP

---

# NAME

CURLOPT_MIME_OPTIONS - set MIME option flags

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MIME_OPTIONS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPOST (3)
  - CURLOPT_MIMEPOST (3)
Protocol:
  - HTTP
  - IMAP
  - SMTP
Added-in: 7.81.0
---

# NAME

CURLOPT_MIME_OPTIONS - set MIME option flags

# SYNOPSIS
52
53
54
55
56
57
58


59
60
61
62
63
64
65
*strangename%22kind*. When this option is set, it is sent as
*strangename"kind*.

# DEFAULT

0, meaning disabled.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  curl_mime *form = NULL;







>
>







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
*strangename%22kind*. When this option is set, it is sent as
*strangename"kind*.

# DEFAULT

0, meaning disabled.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  curl_mime *form = NULL;
84
85
86
87
88
89
90
91
92
93
94
95
96
97

    curl_easy_cleanup(curl);
    curl_mime_free(form);
  }
}
~~~

# AVAILABILITY

Option added in 7.81.0.

# RETURN VALUE

Returns CURLE_OK







|
<
<




87
88
89
90
91
92
93
94


95
96
97
98

    curl_easy_cleanup(curl);
    curl_mime_free(form);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_NETRC.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34


35
36
37
38
39
40
41
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NETRC
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NETRC_FILE (3)
  - CURLOPT_USERNAME (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - All

---

# NAME

CURLOPT_NETRC - enable use of .netrc

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NETRC, long level);
~~~

# DESCRIPTION

This parameter controls the preference *level* of libcurl between using
usernames and passwords from your *~/.netrc* file, relative to usernames and
passwords in the URL supplied with CURLOPT_URL(3).

On Windows, libcurl uses the file as *%HOME%/_netrc*. If *%HOME%* is
not set on Windows, libcurl falls back to *%USERPROFILE%*.



You can also tell libcurl a different filename to use with
CURLOPT_NETRC_FILE(3).

libcurl uses a username (and supplied or prompted password) supplied with
CURLOPT_USERPWD(3) or CURLOPT_USERNAME(3) in preference to any of
the options controlled by this parameter.












>




















|
|
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NETRC
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NETRC_FILE (3)
  - CURLOPT_USERNAME (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_NETRC - enable use of .netrc

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_NETRC, long level);
~~~

# DESCRIPTION

This parameter controls the preference *level* of libcurl between using
usernames and passwords from your *~/.netrc* file, relative to usernames and
passwords in the URL supplied with CURLOPT_URL(3).

On Windows, libcurl primarily checks for *.netrc* in *%HOME%*. If *%HOME%* is
not set on Windows, libcurl falls back to *%USERPROFILE%*. If the file does
not exist, it falls back to check if there is instead a file named *_netrc* -
using an underscore instead of period.

You can also tell libcurl a different filename to use with
CURLOPT_NETRC_FILE(3).

libcurl uses a username (and supplied or prompted password) supplied with
CURLOPT_USERPWD(3) or CURLOPT_USERNAME(3) in preference to any of
the options controlled by this parameter.
111
112
113
114
115
116
117


118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
rest of the .netrc to still work fine, libcurl properly skips every definition
done with "macdef" that it finds.

# DEFAULT

CURL_NETRC_IGNORED



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/");
    curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>















|
<
<




114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138


139
140
141
142
rest of the .netrc to still work fine, libcurl properly skips every definition
done with "macdef" that it finds.

# DEFAULT

CURL_NETRC_IGNORED

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/");
    curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_NETRC_FILE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NETRC_FILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NETRC (3)
  - CURLOPT_PASSWORD (3)
  - CURLOPT_USERNAME (3)
Protocol:
  - All

---

# NAME

CURLOPT_NETRC_FILE - filename to read .netrc info from

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NETRC_FILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NETRC (3)
  - CURLOPT_PASSWORD (3)
  - CURLOPT_USERNAME (3)
Protocol:
  - All
Added-in: 7.11.0
---

# NAME

CURLOPT_NETRC_FILE - filename to read .netrc info from

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/");
    curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
    curl_easy_setopt(curl, CURLOPT_NETRC_FILE, "/tmp/magic-netrc");
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10.9

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|
<
<





35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
65
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/");
    curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
    curl_easy_setopt(curl, CURLOPT_NETRC_FILE, "/tmp/magic-netrc");
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_NEW_DIRECTORY_PERMS.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_FTP_CREATE_MISSING_DIRS (3)
  - CURLOPT_NEW_FILE_PERMS (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - SFTP
  - SCP
  - FILE

---

# NAME

CURLOPT_NEW_DIRECTORY_PERMS - permissions for remotely created directories

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_FTP_CREATE_MISSING_DIRS (3)
  - CURLOPT_NEW_FILE_PERMS (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - SFTP
  - SCP
  - FILE
Added-in: 7.16.4
---

# NAME

CURLOPT_NEW_DIRECTORY_PERMS - permissions for remotely created directories

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
*0755*, but any valid value can be used. The only protocols that can use
this are *sftp://*, *scp://*, and *file://*.

# DEFAULT

0755



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL,
                     "sftp://upload.example.com/newdir/file.zip");
    curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);
    curl_easy_setopt(curl, CURLOPT_NEW_DIRECTORY_PERMS, 0644L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
*0755*, but any valid value can be used. The only protocols that can use
this are *sftp://*, *scp://*, and *file://*.

# DEFAULT

0755

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL,
                     "sftp://upload.example.com/newdir/file.zip");
    curl_easy_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);
    curl_easy_setopt(curl, CURLOPT_NEW_DIRECTORY_PERMS, 0644L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_NEW_FILE_PERMS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NEW_FILE_PERMS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NEW_DIRECTORY_PERMS (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - SFTP
  - SCP
  - FILE

---

# NAME

CURLOPT_NEW_FILE_PERMS - permissions for remotely created files

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NEW_FILE_PERMS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NEW_DIRECTORY_PERMS (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - SFTP
  - SCP
  - FILE
Added-in: 7.16.4
---

# NAME

CURLOPT_NEW_FILE_PERMS - permissions for remotely created files

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
set on newly created files on the remote server. The default value is *0644*.
The only protocols that can use this are *sftp://*, *scp://*, and *file://*.

# DEFAULT

0644



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://upload.example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_NEW_FILE_PERMS, 0664L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>















|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61
set on newly created files on the remote server. The default value is *0644*.
The only protocols that can use this are *sftp://*, *scp://*, and *file://*.

# DEFAULT

0644

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://upload.example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_NEW_FILE_PERMS, 0664L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_NOBODY.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_HTTPGET (3)
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_REQUEST_TARGET (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - All

---

# NAME

CURLOPT_NOBODY - do the download request without getting the body

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_HTTPGET (3)
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_REQUEST_TARGET (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_NOBODY - do the download request without getting the body

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
a body (unless the resource and server sends a zero byte body for the specific
URL you request).

# DEFAULT

0, the body is transferred



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* get us the resource without a body - use HEAD! */
    curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>


















|
<
<




46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73


74
75
76
77
a body (unless the resource and server sends a zero byte body for the specific
URL you request).

# DEFAULT

0, the body is transferred

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* get us the resource without a body - use HEAD! */
    curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_NOPROGRESS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NOPROGRESS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_PROGRESSFUNCTION (3)
  - CURLOPT_VERBOSE (3)
  - CURLOPT_XFERINFOFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_NOPROGRESS - switch off the progress meter

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NOPROGRESS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_PROGRESSFUNCTION (3)
  - CURLOPT_VERBOSE (3)
  - CURLOPT_XFERINFOFUNCTION (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_NOPROGRESS - switch off the progress meter

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
CURLOPT_XFERINFOFUNCTION(3) or CURLOPT_PROGRESSFUNCTION(3) from
getting called.

# DEFAULT

1, meaning it normally runs without a progress meter.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable progress meter */
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK.







>
>


















|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
CURLOPT_XFERINFOFUNCTION(3) or CURLOPT_PROGRESSFUNCTION(3) from
getting called.

# DEFAULT

1, meaning it normally runs without a progress meter.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable progress meter */
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_NOPROXY.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NOPROXY
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_PROXYTYPE (3)

---

# NAME

CURLOPT_NOPROXY - disable proxy use for specific hosts

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NOPROXY
Section: 3
Source: libcurl
Protocol:
  - All
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_PROXYTYPE (3)
Added-in: 7.19.4
---

# NAME

CURLOPT_NOPROXY - disable proxy use for specific hosts

# SYNOPSIS
56
57
58
59
60
61
62


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
it is used if the CURLOPT_NOPROXY(3) option is not set. It works exactly
the same way.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* accept various URLs */
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* use this proxy */
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80");
    /* ... but make sure this host name is not proxied */
    curl_easy_setopt(curl, CURLOPT_NOPROXY, "www.example.com");
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84


85
86
87
88
89
it is used if the CURLOPT_NOPROXY(3) option is not set. It works exactly
the same way.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* accept various URLs */
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* use this proxy */
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80");
    /* ... but make sure this host name is not proxied */
    curl_easy_setopt(curl, CURLOPT_NOPROXY, "www.example.com");
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_NOSIGNAL.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NOSIGNAL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_NOSIGNAL - skip all signal handling

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_NOSIGNAL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All
Added-in: 7.10
---

# NAME

CURLOPT_NOSIGNAL - skip all signal handling

# SYNOPSIS
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
systems have no way to avoid them and even on those that have there are some
corner cases when they may still happen, contrary to our desire.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");

    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71


72
73
74
75
systems have no way to avoid them and even on those that have there are some
corner cases when they may still happen, contrary to our desire.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");

    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_OPENSOCKETDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CLOSESOCKETFUNCTION (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - CURLOPT_SOCKOPTFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_OPENSOCKETDATA - pointer passed to open socket callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_OPENSOCKETDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CLOSESOCKETFUNCTION (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - CURLOPT_SOCKOPTFUNCTION (3)
Protocol:
  - All
Added-in: 7.17.1
---

# NAME

CURLOPT_OPENSOCKETDATA - pointer passed to open socket callback

# SYNOPSIS
28
29
30
31
32
33
34

35

36
37
38
39
40
41
42

Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the open socket callback set with
CURLOPT_OPENSOCKETFUNCTION(3).

# DEFAULT


The default value of this parameter is NULL.


# EXAMPLE

~~~c
/* make libcurl use the already established socket 'sockfd' */

static curl_socket_t opensocket(void *clientp,







>
|
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the open socket callback set with
CURLOPT_OPENSOCKETFUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
/* make libcurl use the already established socket 'sockfd' */

static curl_socket_t opensocket(void *clientp,
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.17.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




80
81
82
83
84
85
86
87


88
89
90
91
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_OPENSOCKETFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_OPENSOCKETFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CLOSESOCKETFUNCTION (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - CURLOPT_SOCKOPTFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_OPENSOCKETFUNCTION - callback for opening socket

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_OPENSOCKETFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CLOSESOCKETFUNCTION (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - CURLOPT_SOCKOPTFUNCTION (3)
Protocol:
  - All
Added-in: 7.17.1
---

# NAME

CURLOPT_OPENSOCKETFUNCTION - callback for opening socket

# SYNOPSIS
66
67
68
69
70
71
72
73
74
75
76


77
78
79
80
81
82
83

If you want to pass in a socket with an already established connection, pass
the socket back with this callback and then use
CURLOPT_SOCKOPTFUNCTION(3) to signal that it already is connected.

# DEFAULT

The default behavior is the equivalent of this:
~~~c
   return socket(addr->family, addr->socktype, addr->protocol);
~~~



# EXAMPLE

~~~c
/* make libcurl use the already established socket 'sockfd' */

static curl_socket_t opensocket(void *clientp,







|



>
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

If you want to pass in a socket with an already established connection, pass
the socket back with this callback and then use
CURLOPT_SOCKOPTFUNCTION(3) to signal that it already is connected.

# DEFAULT

The equivalent of this:
~~~c
   return socket(addr->family, addr->socktype, addr->protocol);
~~~

# %PROTOCOLS%

# EXAMPLE

~~~c
/* make libcurl use the already established socket 'sockfd' */

static curl_socket_t opensocket(void *clientp,
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.17.1.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




120
121
122
123
124
125
126
127


128
129
130
131
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PASSWORD.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PASSWORD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_USERNAME (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - All

---

# NAME

CURLOPT_PASSWORD - password to use in authentication

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PASSWORD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_USERNAME (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - All
Added-in: 7.19.1
---

# NAME

CURLOPT_PASSWORD - password to use in authentication

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_PASSWORD, "qwerty");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
70
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_PASSWORD, "qwerty");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PATH_AS_IS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PATH_AS_IS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
  - CURLOPT_URL (3)
  - curl_url_set (3)
Protocol:
  - All

---

# NAME

CURLOPT_PATH_AS_IS - do not handle dot dot sequences

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PATH_AS_IS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_STDERR (3)
  - CURLOPT_URL (3)
  - curl_url_set (3)
Protocol:
  - All
Added-in: 7.42.0
---

# NAME

CURLOPT_PATH_AS_IS - do not handle dot dot sequences

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
The corresponding flag for the curl_url_set(3) function is called
**CURLU_PATH_AS_IS**.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL,
                     "https://example.com/../../etc/password");

    curl_easy_setopt(curl, CURLOPT_PATH_AS_IS, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.42.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
The corresponding flag for the curl_url_set(3) function is called
**CURLU_PATH_AS_IS**.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL,
                     "https://example.com/../../etc/password");

    curl_easy_setopt(curl, CURLOPT_PATH_AS_IS, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PINNEDPUBLICKEY.md.
14
15
16
17
18
19
20

21
22
23
24
25
26
27
TLS-backend:
  - OpenSSL
  - GnuTLS
  - wolfSSL
  - mbedTLS
  - Secure Transport
  - Schannel

---

# NAME

CURLOPT_PINNEDPUBLICKEY - pinned public key

# SYNOPSIS







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
TLS-backend:
  - OpenSSL
  - GnuTLS
  - wolfSSL
  - mbedTLS
  - Secure Transport
  - Schannel
Added-in: 7.39.0
---

# NAME

CURLOPT_PINNEDPUBLICKEY - pinned public key

# SYNOPSIS
52
53
54
55
56
57
58


59
60
61
62
63
64
65

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
footer:
~~~
-----BEGIN PUBLIC KEY-----
[BASE 64 DATA]
-----END PUBLIC KEY-----
~~~

# AVAILABILITY

## PEM/DER support

7.39.0: OpenSSL, GnuTLS

7.43.0: wolfSSL








|







115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
footer:
~~~
-----BEGIN PUBLIC KEY-----
[BASE 64 DATA]
-----END PUBLIC KEY-----
~~~

# HISTORY

## PEM/DER support

7.39.0: OpenSSL, GnuTLS

7.43.0: wolfSSL

137
138
139
140
141
142
143


144
145
146
147
148
7.47.0: mbedTLS

7.54.1: Secure Transport on macOS 10.7+/iOS 10+

7.58.1: Schannel

Other SSL backends not supported.



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>





140
141
142
143
144
145
146
147
148
149
150
151
152
153
7.47.0: mbedTLS

7.54.1: Secure Transport on macOS 10.7+/iOS 10+

7.58.1: Schannel

Other SSL backends not supported.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PIPEWAIT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PIPEWAIT
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLMOPT_PIPELINING (3)
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_FRESH_CONNECT (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_PIPEWAIT - wait for multiplexing

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PIPEWAIT
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_MAX_HOST_CONNECTIONS (3)
  - CURLMOPT_PIPELINING (3)
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_FRESH_CONNECT (3)
Protocol:
  - HTTP
Added-in: 7.43.0
---

# NAME

CURLOPT_PIPEWAIT - wait for multiplexing

# SYNOPSIS
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
libcurl to get the necessary response back that informs it about its protocol
and support level.

# DEFAULT

0 (off)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PIPEWAIT, 1L);

    /* now add this easy handle to the multi handle */
  }
}
~~~

# AVAILABILITY

Added in 7.43.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>















|
<
<




49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73


74
75
76
77
libcurl to get the necessary response back that informs it about its protocol
and support level.

# DEFAULT

0 (off)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PIPEWAIT, 1L);

    /* now add this easy handle to the multi handle */
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PORT.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PORT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIMARY_PORT (3)
  - CURLOPT_STDERR (3)
  - CURLOPT_URL (3)
Protocol:
  - All

---

# NAME

CURLOPT_PORT - remote port number to connect to

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PORT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIMARY_PORT (3)
  - CURLOPT_STDERR (3)
  - CURLOPT_URL (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_PORT - remote port number to connect to

# SYNOPSIS
38
39
40
41
42
43
44
45
46


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

While this option accepts a 'long', a port number is an unsigned 16 bit number
and therefore using a port number lower than zero or over 65535 causes a
**CURLE_BAD_FUNCTION_ARGUMENT** error.

# DEFAULT

By default this is 0 which makes it not used. This also makes port number zero
impossible to set with this API.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PORT, 8080L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
|
>
>

















|
<
<




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71

While this option accepts a 'long', a port number is an unsigned 16 bit number
and therefore using a port number lower than zero or over 65535 causes a
**CURLE_BAD_FUNCTION_ARGUMENT** error.

# DEFAULT

0 which makes it not used. This also makes port number zero impossible to set
with this API.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PORT, 8080L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_POST.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_POST
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTPPOST (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_PUT (3)

---

# NAME

CURLOPT_POST - make an HTTP POST

# SYNOPSIS











|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_POST
Section: 3
Source: libcurl
Protocol:
  - HTTP
See-also:
  - CURLOPT_HTTPPOST (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_UPLOAD (3)
Added-in: 7.1
---

# NAME

CURLOPT_POST - make an HTTP POST

# SYNOPSIS
67
68
69
70
71
72
73


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
default to disable the POST. Typically that means gets reset to GET. Instead
you should set a new request type explicitly as described above.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_POST, 1L);

    /* set up the read callback with CURLOPT_READFUNCTION */

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<




68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97


98
99
100
101
default to disable the POST. Typically that means gets reset to GET. Instead
you should set a new request type explicitly as described above.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_POST, 1L);

    /* set up the read callback with CURLOPT_READFUNCTION */

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_POSTFIELDS.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POSTFIELDSIZE (3)
  - CURLOPT_READFUNCTION (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - HTTP
  - MQTT

---

# NAME

CURLOPT_POSTFIELDS - data to POST to server

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POSTFIELDSIZE (3)
  - CURLOPT_READFUNCTION (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - HTTP
  - MQTT
Added-in: 7.1
---

# NAME

CURLOPT_POSTFIELDS - data to POST to server

# SYNOPSIS
69
70
71
72
73
74
75


76
77
78
79
80
81
82
To make **multipart/formdata** posts, check out the
CURLOPT_MIMEPOST(3) option combined with curl_mime_init(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
/* send an application/x-www-form-urlencoded POST */
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
To make **multipart/formdata** posts, check out the
CURLOPT_MIMEPOST(3) option combined with curl_mime_init(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
/* send an application/x-www-form-urlencoded POST */
int main(void)
{
  CURL *curl = curl_easy_init();
111
112
113
114
115
116
117
118
119
120
121
122
123
124
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




114
115
116
117
118
119
120
121


122
123
124
125
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_POSTFIELDSIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_POSTFIELDSIZE_LARGE (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_POSTFIELDSIZE - size of POST data pointed to

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_POSTFIELDSIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_POSTFIELDSIZE_LARGE (3)
Protocol:
  - HTTP
Added-in: 7.2
---

# NAME

CURLOPT_POSTFIELDSIZE - size of POST data pointed to

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46

If you post more than 2GB, use CURLOPT_POSTFIELDSIZE_LARGE(3).

# DEFAULT

-1



# EXAMPLE

~~~c
#include <string.h> /* for strlen */

int main(void)
{







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

If you post more than 2GB, use CURLOPT_POSTFIELDSIZE_LARGE(3).

# DEFAULT

-1

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h> /* for strlen */

int main(void)
{
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




59
60
61
62
63
64
65
66


67
68
69
70
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_POSTFIELDSIZE_LARGE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_POSTFIELDSIZE_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COPYPOSTFIELDS (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_POSTFIELDSIZE (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_POSTFIELDSIZE_LARGE - size of POST data pointed to

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_POSTFIELDSIZE_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COPYPOSTFIELDS (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_POSTFIELDSIZE (3)
Protocol:
  - HTTP
Added-in: 7.11.1
---

# NAME

CURLOPT_POSTFIELDSIZE_LARGE - size of POST data pointed to

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
this size is set to -1, libcurl uses strlen() to get the size or relies on the
CURLOPT_READFUNCTION(3) (if used) to signal the end of data.

# DEFAULT

-1



# EXAMPLE

~~~c
extern char *large_chunk; /* pointer to somewhere */

int main(void)
{







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
this size is set to -1, libcurl uses strlen() to get the size or relies on the
CURLOPT_READFUNCTION(3) (if used) to signal the end of data.

# DEFAULT

-1

# %PROTOCOLS%

# EXAMPLE

~~~c
extern char *large_chunk; /* pointer to somewhere */

int main(void)
{
57
58
59
60
61
62
63
64
65
66
67
68
69
70
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_POSTQUOTE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_POSTQUOTE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PREQUOTE (3)
  - CURLOPT_QUOTE (3)
Protocol:
  - FTP
  - SFTP

---

# NAME

CURLOPT_POSTQUOTE - (S)FTP commands to run after the transfer

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_POSTQUOTE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PREQUOTE (3)
  - CURLOPT_QUOTE (3)
Protocol:
  - FTP
  - SFTP
Added-in: 7.1
---

# NAME

CURLOPT_POSTQUOTE - (S)FTP commands to run after the transfer

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47

Disable this operation again by setting a NULL to this option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  struct curl_slist *cmdlist = NULL;
  cmdlist = curl_slist_append(cmdlist, "RNFR source-name");







>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

Disable this operation again by setting a NULL to this option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  struct curl_slist *cmdlist = NULL;
  cmdlist = curl_slist_append(cmdlist, "RNFR source-name");
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

If support for the protocols are built-in.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




61
62
63
64
65
66
67
68


69
70
71
72
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_POSTREDIR.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_EFFECTIVE_METHOD (3)
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - CURLOPT_MAXREDIRS (3)
  - CURLOPT_POSTFIELDS (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_POSTREDIR - how to act on an HTTP POST redirect

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_EFFECTIVE_METHOD (3)
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - CURLOPT_MAXREDIRS (3)
  - CURLOPT_POSTFIELDS (3)
Protocol:
  - HTTP
Added-in: 7.19.1
---

# NAME

CURLOPT_POSTREDIR - how to act on an HTTP POST redirect

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57
POST to remain a POST after such a redirection. This option is meaningful only
when setting CURLOPT_FOLLOWLOCATION(3).

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
POST to remain a POST after such a redirection. This option is meaningful only
when setting CURLOPT_FOLLOWLOCATION(3).

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
65
66
67
68
69
70
71
72
73
74
75


76
77
78
79
    curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.17.1. This option was known as CURLOPT_POST301 up to 7.19.0 as it
only supported the 301 then. CURL_REDIR_POST_303 was added in 7.26.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
|
>
>




68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
    curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);

    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

This option was known as CURLOPT_POST301 up to 7.19.0 as it only supported the
301 then. CURL_REDIR_POST_303 was added in 7.26.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PREQUOTE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PREQUOTE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_POSTQUOTE (3)
  - CURLOPT_QUOTE (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_PREQUOTE - commands to run before an FTP transfer

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PREQUOTE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_POSTQUOTE (3)
  - CURLOPT_QUOTE (3)
Protocol:
  - FTP
Added-in: 7.9.5
---

# NAME

CURLOPT_PREQUOTE - commands to run before an FTP transfer

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
While CURLOPT_QUOTE(3) and CURLOPT_POSTQUOTE(3) work for SFTP,
this option does not.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  struct curl_slist *cmdlist = NULL;
  cmdlist = curl_slist_append(cmdlist, "SYST");







>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
While CURLOPT_QUOTE(3) and CURLOPT_POSTQUOTE(3) work for SFTP,
this option does not.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  struct curl_slist *cmdlist = NULL;
  cmdlist = curl_slist_append(cmdlist, "SYST");
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Along with the protocol support

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




64
65
66
67
68
69
70
71


72
73
74
75
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PREREQDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PREREQDATA
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIMARY_IP (3)
  - CURLINFO_PRIMARY_PORT (3)
  - CURLOPT_PREREQFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_PREREQDATA - pointer passed to the pre-request callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PREREQDATA
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIMARY_IP (3)
  - CURLINFO_PRIMARY_PORT (3)
  - CURLOPT_PREREQFUNCTION (3)
Protocol:
  - All
Added-in: 7.80.0
---

# NAME

CURLOPT_PREREQDATA - pointer passed to the pre-request callback

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41

Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the pre-request callback set with CURLOPT_PREREQFUNCTION(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
struct priv {
  void *custom;
};







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the pre-request callback set with CURLOPT_PREREQFUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *custom;
};
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, prereq_callback);
    curl_easy_setopt(curl, CURLOPT_PREREQDATA, &prereq_data);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.80.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




61
62
63
64
65
66
67
68


69
70
71
72
    curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, prereq_callback);
    curl_easy_setopt(curl, CURLOPT_PREREQDATA, &prereq_data);
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PREREQFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIMARY_IP (3)
  - CURLINFO_PRIMARY_PORT (3)
  - CURLOPT_PREREQDATA (3)
Protocol:
  - All

---

# NAME

CURLOPT_PREREQFUNCTION - user callback called when a connection has been
established, but before a request has been made.













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PREREQFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIMARY_IP (3)
  - CURLINFO_PRIMARY_PORT (3)
  - CURLOPT_PREREQDATA (3)
Protocol:
  - All
Added-in: 7.80.0
---

# NAME

CURLOPT_PREREQFUNCTION - user callback called when a connection has been
established, but before a request has been made.

79
80
81
82
83
84
85

86

87
88
89
90
91
92
93

## `clientp`

The pointer you set with CURLOPT_PREREQDATA(3).

# DEFAULT


By default, this is NULL and unused.


# EXAMPLE

~~~c
struct priv {
  void *custom;
};







>
|
>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

## `clientp`

The pointer you set with CURLOPT_PREREQDATA(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct priv {
  void *custom;
};
110
111
112
113
114
115
116
117
118
119
120
121
122
123
    curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, prereq_callback);
    curl_easy_setopt(curl, CURLOPT_PREREQDATA, &prereq_data);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.80.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




113
114
115
116
117
118
119
120


121
122
123
124
    curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, prereq_callback);
    curl_easy_setopt(curl, CURLOPT_PREREQDATA, &prereq_data);
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PRE_PROXY.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PRE_PROXY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_PROXY (3)
Protocol:
  - All

---

# NAME

CURLOPT_PRE_PROXY - pre-proxy host to use

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PRE_PROXY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_PROXY (3)
Protocol:
  - All
Added-in: 7.52.0
---

# NAME

CURLOPT_PRE_PROXY - pre-proxy host to use

# SYNOPSIS
42
43
44
45
46
47
48



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
of socks is used. Use socks4://, socks4a://, socks5:// or socks5h:// (the last
one to enable socks5 and asking the proxy to do the resolving, also known as
*CURLPROXY_SOCKS5_HOSTNAME* type) to request the specific SOCKS version to
be used. Otherwise SOCKS4 is used as default.

Setting the pre proxy string to "" (an empty string) explicitly disables the
use of a pre proxy.




The application does not have to keep the string around after setting this
option.

# DEFAULT

Default is NULL, meaning no pre proxy is used.

When you set a hostname to use, do not assume that there is any particular
single port number used widely for proxies. Specify it!

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_PRE_PROXY, "socks4://socks-proxy:1080");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80");
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
>






|

|
<
















|
<
<





43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78


79
80
81
82
83
of socks is used. Use socks4://, socks4a://, socks5:// or socks5h:// (the last
one to enable socks5 and asking the proxy to do the resolving, also known as
*CURLPROXY_SOCKS5_HOSTNAME* type) to request the specific SOCKS version to
be used. Otherwise SOCKS4 is used as default.

Setting the pre proxy string to "" (an empty string) explicitly disables the
use of a pre proxy.

When you set a hostname to use, do not assume that there is any particular
single port number used widely for proxies. Specify it.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_PRE_PROXY, "socks4://socks-proxy:1080");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80");
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PRIVATE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PRIVATE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIVATE (3)
  - CURLOPT_STDERR (3)
  - CURLOPT_VERBOSE (3)
Protocol:
  - All

---

# NAME

CURLOPT_PRIVATE - store a private pointer

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PRIVATE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIVATE (3)
  - CURLOPT_STDERR (3)
  - CURLOPT_VERBOSE (3)
Protocol:
  - All
Added-in: 7.10.3
---

# NAME

CURLOPT_PRIVATE - store a private pointer

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
this curl handle. The pointer can subsequently be retrieved using
curl_easy_getinfo(3) with the CURLINFO_PRIVATE(3) option. libcurl itself
never does anything with this data.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct private {
  void *custom;
};







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
this curl handle. The pointer can subsequently be retrieved using
curl_easy_getinfo(3) with the CURLINFO_PRIVATE(3) option. libcurl itself
never does anything with this data.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct private {
  void *custom;
};
57
58
59
60
61
62
63
64
65
66
67
68
69
70

    /* we can extract the private pointer again too */
    curl_easy_getinfo(curl, CURLINFO_PRIVATE, &extracted);
  }
}
~~~

# AVAILABILITY

Added in 7.10.3

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71

    /* we can extract the private pointer again too */
    curl_easy_getinfo(curl, CURLINFO_PRIVATE, &extracted);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROGRESSDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROGRESSDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROGRESSFUNCTION (3)
  - CURLOPT_XFERINFOFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROGRESSDATA - pointer passed to the progress callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROGRESSDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROGRESSFUNCTION (3)
  - CURLOPT_XFERINFOFUNCTION (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_PROGRESSDATA - pointer passed to the progress callback

# SYNOPSIS
26
27
28
29
30
31
32

33

34
35
36
37
38
39
40
# DESCRIPTION

Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the progress callback set with CURLOPT_PROGRESSFUNCTION(3).

# DEFAULT


The default value of this parameter is NULL.


# EXAMPLE

~~~c
struct progress {
  char *private;
  size_t size;







>
|
>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# DESCRIPTION

Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the progress callback set with CURLOPT_PROGRESSFUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct progress {
  char *private;
  size_t size;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




68
69
70
71
72
73
74
75


76
77
78
79
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROGRESSFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROGRESSFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NOPROGRESS (3)
  - CURLOPT_VERBOSE (3)
  - CURLOPT_XFERINFOFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROGRESSFUNCTION - progress meter callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROGRESSFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NOPROGRESS (3)
  - CURLOPT_VERBOSE (3)
  - CURLOPT_XFERINFOFUNCTION (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_PROGRESSFUNCTION - progress meter callback

# SYNOPSIS
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
that performs transfers.

CURLOPT_NOPROGRESS(3) must be set to 0 to make this function actually
get called.

# DEFAULT

By default, libcurl has an internal progress meter. That is rarely wanted by
users.


# EXAMPLE

~~~c
struct progress {
  char *private;
  size_t size;







|
|
>







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
that performs transfers.

CURLOPT_NOPROGRESS(3) must be set to 0 to make this function actually
get called.

# DEFAULT

NULL. libcurl has an internal progress meter. That is rarely wanted by users.

# %PROTOCOLS%

# EXAMPLE

~~~c
struct progress {
  char *private;
  size_t size;
110
111
112
113
114
115
116
117
118
119


120
121
122
123
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Deprecated since 7.32.0.



# RETURN VALUE

Returns CURLE_OK.







|


>
>




112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);

    curl_easy_perform(curl);
  }
}
~~~

# DEPRECATED

Deprecated since 7.32.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROTOCOLS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROTOCOLS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEFAULT_PROTOCOL (3)
  - CURLOPT_REDIR_PROTOCOLS (3)
  - CURLOPT_URL (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROTOCOLS - allowed protocols

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROTOCOLS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEFAULT_PROTOCOL (3)
  - CURLOPT_REDIR_PROTOCOLS (3)
  - CURLOPT_URL (3)
Protocol:
  - All
Added-in: 7.19.4
---

# NAME

CURLOPT_PROTOCOLS - allowed protocols

# SYNOPSIS
69
70
71
72
73
74
75


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98


99
100
101
102
CURLPROTO_TFTP
~~~

# DEFAULT

All protocols built-in.



# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* pass in the URL from an external source */
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);

    /* only allow HTTP, TFTP and SFTP */
    curl_easy_setopt(curl, CURLOPT_PROTOCOLS,
                     CURLPROTO_HTTP | CURLPROTO_TFTP | CURLPROTO_SFTP);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.4. Deprecated since 7.85.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|

|
>
>




70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
CURLPROTO_TFTP
~~~

# DEFAULT

All protocols built-in.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* pass in the URL from an external source */
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);

    /* only allow HTTP, TFTP and SFTP */
    curl_easy_setopt(curl, CURLOPT_PROTOCOLS,
                     CURLPROTO_HTTP | CURLPROTO_TFTP | CURLPROTO_SFTP);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# DEPRECATED

Deprecated since 7.85.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROTOCOLS_STR.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_SCHEME (3)
  - CURLOPT_DEFAULT_PROTOCOL (3)
  - CURLOPT_REDIR_PROTOCOLS_STR (3)
  - CURLOPT_URL (3)
  - curl_version_info (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROTOCOLS_STR - allowed protocols

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_SCHEME (3)
  - CURLOPT_DEFAULT_PROTOCOL (3)
  - CURLOPT_REDIR_PROTOCOLS_STR (3)
  - CURLOPT_URL (3)
  - curl_version_info (3)
Protocol:
  - All
Added-in: 7.85.0
---

# NAME

CURLOPT_PROTOCOLS_STR - allowed protocols

# SYNOPSIS
52
53
54
55
56
57
58


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
protocols in the current libcurl. CURLINFO_SCHEME(3) is the recommended
way to figure out the protocol used in a previous transfer.

# DEFAULT

All protocols built-in



# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* pass in the URL from an external source */
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);

    /* only allow HTTP, TFTP and SFTP */
    curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http,tftp,sftp");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.85.0

# RETURN VALUE

Returns CURLE_UNKNOWN_OPTION if the option is not implemented,
CURLE_UNSUPPORTED_PROTOCOL if a listed protocol is not supported or disabled,
CURLE_BAD_FUNCTION_ARGUMENT if no protocol is listed else CURLE_OK.







>
>



















|
<
<






53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81


82
83
84
85
86
87
protocols in the current libcurl. CURLINFO_SCHEME(3) is the recommended
way to figure out the protocol used in a previous transfer.

# DEFAULT

All protocols built-in

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* pass in the URL from an external source */
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);

    /* only allow HTTP, TFTP and SFTP */
    curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http,tftp,sftp");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_UNKNOWN_OPTION if the option is not implemented,
CURLE_UNSUPPORTED_PROTOCOL if a listed protocol is not supported or disabled,
CURLE_BAD_FUNCTION_ARGUMENT if no protocol is listed else CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_PRE_PROXY (3)
  - CURLOPT_PROXYPORT (3)
  - CURLOPT_PROXYTYPE (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXY - proxy to use

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_PRE_PROXY (3)
  - CURLOPT_PROXYPORT (3)
  - CURLOPT_PROXYTYPE (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_PROXY - proxy to use

# SYNOPSIS
65
66
67
68
69
70
71


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139


140
141
142
143
144

SOCKS5 Proxy.

## socks5h://

SOCKS5 Proxy. Proxy resolves URL hostname.



Without a scheme prefix, CURLOPT_PROXYTYPE(3) can be used to specify
which kind of proxy the string identifies.

When you tell the library to use an HTTP proxy, libcurl transparently converts
operations to HTTP even if you specify an FTP URL etc. This may have an impact
on what other features of the library you can use, such as
CURLOPT_QUOTE(3) and similar FTP specifics that do not work unless you
tunnel through the HTTP proxy. Such tunneling is activated with
CURLOPT_HTTPPROXYTUNNEL(3).

Setting the proxy string to "" (an empty string) explicitly disables the use
of a proxy, even if there is an environment variable set for it.

A proxy host string can also include protocol scheme (http://) and embedded
user + password.

Unix domain sockets are supported for socks proxies since 7.84.0. Set
localhost for the host part. e.g. socks5h://localhost/path/to/socket.sock

The application does not have to keep the string around after setting this
option.

When a proxy is used, the active FTP mode as set with *CUROPT_FTPPORT(3)*,
cannot be used.

# Environment variables

libcurl respects the proxy environment variables named **http_proxy**,
**ftp_proxy**, **sftp_proxy** etc. If set, libcurl uses the specified proxy
for that URL scheme. For an "FTP://" URL, the **ftp_proxy** is
considered. **all_proxy** is used if no protocol specific proxy was set.

If **no_proxy** (or **NO_PROXY**) is set, it is the exact equivalent of
setting the CURLOPT_NOPROXY(3) option.

The CURLOPT_PROXY(3) and CURLOPT_NOPROXY(3) options override environment
variables.

# DEFAULT

Default is NULL, meaning no proxy is used.

When you set a hostname to use, do not assume that there is any particular
single port number used widely for proxies. Specify it!

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80");
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Since 7.14.1 the proxy environment variable names can include the protocol
scheme.

Since 7.21.7 the proxy string supports the socks protocols as "schemes".

Since 7.50.2, unsupported schemes in proxy strings cause libcurl to return
error.



# RETURN VALUE

Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
|
|



|
|
|
<










|
|



















|

|
<















|








>
>





66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

SOCKS5 Proxy.

## socks5h://

SOCKS5 Proxy. Proxy resolves URL hostname.

##

Without a scheme prefix, CURLOPT_PROXYTYPE(3) can be used to specify which
kind of proxy the string identifies.

When you tell the library to use an HTTP proxy, libcurl transparently converts
operations to HTTP even if you specify an FTP URL etc. This may have an impact
on what other features of the library you can use, such as CURLOPT_QUOTE(3)
and similar FTP specifics that do not work unless you tunnel through the HTTP
proxy. Such tunneling is activated with CURLOPT_HTTPPROXYTUNNEL(3).


Setting the proxy string to "" (an empty string) explicitly disables the use
of a proxy, even if there is an environment variable set for it.

A proxy host string can also include protocol scheme (http://) and embedded
user + password.

Unix domain sockets are supported for socks proxies since 7.84.0. Set
localhost for the host part. e.g. socks5h://localhost/path/to/socket.sock

When you set a hostname to use, do not assume that there is any particular
single port number used widely for proxies. Specify it.

When a proxy is used, the active FTP mode as set with *CUROPT_FTPPORT(3)*,
cannot be used.

# Environment variables

libcurl respects the proxy environment variables named **http_proxy**,
**ftp_proxy**, **sftp_proxy** etc. If set, libcurl uses the specified proxy
for that URL scheme. For an "FTP://" URL, the **ftp_proxy** is
considered. **all_proxy** is used if no protocol specific proxy was set.

If **no_proxy** (or **NO_PROXY**) is set, it is the exact equivalent of
setting the CURLOPT_NOPROXY(3) option.

The CURLOPT_PROXY(3) and CURLOPT_NOPROXY(3) options override environment
variables.

# DEFAULT

NULL

# %PROTOCOLS%


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/file.txt");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://proxy:80");
    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

Since 7.14.1 the proxy environment variable names can include the protocol
scheme.

Since 7.21.7 the proxy string supports the socks protocols as "schemes".

Since 7.50.2, unsupported schemes in proxy strings cause libcurl to return
error.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXYAUTH.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYPORT (3)
  - CURLOPT_PROXYTYPE (3)
  - CURLOPT_PROXYUSERPWD (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXYAUTH - HTTP proxy authentication methods

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYPORT (3)
  - CURLOPT_PROXYTYPE (3)
  - CURLOPT_PROXYUSERPWD (3)
Protocol:
  - All
Added-in: 7.10.7
---

# NAME

CURLOPT_PROXYAUTH - HTTP proxy authentication methods

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
The bitmask can be constructed by the bits listed and described in the
CURLOPT_HTTPAUTH(3) man page.

# DEFAULT

CURLAUTH_BASIC



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
The bitmask can be constructed by the bits listed and described in the
CURLOPT_HTTPAUTH(3) man page.

# DEFAULT

CURLAUTH_BASIC

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, "james:007");
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10.7

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_NOT_BUILT_IN if the bitmask specified no supported authentication
methods.







|
<
<






63
64
65
66
67
68
69
70


71
72
73
74
75
76
    curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, "james:007");
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_NOT_BUILT_IN if the bitmask specified no supported authentication
methods.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXYHEADER.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYHEADER
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADEROPT (3)
  - CURLOPT_HTTPHEADER (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXYHEADER - set of HTTP headers to pass to proxy

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYHEADER
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADEROPT (3)
  - CURLOPT_HTTPHEADER (3)
Protocol:
  - All
Added-in: 7.37.0
---

# NAME

CURLOPT_PROXYHEADER - set of HTTP headers to pass to proxy

# SYNOPSIS
40
41
42
43
44
45
46


47
48
49
50
51
52
53

Pass a NULL to this to reset back to no custom headers.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();








>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

Pass a NULL to this to reset back to no custom headers.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();

65
66
67
68
69
70
71
72
73
74
75
76
77
78
    curl_easy_perform(curl);

    curl_slist_free_all(list); /* free the list again */
  }
}
~~~

# AVAILABILITY

Added in 7.37.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




68
69
70
71
72
73
74
75


76
77
78
79
    curl_easy_perform(curl);

    curl_slist_free_all(list); /* free the list again */
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXYPASSWORD.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYPASSWORD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PASSWORD (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_PROXYUSERNAME (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXYPASSWORD - password to use with proxy authentication

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYPASSWORD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PASSWORD (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_PROXYUSERNAME (3)
Protocol:
  - All
Added-in: 7.19.1
---

# NAME

CURLOPT_PROXYPASSWORD - password to use with proxy authentication

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080");
    curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, "mrsmith");
    curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, "qwerty");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64


65
66
67
68
69
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080");
    curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, "mrsmith");
    curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, "qwerty");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXYPORT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34




35
36
37
38
39
40

41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYPORT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIMARY_PORT (3)
  - CURLOPT_PORT (3)
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYTYPE (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXYPORT - port number the proxy listens on

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYPORT, long port);
~~~

# DESCRIPTION

We discourage use of this option.

Pass a long with this option to set the proxy port to connect to unless it is
specified in the proxy string CURLOPT_PROXY(3) or uses 443 for https
proxies and 1080 for all others as default.





While this accepts a 'long', the port number is 16 bit so it cannot be larger
than 65535.

# DEFAULT


0, not specified which makes it use the default port


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "localhost");
    curl_easy_setopt(curl, CURLOPT_PROXYPORT, 8080L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK













>



















|
|
>
>
>
>






>
|
>


















|
<
<




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYPORT
Section: 3
Source: libcurl
See-also:
  - CURLINFO_PRIMARY_PORT (3)
  - CURLOPT_PORT (3)
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYTYPE (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_PROXYPORT - port number the proxy listens on

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXYPORT, long port);
~~~

# DESCRIPTION

We discourage use of this option.

Pass a long with this option to set the proxy port to connect to unless it is
specified in the proxy string CURLOPT_PROXY(3) or uses 443 for https proxies
and 1080 for all others as default.

Disabling this option, setting it to zero, makes it not specified which makes
libcurl use the default proxy port number or the port number specified in the
proxy URL string.

While this accepts a 'long', the port number is 16 bit so it cannot be larger
than 65535.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "localhost");
    curl_easy_setopt(curl, CURLOPT_PROXYPORT, 8080L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXYTYPE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYTYPE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYPORT (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXYTYPE - proxy protocol type

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYTYPE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYPORT (3)
Protocol:
  - All
Added-in: 7.10
---

# NAME

CURLOPT_PROXYTYPE - proxy protocol type

# SYNOPSIS
58
59
60
61
62
63
64


65
66
67
68
69
70
71


72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
## CURLPROXY_SOCKS5

SOCKS5 Proxy.

## CURLPROXY_SOCKS5_HOSTNAME

SOCKS5 Proxy. Proxy resolves URL hostname.



Often it is more convenient to specify the proxy type with the scheme part of
the CURLOPT_PROXY(3) string.

# DEFAULT

CURLPROXY_HTTP



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "local.example.com:1080");
    /* set the proxy type */
    curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>







>
>



















|
<
<




59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96


97
98
99
100
## CURLPROXY_SOCKS5

SOCKS5 Proxy.

## CURLPROXY_SOCKS5_HOSTNAME

SOCKS5 Proxy. Proxy resolves URL hostname.

##

Often it is more convenient to specify the proxy type with the scheme part of
the CURLOPT_PROXY(3) string.

# DEFAULT

CURLPROXY_HTTP

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "local.example.com:1080");
    /* set the proxy type */
    curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
    ret = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXYUSERNAME.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYUSERNAME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_PROXYPASSWORD (3)
  - CURLOPT_USERNAME (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXYUSERNAME - username to use for proxy authentication

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYUSERNAME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_PROXYPASSWORD (3)
  - CURLOPT_USERNAME (3)
Protocol:
  - All
Added-in: 7.19.1
---

# NAME

CURLOPT_PROXYUSERNAME - username to use for proxy authentication

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080");
    curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, "mrsmith");
    curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, "qwerty");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71
72
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080");
    curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME, "mrsmith");
    curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD, "qwerty");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXYUSERPWD.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYUSERPWD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYPASSWORD (3)
  - CURLOPT_PROXYTYPE (3)
  - CURLOPT_PROXYUSERNAME (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXYUSERPWD - username and password to use for proxy authentication

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXYUSERPWD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYPASSWORD (3)
  - CURLOPT_PROXYTYPE (3)
  - CURLOPT_PROXYUSERNAME (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_PROXYUSERPWD - username and password to use for proxy authentication

# SYNOPSIS
36
37
38
39
40
41
42

43

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Use CURLOPT_PROXYAUTH(3) to specify the authentication method.

The application does not have to keep the string around after setting this
option.

# DEFAULT


This is NULL by default.


# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080");
    curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, "clark%20kent:superman");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
|
>


















|
<
<





37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
70
Use CURLOPT_PROXYAUTH(3) to specify the authentication method.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:8080");
    curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, "clark%20kent:superman");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if proxies are supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_CAINFO.md.
14
15
16
17
18
19
20

21
22
23
24
25
26
27
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_PROXY_CAINFO - path to proxy Certificate Authority (CA) bundle

# SYNOPSIS







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_CAINFO - path to proxy Certificate Authority (CA) bundle

# SYNOPSIS
57
58
59
60
61
62
63


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88


89
90
91
92
93

The default value for this can be figured out with CURLINFO_CAINFO(3).

# DEFAULT

Built-in system specific



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* using an HTTPS proxy */
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443");
    curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO, "/etc/certs/cabundle.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

For TLS backends that do not support certificate files, the
CURLOPT_PROXY_CAINFO(3) option is ignored. Refer to
https://curl.se/docs/ssl-compared.html



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















<
|
<




>
>





58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

85

86
87
88
89
90
91
92
93
94
95
96

The default value for this can be figured out with CURLINFO_CAINFO(3).

# DEFAULT

Built-in system specific

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* using an HTTPS proxy */
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443");
    curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO, "/etc/certs/cabundle.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~


# NOTES


For TLS backends that do not support certificate files, the
CURLOPT_PROXY_CAINFO(3) option is ignored. Refer to
https://curl.se/docs/ssl-compared.html

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_CAINFO_BLOB.md.
17
18
19
20
21
22
23

24
25
26
27
28
29
30
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - rustls
  - Secure Transport
  - Schannel

---

# NAME

CURLOPT_PROXY_CAINFO_BLOB - proxy Certificate Authority (CA) bundle in PEM format

# SYNOPSIS







>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - rustls
  - Secure Transport
  - Schannel
Added-in: 7.77.0
---

# NAME

CURLOPT_PROXY_CAINFO_BLOB - proxy Certificate Authority (CA) bundle in PEM format

# SYNOPSIS
53
54
55
56
57
58
59


60
61
62
63
64
65
66

This option overrides CURLOPT_PROXY_CAINFO(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
#include <string.h> /* for strlen */

extern char *strpem; /* strpem must point to a PEM string */
int main(void)







>
>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

This option overrides CURLOPT_PROXY_CAINFO(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <string.h> /* for strlen */

extern char *strpem; /* strpem must point to a PEM string */
int main(void)
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.77.0.

This option is supported by the rustls (since 7.82.0), OpenSSL, Secure
Transport and Schannel backends.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<
<
<
<





81
82
83
84
85
86
87
88





89
90
91
92
93
    curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%






# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_CAPATH.md.
12
13
14
15
16
17
18

19
20
21
22
23
24
25
  - CURLOPT_STDERR (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS

---

# NAME

CURLOPT_PROXY_CAPATH - directory holding HTTPS proxy CA certificates

# SYNOPSIS







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  - CURLOPT_STDERR (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_CAPATH - directory holding HTTPS proxy CA certificates

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

The default value for this can be figured out with CURLINFO_CAPATH(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* using an HTTPS proxy */
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443");
    curl_easy_setopt(curl, CURLOPT_PROXY_CAPATH, "/etc/cert-dir");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

mbedTLS support added in 7.56.0.

# RETURN VALUE

CURLE_OK if supported; or an error such as:

CURLE_NOT_BUILT_IN - Not supported by the SSL backend

CURLE_UNKNOWN_OPTION

CURLE_OUT_OF_MEMORY







>
>


















|
<
<
<
<










44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71




72
73
74
75
76
77
78
79
80
81

The default value for this can be figured out with CURLINFO_CAPATH(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* using an HTTPS proxy */
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443");
    curl_easy_setopt(curl, CURLOPT_PROXY_CAPATH, "/etc/cert-dir");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%





# RETURN VALUE

CURLE_OK if supported; or an error such as:

CURLE_NOT_BUILT_IN - Not supported by the SSL backend

CURLE_UNKNOWN_OPTION

CURLE_OUT_OF_MEMORY
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_CRLFILE.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - GnuTLS
  - mbedTLS
  - OpenSSL

---

# NAME

CURLOPT_PROXY_CRLFILE - HTTPS proxy Certificate Revocation List file

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - GnuTLS
  - mbedTLS
  - OpenSSL
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_CRLFILE - HTTPS proxy Certificate Revocation List file

# SYNOPSIS
54
55
56
57
58
59
60


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:80");
    curl_easy_setopt(curl, CURLOPT_PROXY_CRLFILE, "/etc/certs/crl.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|
<
<





55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81


82
83
84
85
86
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:80");
    curl_easy_setopt(curl, CURLOPT_PROXY_CRLFILE, "/etc/certs/crl.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_PROXY_ISSUERCERT - proxy issuer SSL certificate filename

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.71.0
---

# NAME

CURLOPT_PROXY_ISSUERCERT - proxy issuer SSL certificate filename

# SYNOPSIS
51
52
53
54
55
56
57


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* using an HTTPS proxy */
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443");
    curl_easy_setopt(curl, CURLOPT_PROXY_ISSUERCERT, "/etc/certs/cacert.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.71.0. This option is supported by the OpenSSL and GnuTLS backends.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79


80
81
82
83
84
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* using an HTTPS proxy */
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost:443");
    curl_easy_setopt(curl, CURLOPT_PROXY_ISSUERCERT, "/etc/certs/cacert.pem");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_ISSUERCERT_BLOB.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLOPT_PROXY_ISSUERCERT_BLOB - proxy issuer SSL certificate from memory blob

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.71.0
---

# NAME

CURLOPT_PROXY_ISSUERCERT_BLOB - proxy issuer SSL certificate from memory blob

# SYNOPSIS
55
56
57
58
59
60
61


62
63
64
65
66
67
68
This option is an alternative to CURLOPT_PROXY_ISSUERCERT(3) which
instead expects a filename as input.

# DEFAULT

NULL



# EXAMPLE

~~~c

extern char *certificateData; /* point to the data */
size_t filesize; /* size of the data */








>
>







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
This option is an alternative to CURLOPT_PROXY_ISSUERCERT(3) which
instead expects a filename as input.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c

extern char *certificateData; /* point to the data */
size_t filesize; /* size of the data */

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    curl_easy_setopt(curl, CURLOPT_PROXY_ISSUERCERT_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.71.0. This option is supported by the OpenSSL backends.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<





84
85
86
87
88
89
90
91


92
93
94
95
96
    curl_easy_setopt(curl, CURLOPT_PROXY_ISSUERCERT_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_KEYPASSWD.md.
12
13
14
15
16
17
18

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - mbedTLS
  - Schannel
  - wolfSSL

---

# NAME

CURLOPT_PROXY_KEYPASSWD - passphrase for the proxy private key

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_KEYPASSWD, char *pwd);
~~~

# DESCRIPTION

This option is for connecting to an HTTPS proxy, not an HTTPS server.

Pass a pointer to a null-terminated string as parameter. It is used as the
password required to use the CURLOPT_PROXY_SSLKEY(3) private key. You
never need a pass phrase to load a certificate but you need one to load your
private key.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy:443");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "superman");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>



















|
|
|







>
>


















|
<
<





12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69


70
71
72
73
74
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - mbedTLS
  - Schannel
  - wolfSSL
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_KEYPASSWD - passphrase for the proxy private key

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PROXY_KEYPASSWD, char *pwd);
~~~

# DESCRIPTION

This option is for connecting to an HTTPS proxy, not an HTTPS server.

Pass a pointer to a null-terminated string as parameter. It is used as the
password required to use the CURLOPT_PROXY_SSLKEY(3) private key. You never
need a passphrase to load a certificate but you need one to load your private
key.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy:443");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "superman");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_PINNEDPUBLICKEY.md.
13
14
15
16
17
18
19

20
21
22
23
24
25
26
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - wolfSSL

---

# NAME

CURLOPT_PROXY_PINNEDPUBLICKEY - pinned public key for https proxy

# SYNOPSIS







>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - wolfSSL
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_PINNEDPUBLICKEY - pinned public key for https proxy

# SYNOPSIS
48
49
50
51
52
53
54


55
56
57
58
59
60
61

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







>
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122


123
124
125
126
127
footer:
~~~c
-----BEGIN PUBLIC KEY-----
[BASE 64 DATA]
-----END PUBLIC KEY-----
~~~

# AVAILABILITY

PEM/DER support:

 7.52.0: GnuTLS, OpenSSL, mbedTLS, wolfSSL

sha256 support:

 7.52.0: GnuTLS, OpenSSL, mbedTLS, wolfSSL

Other SSL backends not supported.



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|










>
>





108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
footer:
~~~c
-----BEGIN PUBLIC KEY-----
[BASE 64 DATA]
-----END PUBLIC KEY-----
~~~

# HISTORY

PEM/DER support:

 7.52.0: GnuTLS, OpenSSL, mbedTLS, wolfSSL

sha256 support:

 7.52.0: GnuTLS, OpenSSL, mbedTLS, wolfSSL

Other SSL backends not supported.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SERVICE_NAME.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXY_SERVICE_NAME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYTYPE (3)
  - CURLOPT_SERVICE_NAME (3)
Protocol:
  - All

---

# NAME

CURLOPT_PROXY_SERVICE_NAME - proxy authentication service name

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXY_SERVICE_NAME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYTYPE (3)
  - CURLOPT_SERVICE_NAME (3)
Protocol:
  - All
Added-in: 7.43.0
---

# NAME

CURLOPT_PROXY_SERVICE_NAME - proxy authentication service name

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
The application does not have to keep the string around after setting this
option.

# DEFAULT

See above



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY_SERVICE_NAME, "custom");
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.43.0 for HTTP proxies, 7.49.0 for SOCKS5 proxies.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>















|
<
<





35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
64
The application does not have to keep the string around after setting this
option.

# DEFAULT

See above

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY_SERVICE_NAME, "custom");
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT.md.
13
14
15
16
17
18
19

20
21
22
23
24
25
26
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - Schannel
  - Secure Transport
  - wolfSSL

---

# NAME

CURLOPT_PROXY_SSLCERT - HTTPS proxy client certificate

# SYNOPSIS







>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - Schannel
  - Secure Transport
  - wolfSSL
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSLCERT - HTTPS proxy client certificate

# SYNOPSIS
51
52
53
54
55
56
57


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80


81
82
83
84
85
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERTTYPE.md.
13
14
15
16
17
18
19

20
21
22
23
24
25
26
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - Schannel
  - Secure Transport
  - wolfSSL

---

# NAME

CURLOPT_PROXY_SSLCERTTYPE - type of the proxy client SSL certificate

# SYNOPSIS







>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - Schannel
  - Secure Transport
  - wolfSSL
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSLCERTTYPE - type of the proxy client SSL certificate

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
The application does not have to keep the string around after setting this
option.

# DEFAULT

"PEM"



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERTTYPE, "PEM");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>




















|
<
<
<
<





45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74




75
76
77
78
79
The application does not have to keep the string around after setting this
option.

# DEFAULT

"PEM"

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERTTYPE, "PEM");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%





# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLCERT_BLOB.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - CURLOPT_SSLCERT_BLOB (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - Schannel
  - Secure Transport

---

# NAME

CURLOPT_PROXY_SSLCERT_BLOB - SSL proxy client certificate from memory blob

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - CURLOPT_SSLCERT_BLOB (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - Schannel
  - Secure Transport
Added-in: 7.71.0
---

# NAME

CURLOPT_PROXY_SSLCERT_BLOB - SSL proxy client certificate from memory blob

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58
This option is an alternative to CURLOPT_PROXY_SSLCERT(3) which instead
expects a filename as input.

# DEFAULT

NULL



# EXAMPLE

~~~c

extern char *certificateData; /* point to data */
extern size_t filesize; /* size of the data */








>
>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
This option is an alternative to CURLOPT_PROXY_SSLCERT(3) which instead
expects a filename as input.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c

extern char *certificateData; /* point to data */
extern size_t filesize; /* size of the data */

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.71.0.

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<





75
76
77
78
79
80
81
82


83
84
85
86
87
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT_BLOB, &blob);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY.md.
13
14
15
16
17
18
19

20
21
22
23
24
25
26
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - mbedTLS
  - Schannel
  - wolfSSL

---

# NAME

CURLOPT_PROXY_SSLKEY - private key file for HTTPS proxy client cert

# SYNOPSIS







>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - mbedTLS
  - Schannel
  - wolfSSL
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSLKEY - private key file for HTTPS proxy client cert

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<
<
<





46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74




75
76
77
78
79
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%





# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEYTYPE.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_SSLKEYTYPE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - BearSSL
  - wolfSSL

---

# NAME

CURLOPT_PROXY_SSLKEYTYPE - type of the proxy private key file

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_SSLKEYTYPE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - BearSSL
  - wolfSSL
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSLKEYTYPE - type of the proxy private key file

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

Pass a pointer to a null-terminated string as parameter. The string should be
the format of your private key. Supported formats are "PEM", "DER" and "ENG".

The application does not have to keep the string around after setting this
option.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEYTYPE, "PEM");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>




















|
<
<





35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64


65
66
67
68
69

Pass a pointer to a null-terminated string as parameter. The string should be
the format of your private key. Supported formats are "PEM", "DER" and "ENG".

The application does not have to keep the string around after setting this
option.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSLKEYTYPE, "PEM");
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLKEY_BLOB.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_SSLKEY (3)
  - CURLOPT_SSLKEYTYPE (3)
  - CURLOPT_SSLKEY_BLOB (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLOPT_PROXY_SSLKEY_BLOB - private key for proxy cert from memory blob

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_SSLKEY (3)
  - CURLOPT_SSLKEYTYPE (3)
  - CURLOPT_SSLKEY_BLOB (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.71.0
---

# NAME

CURLOPT_PROXY_SSLKEY_BLOB - private key for proxy cert from memory blob

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
If the blob is initialized with the flags member of struct curl_blob set to
CURL_BLOB_COPY, the application does not have to keep the buffer around after
setting this.

# DEFAULT

NULL



# EXAMPLE

~~~c

extern char *certificateData; /* point to data */
extern size_t filesize; /* size of data */







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
If the blob is initialized with the flags member of struct curl_blob set to
CURL_BLOB_COPY, the application does not have to keep the buffer around after
setting this.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c

extern char *certificateData; /* point to data */
extern size_t filesize; /* size of data */
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.71.0. This option is supported by the OpenSSL backends.

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<





75
76
77
78
79
80
81
82


83
84
85
86
87
    curl_easy_setopt(curl, CURLOPT_PROXY_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSLVERSION.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_IPRESOLVE (3)
  - CURLOPT_SSLVERSION (3)
  - CURLOPT_USE_SSL (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_PROXY_SSLVERSION - preferred HTTPS proxy TLS version

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_IPRESOLVE (3)
  - CURLOPT_SSLVERSION (3)
  - CURLOPT_USE_SSL (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSLVERSION - preferred HTTPS proxy TLS version

# SYNOPSIS
55
56
57
58
59
60
61



62
63
64
65
66
67
68
69
70
71
72
## CURL_SSLVERSION_TLSv1_2

TLSv1.2

## CURL_SSLVERSION_TLSv1_3

TLSv1.3



The maximum TLS version can be set by using *one* of the
CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the
CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros.
The MAX macros are not supported for WolfSSL.

## CURL_SSLVERSION_MAX_DEFAULT

The flag defines the maximum supported TLS version as TLSv1.2, or the default
value from the SSL library.
(Added in 7.54.0)








>
>
>
|
|
|
|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
## CURL_SSLVERSION_TLSv1_2

TLSv1.2

## CURL_SSLVERSION_TLSv1_3

TLSv1.3

##

The maximum TLS version can be set by using *one* of the CURL_SSLVERSION_MAX_
macros below. It is also possible to OR *one* of the CURL_SSLVERSION_ macros
with *one* of the CURL_SSLVERSION_MAX_ macros. The MAX macros are not
supported for wolfSSL.

## CURL_SSLVERSION_MAX_DEFAULT

The flag defines the maximum supported TLS version as TLSv1.2, or the default
value from the SSL library.
(Added in 7.54.0)

85
86
87
88
89
90
91


92
93
94
95
96
97
98
99


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
The flag defines maximum supported TLS version as TLSv1.2.
(Added in 7.54.0)

## CURL_SSLVERSION_MAX_TLSv1_3

The flag defines maximum supported TLS version as TLSv1.3.
(Added in 7.54.0)



In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were
documented to allow *only* the specified TLS version, but behavior was
inconsistent depending on the TLS library.

# DEFAULT

CURL_SSLVERSION_DEFAULT



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* ask libcurl to use TLS version 1.0 or later */
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>








>
>



















|
<
<




89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127


128
129
130
131
The flag defines maximum supported TLS version as TLSv1.2.
(Added in 7.54.0)

## CURL_SSLVERSION_MAX_TLSv1_3

The flag defines maximum supported TLS version as TLSv1.3.
(Added in 7.54.0)

##

In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were
documented to allow *only* the specified TLS version, but behavior was
inconsistent depending on the TLS library.

# DEFAULT

CURL_SSLVERSION_DEFAULT

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* ask libcurl to use TLS version 1.0 or later */
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_CIPHER_LIST.md.
16
17
18
19
20
21
22

23
24
25
26
27
28
29
  - OpenSSL
  - BearSSL
  - Schannel
  - Secure Transport
  - wolfSSL
  - GnuTLS
  - mbedTLS

---

# NAME

CURLOPT_PROXY_SSL_CIPHER_LIST - ciphers to use for HTTPS proxy

# SYNOPSIS







>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  - OpenSSL
  - BearSSL
  - Schannel
  - Secure Transport
  - wolfSSL
  - GnuTLS
  - mbedTLS
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSL_CIPHER_LIST - ciphers to use for HTTPS proxy

# SYNOPSIS
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
colons. Commas or spaces are also acceptable separators but colons are
normally used, &!, &- and &+ can be used as operators.

For OpenSSL and GnuTLS valid examples of cipher lists include **RC4-SHA**,
**SHA1+DES**, **TLSv1** and **DEFAULT**. The default list is normally
set when you compile OpenSSL.

For WolfSSL, valid examples of cipher lists include **ECDHE-RSA-RC4-SHA**,
**AES256-SHA:AES256-SHA256**, etc.

For mbedTLS and BearSSL, valid examples of cipher lists include
**ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256**, or when using
IANA names
**TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256**,
etc. With mbedTLS and BearSSL you do not add/remove ciphers. If one uses this
option then all known ciphers are disabled and only those passed in are
enabled.

Find more details about cipher lists on this URL:

 https://curl.se/docs/ssl-ciphers.html

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use internal default



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, "TLSv1");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0, in 7.83.0 for BearSSL, in 8.8.0 for mbedTLS

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|



















|
>
>


















|
<
<
<
<





44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92




93
94
95
96
97
colons. Commas or spaces are also acceptable separators but colons are
normally used, &!, &- and &+ can be used as operators.

For OpenSSL and GnuTLS valid examples of cipher lists include **RC4-SHA**,
**SHA1+DES**, **TLSv1** and **DEFAULT**. The default list is normally
set when you compile OpenSSL.

For wolfSSL, valid examples of cipher lists include **ECDHE-RSA-RC4-SHA**,
**AES256-SHA:AES256-SHA256**, etc.

For mbedTLS and BearSSL, valid examples of cipher lists include
**ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256**, or when using
IANA names
**TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256**,
etc. With mbedTLS and BearSSL you do not add/remove ciphers. If one uses this
option then all known ciphers are disabled and only those passed in are
enabled.

Find more details about cipher lists on this URL:

 https://curl.se/docs/ssl-ciphers.html

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use internal built-in list.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://localhost");
    curl_easy_setopt(curl, CURLOPT_PROXY_SSL_CIPHER_LIST, "TLSv1");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%





# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_OPTIONS.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_PROXY_SSL_CIPHER_LIST (3)
  - CURLOPT_SSLVERSION (3)
  - CURLOPT_SSL_CIPHER_LIST (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_PROXY_SSL_OPTIONS - HTTPS proxy SSL behavior options

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_PROXY_SSL_CIPHER_LIST (3)
  - CURLOPT_SSLVERSION (3)
  - CURLOPT_SSL_CIPHER_LIST (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSL_OPTIONS - HTTPS proxy SSL behavior options

# SYNOPSIS
87
88
89
90
91
92
93


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
could be a privacy violation and unexpected.
(Added in 7.77.0)

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    /* weaken TLS only for use with silly proxies */
    curl_easy_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST |
                     CURLSSLOPT_NO_REVOKE);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116


117
118
119
120
could be a privacy violation and unexpected.
(Added in 7.77.0)

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    /* weaken TLS only for use with silly proxies */
    curl_easy_setopt(curl, CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_ALLOW_BEAST |
                     CURLSSLOPT_NO_REVOKE);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYHOST.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_PROXY_CAINFO (3)
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_PROXY_SSL_VERIFYHOST - verify the proxy certificate's name against host

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_PROXY_CAINFO (3)
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSL_VERIFYHOST - verify the proxy certificate's name against host

# SYNOPSIS
60
61
62
63
64
65
66


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
See also CURLOPT_PROXY_SSL_VERIFYPEER(3) to verify the digital signature
of the proxy certificate.

# DEFAULT

2



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* Set the default value: strict name check please */
    curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 2L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0.

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if TLS is supported, and CURLE_UNKNOWN_OPTION if not.

If 1 is set as argument, *CURLE_BAD_FUNCTION_ARGUMENT* is returned.







>
>

















|
<
<
<
<






61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87




88
89
90
91
92
93
See also CURLOPT_PROXY_SSL_VERIFYPEER(3) to verify the digital signature
of the proxy certificate.

# DEFAULT

2

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* Set the default value: strict name check please */
    curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 2L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%





# RETURN VALUE

Returns CURLE_OK if TLS is supported, and CURLE_UNKNOWN_OPTION if not.

If 1 is set as argument, *CURLE_BAD_FUNCTION_ARGUMENT* is returned.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_SSL_VERIFYPEER.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_PROXY_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_PROXY_SSL_VERIFYPEER - verify the proxy's SSL certificate

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_PROXY_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_SSL_VERIFYPEER - verify the proxy's SSL certificate

# SYNOPSIS
62
63
64
65
66
67
68


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
transfer is not enough as you cannot be sure that you are communicating with
the correct end-point.

# DEFAULT

1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* Set the default value: strict certificate check please */
    curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<
<
<




63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89




90
91
92
93
transfer is not enough as you cannot be sure that you are communicating with
the correct end-point.

# DEFAULT

1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* Set the default value: strict certificate check please */
    curl_easy_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%





# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_TLS13_CIPHERS.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - CURLOPT_SSL_CIPHER_LIST (3)
  - CURLOPT_TLS13_CIPHERS (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - Schannel

---

# NAME

CURLOPT_PROXY_TLS13_CIPHERS - ciphers suites for proxy TLS 1.3

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - CURLOPT_SSL_CIPHER_LIST (3)
  - CURLOPT_TLS13_CIPHERS (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - Schannel
Added-in: 7.61.0
---

# NAME

CURLOPT_PROXY_TLS13_CIPHERS - ciphers suites for proxy TLS 1.3

# SYNOPSIS
46
47
48
49
50
51
52
53


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
cipher suites by using the CURLOPT_PROXY_SSL_CIPHER_LIST(3) option.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use internal default



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLS13_CIPHERS,
                     "TLS_CHACHA20_POLY1305_SHA256");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0.
Available when built with OpenSSL \>= 1.1.1.

# RETURN VALUE

Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise.







|
>
>


















|
<
<
<




47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75



76
77
78
79
cipher suites by using the CURLOPT_PROXY_SSL_CIPHER_LIST(3) option.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use internal built-in list

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLS13_CIPHERS,
                     "TLS_CHACHA20_POLY1305_SHA256");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_PASSWORD.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_TLSAUTH_TYPE (3)
  - CURLOPT_TLSAUTH_USERNAME (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_PROXY_TLSAUTH_PASSWORD - password to use for proxy TLS authentication

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_TLSAUTH_TYPE (3)
  - CURLOPT_TLSAUTH_USERNAME (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_TLSAUTH_PASSWORD - password to use for proxy TLS authentication

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
73
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_TYPE.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_TLSAUTH_PASSWORD (3)
  - CURLOPT_TLSAUTH_USERNAME (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_PROXY_TLSAUTH_TYPE - HTTPS proxy TLS authentication methods

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_TLSAUTH_PASSWORD (3)
  - CURLOPT_TLSAUTH_USERNAME (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_TLSAUTH_TYPE - HTTPS proxy TLS authentication methods

# SYNOPSIS
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
method is "SRP".

## SRP

TLS-SRP authentication. Secure Remote Password authentication for TLS is
defined in RFC 5054 and provides mutual authentication if both sides have a
shared secret. To use TLS-SRP, you must also set the
CURLOPT_PROXY_TLSAUTH_USERNAME(3) and
CURLOPT_PROXY_TLSAUTH_PASSWORD(3) options.

The application does not have to keep the string around after setting this
option.

# DEFAULT

blank



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0

You need to build libcurl with GnuTLS or OpenSSL with TLS-SRP support for this
to work.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<
<
|




>
>




















|
<
<
<
<
<




37
38
39
40
41
42
43
44



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72





73
74
75
76
method is "SRP".

## SRP

TLS-SRP authentication. Secure Remote Password authentication for TLS is
defined in RFC 5054 and provides mutual authentication if both sides have a
shared secret. To use TLS-SRP, you must also set the
CURLOPT_PROXY_TLSAUTH_USERNAME(3) and CURLOPT_PROXY_TLSAUTH_PASSWORD(3)



options.

# DEFAULT

blank

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%






# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_TLSAUTH_USERNAME.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_TLSAUTH_PASSWORD (3)
  - CURLOPT_TLSAUTH_TYPE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_PROXY_TLSAUTH_USERNAME - username to use for proxy TLS authentication

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_TLSAUTH_PASSWORD (3)
  - CURLOPT_TLSAUTH_TYPE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.52.0
---

# NAME

CURLOPT_PROXY_TLSAUTH_USERNAME - username to use for proxy TLS authentication

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.52.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
73
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "https://proxy");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_PROXY_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PROXY_TRANSFER_MODE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXY_TRANSFER_MODE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CRLF (3)
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_PROXY (3)
  - CURLOPT_TRANSFERTEXT (3)
Protocol:
    - All

---

# NAME

CURLOPT_PROXY_TRANSFER_MODE - append FTP transfer mode to URL for proxy

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PROXY_TRANSFER_MODE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CRLF (3)
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_PROXY (3)
  - CURLOPT_TRANSFERTEXT (3)
Protocol:
    - All
Added-in: 7.18.0
---

# NAME

CURLOPT_PROXY_TRANSFER_MODE - append FTP transfer mode to URL for proxy

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
to 0 (zero, the default), CURLOPT_TRANSFERTEXT(3) has no effect when
doing FTP via a proxy. Beware that not all proxies support this feature.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL,
                     "ftp://example.com/old-server/file.txt");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:80");
    curl_easy_setopt(curl, CURLOPT_PROXY_TRANSFER_MODE, 1L);
    curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.18.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if the
enabled value is not supported.







>
>



















|
<
<





35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
68
to 0 (zero, the default), CURLOPT_TRANSFERTEXT(3) has no effect when
doing FTP via a proxy. Beware that not all proxies support this feature.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL,
                     "ftp://example.com/old-server/file.txt");
    curl_easy_setopt(curl, CURLOPT_PROXY, "http://localhost:80");
    curl_easy_setopt(curl, CURLOPT_PROXY_TRANSFER_MODE, 1L);
    curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if the
enabled value is not supported.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_PUT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PUT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPGET (3)
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_PUT - make an HTTP PUT request

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_PUT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPGET (3)
  - CURLOPT_MIMEPOST (3)
  - CURLOPT_POSTFIELDS (3)
  - CURLOPT_UPLOAD (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_PUT - make an HTTP PUT request

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
CURLOPT_INFILESIZE(3).

This option is **deprecated** since version 7.12.1. Use CURLOPT_UPLOAD(3).

# DEFAULT

0, disabled



# EXAMPLE

~~~c
static size_t read_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
  FILE *src = userdata;







>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
CURLOPT_INFILESIZE(3).

This option is **deprecated** since version 7.12.1. Use CURLOPT_UPLOAD(3).

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
static size_t read_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
  FILE *src = userdata;
74
75
76
77
78
79
80
81
82
83


84
85
86
87

    /* Now run off and do what you have been told */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Deprecated since 7.12.1. Do not use.



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

    /* Now run off and do what you have been told */
    curl_easy_perform(curl);
  }
}
~~~

# DEPRECATED

Deprecated since 7.12.1.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_QUICK_EXIT.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_QUICK_EXIT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FAILONERROR (3)
  - CURLOPT_RESOLVE (3)
Protocol:
  - All

---

# NAME

CURLOPT_QUICK_EXIT - allow to exit quickly

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_QUICK_EXIT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_FAILONERROR (3)
  - CURLOPT_RESOLVE (3)
Protocol:
  - All
Added-in: 7.87.0
---

# NAME

CURLOPT_QUICK_EXIT - allow to exit quickly

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
canceling and/or forgetting about a resolver thread, at the expense of a
possible (though short-lived) leak of associated resources.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.87.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>














|
<
<




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61
canceling and/or forgetting about a resolver thread, at the expense of a
possible (though short-lived) leak of associated resources.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_QUOTE.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_DIRLISTONLY (3)
  - CURLOPT_POSTQUOTE (3)
  - CURLOPT_PREQUOTE (3)
Protocol:
  - FTP
  - SFTP

---

# NAME

CURLOPT_QUOTE - (S)FTP commands to run before transfer

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_DIRLISTONLY (3)
  - CURLOPT_POSTQUOTE (3)
  - CURLOPT_PREQUOTE (3)
Protocol:
  - FTP
  - SFTP
Added-in: 7.1
---

# NAME

CURLOPT_QUOTE - (S)FTP commands to run before transfer

# SYNOPSIS
123
124
125
126
127
128
129


130
131
132
133
134
135
136

See ln.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  struct curl_slist *cmdlist = NULL;
  cmdlist = curl_slist_append(cmdlist, "RNFR source-name");







>
>







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

See ln.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  struct curl_slist *cmdlist = NULL;
  cmdlist = curl_slist_append(cmdlist, "RNFR source-name");
147
148
149
150
151
152
153
154
155
156


157
158
159
160
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

SFTP support added in 7.16.3. *-prefix for SFTP added in 7.24.0



# RETURN VALUE

Returns CURLE_OK







|


>
>




150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

SFTP support added in 7.16.3. *-prefix for SFTP added in 7.24.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RANDOM_FILE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RANDOM_FILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_EGDSOCKET (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLOPT_RANDOM_FILE - file to read random data from

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RANDOM_FILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_EGDSOCKET (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.7
---

# NAME

CURLOPT_RANDOM_FILE - file to read random data from

# SYNOPSIS
28
29
30
31
32
33
34
35
36
37


38
39
40
41

Deprecated option. It serves no purpose anymore.

# DEFAULT

NULL, not used

# AVAILABILITY

This option was deprecated in 7.84.0.



# RETURN VALUE

Returns CURLE_OK.







|

|
>
>




29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Deprecated option. It serves no purpose anymore.

# DEFAULT

NULL, not used

# DEPRECATED

Deprecated since 7.84.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RANGE.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - CURLOPT_RESUME_FROM (3)
Protocol:
  - HTTP
  - FTP
  - FILE
  - RTSP
  - SFTP

---

# NAME

CURLOPT_RANGE - byte range to request

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - CURLOPT_RESUME_FROM (3)
Protocol:
  - HTTP
  - FTP
  - FILE
  - RTSP
  - SFTP
Added-in: 7.1
---

# NAME

CURLOPT_RANGE - byte range to request

# SYNOPSIS
54
55
56
57
58
59
60


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81


82
83
84
85
86
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* get the first 200 bytes */
    curl_easy_setopt(curl, CURLOPT_RANGE, "0-199");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

FILE since 7.18.0, RTSP since 7.20.0



# RETURN VALUE

Returns CURLE_OK on success or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|


>
>





55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* get the first 200 bytes */
    curl_easy_setopt(curl, CURLOPT_RANGE, "0-199");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

FILE since 7.18.0, RTSP since 7.20.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK on success or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_READDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_READDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERDATA (3)
  - CURLOPT_READFUNCTION (3)
  - CURLOPT_WRITEDATA (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_READDATA - pointer passed to the read callback

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_READDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERDATA (3)
  - CURLOPT_READFUNCTION (3)
  - CURLOPT_WRITEDATA (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - All
Added-in: 7.9.7
---

# NAME

CURLOPT_READDATA - pointer passed to the read callback

# SYNOPSIS
36
37
38
39
40
41
42

43

44
45
46
47
48
49
50

If you are using libcurl as a DLL on Windows, you must use the
CURLOPT_READFUNCTION(3) callback if you set this option, otherwise you
might experience crashes.

# DEFAULT


By default, this is a FILE * to stdin.


# EXAMPLE

~~~c
struct MyData {
  void *custom;
};







>
|
>







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

If you are using libcurl as a DLL on Windows, you must use the
CURLOPT_READFUNCTION(3) callback if you set this option, otherwise you
might experience crashes.

# DEFAULT

stdin

# %PROTOCOLS%

# EXAMPLE

~~~c
struct MyData {
  void *custom;
};
61
62
63
64
65
66
67
68
69
70
71


72
73
74
75
    curl_easy_setopt(curl, CURLOPT_READDATA, &this);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

This option was once known by the older name CURLOPT_INFILE, the name
CURLOPT_READDATA(3) was introduced in 7.9.7.



# RETURN VALUE

This returns CURLE_OK.







|



>
>




64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    curl_easy_setopt(curl, CURLOPT_READDATA, &this);

    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

This option was once known by the older name CURLOPT_INFILE, the name
CURLOPT_READDATA(3) was introduced in 7.9.7.

# %AVAILABILITY%

# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_READFUNCTION.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_READDATA (3)
  - CURLOPT_SEEKFUNCTION (3)
  - CURLOPT_UPLOAD (3)
  - CURLOPT_UPLOAD_BUFFERSIZE (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_READFUNCTION - read callback for data uploads

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_READDATA (3)
  - CURLOPT_SEEKFUNCTION (3)
  - CURLOPT_UPLOAD (3)
  - CURLOPT_UPLOAD_BUFFERSIZE (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_READFUNCTION - read callback for data uploads

# SYNOPSIS
68
69
70
71
72
73
74

75

76
77
78
79
80
81
82
You can set the total size of the data you are sending by using
CURLOPT_INFILESIZE_LARGE(3) or CURLOPT_POSTFIELDSIZE_LARGE(3),
depending on the type of transfer. For some transfer types it may be required
and it allows for better error checking.

# DEFAULT


The default internal read callback is fread().


# EXAMPLE

~~~c
size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
  FILE *readhere = (FILE *)userdata;







>
|
>







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
You can set the total size of the data you are sending by using
CURLOPT_INFILESIZE_LARGE(3) or CURLOPT_POSTFIELDSIZE_LARGE(3),
depending on the type of transfer. For some transfer types it may be required
and it allows for better error checking.

# DEFAULT

fread(3)

# %PROTOCOLS%

# EXAMPLE

~~~c
size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
  FILE *readhere = (FILE *)userdata;
107
108
109
110
111
112
113
114
115
116
117


118
119
120
121
    curl_easy_setopt(curl, CURLOPT_READDATA, (void *)file);

    result = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

CURL_READFUNC_PAUSE return code was added in 7.18.0 and CURL_READFUNC_ABORT
was added in 7.12.1.



# RETURN VALUE

This returns CURLE_OK.







|



>
>




110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
    curl_easy_setopt(curl, CURLOPT_READDATA, (void *)file);

    result = curl_easy_perform(curl);
  }
}
~~~

# HISTORY

CURL_READFUNC_PAUSE return code was added in 7.18.0 and CURL_READFUNC_ABORT
was added in 7.12.1.

# %AVAILABILITY%

# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_REDIR_PROTOCOLS
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SCHEME (3)
  - CURLOPT_DEFAULT_PROTOCOL (3)
  - CURLOPT_PROTOCOLS (3)
  - CURLOPT_REDIR_PROTOCOLS_STR (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_REDIR_PROTOCOLS - protocols allowed to redirect to

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_REDIR_PROTOCOLS
Section: 3
Source: libcurl
See-also:
  - CURLINFO_SCHEME (3)
  - CURLOPT_DEFAULT_PROTOCOL (3)
  - CURLOPT_PROTOCOLS (3)
  - CURLOPT_REDIR_PROTOCOLS_STR (3)
Protocol:
  - HTTP
Added-in: 7.19.4
---

# NAME

CURLOPT_REDIR_PROTOCOLS - protocols allowed to redirect to

# SYNOPSIS
79
80
81
82
83
84
85


86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109


110
111
112
113
# DEFAULT

HTTP, HTTPS, FTP and FTPS (Added in 7.65.2).

Older versions defaulted to all protocols except FILE, SCP and since 7.40.0
SMB and SMBS.



# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* pass in the URL from an external source */
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);

    /* only allow redirects to HTTP and HTTPS URLs */
    curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS,
                     CURLPROTO_HTTP | CURLPROTO_HTTPS);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.4, before then it would follow all protocols. Deprecated
since 7.85.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|

<
|
>
>




80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
# DEFAULT

HTTP, HTTPS, FTP and FTPS (Added in 7.65.2).

Older versions defaulted to all protocols except FILE, SCP and since 7.40.0
SMB and SMBS.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* pass in the URL from an external source */
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);

    /* only allow redirects to HTTP and HTTPS URLs */
    curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS,
                     CURLPROTO_HTTP | CURLPROTO_HTTPS);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# DEPRECATED


Deprecated since 7.85.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_REDIR_PROTOCOLS_STR.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_SCHEME (3)
  - CURLOPT_DEFAULT_PROTOCOL (3)
  - CURLOPT_PROTOCOLS (3)
  - CURLOPT_PROTOCOLS_STR (3)
  - CURLOPT_REDIR_PROTOCOLS (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_REDIR_PROTOCOLS_STR - protocols allowed to redirect to

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_SCHEME (3)
  - CURLOPT_DEFAULT_PROTOCOL (3)
  - CURLOPT_PROTOCOLS (3)
  - CURLOPT_PROTOCOLS_STR (3)
  - CURLOPT_REDIR_PROTOCOLS (3)
Protocol:
  - HTTP
Added-in: 7.85.0
---

# NAME

CURLOPT_REDIR_PROTOCOLS_STR - protocols allowed to redirect to

# SYNOPSIS
58
59
60
61
62
63
64


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# DEFAULT

HTTP, HTTPS, FTP and FTPS (Added in 7.65.2).

Older versions defaulted to all protocols except FILE, SCP and since 7.40.0
SMB and SMBS.



# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* pass in the URL from an external source */
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);

    /* only allow redirects to HTTP and HTTPS URLs */
    curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.85.0.

# RETURN VALUE

Returns CURLE_UNKNOWN_OPTION if the option is not implemented,
CURLE_UNSUPPORTED_PROTOCOL if a listed protocol is not supported or disabled,
CURLE_BAD_FUNCTION_ARGUMENT if no protocol is listed else CURLE_OK.







>
>



















|
<
<






59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87


88
89
90
91
92
93
# DEFAULT

HTTP, HTTPS, FTP and FTPS (Added in 7.65.2).

Older versions defaulted to all protocols except FILE, SCP and since 7.40.0
SMB and SMBS.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(int argc, char **argv)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    /* pass in the URL from an external source */
    curl_easy_setopt(curl, CURLOPT_URL, argv[1]);

    /* only allow redirects to HTTP and HTTPS URLs */
    curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_UNKNOWN_OPTION if the option is not implemented,
CURLE_UNSUPPORTED_PROTOCOL if a listed protocol is not supported or disabled,
CURLE_BAD_FUNCTION_ARGUMENT if no protocol is listed else CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_REFERER.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_REFERER
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_URL (3)
  - CURLINFO_REFERER (3)
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_USERAGENT (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_REFERER - the HTTP referer header

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_REFERER
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_URL (3)
  - CURLINFO_REFERER (3)
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_USERAGENT (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_REFERER - the HTTP referer header

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* tell it where we found the link to this place */
    curl_easy_setopt(curl, CURLOPT_REFERER, "https://example.org/me.html");

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

If built with HTTP support

# RETURN VALUE

Returns CURLE_OK if HTTP support is enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|
<
<





35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
66
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* tell it where we found the link to this place */
    curl_easy_setopt(curl, CURLOPT_REFERER, "https://example.org/me.html");

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP support is enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_REQUEST_TARGET.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_REQUEST_TARGET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_HTTPGET (3)
  - CURLOPT_PATH_AS_IS (3)
  - CURLOPT_URL (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_REQUEST_TARGET - alternative target for this request

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_REQUEST_TARGET
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_HTTPGET (3)
  - CURLOPT_PATH_AS_IS (3)
  - CURLOPT_URL (3)
Protocol:
  - HTTP
Added-in: 7.55.0
---

# NAME

CURLOPT_REQUEST_TARGET - alternative target for this request

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
libcurl passes on the verbatim string in its request without any filter or
other safe guards. That includes white space and control characters.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/*");
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "OPTIONS");

    /* issue an OPTIONS * request (no leading slash) */
    curl_easy_setopt(curl, CURLOPT_REQUEST_TARGET, "*");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.55.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62


63
64
65
66
libcurl passes on the verbatim string in its request without any filter or
other safe guards. That includes white space and control characters.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/*");
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "OPTIONS");

    /* issue an OPTIONS * request (no leading slash) */
    curl_easy_setopt(curl, CURLOPT_REQUEST_TARGET, "*");

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RESOLVE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESOLVE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECT_TO (3)
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_IPRESOLVE (3)
Protocol:
  - All

---

# NAME

CURLOPT_RESOLVE - provide custom hostname to IP address resolves

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESOLVE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECT_TO (3)
  - CURLOPT_DNS_CACHE_TIMEOUT (3)
  - CURLOPT_IPRESOLVE (3)
Protocol:
  - All
Added-in: 7.21.3
---

# NAME

CURLOPT_RESOLVE - provide custom hostname to IP address resolves

# SYNOPSIS
40
41
42
43
44
45
46




47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74


75
76
77
78
79
80
81
~~~

HOST is the name libcurl wants to resolve, PORT is the port number of the
service where libcurl wants to connect to the HOST and ADDRESS is one or more
numerical IP addresses. If you specify multiple IP addresses they need to be
separated by comma. If libcurl is built to support IPv6, each of the ADDRESS
entries can of course be either IPv4 or IPv6 style addressing.





This option effectively populates the DNS cache with entries for the host+port
pair so redirects and everything that operations against the HOST+PORT instead
use your provided ADDRESS.

The optional leading "+" specifies that the new entry should time-out. Entries
added without the leading plus character never times out whereas entries added
with "+HOST:..." times out just like ordinary DNS cache entries.

If the DNS cache already has an entry for the given host+port pair, the new
entry overrides the former one.

An ADDRESS provided by this option is only used if not restricted by the
setting of CURLOPT_IPRESOLVE(3) to a different IP version.

To remove names from the DNS cache again, to stop providing these fake
resolves, include a string in the linked list that uses the format

~~~c
  -HOST:PORT
~~~

The entry to remove must be prefixed with a dash, and the hostname and port
number must exactly match what was added previously.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl;







>
>
>
>





|
|
|










|









>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
~~~

HOST is the name libcurl wants to resolve, PORT is the port number of the
service where libcurl wants to connect to the HOST and ADDRESS is one or more
numerical IP addresses. If you specify multiple IP addresses they need to be
separated by comma. If libcurl is built to support IPv6, each of the ADDRESS
entries can of course be either IPv4 or IPv6 style addressing.

Specify the host as a single ampersand (`*`) to match all names. This wildcard
is resolved last so any resolve with a specific host and port number is given
priority.

This option effectively populates the DNS cache with entries for the host+port
pair so redirects and everything that operations against the HOST+PORT instead
use your provided ADDRESS.

The optional leading plus (`+`) specifies that the new entry should timeout.
Entries added without the leading plus character never times out whereas
entries added with `+HOST:...` times out just like ordinary DNS cache entries.

If the DNS cache already has an entry for the given host+port pair, the new
entry overrides the former one.

An ADDRESS provided by this option is only used if not restricted by the
setting of CURLOPT_IPRESOLVE(3) to a different IP version.

To remove names from the DNS cache again, to stop providing these fake
resolves, include a string in the linked list that uses the format

~~~
  -HOST:PORT
~~~

The entry to remove must be prefixed with a dash, and the hostname and port
number must exactly match what was added previously.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl;
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109


110
111
112
113
    curl_easy_cleanup(curl);
  }

  curl_slist_free_all(host);
}
~~~

# AVAILABILITY

Added in 7.21.3. Removal support added in 7.42.0.

Support for providing the ADDRESS within [brackets] was added in 7.57.0.

Support for providing multiple IP addresses per entry was added in 7.59.0.

Support for adding non-permanent entries by using the "+" prefix was added in
7.75.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|









>
>




100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
    curl_easy_cleanup(curl);
  }

  curl_slist_free_all(host);
}
~~~

# HISTORY

Added in 7.21.3. Removal support added in 7.42.0.

Support for providing the ADDRESS within [brackets] was added in 7.57.0.

Support for providing multiple IP addresses per entry was added in 7.59.0.

Support for adding non-permanent entries by using the "+" prefix was added in
7.75.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_DATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESOLVER_START_DATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PREREQFUNCTION (3)
  - CURLOPT_RESOLVER_START_FUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_RESOLVER_START_DATA - pointer passed to the resolver start callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESOLVER_START_DATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PREREQFUNCTION (3)
  - CURLOPT_RESOLVER_START_FUNCTION (3)
Protocol:
  - All
Added-in: 7.59.0
---

# NAME

CURLOPT_RESOLVER_START_DATA - pointer passed to the resolver start callback

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42
Pass a *pointer* is be untouched by libcurl and passed as the third
argument in the resolver start callback set with
CURLOPT_RESOLVER_START_FUNCTION(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
static int resolver_start_cb(void *resolver_state, void *reserved,
                             void *userdata)
{







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Pass a *pointer* is be untouched by libcurl and passed as the third
argument in the resolver start callback set with
CURLOPT_RESOLVER_START_FUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
static int resolver_start_cb(void *resolver_state, void *reserved,
                             void *userdata)
{
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.59.0

# RETURN VALUE

Returns CURLE_OK







|
<
<




58
59
60
61
62
63
64
65


66
67
68
69
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RESOLVER_START_FUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESOLVER_START_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PREREQFUNCTION (3)
  - CURLOPT_RESOLVER_START_DATA (3)
Protocol:
  - All

---

# NAME

CURLOPT_RESOLVER_START_FUNCTION - callback called before a new name resolve is started

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESOLVER_START_FUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PREREQFUNCTION (3)
  - CURLOPT_RESOLVER_START_DATA (3)
Protocol:
  - All
Added-in: 7.59.0
---

# NAME

CURLOPT_RESOLVER_START_FUNCTION - callback called before a new name resolve is started

# SYNOPSIS
48
49
50
51
52
53
54


55
56
57
58
59
60
61
The callback must return 0 on success. Returning a non-zero value causes the
resolve to fail.

# DEFAULT

NULL (No callback)



# EXAMPLE

~~~c
static int start_cb(void *resolver_state, void *reserved,
                    void *userdata)
{
  (void)reserved;







>
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
The callback must return 0 on success. Returning a non-zero value causes the
resolve to fail.

# DEFAULT

NULL (No callback)

# %PROTOCOLS%

# EXAMPLE

~~~c
static int start_cb(void *resolver_state, void *reserved,
                    void *userdata)
{
  (void)reserved;
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.59.0

# RETURN VALUE

Returns CURLE_OK







|
<
<




76
77
78
79
80
81
82
83


84
85
86
87
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESUME_FROM
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INFILESIZE (3)
  - CURLOPT_RANGE (3)
  - CURLOPT_RESUME_FROM_LARGE (3)
Protocol:
  - All

---

# NAME

CURLOPT_RESUME_FROM - offset to resume transfer from

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESUME_FROM
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INFILESIZE (3)
  - CURLOPT_RANGE (3)
  - CURLOPT_RESUME_FROM_LARGE (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_RESUME_FROM - offset to resume transfer from

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
If you need to resume a transfer beyond the 2GB limit, use
CURLOPT_RESUME_FROM_LARGE(3) instead.

# DEFAULT

0, not used



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
If you need to resume a transfer beyond the 2GB limit, use
CURLOPT_RESUME_FROM_LARGE(3) instead.

# DEFAULT

0, not used

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
65
66
67
68
69
70
71
72
73
74
75
76
77
78

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




68
69
70
71
72
73
74
75


76
77
78
79

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RESUME_FROM_LARGE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESUME_FROM_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INFILESIZE_LARGE (3)
  - CURLOPT_RANGE (3)
  - CURLOPT_RESUME_FROM (3)
Protocol:
  - All

---

# NAME

CURLOPT_RESUME_FROM_LARGE - offset to resume transfer from

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RESUME_FROM_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INFILESIZE_LARGE (3)
  - CURLOPT_RANGE (3)
  - CURLOPT_RESUME_FROM (3)
Protocol:
  - All
Added-in: 7.11.0
---

# NAME

CURLOPT_RESUME_FROM_LARGE - offset to resume transfer from

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
file libcurl should try to resume the upload from and it appends the source
file to the remote target file.

# DEFAULT

0, not used



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
file libcurl should try to resume the upload from and it appends the source
file to the remote target file.

# DEFAULT

0, not used

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
64
65
66
67
68
69
70
71
72
73
74
75
76
77

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.11.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




67
68
69
70
71
72
73
74


75
76
77
78

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RTSP_CLIENT_CSEQ.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_CLIENT_CSEQ
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_CLIENT_CSEQ (3)
  - CURLINFO_RTSP_SERVER_CSEQ (3)
  - CURLOPT_RTSP_REQUEST (3)
  - CURLOPT_RTSP_SERVER_CSEQ (3)
Protocol:
  - RTSP

---

# NAME

CURLOPT_RTSP_CLIENT_CSEQ - RTSP client CSEQ number

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_CLIENT_CSEQ
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_CLIENT_CSEQ (3)
  - CURLINFO_RTSP_SERVER_CSEQ (3)
  - CURLOPT_RTSP_REQUEST (3)
  - CURLOPT_RTSP_SERVER_CSEQ (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLOPT_RTSP_CLIENT_CSEQ - RTSP client CSEQ number

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
if the application is resuming a previously broken connection. The CSEQ
increments from this new number henceforth.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_CLIENT_CSEQ, 1234L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>
















|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61
if the application is resuming a previously broken connection. The CSEQ
increments from this new number henceforth.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_CLIENT_CSEQ, 1234L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RTSP_REQUEST.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_REQUEST
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RTSP_SESSION_ID (3)
  - CURLOPT_RTSP_STREAM_URI (3)
Protocol:
  - RTSP

---

# NAME

CURLOPT_RTSP_REQUEST - RTSP request

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_REQUEST
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RTSP_SESSION_ID (3)
  - CURLOPT_RTSP_STREAM_URI (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLOPT_RTSP_REQUEST - RTSP request

# SYNOPSIS
107
108
109
110
111
112
113


114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
This is a special request because it does not send any data to the server. The
application may call this function in order to receive interleaved RTP
data. It returns after processing one read buffer of data in order to give the
application a chance to run.

# DEFAULT



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    /* ask for options! */
    curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134


135
136
137
138
This is a special request because it does not send any data to the server. The
application may call this function in order to receive interleaved RTP
data. It returns after processing one read buffer of data in order to give the
application a chance to run.

# DEFAULT

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    /* ask for options! */
    curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RTSP_SERVER_CSEQ.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_SERVER_CSEQ
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_SERVER_CSEQ (3)
  - CURLOPT_RTSP_CLIENT_CSEQ (3)
  - CURLOPT_RTSP_STREAM_URI (3)
Protocol:
  - RTSP

---

# NAME

CURLOPT_RTSP_SERVER_CSEQ - RTSP server CSEQ number

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_SERVER_CSEQ
Section: 3
Source: libcurl
See-also:
  - CURLINFO_RTSP_SERVER_CSEQ (3)
  - CURLOPT_RTSP_CLIENT_CSEQ (3)
  - CURLOPT_RTSP_STREAM_URI (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLOPT_RTSP_SERVER_CSEQ - RTSP server CSEQ number

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Client request. **NOTE**: this feature (listening for Server requests) is
unimplemented.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_SERVER_CSEQ, 1234L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>
















|
<
<




31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
Client request. **NOTE**: this feature (listening for Server requests) is
unimplemented.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_SERVER_CSEQ, 1234L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RTSP_SESSION_ID.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_SESSION_ID
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RTSP_REQUEST (3)
  - CURLOPT_RTSP_STREAM_URI (3)
Protocol:
  - RTSP

---

# NAME

CURLOPT_RTSP_SESSION_ID - RTSP session ID

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_SESSION_ID
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RTSP_REQUEST (3)
  - CURLOPT_RTSP_STREAM_URI (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLOPT_RTSP_SESSION_ID - RTSP session ID

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    char *prev_id; /* saved from before somehow */
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_SESSION_ID, prev_id);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|
<
<





36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62


63
64
65
66
67
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    char *prev_id; /* saved from before somehow */
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_SESSION_ID, prev_id);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RTSP_STREAM_URI.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_STREAM_URI
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RTSP_REQUEST (3)
  - CURLOPT_RTSP_TRANSPORT (3)
Protocol:
  - RTSP

---

# NAME

CURLOPT_RTSP_STREAM_URI - RTSP stream URI

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_STREAM_URI
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RTSP_REQUEST (3)
  - CURLOPT_RTSP_TRANSPORT (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLOPT_RTSP_STREAM_URI - RTSP stream URI

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
The application does not have to keep the string around after setting this
option.

# DEFAULT

"*"



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI,
                     "rtsp://foo.example.com/twister/video");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|
<
<





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
71
The application does not have to keep the string around after setting this
option.

# DEFAULT

"*"

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI,
                     "rtsp://foo.example.com/twister/video");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_RTSP_TRANSPORT.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_TRANSPORT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RTSP_REQUEST (3)
  - CURLOPT_RTSP_SESSION_ID (3)
Protocol:
  - RTSP

---

# NAME

CURLOPT_RTSP_TRANSPORT - RTSP Transport: header

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_RTSP_TRANSPORT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_RTSP_REQUEST (3)
  - CURLOPT_RTSP_SESSION_ID (3)
Protocol:
  - RTSP
Added-in: 7.20.0
---

# NAME

CURLOPT_RTSP_TRANSPORT - RTSP Transport: header

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_SETUP);
    curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT,
                     "RTP/AVP;unicast;client_port=4588-4589");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.20.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62


63
64
65
66
67
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "rtsp://example.com/");
    curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_SETUP);
    curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT,
                     "RTP/AVP;unicast;client_port=4588-4589");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SASL_AUTHZID.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SASL_AUTHZID
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PASSWORD (3)
  - CURLOPT_USERNAME (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - IMAP

---

# NAME

CURLOPT_SASL_AUTHZID - authorization identity (identity to act as)

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SASL_AUTHZID
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PASSWORD (3)
  - CURLOPT_USERNAME (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - IMAP
Added-in: 7.66.0
---

# NAME

CURLOPT_SASL_AUTHZID - authorization identity (identity to act as)

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
can be used to access another user's inbox, that the user has been granted
access to, or a shared mailbox for example.

# DEFAULT

blank



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "imap://example.com/");
    curl_easy_setopt(curl, CURLOPT_USERNAME, "Kurt");
    curl_easy_setopt(curl, CURLOPT_PASSWORD, "xipj3plmq");
    curl_easy_setopt(curl, CURLOPT_SASL_AUTHZID, "Ursel");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.66.0. Support for OpenLDAP added in 7.82.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|
<
<




40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71
can be used to access another user's inbox, that the user has been granted
access to, or a shared mailbox for example.

# DEFAULT

blank

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "imap://example.com/");
    curl_easy_setopt(curl, CURLOPT_USERNAME, "Kurt");
    curl_easy_setopt(curl, CURLOPT_PASSWORD, "xipj3plmq");
    curl_easy_setopt(curl, CURLOPT_SASL_AUTHZID, "Ursel");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SASL_IR.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SASL_IR
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_AUTH (3)
  - CURLOPT_MAIL_FROM (3)
  - CURLOPT_SASL_AUTHZID (3)
Protocol:
  - SMTP
  - IMAP

---

# NAME

CURLOPT_SASL_IR - send initial response in first packet

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SASL_IR
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAIL_AUTH (3)
  - CURLOPT_MAIL_FROM (3)
  - CURLOPT_SASL_AUTHZID (3)
Protocol:
  - SMTP
  - IMAP
Added-in: 7.31.0
---

# NAME

CURLOPT_SASL_IR - send initial response in first packet

# SYNOPSIS
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
as libcurl can determine the feature itself when the server supports the
SASL-IR CAPABILITY.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_SASL_IR, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.31.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>
















|
<
<




43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
as libcurl can determine the feature itself when the server supports the
SASL-IR CAPABILITY.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
    curl_easy_setopt(curl, CURLOPT_SASL_IR, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SEEKDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SEEKDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_IOCTLFUNCTION (3)
  - CURLOPT_SEEKFUNCTION (3)
  - CURLOPT_STDERR (3)
Protocol:
  - All

---

# NAME

CURLOPT_SEEKDATA - pointer passed to the seek callback

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SEEKDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_IOCTLFUNCTION (3)
  - CURLOPT_SEEKFUNCTION (3)
  - CURLOPT_STDERR (3)
Protocol:
  - All
Added-in: 7.18.0
---

# NAME

CURLOPT_SEEKDATA - pointer passed to the seek callback

# SYNOPSIS
29
30
31
32
33
34
35


36
37
38
39
40
41
42

Data *pointer* to pass to the seek callback function. If you use the
CURLOPT_SEEKFUNCTION(3) option, this is the pointer you get as input.

# DEFAULT

If you do not set this, NULL is passed to the callback.



# EXAMPLE

~~~c
#include <unistd.h> /* for lseek() */

struct data {







>
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

Data *pointer* to pass to the seek callback function. If you use the
CURLOPT_SEEKFUNCTION(3) option, this is the pointer you get as input.

# DEFAULT

If you do not set this, NULL is passed to the callback.

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <unistd.h> /* for lseek() */

struct data {
57
58
59
60
61
62
63
64
65
66
67
68
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_cb);
    curl_easy_setopt(curl, CURLOPT_SEEKDATA, &seek_data);
  }
}
~~~

# AVAILABILITY

Added in 7.18.0

# RETURN VALUE







|

<
<

60
61
62
63
64
65
66
67
68


69
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_cb);
    curl_easy_setopt(curl, CURLOPT_SEEKDATA, &seek_data);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SEEKFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SEEKFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_IOCTLFUNCTION (3)
  - CURLOPT_SEEKDATA (3)
  - CURLOPT_STDERR (3)
Protocol:
  - All

---

# NAME

CURLOPT_SEEKFUNCTION - user callback for seeking in input stream

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SEEKFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_IOCTLFUNCTION (3)
  - CURLOPT_SEEKDATA (3)
  - CURLOPT_STDERR (3)
Protocol:
  - All
Added-in: 7.18.0
---

# NAME

CURLOPT_SEEKFUNCTION - user callback for seeking in input stream

# SYNOPSIS
59
60
61
62
63
64
65

66

67
68
69
70
71
72
73

If you forward the input arguments directly to fseek(3) or lseek(3), note that
the data type for *offset* is not the same as defined for curl_off_t on
many systems!

# DEFAULT


By default, this is NULL and unused.


# EXAMPLE

~~~c
#include <unistd.h> /* for lseek */

struct data {







>
|
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

If you forward the input arguments directly to fseek(3) or lseek(3), note that
the data type for *offset* is not the same as defined for curl_off_t on
many systems!

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <unistd.h> /* for lseek */

struct data {
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_cb);
    curl_easy_setopt(curl, CURLOPT_SEEKDATA, &seek_data);
  }
}
~~~

# AVAILABILITY

Added in 7.18.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




90
91
92
93
94
95
96
97


98
99
100
101
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_cb);
    curl_easy_setopt(curl, CURLOPT_SEEKDATA, &seek_data);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
Protocol:
  - FTP
  - IMAP
  - POP3
  - SMTP
  - SFTP
  - SCP

---

# NAME

CURLOPT_SERVER_RESPONSE_TIMEOUT - time allowed to wait for server response

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Protocol:
  - FTP
  - IMAP
  - POP3
  - SMTP
  - SFTP
  - SCP
Added-in: 7.20.0
---

# NAME

CURLOPT_SERVER_RESPONSE_TIMEOUT - time allowed to wait for server response

# SYNOPSIS
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

This option was formerly known as CURLOPT_FTP_RESPONSE_TIMEOUT.

# DEFAULT

None



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/slow.txt");
    /* wait no more than 23 seconds */
    curl_easy_setopt(curl, CURLOPT_SERVER_RESPONSE_TIMEOUT, 23L);
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.10.8. Used under this name since 7.20.0

Support for SSH is predicated on a new enough (1.11.0) version of libssh2
being available when compiling libcurl.

# RETURN VALUE

Returns CURLE_OK if supported, and CURLE_UNKNOWN_OPTION if not. Returns
CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value or a value that when
converted to milliseconds is too large.







>
>


















|
<
<
<
<
<






43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70





71
72
73
74
75
76

This option was formerly known as CURLOPT_FTP_RESPONSE_TIMEOUT.

# DEFAULT

None

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/slow.txt");
    /* wait no more than 23 seconds */
    curl_easy_setopt(curl, CURLOPT_SERVER_RESPONSE_TIMEOUT, 23L);
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%






# RETURN VALUE

Returns CURLE_OK if supported, and CURLE_UNKNOWN_OPTION if not. Returns
CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value or a value that when
converted to milliseconds is too large.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
Protocol:
  - FTP
  - IMAP
  - POP3
  - SMTP
  - SFTP
  - SCP

---

# NAME

CURLOPT_SERVER_RESPONSE_TIMEOUT_MS - time allowed to wait for server response

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Protocol:
  - FTP
  - IMAP
  - POP3
  - SMTP
  - SFTP
  - SCP
Added-in: 8.6.0
---

# NAME

CURLOPT_SERVER_RESPONSE_TIMEOUT_MS - time allowed to wait for server response

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

This is the millisecond version of CURLOPT_SERVER_RESPONSE_TIMEOUT(3).

# DEFAULT

None



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/slow.txt");
    /* wait no more than 237 milliseconds */
    curl_easy_setopt(curl, CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, 237L);
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 8.6.0.

# RETURN VALUE

Returns CURLE_OK if supported, and CURLE_UNKNOWN_OPTION if not. Returns
CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value or a value that when
converted to milliseconds is too large.







>
>


















|
<
<






45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
77
78

This is the millisecond version of CURLOPT_SERVER_RESPONSE_TIMEOUT(3).

# DEFAULT

None

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/slow.txt");
    /* wait no more than 237 milliseconds */
    curl_easy_setopt(curl, CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, 237L);
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if supported, and CURLE_UNKNOWN_OPTION if not. Returns
CURLE_BAD_FUNCTION_ARGUMENT if set to a negative value or a value that when
converted to milliseconds is too large.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SERVICE_NAME.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
Protocol:
  - HTTP
  - FTP
  - IMAP
  - POP3
  - SMTP
  - LDAP

---

# NAME

CURLOPT_SERVICE_NAME - authentication service name

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Protocol:
  - HTTP
  - FTP
  - IMAP
  - POP3
  - SMTP
  - LDAP
Added-in: 7.43.0
---

# NAME

CURLOPT_SERVICE_NAME - authentication service name

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
The application does not have to keep the string around after setting this
option.

# DEFAULT

See above



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SERVICE_NAME, "custom");
    ret = curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.43.0 for HTTP, 7.49.0 for FTP, IMAP, POP3 and SMTP,
7.82.0 for OpenLDAP.

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>















|
<
<
<





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64



65
66
67
68
69
The application does not have to keep the string around after setting this
option.

# DEFAULT

See above

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode ret;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SERVICE_NAME, "custom");
    ret = curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SHARE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SHARE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIE (3)
  - CURLSHOPT_SHARE (3)
Protocol:
  - All

---

# NAME

CURLOPT_SHARE - share handle to use

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SHARE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_COOKIE (3)
  - CURLSHOPT_SHARE (3)
Protocol:
  - All
Added-in: 7.10
---

# NAME

CURLOPT_SHARE - share handle to use

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56

Set this option to NULL again to stop using that share object.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  CURL *curl2 = curl_easy_init(); /* a second handle */







>
>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

Set this option to NULL again to stop using that share object.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  CURL *curl2 = curl_easy_init(); /* a second handle */
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    curl_easy_cleanup(curl2);

    curl_share_cleanup(shobject);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




76
77
78
79
80
81
82
83


84
85
86
87
    curl_easy_cleanup(curl2);

    curl_share_cleanup(shobject);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SOCKOPTDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKOPTDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - CURLOPT_SOCKOPTFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_SOCKOPTDATA - pointer to pass to sockopt callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKOPTDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - CURLOPT_SOCKOPTFUNCTION (3)
Protocol:
  - All
Added-in: 7.16.0
---

# NAME

CURLOPT_SOCKOPTDATA - pointer to pass to sockopt callback

# SYNOPSIS
26
27
28
29
30
31
32

33

34
35
36
37
38
39
40
# DESCRIPTION

Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the sockopt callback set with CURLOPT_SOCKOPTFUNCTION(3).

# DEFAULT


The default value of this parameter is NULL.


# EXAMPLE

~~~c
static int sockopt_callback(void *clientp, curl_socket_t curlfd,
                            curlsocktype purpose)
{







>
|
>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# DESCRIPTION

Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the sockopt callback set with CURLOPT_SOCKOPTFUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
static int sockopt_callback(void *clientp, curl_socket_t curlfd,
                            curlsocktype purpose)
{
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.0

# RETURN VALUE

Returns *CURLE_OK* if the option is supported, and *CURLE_UNKNOWN_OPTION* if not.







|
<
<




63
64
65
66
67
68
69
70


71
72
73
74
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns *CURLE_OK* if the option is supported, and *CURLE_UNKNOWN_OPTION* if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SOCKOPTFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKOPTFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - CURLOPT_SEEKFUNCTION (3)
  - CURLOPT_SOCKOPTDATA (3)
Protocol:
  - All

---

# NAME

CURLOPT_SOCKOPTFUNCTION - callback for setting socket options

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKOPTFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - CURLOPT_SEEKFUNCTION (3)
  - CURLOPT_SOCKOPTDATA (3)
Protocol:
  - All
Added-in: 7.16.0
---

# NAME

CURLOPT_SOCKOPTFUNCTION - callback for setting socket options

# SYNOPSIS
68
69
70
71
72
73
74

75

76
77
78
79
80
81
82
already connected and then libcurl does no attempt to connect. This allows an
application to pass in an already connected socket with
CURLOPT_OPENSOCKETFUNCTION(3) and then have this function make libcurl
not attempt to connect (again).

# DEFAULT


By default, this callback is NULL and unused.


# EXAMPLE

~~~c
/* make libcurl use the already established socket 'sockfd' */

static curl_socket_t opensocket(void *clientp,







>
|
>







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
already connected and then libcurl does no attempt to connect. This allows an
application to pass in an already connected socket with
CURLOPT_OPENSOCKETFUNCTION(3) and then have this function make libcurl
not attempt to connect (again).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
/* make libcurl use the already established socket 'sockfd' */

static curl_socket_t opensocket(void *clientp,
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.0. The *CURL_SOCKOPT_ALREADY_CONNECTED* return code was
added in 7.21.5.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<
<




119
120
121
122
123
124
125
126



127
128
129
130
    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SOCKS5_AUTH.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKS5_AUTH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYTYPE (3)
Protocol:
  - All

---

# NAME

CURLOPT_SOCKS5_AUTH - methods for SOCKS5 proxy authentication

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKS5_AUTH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYTYPE (3)
Protocol:
  - All
Added-in: 7.55.0
---

# NAME

CURLOPT_SOCKS5_AUTH - methods for SOCKS5 proxy authentication

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
*CURLAUTH_NONE*, which allows no authentication. Set the actual username and
password with the CURLOPT_PROXYUSERPWD(3) option.

# DEFAULT

CURLAUTH_BASIC|CURLAUTH_GSSAPI



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
*CURLAUTH_NONE*, which allows no authentication. Set the actual username and
password with the CURLOPT_PROXYUSERPWD(3) option.

# DEFAULT

CURLAUTH_BASIC|CURLAUTH_GSSAPI

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.55.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_NOT_BUILT_IN if the bitmask contains unsupported flags.







|
<
<





56
57
58
59
60
61
62
63


64
65
66
67
68

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_NOT_BUILT_IN if the bitmask contains unsupported flags.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_NEC.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKS5_GSSAPI_NEC
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_SOCKS5_GSSAPI_SERVICE (3)
Protocol:
  - All

---

# NAME

CURLOPT_SOCKS5_GSSAPI_NEC - SOCKS proxy GSSAPI negotiation protection

# SYNOPSIS








|


>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKS5_GSSAPI_NEC
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXY_SERVICE_NAME (3)
Protocol:
  - All
Added-in: 7.19.4
---

# NAME

CURLOPT_SOCKS5_GSSAPI_NEC - SOCKS proxy GSSAPI negotiation protection

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
If enabled, this option allows the unprotected exchange of the protection mode
negotiation.

# DEFAULT

?



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://proxy");
    curl_easy_setopt(curl, CURLOPT_SOCKS5_GSSAPI_NEC, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


59
60
61
62
If enabled, this option allows the unprotected exchange of the protection mode
negotiation.

# DEFAULT

?

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://proxy");
    curl_easy_setopt(curl, CURLOPT_SOCKS5_GSSAPI_NEC, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SOCKS5_GSSAPI_SERVICE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKS5_GSSAPI_SERVICE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYTYPE (3)
Protocol:
  - All

---

# NAME

CURLOPT_SOCKS5_GSSAPI_SERVICE - SOCKS5 proxy authentication service name

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SOCKS5_GSSAPI_SERVICE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PROXY (3)
  - CURLOPT_PROXYTYPE (3)
Protocol:
  - All
Added-in: 7.19.4
---

# NAME

CURLOPT_SOCKS5_GSSAPI_SERVICE - SOCKS5 proxy authentication service name

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
66
The application does not have to keep the string around after setting this
option.

# DEFAULT

See above



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://proxy");
    curl_easy_setopt(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE, "rcmd-special");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.4, deprecated in 7.49.0



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|

|
>
>





36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
The application does not have to keep the string around after setting this
option.

# DEFAULT

See above

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_PROXY, "socks5://proxy");
    curl_easy_setopt(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE, "rcmd-special");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# DEPRECATED

Deprecated since 7.49.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_AUTH_TYPES.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_AUTH_TYPES
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3)
  - CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 (3)
  - CURLOPT_SSH_PUBLIC_KEYFILE (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_AUTH_TYPES - auth types for SFTP and SCP

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_AUTH_TYPES
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3)
  - CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 (3)
  - CURLOPT_SSH_PUBLIC_KEYFILE (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.16.1
---

# NAME

CURLOPT_SSH_AUTH_TYPES - auth types for SFTP and SCP

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
attempts to connect to ssh-agent or pageant and let the agent attempt the
authentication.

# DEFAULT

CURLSSH_AUTH_ANY (all available)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_AUTH_TYPES,
                     CURLSSH_AUTH_PUBLICKEY | CURLSSH_AUTH_KEYBOARD);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

CURLSSH_AUTH_HOST was added in 7.16.1, CURLSSH_AUTH_AGENT was added in 7.28.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
attempts to connect to ssh-agent or pageant and let the agent attempt the
authentication.

# DEFAULT

CURLSSH_AUTH_ANY (all available)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_AUTH_TYPES,
                     CURLSSH_AUTH_PUBLICKEY | CURLSSH_AUTH_KEYBOARD);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_COMPRESSION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_COMPRESSION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ACCEPT_ENCODING (3)
  - CURLOPT_TRANSFER_ENCODING (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_COMPRESSION - enable SSH compression

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_COMPRESSION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ACCEPT_ENCODING (3)
  - CURLOPT_TRANSFER_ENCODING (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.56.0
---

# NAME

CURLOPT_SSH_COMPRESSION - enable SSH compression

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Enables built-in SSH compression. This is a request, not an order; the server
may or may not do it.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com");

    /* enable built-in compression */
    curl_easy_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.56.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
64
Enables built-in SSH compression. This is a request, not an order; the server
may or may not do it.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com");

    /* enable built-in compression */
    curl_easy_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_KEYDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_HOSTKEYFUNCTION (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_HOSTKEYDATA - pointer to pass to the SSH host key callback

# SYNOPSIS



|







>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_HOSTKEYDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_HOSTKEYFUNCTION (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.84.0
---

# NAME

CURLOPT_SSH_HOSTKEYDATA - pointer to pass to the SSH host key callback

# SYNOPSIS
27
28
29
30
31
32
33


34
35
36
37
38
39
40

Pass a void * as parameter. This *pointer* is passed along untouched to
the callback set with CURLOPT_SSH_HOSTKEYFUNCTION(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
struct mine {
  void *custom;
};







>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

Pass a void * as parameter. This *pointer* is passed along untouched to
the callback set with CURLOPT_SSH_HOSTKEYFUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct mine {
  void *custom;
};
59
60
61
62
63
64
65
66
67
68


69
70
71
72
    curl_easy_setopt(curl, CURLOPT_SSH_HOSTKEYDATA, &callback_data);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.84.0, works only with libssh2 backend.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
    curl_easy_setopt(curl, CURLOPT_SSH_HOSTKEYDATA, &callback_data);

    curl_easy_perform(curl);
  }
}
~~~

# NOTES

Works only with the libssh2 backend.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_HOSTKEYFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_HOSTKEYFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_HOSTKEYDATA (3)
  - CURLOPT_SSH_KNOWNHOSTS (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_HOSTKEYFUNCTION - callback to check host key

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_HOSTKEYFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_HOSTKEYDATA (3)
  - CURLOPT_SSH_KNOWNHOSTS (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.84.0
---

# NAME

CURLOPT_SSH_HOSTKEYFUNCTION - callback to check host key

# SYNOPSIS
54
55
56
57
58
59
60


61
62
63
64
65
66
67

the host key is rejected, the connection is canceled.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct mine {
  void *custom;
};








>
>







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

the host key is rejected, the connection is canceled.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct mine {
  void *custom;
};

84
85
86
87
88
89
90
91
92
93


94
95
96
97
    curl_easy_setopt(curl, CURLOPT_SSH_HOSTKEYDATA, &callback_data);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.84.0 , work only with libssh2 backend.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|

|
>
>




87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
    curl_easy_setopt(curl, CURLOPT_SSH_HOSTKEYDATA, &callback_data);

    curl_easy_perform(curl);
  }
}
~~~

# NOTES

Work only with the libssh2 backend.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 (3)
  - CURLOPT_SSH_KNOWNHOSTS (3)
  - CURLOPT_SSH_PUBLIC_KEYFILE (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 - MD5 checksum of SSH server public key

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 (3)
  - CURLOPT_SSH_KNOWNHOSTS (3)
  - CURLOPT_SSH_PUBLIC_KEYFILE (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.17.1
---

# NAME

CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 - MD5 checksum of SSH server public key

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
                     "afe17cd62a0f3b61f1ab9cb22ba269a7");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.17.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|
<
<





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
71
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
                     "afe17cd62a0f3b61f1ab9cb22ba269a7");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3)
  - CURLOPT_SSH_PUBLIC_KEYFILE (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 - SHA256 hash of SSH server public key

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3)
  - CURLOPT_SSH_PUBLIC_KEYFILE (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.80.0
---

# NAME

CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 - SHA256 hash of SSH server public key

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
64
hash of the remote host's public key. The transfer fails if the given hash
does not match the hash the remote host provides.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
                     "NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ=");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.80.0
Requires the libssh2 backend.



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|

<

>
>





33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
68
hash of the remote host's public key. The transfer fails if the given hash
does not match the hash the remote host provides.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
                     "NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ=");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# NOTES


Requires the libssh2 backend.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_KEYDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_KEYDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_KEYDATA (3)
  - CURLOPT_SSH_KNOWNHOSTS (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_KEYDATA - pointer passed to the SSH key callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_KEYDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_KEYDATA (3)
  - CURLOPT_SSH_KNOWNHOSTS (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.19.6
---

# NAME

CURLOPT_SSH_KEYDATA - pointer passed to the SSH key callback

# SYNOPSIS
28
29
30
31
32
33
34


35
36
37
38
39
40
41

Pass a void * as parameter. This *pointer* is passed along verbatim to the
callback set with CURLOPT_SSH_KEYFUNCTION(3).

# DEFAULT

NULL



# EXAMPLE

~~~c
struct mine {
  void *custom;
};







>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Pass a void * as parameter. This *pointer* is passed along verbatim to the
callback set with CURLOPT_SSH_KEYFUNCTION(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct mine {
  void *custom;
};
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, "/home/user/known_hosts");

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.6

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




64
65
66
67
68
69
70
71


72
73
74
75
    curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, "/home/user/known_hosts");

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_KEYFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_KEYFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_KEYDATA (3)
  - CURLOPT_SSH_KNOWNHOSTS (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_KEYFUNCTION - callback for known host matching logic

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_KEYFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_KEYDATA (3)
  - CURLOPT_SSH_KNOWNHOSTS (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.19.6
---

# NAME

CURLOPT_SSH_KEYFUNCTION - callback for known host matching logic

# SYNOPSIS
105
106
107
108
109
110
111


112
113
114
115
116
117
118
host+key situation and then retry without needing the overhead of setting it
up from scratch again.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct mine {
  void *custom;
};








>
>







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
host+key situation and then retry without needing the overhead of setting it
up from scratch again.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct mine {
  void *custom;
};

138
139
140
141
142
143
144
145
146
147
148
149
150
151
    curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, "/home/user/known_hosts");

    curl_easy_perform(curl);
}
}
~~~

# AVAILABILITY

Added in 7.19.6

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




141
142
143
144
145
146
147
148


149
150
151
152
    curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS, "/home/user/known_hosts");

    curl_easy_perform(curl);
}
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_KNOWNHOSTS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_KNOWNHOSTS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_KNOWNHOSTS - filename holding the SSH known hosts

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_KNOWNHOSTS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.19.6
---

# NAME

CURLOPT_SSH_KNOWNHOSTS - filename holding the SSH known hosts

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS,
                     "/home/clarkkent/.ssh/known_hosts");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.6

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|
<
<





37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
68
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_KNOWNHOSTS,
                     "/home/clarkkent/.ssh/known_hosts");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_PRIVATE_KEYFILE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_PRIVATE_KEYFILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_PUBLIC_KEYFILE (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_PRIVATE_KEYFILE - private key file for SSH auth

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_PRIVATE_KEYFILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_PUBLIC_KEYFILE (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.16.1
---

# NAME

CURLOPT_SSH_PRIVATE_KEYFILE - private key file for SSH auth

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
The application does not have to keep the string around after setting this
option.

# DEFAULT

As explained above



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE,
                     "/home/clarkkent/.ssh/id_rsa");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "password");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71


72
73
74
75
76
The application does not have to keep the string around after setting this
option.

# DEFAULT

As explained above

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE,
                     "/home/clarkkent/.ssh/id_rsa");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "password");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSH_PUBLIC_KEYFILE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_PUBLIC_KEYFILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_PRIVATE_KEYFILE (3)
Protocol:
  - SFTP
  - SCP

---

# NAME

CURLOPT_SSH_PUBLIC_KEYFILE - public key file for SSH auth

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSH_PUBLIC_KEYFILE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSH_AUTH_TYPES (3)
  - CURLOPT_SSH_PRIVATE_KEYFILE (3)
Protocol:
  - SFTP
  - SCP
Added-in: 7.16.1
---

# NAME

CURLOPT_SSH_PUBLIC_KEYFILE - public key file for SSH auth

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
70
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE,
                     "/home/clarkkent/.ssh/id_rsa.pub");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

The "" trick was added in 7.26.0



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>

















|


>
>





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
    curl_easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE,
                     "/home/clarkkent/.ssh/id_rsa.pub");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

The "" trick was added in 7.26.0

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLCERT.md.
13
14
15
16
17
18
19

20
21
22
23
24
25
26
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - Schannel
  - Secure Transport
  - wolfSSL

---

# NAME

CURLOPT_SSLCERT - SSL client certificate

# SYNOPSIS







>







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - Schannel
  - Secure Transport
  - wolfSSL
Added-in: 7.1
---

# NAME

CURLOPT_SSLCERT - SSL client certificate

# SYNOPSIS
61
62
63
64
65
66
67


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89


90
91
92
93
94
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLCERTTYPE.md.
12
13
14
15
16
17
18

19
20
21
22
23
24
25
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - Schannel
  - Secure Transport
  - wolfSSL

---

# NAME

CURLOPT_SSLCERTTYPE - type of client SSL certificate

# SYNOPSIS







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
TLS-backend:
  - OpenSSL
  - GnuTLS
  - mbedTLS
  - Schannel
  - Secure Transport
  - wolfSSL
Added-in: 7.9.3
---

# NAME

CURLOPT_SSLCERTTYPE - type of client SSL certificate

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
The application does not have to keep the string around after setting this
option.

# DEFAULT

"PEM"



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

If built TLS enabled. Added in 7.9.3

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
77
The application does not have to keep the string around after setting this
option.

# DEFAULT

"PEM"

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLCERT_BLOB.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - Secure Transport
  - Schannel
  - mbedTLS

---

# NAME

CURLOPT_SSLCERT_BLOB - SSL client certificate from memory blob

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - Secure Transport
  - Schannel
  - mbedTLS
Added-in: 7.71.0
---

# NAME

CURLOPT_SSLCERT_BLOB - SSL client certificate from memory blob

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58
This option is an alternative to CURLOPT_SSLCERT(3) which instead
expects a filename as input.

# DEFAULT

NULL



# EXAMPLE

~~~c

extern char *certificateData; /* point to data */
extern size_t filesize; /* size of data */








>
>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
This option is an alternative to CURLOPT_SSLCERT(3) which instead
expects a filename as input.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c

extern char *certificateData; /* point to data */
extern size_t filesize; /* size of data */

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.71.0. This option is supported by the OpenSSL, Secure Transport,
Schannel and mbedTLS (since 7.78.0) backends.

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<
<





74
75
76
77
78
79
80
81



82
83
84
85
86
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLENGINE.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_SSL_ENGINES (3)
  - CURLOPT_SSLENGINE_DEFAULT (3)
  - CURLOPT_SSLKEY (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLOPT_SSLENGINE - SSL engine identifier

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_SSL_ENGINES (3)
  - CURLOPT_SSLENGINE_DEFAULT (3)
  - CURLOPT_SSLKEY (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.9.3
---

# NAME

CURLOPT_SSLENGINE - SSL engine identifier

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLENGINE, "dynamic");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Only if OpenSSL is built with engine support.

# RETURN VALUE

CURLE_OK - Engine found.

CURLE_SSL_ENGINE_NOTFOUND - Engine not found, or OpenSSL was not built with
engine support.







>
>
















|
<
<







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
65
66
67
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLENGINE, "dynamic");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK - Engine found.

CURLE_SSL_ENGINE_NOTFOUND - Engine not found, or OpenSSL was not built with
engine support.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLENGINE_DEFAULT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSLENGINE_DEFAULT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSLCERT (3)
  - CURLOPT_SSLENGINE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLOPT_SSLENGINE_DEFAULT - make SSL engine default

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSLENGINE_DEFAULT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSLCERT (3)
  - CURLOPT_SSLENGINE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.9.3
---

# NAME

CURLOPT_SSLENGINE_DEFAULT - make SSL engine default

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

This option has no effect unless set after CURLOPT_SSLENGINE(3).

# DEFAULT

None



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLENGINE, "dynamic");
    curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Only if the SSL backend is OpenSSL built with engine support.

# RETURN VALUE

CURLE_OK - Engine set as default.

CURLE_SSL_ENGINE_SETFAILED - Engine could not be set as default.

CURLE_NOT_BUILT_IN - Option not built in, OpenSSL is not the SSL backend.

CURLE_UNKNOWN_OPTION - Option not recognized.

CURLE_OUT_OF_MEMORY - Insufficient heap space.







>
>

















|
<
<












33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
64
65
66
67
68
69
70
71

This option has no effect unless set after CURLOPT_SSLENGINE(3).

# DEFAULT

None

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLENGINE, "dynamic");
    curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK - Engine set as default.

CURLE_SSL_ENGINE_SETFAILED - Engine could not be set as default.

CURLE_NOT_BUILT_IN - Option not built in, OpenSSL is not the SSL backend.

CURLE_UNKNOWN_OPTION - Option not recognized.

CURLE_OUT_OF_MEMORY - Insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLKEY.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - mbedTLS
  - Schannel
  - wolfSSL

---

# NAME

CURLOPT_SSLKEY - private key file for TLS and SSL client cert

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - mbedTLS
  - Schannel
  - wolfSSL
Added-in: 7.9.3
---

# NAME

CURLOPT_SSLKEY - private key file for TLS and SSL client cert

# SYNOPSIS
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>


















|
<
<





43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
75
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLKEYTYPE.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
  - CURLOPT_SSLKEY (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - BearSSL
  - wolfSSL

---

# NAME

CURLOPT_SSLKEYTYPE - type of the private key file

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  - CURLOPT_SSLKEY (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - BearSSL
  - wolfSSL
Added-in: 7.9.3
---

# NAME

CURLOPT_SSLKEYTYPE - type of the private key file

# SYNOPSIS
41
42
43
44
45
46
47


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
The application does not have to keep the string around after setting this
option.

# DEFAULT

"PEM"



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
75
The application does not have to keep the string around after setting this
option.

# DEFAULT

"PEM"

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEY, "key.pem");
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
    curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "s3cret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLKEY_BLOB.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSLKEY_BLOB
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSLKEY (3)
  - CURLOPT_SSLKEYTYPE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL

---

# NAME

CURLOPT_SSLKEY_BLOB - private key for client cert from memory blob

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSLKEY_BLOB
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSLKEY (3)
  - CURLOPT_SSLKEYTYPE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
Added-in: 7.71.0
---

# NAME

CURLOPT_SSLKEY_BLOB - private key for client cert from memory blob

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51

This option is an alternative to CURLOPT_SSLKEY(3) which instead expects a
filename as input.

# DEFAULT

NULL



# EXAMPLE

~~~c

extern char *certificateData; /* point to cert */
extern size_t filesize; /* size of cert */







>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

This option is an alternative to CURLOPT_SSLKEY(3) which instead expects a
filename as input.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c

extern char *certificateData; /* point to cert */
extern size_t filesize; /* size of cert */
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.71.0. This option is supported by the OpenSSL backends.

# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
<
<





76
77
78
79
80
81
82
83


84
85
86
87
88
    curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TLS enabled, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSLVERSION.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_IPRESOLVE (3)
  - CURLOPT_PROXY_SSLVERSION (3)
  - CURLOPT_USE_SSL (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_SSLVERSION - preferred TLS/SSL version

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_IPRESOLVE (3)
  - CURLOPT_PROXY_SSLVERSION (3)
  - CURLOPT_USE_SSL (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_SSLVERSION - preferred TLS/SSL version

# SYNOPSIS
66
67
68
69
70
71
72


73
74
75
76
77
78
79
80
81
82
83
84
## CURL_SSLVERSION_TLSv1_2

TLS v1.2 or later (Added in 7.34.0)

## CURL_SSLVERSION_TLSv1_3

TLS v1.3 or later (Added in 7.52.0)



The maximum TLS version can be set by using *one* of the
CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the
CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros.
The MAX macros are not supported for WolfSSL.

## CURL_SSLVERSION_MAX_DEFAULT

The flag defines the maximum supported TLS version by libcurl, or the default
value from the SSL library is used. libcurl uses a sensible default maximum,
which was TLS v1.2 up to before 7.61.0 and is TLS v1.3 since then - assuming
the TLS library support it. (Added in 7.54.0)







>
>




|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
## CURL_SSLVERSION_TLSv1_2

TLS v1.2 or later (Added in 7.34.0)

## CURL_SSLVERSION_TLSv1_3

TLS v1.3 or later (Added in 7.52.0)

##

The maximum TLS version can be set by using *one* of the
CURL_SSLVERSION_MAX_ macros below. It is also possible to OR *one* of the
CURL_SSLVERSION_ macros with *one* of the CURL_SSLVERSION_MAX_ macros.
The MAX macros are not supported for wolfSSL.

## CURL_SSLVERSION_MAX_DEFAULT

The flag defines the maximum supported TLS version by libcurl, or the default
value from the SSL library is used. libcurl uses a sensible default maximum,
which was TLS v1.2 up to before 7.61.0 and is TLS v1.3 since then - assuming
the TLS library support it. (Added in 7.54.0)
98
99
100
101
102
103
104


105
106
107
108
109
110
111
112


113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139


140
141
142
143
The flag defines maximum supported TLS version as TLS v1.2.
(Added in 7.54.0)

## CURL_SSLVERSION_MAX_TLSv1_3

The flag defines maximum supported TLS version as TLS v1.3.
(Added in 7.54.0)



In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were
documented to allow *only* the specified TLS version, but behavior was
inconsistent depending on the TLS library.

# DEFAULT

CURL_SSLVERSION_DEFAULT



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* ask libcurl to use TLS version 1.0 or later */
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

SSLv2 and SSLv3 are refused completely since curl 7.77.0

SSLv2 is disabled by default since 7.18.1. Other SSL versions availability may
vary depending on which backend libcurl has been built to use.

SSLv3 is disabled by default since 7.39.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>








>
>



















|







>
>




101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
The flag defines maximum supported TLS version as TLS v1.2.
(Added in 7.54.0)

## CURL_SSLVERSION_MAX_TLSv1_3

The flag defines maximum supported TLS version as TLS v1.3.
(Added in 7.54.0)

##

In versions of curl prior to 7.54 the CURL_SSLVERSION_TLS options were
documented to allow *only* the specified TLS version, but behavior was
inconsistent depending on the TLS library.

# DEFAULT

CURL_SSLVERSION_DEFAULT

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* ask libcurl to use TLS version 1.0 or later */
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

SSLv2 and SSLv3 are refused completely since curl 7.77.0

SSLv2 is disabled by default since 7.18.1. Other SSL versions availability may
vary depending on which backend libcurl has been built to use.

SSLv3 is disabled by default since 7.39.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_CIPHER_LIST.md.
16
17
18
19
20
21
22

23
24
25
26
27
28
29
  - OpenSSL
  - BearSSL
  - Schannel
  - Secure Transport
  - wolfSSL
  - GnuTLS
  - mbedTLS

---

# NAME

CURLOPT_SSL_CIPHER_LIST - ciphers to use for TLS

# SYNOPSIS







>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  - OpenSSL
  - BearSSL
  - Schannel
  - Secure Transport
  - wolfSSL
  - GnuTLS
  - mbedTLS
Added-in: 7.9
---

# NAME

CURLOPT_SSL_CIPHER_LIST - ciphers to use for TLS

# SYNOPSIS
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
spaces are also acceptable separators but colons are normally used, !, - and
+ can be used as operators.

For OpenSSL and GnuTLS valid examples of cipher lists include **RC4-SHA**,
**SHA1+DES**, **TLSv1** and **DEFAULT**. The default list is normally set when
you compile OpenSSL.

For WolfSSL, valid examples of cipher lists include **ECDHE-RSA-RC4-SHA**,
**AES256-SHA:AES256-SHA256**, etc.

For mbedTLS and BearSSL, valid examples of cipher lists include
**ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256**, or when using
IANA names
**TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256**,
etc. With mbedTLS and BearSSL you do not add/remove ciphers. If one uses this







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
spaces are also acceptable separators but colons are normally used, !, - and
+ can be used as operators.

For OpenSSL and GnuTLS valid examples of cipher lists include **RC4-SHA**,
**SHA1+DES**, **TLSv1** and **DEFAULT**. The default list is normally set when
you compile OpenSSL.

For wolfSSL, valid examples of cipher lists include **ECDHE-RSA-RC4-SHA**,
**AES256-SHA:AES256-SHA256**, etc.

For mbedTLS and BearSSL, valid examples of cipher lists include
**ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256**, or when using
IANA names
**TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256**,
etc. With mbedTLS and BearSSL you do not add/remove ciphers. If one uses this
65
66
67
68
69
70
71
72


73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
 https://curl.se/docs/ssl-ciphers.html

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use internal default



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "TLSv1");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.9, in 7.83.0 for BearSSL, in 8.8.0 for mbedTLS

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
>
>

















|



|





66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
 https://curl.se/docs/ssl-ciphers.html

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use built-in list

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "TLSv1");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Added in 7.9, in 7.83.0 for BearSSL, in 8.8.0 for mbedTLS

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if TLS is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_DATA.md.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - wolfSSL
  - mbedTLS
  - BearSSL

---

# NAME

CURLOPT_SSL_CTX_DATA - pointer passed to SSL context callback

# SYNOPSIS







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - wolfSSL
  - mbedTLS
  - BearSSL
Added-in: 7.10.6
---

# NAME

CURLOPT_SSL_CTX_DATA - pointer passed to SSL context callback

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
Data *pointer* to pass to the ssl context callback set by the option
CURLOPT_SSL_CTX_FUNCTION(3), this is the pointer you get as third
parameter.

# DEFAULT

NULL



# EXAMPLE

~~~c
/* OpenSSL specific */

#include <openssl/ssl.h>







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Data *pointer* to pass to the ssl context callback set by the option
CURLOPT_SSL_CTX_FUNCTION(3), this is the pointer you get as third
parameter.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
/* OpenSSL specific */

#include <openssl/ssl.h>
109
110
111
112
113
114
115
116
117
118
119


120
121
122
123
124
125
126
127

  curl_easy_cleanup(ch);
  curl_global_cleanup();
  return rv;
}
~~~

# AVAILABILITY

Added in 7.11.0 for OpenSSL, in 7.42.0 for wolfSSL, in 7.54.0 for mbedTLS,
in 7.83.0 in BearSSL.



# RETURN VALUE

CURLE_OK if supported; or an error such as:

CURLE_NOT_BUILT_IN - Not supported by the SSL backend

CURLE_UNKNOWN_OPTION







|



>
>








112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

  curl_easy_cleanup(ch);
  curl_global_cleanup();
  return rv;
}
~~~

# HISTORY

Added in 7.11.0 for OpenSSL, in 7.42.0 for wolfSSL, in 7.54.0 for mbedTLS,
in 7.83.0 in BearSSL.

# %AVAILABILITY%

# RETURN VALUE

CURLE_OK if supported; or an error such as:

CURLE_NOT_BUILT_IN - Not supported by the SSL backend

CURLE_UNKNOWN_OPTION
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_CTX_FUNCTION.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - wolfSSL
  - mbedTLS
  - BearSSL

---

# NAME

CURLOPT_SSL_CTX_FUNCTION - SSL context callback

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - wolfSSL
  - mbedTLS
  - BearSSL
Added-in: 7.10.6
---

# NAME

CURLOPT_SSL_CTX_FUNCTION - SSL context callback

# SYNOPSIS
77
78
79
80
81
82
83


84
85
86
87
88
89
90
callback function has returned. Your application must not assume that it can
keep using the SSL context or data derived from it once this function is
completed.

# DEFAULT

NULL



# EXAMPLE

~~~c
/* OpenSSL specific */

#include <openssl/ssl.h>







>
>







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
callback function has returned. Your application must not assume that it can
keep using the SSL context or data derived from it once this function is
completed.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
/* OpenSSL specific */

#include <openssl/ssl.h>
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

  curl_easy_cleanup(ch);
  curl_global_cleanup();
  return rv;
}
~~~

# AVAILABILITY

OpenSSL (added in 7.11.0), wolfSSL (added in 7.42.0), mbedTLS (added in
7.54.0) or BearSSL (added in 7.83.0)

# RETURN VALUE

CURLE_OK if supported; or an error such as:

CURLE_NOT_BUILT_IN - Not supported by the SSL backend







|
<
<
<






156
157
158
159
160
161
162
163



164
165
166
167
168
169

  curl_easy_cleanup(ch);
  curl_global_cleanup();
  return rv;
}
~~~

# %AVAILABILITY%




# RETURN VALUE

CURLE_OK if supported; or an error such as:

CURLE_NOT_BUILT_IN - Not supported by the SSL backend
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_EC_CURVES.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_SSL_OPTIONS (3)
  - CURLOPT_TLS13_CIPHERS (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - wolfSSL

---

# NAME

CURLOPT_SSL_EC_CURVES - key exchange curves

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_SSL_OPTIONS (3)
  - CURLOPT_TLS13_CIPHERS (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - wolfSSL
Added-in: 7.73.0
---

# NAME

CURLOPT_SSL_EC_CURVES - key exchange curves

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
option defines the client's key exchange algorithms in the SSL handshake (if
the SSL backend libcurl is built to use supports it).

# DEFAULT

"", embedded in SSL backend



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_EC_CURVES, "X25519:P-521");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.73.0. Supported by the OpenSSL backend.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>
















|
<
<




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
option defines the client's key exchange algorithms in the SSL handshake (if
the SSL backend libcurl is built to use supports it).

# DEFAULT

"", embedded in SSL backend

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_EC_CURVES, "X25519:P-521");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_ALPN.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSL_ENABLE_ALPN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSL_ENABLE_NPN (3)
  - CURLOPT_SSL_OPTIONS (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_SSL_ENABLE_ALPN - Application Layer Protocol Negotiation

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSL_ENABLE_ALPN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSL_ENABLE_NPN (3)
  - CURLOPT_SSL_OPTIONS (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.36.0
---

# NAME

CURLOPT_SSL_ENABLE_ALPN - Application Layer Protocol Negotiation

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
option enables/disables ALPN in the SSL handshake (if the SSL backend libcurl
is built to use supports it), which can be used to negotiate http2.

# DEFAULT

1, enabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.36.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>
















|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61
option enables/disables ALPN in the SSL handshake (if the SSL backend libcurl
is built to use supports it), which can be used to negotiate http2.

# DEFAULT

1, enabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_ENABLE_NPN.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


59
60
61
62
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSL_ENABLE_NPN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSL_ENABLE_ALPN (3)
  - CURLOPT_SSL_OPTIONS (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_SSL_ENABLE_NPN - use NPN

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_ENABLE_NPN, long npn);
~~~

# DESCRIPTION

Deprecated in 7.86.0. Setting this option has no function.

Pass a long as parameter, 0 or 1 where 1 is for enable and 0 for disable. This
option enables/disables NPN in the SSL handshake (if the SSL backend libcurl
is built to use supports it), which can be used to negotiate http2.

# DEFAULT

1, enabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.36.0. Deprecated in 7.86.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.













>
















|








>
>

















|

|
>
>




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSL_ENABLE_NPN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSL_ENABLE_ALPN (3)
  - CURLOPT_SSL_OPTIONS (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.36.0
---

# NAME

CURLOPT_SSL_ENABLE_NPN - use NPN

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_ENABLE_NPN, long npn);
~~~

# DESCRIPTION

Deprecated since 7.86.0. Setting this option has no function.

Pass a long as parameter, 0 or 1 where 1 is for enable and 0 for disable. This
option enables/disables NPN in the SSL handshake (if the SSL backend libcurl
is built to use supports it), which can be used to negotiate http2.

# DEFAULT

1, enabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_NPN, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# DEPRECATED

Deprecated since 7.86.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSL_FALSESTART
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_FASTOPEN (3)
Protocol:
  - TLS
TLS-backend:
  - Secure Transport

---

# NAME

CURLOPT_SSL_FALSESTART - TLS false start

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SSL_FALSESTART
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_FASTOPEN (3)
Protocol:
  - TLS
TLS-backend:
  - Secure Transport
Added-in: 7.42.0
---

# NAME

CURLOPT_SSL_FALSESTART - TLS false start

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
data before verifying the server's Finished message, thus saving a round trip
when performing a full handshake.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.42.0. This option is currently only supported by the Secure
Transport (on iOS 7.0 or later, or OS X 10.9 or later) TLS backend.

# RETURN VALUE

Returns CURLE_OK if false start is supported by the SSL backend, otherwise
returns CURLE_NOT_BUILT_IN.







>
>














|
<
<
<





34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57



58
59
60
61
62
data before verifying the server's Finished message, thus saving a round trip
when performing a full handshake.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if false start is supported by the SSL backend, otherwise
returns CURLE_NOT_BUILT_IN.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_OPTIONS.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_PROXY_SSL_OPTIONS (3)
  - CURLOPT_SSLVERSION (3)
  - CURLOPT_SSL_CIPHER_LIST (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_SSL_OPTIONS - SSL behavior options

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_PROXY_SSL_OPTIONS (3)
  - CURLOPT_SSLVERSION (3)
  - CURLOPT_SSL_CIPHER_LIST (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.25.0
---

# NAME

CURLOPT_SSL_OPTIONS - SSL behavior options

# SYNOPSIS
85
86
87
88
89
90
91


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
could be a privacy violation and unexpected.
(Added in 7.77.0)

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* weaken TLS only for use with silly servers */
    curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST |
                     CURLSSLOPT_NO_REVOKE);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.25.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|
<
<




86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113


114
115
116
117
could be a privacy violation and unexpected.
(Added in 7.77.0)

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* weaken TLS only for use with silly servers */
    curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST |
                     CURLSSLOPT_NO_REVOKE);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_SESSIONID_CACHE.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_MAXAGE_CONN (3)
  - CURLOPT_MAXLIFETIME_CONN (3)
  - CURLOPT_SSLVERSION (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_SSL_SESSIONID_CACHE - use the SSL session-ID cache

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_MAXAGE_CONN (3)
  - CURLOPT_MAXLIFETIME_CONN (3)
  - CURLOPT_SSLVERSION (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.16.0
---

# NAME

CURLOPT_SSL_SESSIONID_CACHE - use the SSL session-ID cache

# SYNOPSIS
36
37
38
39
40
41
42


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
session-IDs, there seem to be or have been broken SSL implementations in the
wild that may require you to disable this in order for you to succeed.

# DEFAULT

1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* switch off session-id use! */
    curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.16.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
session-IDs, there seem to be or have been broken SSL implementations in the
wild that may require you to disable this in order for you to succeed.

# DEFAULT

1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* switch off session-id use! */
    curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYHOST.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76











77
78
79
80
81
82
83
84
85
86
87


88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

108







109
110
111
112
113
114
  - CURLOPT_CAINFO (3)
  - CURLOPT_PINNEDPUBLICKEY (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_SSL_VERIFYHOST - verify the certificate's name against host

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_VERIFYHOST, long verify);
~~~

# DESCRIPTION

Pass a long as parameter specifying what to *verify*.

This option determines whether libcurl verifies that the server cert is for
the server it is known as.

When negotiating TLS and SSL connections, the server sends a certificate
indicating its identity.

When CURLOPT_SSL_VERIFYHOST(3) is 2, that certificate must indicate that
the server is the server to which you meant to connect, or the connection
fails. Simply put, it means it has to have the same name in the certificate as
is in the URL you operate against.

Curl considers the server the intended one when the Common Name field or a
Subject Alternate Name field in the certificate matches the hostname in the
URL to which you told Curl to connect.

If *verify* value is set to 1:

In 7.28.0 and earlier: treated as a debug option of some sorts, not supported
anymore due to frequently leading to programmer mistakes.

From 7.28.1 to 7.65.3: setting it to 1 made curl_easy_setopt(3) return
an error and leaving the flag untouched.

From 7.66.0: treats 1 and 2 the same.

When the *verify* value is 0, the connection succeeds regardless of the
names in the certificate. Use that ability with caution!

The default value for this option is 2.

This option controls checking the server's certificate's claimed identity.
The server could be lying. To control lying, see CURLOPT_SSL_VERIFYPEER(3).


WARNING: disabling verification of the certificate allows bad guys to
man-in-the-middle the communication without you knowing it. Disabling
verification makes the communication insecure. Just having encryption on a
transfer is not enough as you cannot be sure that you are communicating with
the correct end-point.

When libcurl uses secure protocols it trusts responses and allows for example
HSTS and Alt-Svc information to be stored and used subsequently. Disabling
certificate verification can make libcurl trust and use such information from
malicious servers.












# LIMITATIONS

Secure Transport: If *verify* value is 0, then SNI is also disabled. SNI is
a TLS extension that sends the hostname to the server. The server may use that
information to do such things as sending back a specific certificate for the
hostname, or forwarding the request to a specific origin server. Some hostnames
may be inaccessible if SNI is not sent.

# DEFAULT

2



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* Set the default value: strict name check please */
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY


If built TLS enabled.








# RETURN VALUE

Returns CURLE_OK if TLS is supported, and CURLE_UNKNOWN_OPTION if not.

If 1 is set as argument, *CURLE_BAD_FUNCTION_ARGUMENT* is returned.







>
















|
|
<
<

|
|

|
|
|
|

|

|

<
<
<
<
<
<
<
<
<
<
|
|

<
<
|
|
>












>
>
>
>
>
>
>
>
>
>
>


|
|

|
|




>
>


















|

>
|
>
>
>
>
>
>
>




<
<
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46










47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121


  - CURLOPT_CAINFO (3)
  - CURLOPT_PINNEDPUBLICKEY (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.8.1
---

# NAME

CURLOPT_SSL_VERIFYHOST - verify the certificate's name against host

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_VERIFYHOST, long verify);
~~~

# DESCRIPTION

Pass a long set to 2L to make libcurl verify the host in the server's TLS
certificate.



When negotiating a TLS connection, the server sends a certificate indicating
its identity.

When CURLOPT_SSL_VERIFYHOST(3) is set to 1 or 2, the server certificate must
indicate that it was made for the hostname or address curl connects to, or the
connection fails. Simply put, it means it has to have the same name in the
certificate as is used in the URL you operate against.

curl considers the server the intended one when the Common Name field or a
Subject Alternate Name field in the certificate matches the hostname in the
URL to which you told curl to connect.











When the *verify* value is 0, the connection succeeds regardless of the names
in the certificate. Use that ability with caution,



This option controls checking the server's certificate's claimed identity. The
separate CURLOPT_SSL_VERIFYPEER(3) options enables/disables verification that
the certificate is signed by a trusted Certificate Authority.

WARNING: disabling verification of the certificate allows bad guys to
man-in-the-middle the communication without you knowing it. Disabling
verification makes the communication insecure. Just having encryption on a
transfer is not enough as you cannot be sure that you are communicating with
the correct end-point.

When libcurl uses secure protocols it trusts responses and allows for example
HSTS and Alt-Svc information to be stored and used subsequently. Disabling
certificate verification can make libcurl trust and use such information from
malicious servers.

# MATCHING

A certificate can have the name as a wildcard. The only asterisk (`*`) must
then be the left-most character and it must be followed by a period. The
wildcard must further contain more than one period as it cannot be set for a
top-level domain.

A certificate can be set for a numerical IP address (IPv4 or IPv6), but then
it should be a Subject Alternate Name kind and its type should correctly
identify the field as an IP address.

# LIMITATIONS

Secure Transport: If *verify* value is 0, then SNI is also disabled. SNI is a
TLS extension that sends the hostname to the server. The server may use that
information to do such things as sending back a specific certificate for the
hostname, or forwarding the request to a specific origin server. Some
hostnames may be inaccessible if SNI is not sent.

# DEFAULT

2

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* Set the default value: strict name check please */
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%

# HISTORY

In 7.28.0 and earlier: the value 1 was treated as a debug option of some
sorts, not supported anymore due to frequently leading to programmer mistakes.

From 7.28.1 to 7.65.3: setting it to 1 made curl_easy_setopt(3) return
an error and leaving the flag untouched.

From 7.66.0: libcurl treats 1 and 2 to this option the same.

# RETURN VALUE

Returns CURLE_OK if TLS is supported, and CURLE_UNKNOWN_OPTION if not.


Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYPEER.md.
11
12
13
14
15
16
17

18
19
20
21
22
23
24
  - CURLOPT_PROXY_SSL_VERIFYHOST (3)
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
Protocol:
  - TLS
TLS-backend:
  - All

---

# NAME

CURLOPT_SSL_VERIFYPEER - verify the peer's SSL certificate

# SYNOPSIS







>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  - CURLOPT_PROXY_SSL_VERIFYHOST (3)
  - CURLOPT_PROXY_SSL_VERIFYPEER (3)
  - CURLOPT_SSL_VERIFYHOST (3)
Protocol:
  - TLS
TLS-backend:
  - All
Added-in: 7.4.2
---

# NAME

CURLOPT_SSL_VERIFYPEER - verify the peer's SSL certificate

# SYNOPSIS
68
69
70
71
72
73
74


75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
certificate verification can make libcurl trust and use such information from
malicious servers.

# DEFAULT

1 - enabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* Set the default value: strict certificate check please */
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

If built TLS enabled.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95


96
97
98
99
certificate verification can make libcurl trust and use such information from
malicious servers.

# DEFAULT

1 - enabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* Set the default value: strict certificate check please */
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SSL_VERIFYSTATUS.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_SSL_VERIFYSTATUS - verify the certificate's status

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_SSL_VERIFYHOST (3)
  - CURLOPT_SSL_VERIFYPEER (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.41.0
---

# NAME

CURLOPT_SSL_VERIFYSTATUS - verify the certificate's status

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Note that if this option is enabled but the server does not support the TLS
extension, the verification fails.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* ask for OCSP stapling! */
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.41.0. This option is currently only supported by the OpenSSL and
GnuTLS TLS backends.

# RETURN VALUE

Returns CURLE_OK if OCSP stapling is supported by the SSL backend, otherwise
returns CURLE_NOT_BUILT_IN.







>
>

















|
<
<
<





38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64



65
66
67
68
69
Note that if this option is enabled but the server does not support the TLS
extension, the verification fails.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* ask for OCSP stapling! */
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if OCSP stapling is supported by the SSL backend, otherwise
returns CURLE_NOT_BUILT_IN.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_STDERR.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_STDERR
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_NOPROGRESS (3)
  - CURLOPT_VERBOSE (3)
Protocol:
  - All

---

# NAME

CURLOPT_STDERR - redirect stderr to another stream

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_STDERR
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_NOPROGRESS (3)
  - CURLOPT_VERBOSE (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_STDERR - redirect stderr to another stream

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
a crash in the library since it cannot access a FILE * passed on from the
application. A work-around is to instead use CURLOPT_DEBUGFUNCTION(3).

# DEFAULT

stderr



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  FILE *filep = fopen("dump", "wb");
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_STDERR, filep);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>
















|
<
<




35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
a crash in the library since it cannot access a FILE * passed on from the
application. A work-around is to instead use CURLOPT_DEBUGFUNCTION(3).

# DEFAULT

stderr

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  FILE *filep = fopen("dump", "wb");
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_STDERR, filep);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_STREAM_DEPENDS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_STREAM_DEPENDS_E (3)
  - CURLOPT_STREAM_WEIGHT (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_STREAM_DEPENDS - stream this transfer depends on

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_STREAM_DEPENDS
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_STREAM_DEPENDS_E (3)
  - CURLOPT_STREAM_WEIGHT (3)
Protocol:
  - HTTP
Added-in: 7.46.0
---

# NAME

CURLOPT_STREAM_DEPENDS - stream this transfer depends on

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
a transfer that is about to be sent over the same HTTP/2 connection for this
option to have an actual effect.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  CURL *curl2 = curl_easy_init(); /* a second handle */
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/one");

    /* the second depends on the first */
    curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two");
    curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS, curl);

    /* then add both to a multi handle and transfer them! */
  }
}
~~~

# AVAILABILITY

Added in 7.46.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72


73
74
75
76
a transfer that is about to be sent over the same HTTP/2 connection for this
option to have an actual effect.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  CURL *curl2 = curl_easy_init(); /* a second handle */
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/one");

    /* the second depends on the first */
    curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two");
    curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS, curl);

    /* then add both to a multi handle and transfer them! */
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_STREAM_DEPENDS_E.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_STREAM_DEPENDS_E
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_STREAM_DEPENDS (3)
  - CURLOPT_STREAM_WEIGHT (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_STREAM_DEPENDS_E - stream this transfer depends on exclusively

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_STREAM_DEPENDS_E
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLOPT_HTTP_VERSION (3)
  - CURLOPT_STREAM_DEPENDS (3)
  - CURLOPT_STREAM_WEIGHT (3)
Protocol:
  - HTTP
Added-in: 7.46.0
---

# NAME

CURLOPT_STREAM_DEPENDS_E - stream this transfer depends on exclusively

# SYNOPSIS
46
47
48
49
50
51
52


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
a transfer that is about to be sent over the same HTTP/2 connection for this
option to have an actual effect.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  CURL *curl2 = curl_easy_init(); /* a second handle */
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/one");

    /* the second depends on the first */
    curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two");
    curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS_E, curl);

    /* then add both to a multi handle and transfer them! */
  }
}
~~~

# AVAILABILITY

Added in 7.46.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>



















|
<
<




47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75


76
77
78
79
a transfer that is about to be sent over the same HTTP/2 connection for this
option to have an actual effect.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  CURL *curl2 = curl_easy_init(); /* a second handle */
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/one");

    /* the second depends on the first */
    curl_easy_setopt(curl2, CURLOPT_URL, "https://example.com/two");
    curl_easy_setopt(curl2, CURLOPT_STREAM_DEPENDS_E, curl);

    /* then add both to a multi handle and transfer them! */
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_STREAM_WEIGHT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_STREAM_WEIGHT
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLOPT_PIPEWAIT (3)
  - CURLOPT_STREAM_DEPENDS (3)
  - CURLOPT_STREAM_DEPENDS_E (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_STREAM_WEIGHT - numerical stream weight

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_STREAM_WEIGHT
Section: 3
Source: libcurl
See-also:
  - CURLMOPT_PIPELINING (3)
  - CURLOPT_PIPEWAIT (3)
  - CURLOPT_STREAM_DEPENDS (3)
  - CURLOPT_STREAM_DEPENDS_E (3)
Protocol:
  - HTTP
Added-in: 7.46.0
---

# NAME

CURLOPT_STREAM_WEIGHT - numerical stream weight

# SYNOPSIS
43
44
45
46
47
48
49
50
51


52
53
54
55
56
57
58
based on their weight. If you have two streams going, stream A with weight 16
and stream B with weight 32, stream B gets two thirds (32/48) of the available
bandwidth (assuming the server can send off the data equally for both
streams).

# DEFAULT

If nothing is set, the HTTP/2 protocol itself uses its own default which is
16.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







<
|
>
>







44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59
60
based on their weight. If you have two streams going, stream A with weight 16
and stream B with weight 32, stream B gets two thirds (32/48) of the available
bandwidth (assuming the server can send off the data equally for both
streams).

# DEFAULT


16

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    curl_easy_setopt(curl2, CURLOPT_STREAM_WEIGHT, 20L);

    /* then add both to a multi handle and transfer them! */
  }
}
~~~

# AVAILABILITY

Added in 7.46.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




68
69
70
71
72
73
74
75


76
77
78
79
    curl_easy_setopt(curl2, CURLOPT_STREAM_WEIGHT, 20L);

    /* then add both to a multi handle and transfer them! */
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_SUPPRESS_CONNECT_HEADERS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SUPPRESS_CONNECT_HEADERS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADER (3)
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_PROXY (3)
Protocol:
  - All

---

# NAME

CURLOPT_SUPPRESS_CONNECT_HEADERS - suppress proxy CONNECT response headers

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_SUPPRESS_CONNECT_HEADERS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADER (3)
  - CURLOPT_HTTPPROXYTUNNEL (3)
  - CURLOPT_PROXY (3)
Protocol:
  - All
Added-in: 7.54.0
---

# NAME

CURLOPT_SUPPRESS_CONNECT_HEADERS - suppress proxy CONNECT response headers

# SYNOPSIS
66
67
68
69
70
71
72


73
74
75
76
77
78
79
...
~~~

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
...
~~~

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
88
89
90
91
92
93
94
95
96
97
98
99
100
101

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.54.0

# RETURN VALUE

CURLE_OK or an error such as CURLE_UNKNOWN_OPTION.







|
<
<




91
92
93
94
95
96
97
98


99
100
101
102

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLE_OK or an error such as CURLE_UNKNOWN_OPTION.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_FASTOPEN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSL_FALSESTART (3)
Protocol:
  - All

---

# NAME

CURLOPT_TCP_FASTOPEN - TCP Fast Open

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_FASTOPEN
Section: 3
Source: libcurl
See-also:
  - CURLOPT_SSL_FALSESTART (3)
Protocol:
  - All
Added-in: 7.49.0
---

# NAME

CURLOPT_TCP_FASTOPEN - TCP Fast Open

# SYNOPSIS
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

58
59
60
61
62
Beware: the TLS session cache does not work when TCP Fast Open is enabled. TCP
Fast Open is also known to be problematic on or across certain networks.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.49.0. This option is currently only supported on Linux and macOS
10.11 or later.


# RETURN VALUE

Returns CURLE_OK if fast open is supported by the operating system, otherwise
returns CURLE_NOT_BUILT_IN.







>
>














|

|
|
>





34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
Beware: the TLS session cache does not work when TCP Fast Open is enabled. TCP
Fast Open is also known to be problematic on or across certain networks.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# NOTES

This option is only supported on Linux and macOS 10.11 or later.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if fast open is supported by the operating system, otherwise
returns CURLE_NOT_BUILT_IN.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPALIVE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57



58
59
60
61
62
63
64
65
66
67
68
69
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_KEEPALIVE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_TCP_KEEPIDLE (3)
  - CURLOPT_TCP_KEEPINTVL (3)

Protocol:
  - All

---

# NAME

CURLOPT_TCP_KEEPALIVE - TCP keep-alive probing

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPALIVE, long probe);
~~~

# DESCRIPTION

Pass a long. If set to 1, TCP keepalive probes are used. The delay and
frequency of these probes can be controlled by the
CURLOPT_TCP_KEEPIDLE(3) and CURLOPT_TCP_KEEPINTVL(3) options,
provided the operating system supports them. Set to 0 (default behavior) to
disable keepalive probes

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable TCP keep-alive for this transfer */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

    /* keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);




    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.25.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.











>

|
>


















|
|
|




>
>



















>
>
>





|
<
<




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_KEEPALIVE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_MAX_RECV_SPEED_LARGE (3)
  - CURLOPT_TCP_KEEPIDLE (3)
  - CURLOPT_TCP_KEEPINTVL (3)
  - CURLOPT_TCP_KEEPCNT (3)
Protocol:
  - TCP
Added-in: 7.25.0
---

# NAME

CURLOPT_TCP_KEEPALIVE - TCP keep-alive probing

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPALIVE, long probe);
~~~

# DESCRIPTION

Pass a long. If set to 1, TCP keepalive probes are used. The delay and
frequency of these probes can be controlled by the
CURLOPT_TCP_KEEPIDLE(3), CURLOPT_TCP_KEEPINTVL(3), and CURLOPT_TCP_KEEPCNT(3)
options, provided the operating system supports them. Set to 0 (default behavior)
to disable keepalive probes.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable TCP keep-alive for this transfer */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

    /* keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

    /* maximum number of keep-alive probes: 3 */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Added jni/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPCNT.md.




















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_KEEPCNT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TCP_KEEPIDLE (3)
  - CURLOPT_TCP_KEEPINTVL (3)
Protocol:
  - TCP
Added-in: 8.9.0
---

# NAME

CURLOPT_TCP_KEEPCNT - Maximum number of TCP keep-alive probes

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TCP_KEEPCNT, long cnt);
~~~

# DESCRIPTION

Pass a long. Sets the number of probes to send before dropping
the connection. Not all operating systems support this option.
(Added in 8.9.0)

The maximum value this option accepts is INT_MAX or whatever your
system allows.
Any larger value is capped to this amount.

# DEFAULT

9

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable TCP keep-alive for this transfer */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

    /* set keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

    /* maximum number of keep-alive probes: 3 */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPIDLE.md.
1
2
3
4
5
6
7
8
9

10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_KEEPIDLE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TCP_KEEPINTVL (3)

Protocol:
  - All

---

# NAME

CURLOPT_TCP_KEEPIDLE - TCP keep-alive idle time wait

# SYNOPSIS









>

|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_KEEPIDLE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TCP_KEEPINTVL (3)
  - CURLOPT_TCP_KEEPCNT (3)
Protocol:
  - TCP
Added-in: 7.25.0
---

# NAME

CURLOPT_TCP_KEEPIDLE - TCP keep-alive idle time wait

# SYNOPSIS
32
33
34
35
36
37
38


39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56



57
58
59
60
61
62
63
64
65
66
67
68
The maximum value this accepts is 2147483648. Any larger value is capped to
this amount.

# DEFAULT

60



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable TCP keep-alive for this transfer */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

    /* set keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);




    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.25.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















>
>
>





|
<
<




34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69


70
71
72
73
The maximum value this accepts is 2147483648. Any larger value is capped to
this amount.

# DEFAULT

60

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable TCP keep-alive for this transfer */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

    /* set keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

    /* maximum number of keep-alive probes: 3 */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TCP_KEEPINTVL.md.
1
2
3
4
5
6
7
8
9

10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_KEEPINTVL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TCP_KEEPIDLE (3)

Protocol:
  - All

---

# NAME

CURLOPT_TCP_KEEPINTVL - TCP keep-alive interval

# SYNOPSIS









>

|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_KEEPINTVL
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TCP_KEEPIDLE (3)
  - CURLOPT_TCP_KEEPCNT (3)
Protocol:
  - TCP
Added-in: 7.25.0
---

# NAME

CURLOPT_TCP_KEEPINTVL - TCP keep-alive interval

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55



56
57
58
59
60
61
62
63
64
65
66
67
The maximum value this accepts is 2147483648. Any larger value is capped to
this amount.

# DEFAULT

60



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable TCP keep-alive for this transfer */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

    /* set keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);




    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















>
>
>





|
<
<




33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
The maximum value this accepts is 2147483648. Any larger value is capped to
this amount.

# DEFAULT

60

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* enable TCP keep-alive for this transfer */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);

    /* set keep-alive idle time to 120 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L);

    /* interval time between keep-alive probes: 60 seconds */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L);

    /* maximum number of keep-alive probes: 3 */
    curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 3L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TCP_NODELAY.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_NODELAY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_BUFFERSIZE (3)
  - CURLOPT_SOCKOPTFUNCTION (3)
  - CURLOPT_TCP_KEEPALIVE (3)
Protocol:
  - All

---

# NAME

CURLOPT_TCP_NODELAY - the TCP_NODELAY option

# SYNOPSIS











|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TCP_NODELAY
Section: 3
Source: libcurl
See-also:
  - CURLOPT_BUFFERSIZE (3)
  - CURLOPT_SOCKOPTFUNCTION (3)
  - CURLOPT_TCP_KEEPALIVE (3)
Protocol:
  - TCP
Added-in: 7.11.2
---

# NAME

CURLOPT_TCP_NODELAY - the TCP_NODELAY option

# SYNOPSIS
41
42
43
44
45
46
47


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
amounts of data at a time, and can contribute to congestion on the network if
overdone.

# DEFAULT

1



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    /* leave Nagle enabled */
    curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 0);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always. The default was changed to 1 from 0 in 7.50.2.



# RETURN VALUE

Returns CURLE_OK







>
>















|

|
>
>




42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
amounts of data at a time, and can contribute to congestion on the network if
overdone.

# DEFAULT

1

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    /* leave Nagle enabled */
    curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 0);
    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

The default was changed to 1 from 0 in 7.50.2.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TELNETOPTIONS.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TELNETOPTIONS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_QUOTE (3)
Protocol:
  - TELNET

---

# NAME

CURLOPT_TELNETOPTIONS - set of telnet options

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TELNETOPTIONS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_QUOTE (3)
Protocol:
  - TELNET
Added-in: 7.7
---

# NAME

CURLOPT_TELNETOPTIONS - set of telnet options

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
supports the options **TTYPE**, **XDISPLOC** and **NEW_ENV**. See the TELNET
standard for details.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    struct curl_slist *options;
    options = curl_slist_append(NULL, "TTTYPE=vt100");
    options = curl_slist_append(options, "USER=foobar");
    curl_easy_setopt(curl, CURLOPT_URL, "telnet://example.com/");
    curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, options);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
    curl_slist_free_all(options);
  }
}
~~~

# AVAILABILITY

Along with TELNET

# RETURN VALUE

Returns CURLE_OK if TELNET is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
supports the options **TTYPE**, **XDISPLOC** and **NEW_ENV**. See the TELNET
standard for details.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    struct curl_slist *options;
    options = curl_slist_append(NULL, "TTTYPE=vt100");
    options = curl_slist_append(options, "USER=foobar");
    curl_easy_setopt(curl, CURLOPT_URL, "telnet://example.com/");
    curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, options);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
    curl_slist_free_all(options);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if TELNET is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TFTP_BLKSIZE.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TFTP_BLKSIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAXFILESIZE (3)
Protocol:
  - TFTP

---

# NAME

CURLOPT_TFTP_BLKSIZE - TFTP block size

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TFTP_BLKSIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_MAXFILESIZE (3)
Protocol:
  - TFTP
Added-in: 7.19.4
---

# NAME

CURLOPT_TFTP_BLKSIZE - TFTP block size

# SYNOPSIS
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
returns an option acknowledgment with no block size, the default of 512 bytes
is used.

# DEFAULT

512



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "tftp://example.com/bootimage");
    /* try using larger blocks */
    curl_easy_setopt(curl, CURLOPT_TFTP_BLKSIZE, 2048L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58


59
60
61
62
returns an option acknowledgment with no block size, the default of 512 bytes
is used.

# DEFAULT

512

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "tftp://example.com/bootimage");
    /* try using larger blocks */
    curl_easy_setopt(curl, CURLOPT_TFTP_BLKSIZE, 2048L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TFTP_NO_OPTIONS.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TFTP_NO_OPTIONS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TFTP_BLKSIZE (3)
Protocol:
  - TFTP

---

# NAME

CURLOPT_TFTP_NO_OPTIONS - send no TFTP options requests

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TFTP_NO_OPTIONS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TFTP_BLKSIZE (3)
Protocol:
  - TFTP
Added-in: 7.48.0
---

# NAME

CURLOPT_TFTP_NO_OPTIONS - send no TFTP options requests

# SYNOPSIS
30
31
32
33
34
35
36


37
38
39
40
41
42
43
This option improves interoperability with legacy servers that do not
acknowledge or properly implement TFTP options. When this option is used
CURLOPT_TFTP_BLKSIZE(3) is ignored.

# DEFAULT

0



# EXAMPLE

~~~c
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *fp)
{
  return fwrite(ptr, size, nmemb, (FILE *)fp);







>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
This option improves interoperability with legacy servers that do not
acknowledge or properly implement TFTP options. When this option is used
CURLOPT_TFTP_BLKSIZE(3) is ignored.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
size_t write_callback(char *ptr, size_t size, size_t nmemb, void *fp)
{
  return fwrite(ptr, size, nmemb, (FILE *)fp);
63
64
65
66
67
68
69
70
71
72
73
74
75
76
      fclose(fp);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.48.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




66
67
68
69
70
71
72
73


74
75
76
77
      fclose(fp);
    }
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TIMECONDITION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMECONDITION
Section: 3
Source: libcurl
See-also:
  - CURLINFO_FILETIME (3)
  - CURLOPT_TIMEVALUE (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_TIMECONDITION - select condition for a time request

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMECONDITION
Section: 3
Source: libcurl
See-also:
  - CURLINFO_FILETIME (3)
  - CURLOPT_TIMEVALUE (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_TIMECONDITION - select condition for a time request

# SYNOPSIS
35
36
37
38
39
40
41


42
43
44
45
46
47
48
option can be used after a transfer to learn if a zero-byte successful
"transfer" was due to this condition not matching.

# DEFAULT

CURL_TIMECOND_NONE (0)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
option can be used after a transfer to learn if a zero-byte successful
"transfer" was due to this condition not matching.

# DEFAULT

CURL_TIMECOND_NONE (0)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
57
58
59
60
61
62
63
64
65
66
67
68
69
70

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




60
61
62
63
64
65
66
67


68
69
70
71

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TIMEOUT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMEOUT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECTTIMEOUT (3)
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TIMEOUT_MS (3)
Protocol:
  - All

---

# NAME

CURLOPT_TIMEOUT - maximum time the transfer is allowed to complete

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMEOUT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECTTIMEOUT (3)
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TIMEOUT_MS (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_TIMEOUT - maximum time the transfer is allowed to complete

# SYNOPSIS
55
56
57
58
59
60
61
62


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

This option may cause libcurl to use the SIGALRM signal to timeout system
calls on builds not using asynch DNS. In unix-like systems, this might cause
signals to be used unless CURLOPT_NOSIGNAL(3) is set.

# DEFAULT

Default timeout is 0 (zero) which means it never times out during transfer.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* complete within 20 seconds */
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK. Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative
value or a value that when converted to milliseconds is too large.







|
>
>


















|
<
<





56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84


85
86
87
88
89

This option may cause libcurl to use the SIGALRM signal to timeout system
calls on builds not using asynch DNS. In unix-like systems, this might cause
signals to be used unless CURLOPT_NOSIGNAL(3) is set.

# DEFAULT

0 (zero) which means it never times out during transfer.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* complete within 20 seconds */
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 20L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK. Returns CURLE_BAD_FUNCTION_ARGUMENT if set to a negative
value or a value that when converted to milliseconds is too large.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TIMEOUT_MS.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMEOUT_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECTTIMEOUT (3)
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All

---

# NAME

CURLOPT_TIMEOUT_MS - maximum time the transfer is allowed to complete

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMEOUT_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECTTIMEOUT (3)
  - CURLOPT_LOW_SPEED_LIMIT (3)
  - CURLOPT_TCP_KEEPALIVE (3)
  - CURLOPT_TIMEOUT (3)
Protocol:
  - All
Added-in: 7.16.2
---

# NAME

CURLOPT_TIMEOUT_MS - maximum time the transfer is allowed to complete

# SYNOPSIS
30
31
32
33
34
35
36
37


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Pass a long as parameter containing *timeout* - the maximum time in
milliseconds that you allow the libcurl transfer operation to take.

See CURLOPT_TIMEOUT(3) for details.

# DEFAULT

Default timeout is 0 (zero) which means it never times out during transfer.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* complete within 20000 milliseconds */
    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 20000L);

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
>
>


















|
<
<




31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60
61
62
63
Pass a long as parameter containing *timeout* - the maximum time in
milliseconds that you allow the libcurl transfer operation to take.

See CURLOPT_TIMEOUT(3) for details.

# DEFAULT

0 (zero) which means it never times out during transfer.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* complete within 20000 milliseconds */
    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 20000L);

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38


39
40
41
42
43
44
45
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMEVALUE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TIMECONDITION (3)
  - CURLOPT_TIMEVALUE_LARGE (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_TIMEVALUE - time value for conditional

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMEVALUE, long val);
~~~

# DESCRIPTION

Pass a long *val* as parameter. This should be the time counted as seconds
since 1 Jan 1970, and the time is used in a condition as specified with
CURLOPT_TIMECONDITION(3).

On systems with 32 bit 'long' variables (such as Windows), this option cannot
set dates beyond the year 2038. Consider CURLOPT_TIMEVALUE_LARGE(3)
instead.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();











>




















|






>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMEVALUE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TIMECONDITION (3)
  - CURLOPT_TIMEVALUE_LARGE (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_TIMEVALUE - time value for conditional

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TIMEVALUE, long val);
~~~

# DESCRIPTION

Pass a long *val* as parameter. This should be the time counted as seconds
since 1 Jan 1970, and the time is used in a condition as specified with
CURLOPT_TIMECONDITION(3).

On systems with 32-bit 'long' variables (such as Windows), this option cannot
set dates beyond the year 2038. Consider CURLOPT_TIMEVALUE_LARGE(3)
instead.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
54
55
56
57
58
59
60
61
62
63
64
65
66
67

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




57
58
59
60
61
62
63
64


65
66
67
68

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TIMEVALUE_LARGE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMEVALUE_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_FILETIME (3)
  - CURLOPT_TIMECONDITION (3)
  - CURLOPT_TIMEVALUE (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_TIMEVALUE_LARGE - time value for conditional

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TIMEVALUE_LARGE
Section: 3
Source: libcurl
See-also:
  - CURLINFO_FILETIME (3)
  - CURLOPT_TIMECONDITION (3)
  - CURLOPT_TIMEVALUE (3)
Protocol:
  - HTTP
Added-in: 7.59.0
---

# NAME

CURLOPT_TIMEVALUE_LARGE - time value for conditional

# SYNOPSIS
27
28
29
30
31
32
33
34
35
36
37
38
39
40


41
42
43
44
45
46
47

# DESCRIPTION

Pass a curl_off_t *val* as parameter. This should be the time counted as
seconds since 1 Jan 1970, and the time is used in a condition as specified
with CURLOPT_TIMECONDITION(3).

The difference between this option and CURLOPT_TIMEVALUE(3) is the type
of the argument. On systems where 'long' is only 32 bit wide, this option has
to be used to set dates beyond the year 2038.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







|
|
|




>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# DESCRIPTION

Pass a curl_off_t *val* as parameter. This should be the time counted as
seconds since 1 Jan 1970, and the time is used in a condition as specified
with CURLOPT_TIMECONDITION(3).

The difference between this option and CURLOPT_TIMEVALUE(3) is the type of the
argument. On systems where 'long' is only 32 bits wide, this option has to be
used to set dates beyond the year 2038.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
56
57
58
59
60
61
62
63
64
65
66
67
68
69

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.59.0.

# RETURN VALUE

Returns CURLE_OK







|
<
<




59
60
61
62
63
64
65
66


67
68
69
70

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TLS13_CIPHERS.md.
12
13
14
15
16
17
18

19
20
21
22
23
24
25
  - CURLOPT_SSL_CIPHER_LIST (3)
  - CURLOPT_USE_SSL (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - Schannel

---

# NAME

CURLOPT_TLS13_CIPHERS - ciphers suites to use for TLS 1.3

# SYNOPSIS







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  - CURLOPT_SSL_CIPHER_LIST (3)
  - CURLOPT_USE_SSL (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - Schannel
Added-in: 7.61.0
---

# NAME

CURLOPT_TLS13_CIPHERS - ciphers suites to use for TLS 1.3

# SYNOPSIS
47
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77


78
79
80
81
option.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use internal default



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_TLS13_CIPHERS,
                     "TLS_CHACHA20_POLY1305_SHA256");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.61.0 for OpenSSL. Available when built with OpenSSL \>= 1.1.1.

Added in 7.85.0 for Schannel.



# RETURN VALUE

Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise.







|
>
>


















|




>
>




48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
option.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, use internal built-in

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_TLS13_CIPHERS,
                     "TLS_CHACHA20_POLY1305_SHA256");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Added in 7.61.0 for OpenSSL. Available when built with OpenSSL \>= 1.1.1.

Added in 7.85.0 for Schannel.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if supported, CURLE_NOT_BUILT_IN otherwise.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_PASSWORD.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  - CURLOPT_TLSAUTH_TYPE (3)
  - CURLOPT_TLSAUTH_USERNAME (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_TLSAUTH_PASSWORD - password to use for TLS authentication

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_PASSWORD, char *pwd);
~~~

# DESCRIPTION

Pass a char pointer as parameter, which should point to the null-terminated
password to use for the TLS authentication method specified with the
CURLOPT_TLSAUTH_TYPE(3) option. Requires that the
CURLOPT_TLSAUTH_USERNAME(3) option also be set.

The application does not have to keep the string around after setting this
option.

This feature relies in TLS SRP which does not work with TLS 1.3.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.21.4, with the OpenSSL and GnuTLS backends only

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>


















|
|




|




>
>



















|
<
<





9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71
72
  - CURLOPT_TLSAUTH_TYPE (3)
  - CURLOPT_TLSAUTH_USERNAME (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.21.4
---

# NAME

CURLOPT_TLSAUTH_PASSWORD - password to use for TLS authentication

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_PASSWORD, char *pwd);
~~~

# DESCRIPTION

Pass a char pointer as parameter, which should point to the null-terminated
password to use for the TLS authentication method specified with the
CURLOPT_TLSAUTH_TYPE(3) option. Requires that the CURLOPT_TLSAUTH_USERNAME(3)
option also be set.

The application does not have to keep the string around after setting this
option.

This feature relies on TLS SRP which does not work with TLS 1.3.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_TYPE.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLOPT_TLSAUTH_PASSWORD (3)
  - CURLOPT_TLSAUTH_USERNAME (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_TLSAUTH_TYPE - TLS authentication methods

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLOPT_TLSAUTH_PASSWORD (3)
  - CURLOPT_TLSAUTH_USERNAME (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.21.4
---

# NAME

CURLOPT_TLSAUTH_TYPE - TLS authentication methods

# SYNOPSIS
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
the method of the TLS authentication. Supported method is "SRP".

## SRP

TLS-SRP authentication. Secure Remote Password authentication for TLS is
defined in RFC 5054 and provides mutual authentication if both sides have a
shared secret. To use TLS-SRP, you must also set the
CURLOPT_TLSAUTH_USERNAME(3) and CURLOPT_TLSAUTH_PASSWORD(3)
options.

The application does not have to keep the string around after setting this
option.

TLS SRP does not work with TLS 1.3.

# DEFAULT

blank



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

You need to build libcurl with GnuTLS or OpenSSL with TLS-SRP support for this
to work. Added in 7.21.4

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<
<
<






>
>



















|
<
<
<




33
34
35
36
37
38
39
40




41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68



69
70
71
72
the method of the TLS authentication. Supported method is "SRP".

## SRP

TLS-SRP authentication. Secure Remote Password authentication for TLS is
defined in RFC 5054 and provides mutual authentication if both sides have a
shared secret. To use TLS-SRP, you must also set the
CURLOPT_TLSAUTH_USERNAME(3) and CURLOPT_TLSAUTH_PASSWORD(3) options.





TLS SRP does not work with TLS 1.3.

# DEFAULT

blank

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%




# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TLSAUTH_USERNAME.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43


44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
  - CURLOPT_TLSAUTH_PASSWORD (3)
  - CURLOPT_TLSAUTH_TYPE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS

---

# NAME

CURLOPT_TLSAUTH_USERNAME - username to use for TLS authentication

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_USERNAME, char *user);
~~~

# DESCRIPTION

Pass a char pointer as parameter, which should point to the null-terminated
username to use for the TLS authentication method specified with the
CURLOPT_TLSAUTH_TYPE(3) option. Requires that the
CURLOPT_TLSAUTH_PASSWORD(3) option also be set.

The application does not have to keep the string around after setting this
option.

This feature relies in TLS SRP which does not work with TLS 1.3.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.21.4, with the OpenSSL and GnuTLS backends only

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>


















|
|




|




>
>



















|
<
<





8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
71
  - CURLOPT_TLSAUTH_PASSWORD (3)
  - CURLOPT_TLSAUTH_TYPE (3)
Protocol:
  - TLS
TLS-backend:
  - OpenSSL
  - GnuTLS
Added-in: 7.21.4
---

# NAME

CURLOPT_TLSAUTH_USERNAME - username to use for TLS authentication

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_TLSAUTH_USERNAME, char *user);
~~~

# DESCRIPTION

Pass a char pointer as parameter, which should point to the null-terminated
username to use for the TLS authentication method specified with the
CURLOPT_TLSAUTH_TYPE(3) option. Requires that the CURLOPT_TLSAUTH_PASSWORD(3)
option also be set.

The application does not have to keep the string around after setting this
option.

This feature relies on TLS SRP which does not work with TLS 1.3.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_TYPE, "SRP");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, "user");
    curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, "secret");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TRAILERDATA.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TRAILERDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TRAILERFUNCTION (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_TRAILERDATA - pointer passed to trailing headers callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TRAILERDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TRAILERFUNCTION (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - HTTP
Added-in: 7.64.0
---

# NAME

CURLOPT_TRAILERDATA - pointer passed to trailing headers callback

# SYNOPSIS
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

Data pointer to be passed to the HTTP trailer callback function.

# DEFAULT

NULL



# EXAMPLE

~~~c
struct MyData {
  void *custom;
};

int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    struct MyData data;
    curl_easy_setopt(curl, CURLOPT_TRAILERDATA, &data);
  }
}
~~~

# AVAILABILITY

This option was added in curl 7.64.0 and is present if HTTP support is enabled

# RETURN VALUE

Returns CURLE_OK.







>
>

















|
<
<




28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


55
56
57
58

Data pointer to be passed to the HTTP trailer callback function.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct MyData {
  void *custom;
};

int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    struct MyData data;
    curl_easy_setopt(curl, CURLOPT_TRAILERDATA, &data);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TRAILERFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TRAILERFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TRAILERDATA (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_TRAILERFUNCTION - callback for sending trailing headers

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TRAILERFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TRAILERDATA (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - HTTP
Added-in: 7.64.0
---

# NAME

CURLOPT_TRAILERFUNCTION - callback for sending trailing headers

# SYNOPSIS
55
56
57
58
59
60
61


62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
If you set this option to NULL, then the transfer proceeds as usual
without any interruptions.

# DEFAULT

NULL



# EXAMPLE
~~~c
static int trailer_cb(struct curl_slist **tr, void *data)
{
  /* libcurl frees the list */
  *tr = curl_slist_append(*tr, "My-super-awesome-trailer: trailer-stuff");
  return CURL_TRAILERFUNC_OK;
}

int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;

    /* Set the URL of the request */
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* Now set it as a put */
    curl_easy_setopt(curl, CURLOPT_PUT, 1L);

    /* Assuming we have a function that returns the data to be pushed
       Let that function be read_cb */
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, trailer_cb);

    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Trailer: My-super-awesome-trailer");







>
>


















|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
If you set this option to NULL, then the transfer proceeds as usual
without any interruptions.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE
~~~c
static int trailer_cb(struct curl_slist **tr, void *data)
{
  /* libcurl frees the list */
  *tr = curl_slist_append(*tr, "My-super-awesome-trailer: trailer-stuff");
  return CURL_TRAILERFUNC_OK;
}

int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;

    /* Set the URL of the request */
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
    /* Now set it as a put */
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

    /* Assuming we have a function that returns the data to be pushed
       Let that function be read_cb */
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, trailer_cb);

    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Trailer: My-super-awesome-trailer");
95
96
97
98
99
100
101
102
103
104

105
106
107
108

    curl_easy_cleanup(curl);

    curl_slist_free_all(headers);
  }
}
~~~
# AVAILABILITY

This option was added in curl 7.64.0 and is present if HTTP support is enabled.


# RETURN VALUE

Returns CURLE_OK.







<

<
>




98
99
100
101
102
103
104

105

106
107
108
109
110

    curl_easy_cleanup(curl);

    curl_slist_free_all(headers);
  }
}
~~~



# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TRANSFERTEXT.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TRANSFERTEXT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CRLF (3)
Protocol:
  - All

---

# NAME

CURLOPT_TRANSFERTEXT - request a text based transfer for FTP

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TRANSFERTEXT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CRLF (3)
Protocol:
  - All
Added-in: 7.1.1
---

# NAME

CURLOPT_TRANSFERTEXT - request a text based transfer for FTP

# SYNOPSIS
34
35
36
37
38
39
40


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
over FTP. This is a known limitation/flaw that nobody has rectified. libcurl
simply sets the mode to ASCII and performs a standard transfer.

# DEFAULT

0, disabled



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/textfile");
    curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Along with FTP

# RETURN VALUE

Returns CURLE_OK if FTP is supported, and CURLE_UNKNOWN_OPTION if not.







>
>
















|
<
<




35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
over FTP. This is a known limitation/flaw that nobody has rectified. libcurl
simply sets the mode to ASCII and performs a standard transfer.

# DEFAULT

0, disabled

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/textfile");
    curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 1L);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if FTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_TRANSFER_ENCODING.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TRANSFER_ENCODING
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ACCEPT_ENCODING (3)
  - CURLOPT_HTTP_TRANSFER_DECODING (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_TRANSFER_ENCODING - ask for HTTP Transfer Encoding

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_TRANSFER_ENCODING
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ACCEPT_ENCODING (3)
  - CURLOPT_HTTP_TRANSFER_DECODING (3)
Protocol:
  - HTTP
Added-in: 7.21.6
---

# NAME

CURLOPT_TRANSFER_ENCODING - ask for HTTP Transfer Encoding

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
client. Traditionally, Transfer-Encoding has been much less used and supported
by both HTTP clients and HTTP servers.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.21.6

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>














|
<
<




40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


64
65
66
67
client. Traditionally, Transfer-Encoding has been much less used and supported
by both HTTP clients and HTTP servers.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_UNIX_SOCKET_PATH.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UNIX_SOCKET_PATH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ABSTRACT_UNIX_SOCKET (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - unix (7)
Protocol:
  - All

---

# NAME

CURLOPT_UNIX_SOCKET_PATH - Unix domain socket

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UNIX_SOCKET_PATH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_ABSTRACT_UNIX_SOCKET (3)
  - CURLOPT_OPENSOCKETFUNCTION (3)
  - unix (7)
Protocol:
  - All
Added-in: 7.40.0
---

# NAME

CURLOPT_UNIX_SOCKET_PATH - Unix domain socket

# SYNOPSIS
43
44
45
46
47
48
49
50


51
52
53
54
55
56
57
Unix domain socket is not possible.

The application does not have to keep the string around after setting this
option.

# DEFAULT

Default is NULL, meaning that no Unix domain sockets are used.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();







|
>
>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Unix domain socket is not possible.

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL - no Unix domain sockets are used.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  int dirfd = open(long_directory_path_to_socket, O_DIRECTORY | O_RDONLY);
  char path[108];
  snprintf(path, sizeof(path), "/proc/self/fd/%d/httpd.sock", dirfd);
  curl_easy_setopt(curl_handle, CURLOPT_UNIX_SOCKET_PATH, path);
  /* Be sure to keep dirfd valid until you discard the handle */
~~~

# AVAILABILITY

Added in 7.40.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




74
75
76
77
78
79
80
81


82
83
84
85
  int dirfd = open(long_directory_path_to_socket, O_DIRECTORY | O_RDONLY);
  char path[108];
  snprintf(path, sizeof(path), "/proc/self/fd/%d/httpd.sock", dirfd);
  curl_easy_setopt(curl_handle, CURLOPT_UNIX_SOCKET_PATH, path);
  /* Be sure to keep dirfd valid until you discard the handle */
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_UNRESTRICTED_AUTH.md.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - CURLOPT_MAXREDIRS (3)
  - CURLOPT_REDIR_PROTOCOLS_STR (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_UNRESTRICTED_AUTH - send credentials to other hosts too

# SYNOPSIS







>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  - CURLINFO_REDIRECT_COUNT (3)
  - CURLOPT_FOLLOWLOCATION (3)
  - CURLOPT_MAXREDIRS (3)
  - CURLOPT_REDIR_PROTOCOLS_STR (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - HTTP
Added-in: 7.10.4
---

# NAME

CURLOPT_UNRESTRICTED_AUTH - send credentials to other hosts too

# SYNOPSIS
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
possibly sensitive credentials to any host the server points to, possibly
again and again as the following hosts can keep redirecting to new hosts.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Along with HTTP

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.







>
>















|
<
<




49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73


74
75
76
77
possibly sensitive credentials to any host the server points to, possibly
again and again as the following hosts can keep redirecting to new hosts.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, 1L);
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_UPKEEP_INTERVAL_MS.md.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UPKEEP_INTERVAL_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
Protocol:
  - All

---

# NAME

CURLOPT_UPKEEP_INTERVAL_MS - connection upkeep interval

# SYNOPSIS










>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UPKEEP_INTERVAL_MS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_TCP_KEEPALIVE (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

CURLOPT_UPKEEP_INTERVAL_MS - connection upkeep interval

# SYNOPSIS
37
38
39
40
41
42
43


44
45
46
47
48
49
50
the connection upkeep interval is exceeded and curl_easy_upkeep(3)
is called, an HTTP/2 PING frame is sent on the connection.

# DEFAULT

CURL_UPKEEP_INTERVAL_DEFAULT (currently defined as 60000L, which is 60 seconds)



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
the connection upkeep interval is exceeded and curl_easy_upkeep(3)
is called, an HTTP/2 PING frame is sent on the connection.

# DEFAULT

CURL_UPKEEP_INTERVAL_DEFAULT (currently defined as 60000L, which is 60 seconds)

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
67
68
69
70
71
72
73
74
75
76
77
78
79
80

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.62.0

# RETURN VALUE

Returns CURLE_OK







|
<
<




70
71
72
73
74
75
76
77


78
79
80
81

    /* always cleanup */
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_UPLOAD.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

46

47
48
49
50
51
52
53
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UPLOAD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INFILESIZE_LARGE (3)
  - CURLOPT_PUT (3)
  - CURLOPT_READFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_UPLOAD - data upload

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UPLOAD, long upload);
~~~

# DESCRIPTION

The long parameter *upload* set to 1 tells the library to prepare for and
perform an upload. The CURLOPT_READDATA(3) and
CURLOPT_INFILESIZE(3) or CURLOPT_INFILESIZE_LARGE(3) options are
also interesting for uploads. If the protocol is HTTP, uploading means using
the PUT request unless you tell libcurl otherwise.

Using PUT with HTTP 1.1 implies the use of a "Expect: 100-continue" header.
You can disable this header with CURLOPT_HTTPHEADER(3) as usual.

If you use PUT to an HTTP 1.1 server, you can upload data without knowing the
size before starting the transfer. The library enables this by adding a header
"Transfer-Encoding: chunked". With HTTP 1.0 or if you prefer not to use chunked
transfer, you must specify the size of the data with
CURLOPT_INFILESIZE(3) or CURLOPT_INFILESIZE_LARGE(3).

# DEFAULT


0, default is download


# EXAMPLE

~~~c
static size_t read_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
  FILE *src = userdata;












>

















|
|
|
|






|
|




>
|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UPLOAD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_INFILESIZE_LARGE (3)
  - CURLOPT_PUT (3)
  - CURLOPT_READFUNCTION (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_UPLOAD - data upload

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UPLOAD, long upload);
~~~

# DESCRIPTION

The long parameter *upload* set to 1 tells the library to prepare for and
perform an upload. The CURLOPT_READDATA(3) and CURLOPT_INFILESIZE(3) or
CURLOPT_INFILESIZE_LARGE(3) options are also interesting for uploads. If the
protocol is HTTP, uploading means using the PUT request unless you tell
libcurl otherwise.

Using PUT with HTTP 1.1 implies the use of a "Expect: 100-continue" header.
You can disable this header with CURLOPT_HTTPHEADER(3) as usual.

If you use PUT to an HTTP 1.1 server, you can upload data without knowing the
size before starting the transfer. The library enables this by adding a header
"Transfer-Encoding: chunked". With HTTP 1.0 or if you prefer not to use
chunked transfer, you must specify the size of the data with
CURLOPT_INFILESIZE(3) or CURLOPT_INFILESIZE_LARGE(3).

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
static size_t read_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
  FILE *src = userdata;
82
83
84
85
86
87
88
89
90
91
92
93
94
95

    /* Now run off and do what you have been told! */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







|
<
<




85
86
87
88
89
90
91
92


93
94
95
96

    /* Now run off and do what you have been told! */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_UPLOAD_BUFFERSIZE.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UPLOAD_BUFFERSIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_BUFFERSIZE (3)
  - CURLOPT_READFUNCTION (3)
  - CURLOPT_TCP_NODELAY (3)
Protocol:
  - All

---

# NAME

CURLOPT_UPLOAD_BUFFERSIZE - upload buffer size

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UPLOAD_BUFFERSIZE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_BUFFERSIZE (3)
  - CURLOPT_READFUNCTION (3)
  - CURLOPT_TCP_NODELAY (3)
Protocol:
  - All
Added-in: 7.62.0
---

# NAME

CURLOPT_UPLOAD_BUFFERSIZE - upload buffer size

# SYNOPSIS
45
46
47
48
49
50
51


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
DO NOT set this option on a handle that is currently used for an active
transfer as that may lead to unintended consequences.

# DEFAULT

65536 bytes



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/foo.bin");

    /* ask libcurl to allocate a larger upload buffer */
    curl_easy_setopt(curl, CURLOPT_UPLOAD_BUFFERSIZE, 120000L);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.62.0.

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>




















|
<
<




46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75


76
77
78
79
DO NOT set this option on a handle that is currently used for an active
transfer as that may lead to unintended consequences.

# DEFAULT

65536 bytes

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/foo.bin");

    /* ask libcurl to allocate a larger upload buffer */
    curl_easy_setopt(curl, CURLOPT_UPLOAD_BUFFERSIZE, 120000L);

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_URL.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

19
20
21
22
23
24
25
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_URL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_URL (3)
  - CURLOPT_CURLU (3)
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_FRESH_CONNECT (3)
  - CURLOPT_PATH_AS_IS (3)
  - CURLOPT_PROTOCOLS (3)
  - curl_easy_perform (3)
  - curl_url_get (3)
  - curl_url_set (3)
Protocol:
  - All

---

# NAME

CURLOPT_URL - URL for this transfer

# SYNOPSIS












|





>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_URL
Section: 3
Source: libcurl
See-also:
  - CURLINFO_REDIRECT_URL (3)
  - CURLOPT_CURLU (3)
  - CURLOPT_FORBID_REUSE (3)
  - CURLOPT_FRESH_CONNECT (3)
  - CURLOPT_PATH_AS_IS (3)
  - CURLOPT_PROTOCOLS_STR (3)
  - curl_easy_perform (3)
  - curl_url_get (3)
  - curl_url_set (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_URL - URL for this transfer

# SYNOPSIS
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116


117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
UTF-8 (when winidn is used; or a Windows Unicode build using libidn2).

If libcurl is built without IDN support, the server name is used exactly as
specified when passed to the name resolver functions.

# DEFAULT

There is no default URL. If this option is not set, no transfer can be
performed.

# SECURITY CONCERNS

Applications may at times find it convenient to allow users to specify URLs
for various purposes and that string would then end up fed to this option.

Getting a URL from an external untrusted party brings several security
concerns:

If you have an application that runs as or in a server application, getting an
unfiltered URL can easily trick your application to access a local resource
instead of a remote. Protecting yourself against localhost accesses is hard
when accepting user provided URLs.

Such custom URLs can also access other ports than you planned as port numbers
are part of the regular URL format. The combination of a local host and a
custom port number can allow external users to play tricks with your local
services.

Accepting external URLs may also use other protocols than http:// or other
common ones. Restrict what accept with CURLOPT_PROTOCOLS(3).

User provided URLs can also be made to point to sites that redirect further on
(possibly to other protocols too). Consider your
CURLOPT_FOLLOWLOCATION(3) and CURLOPT_REDIR_PROTOCOLS(3) settings.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

POP3 and SMTP were added in 7.31.0

# RETURN VALUE

Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient
heap space.

Note that curl_easy_setopt(3) does not parse the given string so given a
bad URL, it is not detected until curl_easy_perform(3) or similar is
called.







|
<




















|



|
>
>















|
<
<









84
85
86
87
88
89
90
91

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134


135
136
137
138
139
140
141
142
143
UTF-8 (when winidn is used; or a Windows Unicode build using libidn2).

If libcurl is built without IDN support, the server name is used exactly as
specified when passed to the name resolver functions.

# DEFAULT

NULL. If this option is not set, no transfer can be performed.


# SECURITY CONCERNS

Applications may at times find it convenient to allow users to specify URLs
for various purposes and that string would then end up fed to this option.

Getting a URL from an external untrusted party brings several security
concerns:

If you have an application that runs as or in a server application, getting an
unfiltered URL can easily trick your application to access a local resource
instead of a remote. Protecting yourself against localhost accesses is hard
when accepting user provided URLs.

Such custom URLs can also access other ports than you planned as port numbers
are part of the regular URL format. The combination of a local host and a
custom port number can allow external users to play tricks with your local
services.

Accepting external URLs may also use other protocols than http:// or other
common ones. Restrict what accept with CURLOPT_PROTOCOLS_STR(3).

User provided URLs can also be made to point to sites that redirect further on
(possibly to other protocols too). Consider your
CURLOPT_FOLLOWLOCATION(3) and CURLOPT_REDIR_PROTOCOLS_STR(3) settings.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK on success or CURLE_OUT_OF_MEMORY if there was insufficient
heap space.

Note that curl_easy_setopt(3) does not parse the given string so given a
bad URL, it is not detected until curl_easy_perform(3) or similar is
called.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_USERAGENT.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_USERAGENT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_REFERER (3)
  - CURLOPT_REQUEST_TARGET (3)
Protocol:
  - HTTP

---

# NAME

CURLOPT_USERAGENT - HTTP user-agent header

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_USERAGENT
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CUSTOMREQUEST (3)
  - CURLOPT_HTTPHEADER (3)
  - CURLOPT_REFERER (3)
  - CURLOPT_REQUEST_TARGET (3)
Protocol:
  - HTTP
Added-in: 7.1
---

# NAME

CURLOPT_USERAGENT - HTTP user-agent header

# SYNOPSIS
32
33
34
35
36
37
38
39


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
can also set any custom header with CURLOPT_HTTPHEADER(3).

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, no User-Agent: header is used by default.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");

    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

As long as HTTP is supported

# RETURN VALUE

Returns CURLE_OK if HTTP is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







|
>
>

















|
<
<





33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62
63
64
65
can also set any custom header with CURLOPT_HTTPHEADER(3).

The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL, no User-Agent: header is used.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    curl_easy_setopt(curl, CURLOPT_USERAGENT, "Dark Secret Ninja/1.0");

    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if HTTP is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_USERNAME.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_USERNAME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PASSWORD (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - All

---

# NAME

CURLOPT_USERNAME - username to use in authentication

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_USERNAME
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HTTPAUTH (3)
  - CURLOPT_PASSWORD (3)
  - CURLOPT_PROXYAUTH (3)
  - CURLOPT_USERPWD (3)
Protocol:
  - All
Added-in: 7.19.1
---

# NAME

CURLOPT_USERNAME - username to use in authentication

# SYNOPSIS
56
57
58
59
60
61
62


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_USERNAME, "clark");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.19.1

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85


86
87
88
89
90
The application does not have to keep the string around after setting this
option.

# DEFAULT

blank

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_USERNAME, "clark");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_USERPWD.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_USERPWD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PASSWORD (3)
  - CURLOPT_PROXYUSERPWD (3)
  - CURLOPT_USERNAME (3)
Protocol:
  - All

---

# NAME

CURLOPT_USERPWD - username and password to use in authentication

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_USERPWD
Section: 3
Source: libcurl
See-also:
  - CURLOPT_PASSWORD (3)
  - CURLOPT_PROXYUSERPWD (3)
  - CURLOPT_USERNAME (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_USERPWD - username and password to use in authentication

# SYNOPSIS
62
63
64
65
66
67
68


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_USERPWD, "clark:kent");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK on success or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>



















|
<
<





63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91


92
93
94
95
96
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/foo.bin");

    curl_easy_setopt(curl, CURLOPT_USERPWD, "clark:kent");

    res = curl_easy_perform(curl);

    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK on success or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_USE_SSL.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_SSLVERSION (3)
  - CURLOPT_SSL_OPTIONS (3)
Protocol:
  - FTP
  - SMTP
  - POP3
  - IMAP

---

# NAME

CURLOPT_USE_SSL - request using SSL / TLS for the transfer

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_SSLVERSION (3)
  - CURLOPT_SSL_OPTIONS (3)
Protocol:
  - FTP
  - SMTP
  - POP3
  - IMAP
Added-in: 7.17.0
---

# NAME

CURLOPT_USE_SSL - request using SSL / TLS for the transfer

# SYNOPSIS
54
55
56
57
58
59
60


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83


84
85
86
87

Require SSL for all communication or fail with *CURLE_USE_SSL_FAILED*.

# DEFAULT

CURLUSESSL_NONE



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/file.ext");

    /* require use of SSL for this, or fail */
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.11.0. This option was known as CURLOPT_FTP_SSL up to 7.16.4, and
the constants were known as CURLFTPSSL_*
Handled by LDAP since 7.81.0. Fully supported by the OpenLDAP backend only.



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>


















|

|
|
|
>
>




55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

Require SSL for all communication or fail with *CURLE_USE_SSL_FAILED*.

# DEFAULT

CURLUSESSL_NONE

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "ftp://example.com/dir/file.ext");

    /* require use of SSL for this, or fail */
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# HISTORY

This option was known as CURLOPT_FTP_SSL up to 7.16.4, and the constants were
known as CURLFTPSSL_* Handled by LDAP since 7.81.0. Fully supported by the
OpenLDAP backend only.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_VERBOSE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_VERBOSE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_ERRORBUFFER (3)
  - CURLOPT_STDERR (3)
  - curl_global_trace (3)
Protocol:
  - All

---

# NAME

CURLOPT_VERBOSE - verbose mode

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_VERBOSE
Section: 3
Source: libcurl
See-also:
  - CURLOPT_DEBUGFUNCTION (3)
  - CURLOPT_ERRORBUFFER (3)
  - CURLOPT_STDERR (3)
  - curl_global_trace (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_VERBOSE - verbose mode

# SYNOPSIS
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
To also get all the protocol data sent and received, consider using the
CURLOPT_DEBUGFUNCTION(3).

# DEFAULT

0, meaning disabled.



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* ask libcurl to show us the verbose output */
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# AVAILABILITY

Always

# RETURN VALUE

Returns CURLE_OK







>
>


















|
<
<




39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
To also get all the protocol data sent and received, consider using the
CURLOPT_DEBUGFUNCTION(3).

# DEFAULT

0, meaning disabled.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");

    /* ask libcurl to show us the verbose output */
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    /* Perform the request */
    curl_easy_perform(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_WILDCARDMATCH.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_WILDCARDMATCH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CHUNK_BGN_FUNCTION (3)
  - CURLOPT_CHUNK_END_FUNCTION (3)
  - CURLOPT_FNMATCH_FUNCTION (3)
  - CURLOPT_URL (3)
Protocol:
  - FTP

---

# NAME

CURLOPT_WILDCARDMATCH - directory wildcard transfers

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_WILDCARDMATCH
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CHUNK_BGN_FUNCTION (3)
  - CURLOPT_CHUNK_END_FUNCTION (3)
  - CURLOPT_FNMATCH_FUNCTION (3)
  - CURLOPT_URL (3)
Protocol:
  - FTP
Added-in: 7.21.0
---

# NAME

CURLOPT_WILDCARDMATCH - directory wildcard transfers

# SYNOPSIS
72
73
74
75
76
77
78


79
80
81
82
83
84
85

**[[]]** - escape syntax. Matches '[', ']' or 'e'.

Using the rules above, a filename pattern can be constructed:

    ftp://example.com/some/path/[a-z[:upper:]\\].jpg



# EXAMPLE

~~~c
extern long begin_cb(struct curl_fileinfo *, void *, int);
extern long end_cb(void *ptr);

int main(void)







>
>







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

**[[]]** - escape syntax. Matches '[', ']' or 'e'.

Using the rules above, a filename pattern can be constructed:

    ftp://example.com/some/path/[a-z[:upper:]\\].jpg

# %PROTOCOLS%

# EXAMPLE

~~~c
extern long begin_cb(struct curl_fileinfo *, void *, int);
extern long end_cb(void *ptr);

int main(void)
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, end_cb);

    /* See more on https://curl.se/libcurl/c/ftp-wildcard.html */
  }
}
~~~

# AVAILABILITY

Added in 7.21.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







|
<
<




99
100
101
102
103
104
105
106


107
108
109
110
    curl_easy_setopt(curl, CURLOPT_CHUNK_END_FUNCTION, end_cb);

    /* See more on https://curl.se/libcurl/c/ftp-wildcard.html */
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_WRITEDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_WRITEDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERDATA (3)
  - CURLOPT_READDATA (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_WRITEDATA - pointer passed to the write callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_WRITEDATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERDATA (3)
  - CURLOPT_READDATA (3)
  - CURLOPT_WRITEFUNCTION (3)
Protocol:
  - All
Added-in: 7.9.7
---

# NAME

CURLOPT_WRITEDATA - pointer passed to the write callback

# SYNOPSIS
37
38
39
40
41
42
43

44

45
46
47
48
49
50
51
52
53
54
55
56
57


58
59
60
61

If you are using libcurl as a Windows DLL, you **MUST** use a
CURLOPT_WRITEFUNCTION(3) if you set this option or you might experience
crashes.

# DEFAULT


By default, this is a FILE * to stdout.


# EXAMPLE

A common technique is to use the write callback to store the incoming data
into a dynamically growing allocated buffer, and then this
CURLOPT_WRITEDATA(3) is used to point to a struct or the buffer to store
data in. Like in the getinmemory example:
https://curl.se/libcurl/c/getinmemory.html

# AVAILABILITY

Available in all libcurl versions. This option was formerly known as
CURLOPT_FILE, the name CURLOPT_WRITEDATA(3) was added in 7.9.7.



# RETURN VALUE

This returns CURLE_OK.







>
|
>





|
|


|

|
|
>
>




38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

If you are using libcurl as a Windows DLL, you **MUST** use a
CURLOPT_WRITEFUNCTION(3) if you set this option or you might experience
crashes.

# DEFAULT

stdout

# %PROTOCOLS%

# EXAMPLE

A common technique is to use the write callback to store the incoming data
into a dynamically growing allocated buffer, and then this
CURLOPT_WRITEDATA(3) is used to point to a struct or the buffer to store data
in. Like in the getinmemory example:
https://curl.se/libcurl/c/getinmemory.html

# HISTORY

This option was formerly known as CURLOPT_FILE, the name CURLOPT_WRITEDATA(3)
was added in 7.9.7.

# %AVAILABILITY%

# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_WRITEFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_WRITEFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - CURLOPT_READFUNCTION (3)
  - CURLOPT_WRITEDATA (3)
Protocol:
  - All

---

# NAME

CURLOPT_WRITEFUNCTION - callback for writing received data

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_WRITEFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_HEADERFUNCTION (3)
  - CURLOPT_READFUNCTION (3)
  - CURLOPT_WRITEDATA (3)
Protocol:
  - All
Added-in: 7.1
---

# NAME

CURLOPT_WRITEFUNCTION - callback for writing received data

# SYNOPSIS
68
69
70
71
72
73
74

75

76
77
78
79
80
81
82
given with CURLOPT_WRITEDATA(3).

This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT


libcurl uses 'fwrite' as a callback by default.


# EXAMPLE

~~~c
#include <stdlib.h> /* for realloc */
#include <string.h> /* for memcpy */








>
|
>







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
given with CURLOPT_WRITEDATA(3).

This option does not enable HSTS, you need to use CURLOPT_HSTS_CTRL(3) to
do that.

# DEFAULT

fwrite(3)

# %PROTOCOLS%

# EXAMPLE

~~~c
#include <stdlib.h> /* for realloc */
#include <string.h> /* for memcpy */

121
122
123
124
125
126
127
128
129
130


131
132
133
134
    free(chunk.response);

    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Support for the CURL_WRITEFUNC_PAUSE return code was added in version 7.18.0.



# RETURN VALUE

This returns CURLE_OK.







|


>
>




124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
    free(chunk.response);

    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Support for the CURL_WRITEFUNC_PAUSE return code was added in version 7.18.0.

# %AVAILABILITY%

# RETURN VALUE

This returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_WS_OPTIONS.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_WS_OPTIONS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECT_ONLY (3)
  - curl_ws_recv (3)
  - curl_ws_send (3)
Protocol:
  - WS

---

# NAME

CURLOPT_WS_OPTIONS - WebSocket behavior options

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_WS_OPTIONS
Section: 3
Source: libcurl
See-also:
  - CURLOPT_CONNECT_ONLY (3)
  - curl_ws_recv (3)
  - curl_ws_send (3)
Protocol:
  - WS
Added-in: 7.86.0
---

# NAME

CURLOPT_WS_OPTIONS - WebSocket behavior options

# SYNOPSIS
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
In raw mode, libcurl does not handle pings or any other frame for the
application.

# DEFAULT

0



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ws://example.com/");
    /* tell curl we deal with all the WebSocket magic ourselves */
    curl_easy_setopt(curl, CURLOPT_WS_OPTIONS, (long)CURLWS_RAW_MODE);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.86.0

# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.







>
>

















|
<
<




44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
In raw mode, libcurl does not handle pings or any other frame for the
application.

# DEFAULT

0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "ws://example.com/");
    /* tell curl we deal with all the WebSocket magic ourselves */
    curl_easy_setopt(curl, CURLOPT_WS_OPTIONS, (long)CURLWS_RAW_MODE);
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_XFERINFODATA.md.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_XFERINFODATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NOPROGRESS (3)
  - CURLOPT_VERBOSE (3)
  - CURLOPT_XFERINFOFUNCTION (3)
Protocol:
  - All

---

# NAME

CURLOPT_XFERINFODATA - pointer passed to the progress callback

# SYNOPSIS












>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_XFERINFODATA
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NOPROGRESS (3)
  - CURLOPT_VERBOSE (3)
  - CURLOPT_XFERINFOFUNCTION (3)
Protocol:
  - All
Added-in: 7.32.0
---

# NAME

CURLOPT_XFERINFODATA - pointer passed to the progress callback

# SYNOPSIS
29
30
31
32
33
34
35

36

37
38
39
40
41
42
43
Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the progress callback set with CURLOPT_XFERINFOFUNCTION(3).

This is an alias for CURLOPT_PROGRESSDATA(3).

# DEFAULT


The default value of this parameter is NULL.


# EXAMPLE

~~~c
struct progress {
  char *private;
  size_t size;







>
|
>







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Pass a *pointer* that is untouched by libcurl and passed as the first
argument in the progress callback set with CURLOPT_XFERINFOFUNCTION(3).

This is an alias for CURLOPT_PROGRESSDATA(3).

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
struct progress {
  char *private;
  size_t size;
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    /* pass struct to callback  */
    curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &data);
    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_cb);
  }
}
~~~

# AVAILABILITY

Added in 7.32.0

# RETURN VALUE

Returns CURLE_OK







|
<
<




68
69
70
71
72
73
74
75


76
77
78
79
    /* pass struct to callback  */
    curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &data);
    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_cb);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK
Changes to jni/curl/docs/libcurl/opts/CURLOPT_XFERINFOFUNCTION.md.
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17
18
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_XFERINFOFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NOPROGRESS (3)
  - CURLOPT_XFERINFODATA (3)
Protocol:
  - All

---

# NAME

CURLOPT_XFERINFOFUNCTION - progress meter callback

# SYNOPSIS











>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_XFERINFOFUNCTION
Section: 3
Source: libcurl
See-also:
  - CURLOPT_NOPROGRESS (3)
  - CURLOPT_XFERINFODATA (3)
Protocol:
  - All
Added-in: 7.32.0
---

# NAME

CURLOPT_XFERINFOFUNCTION - progress meter callback

# SYNOPSIS
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80
81
that performs transfers.

CURLOPT_NOPROGRESS(3) must be set to 0 to make this function actually
get called.

# DEFAULT

By default, libcurl has an internal progress meter. That is rarely wanted by
users.


# EXAMPLE

~~~c
struct progress {
  char *private;
  size_t size;







|
|
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
that performs transfers.

CURLOPT_NOPROGRESS(3) must be set to 0 to make this function actually
get called.

# DEFAULT

NULL - use the internal progress meter. That is rarely wanted by users.

# %PROTOCOLS%

# EXAMPLE

~~~c
struct progress {
  char *private;
  size_t size;
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);

    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
  }
}
~~~

# AVAILABILITY

Added in 7.32.0. This callback replaces CURLOPT_PROGRESSFUNCTION(3)

# RETURN VALUE

Returns CURLE_OK.







|
<
<




110
111
112
113
114
115
116
117


118
119
120
121
    curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);

    curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback);
  }
}
~~~

# %AVAILABILITY%



# RETURN VALUE

Returns CURLE_OK.
Changes to jni/curl/docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.md.
9
10
11
12
13
14
15

16
17
18
19
20
21
22
  - CURLOPT_USERNAME (3)
Protocol:
  - HTTP
  - IMAP
  - LDAP
  - POP3
  - SMTP

---

# NAME

CURLOPT_XOAUTH2_BEARER - OAuth 2.0 access token

# SYNOPSIS







>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  - CURLOPT_USERNAME (3)
Protocol:
  - HTTP
  - IMAP
  - LDAP
  - POP3
  - SMTP
Added-in: 7.33.0
---

# NAME

CURLOPT_XOAUTH2_BEARER - OAuth 2.0 access token

# SYNOPSIS
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64


65
66
67
68
69
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL



# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "pop3://example.com/");
    curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, "1ab9cb22ba269a7");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# AVAILABILITY

Added in 7.33.0. Support for OpenLDAP added in 7.82.0.



# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.







>
>
















|

|
>
>





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
The application does not have to keep the string around after setting this
option.

# DEFAULT

NULL

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURL *curl = curl_easy_init();
  if(curl) {
    CURLcode res;
    curl_easy_setopt(curl, CURLOPT_URL, "pop3://example.com/");
    curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, "1ab9cb22ba269a7");
    res = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
  }
}
~~~

# HISTORY

Support for OpenLDAP added in 7.82.0.

# %AVAILABILITY%

# RETURN VALUE

Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
Changes to jni/curl/docs/libcurl/opts/CURLSHOPT_LOCKFUNC.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_LOCKFUNC
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_UNLOCKFUNC (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All

---

# NAME

CURLSHOPT_LOCKFUNC - mutex lock callback

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_LOCKFUNC
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_UNLOCKFUNC (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All
Added-in: 7.10.3
---

# NAME

CURLSHOPT_LOCKFUNC - mutex lock callback

# SYNOPSIS
44
45
46
47
48
49
50


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
sure that the callback uses a different lock for each kind of data.

*access* defines what access type libcurl wants, shared or single.

*clientp* is the private pointer you set with CURLSHOPT_USERDATA(3).
This pointer is not used by libcurl itself.



# EXAMPLE

~~~c
extern void mutex_lock(CURL *handle, curl_lock_data data,
                       curl_lock_access access, void *clientp);

int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, mutex_lock);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.







>
>
















|
<
<






45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70


71
72
73
74
75
76
sure that the callback uses a different lock for each kind of data.

*access* defines what access type libcurl wants, shared or single.

*clientp* is the private pointer you set with CURLSHOPT_USERDATA(3).
This pointer is not used by libcurl itself.

# %PROTOCOLS%

# EXAMPLE

~~~c
extern void mutex_lock(CURL *handle, curl_lock_data data,
                       curl_lock_access access, void *clientp);

int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, mutex_lock);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.
Changes to jni/curl/docs/libcurl/opts/CURLSHOPT_SHARE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_SHARE
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_UNSHARE (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All

---

# NAME

CURLSHOPT_SHARE - add data to share

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_SHARE
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_UNSHARE (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All
Added-in: 7.10.3
---

# NAME

CURLSHOPT_SHARE - add data to share

# SYNOPSIS
87
88
89
90
91
92
93


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

The in-memory HSTS cache.

It is not supported to share the HSTS between multiple concurrent threads.

Added in 7.88.0



# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.







>
>













|
<
<






88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110


111
112
113
114
115
116

The in-memory HSTS cache.

It is not supported to share the HSTS between multiple concurrent threads.

Added in 7.88.0

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.
Changes to jni/curl/docs/libcurl/opts/CURLSHOPT_UNLOCKFUNC.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_UNLOCKFUNC
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_LOCKFUNC (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All

---

# NAME

CURLSHOPT_UNLOCKFUNC - mutex unlock callback

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_UNLOCKFUNC
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_LOCKFUNC (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All
Added-in: 7.10.3
---

# NAME

CURLSHOPT_UNLOCKFUNC - mutex unlock callback

# SYNOPSIS
40
41
42
43
44
45
46


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

The *data* argument tells what kind of data libcurl wants to unlock. Make
sure that the callback uses a different lock for each kind of data.

*clientp* is the private pointer you set with CURLSHOPT_USERDATA(3).
This pointer is not used by libcurl itself.



# EXAMPLE

~~~c
extern void mutex_unlock(CURL *, curl_lock_data, void *);

int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, mutex_unlock);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.







>
>















|
<
<






41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65


66
67
68
69
70
71

The *data* argument tells what kind of data libcurl wants to unlock. Make
sure that the callback uses a different lock for each kind of data.

*clientp* is the private pointer you set with CURLSHOPT_USERDATA(3).
This pointer is not used by libcurl itself.

# %PROTOCOLS%

# EXAMPLE

~~~c
extern void mutex_unlock(CURL *, curl_lock_data, void *);

int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, mutex_unlock);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.
Changes to jni/curl/docs/libcurl/opts/CURLSHOPT_UNSHARE.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_UNSHARE
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_SHARE (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All

---

# NAME

CURLSHOPT_UNSHARE - remove data to share

# SYNOPSIS













>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_UNSHARE
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_SHARE (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All
Added-in: 7.10.3
---

# NAME

CURLSHOPT_UNSHARE - remove data to share

# SYNOPSIS
54
55
56
57
58
59
60


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

The connection cache is no longer shared.

## CURL_LOCK_DATA_PSL

The Public Suffix List is no longer shared.



# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.







>
>













|
<
<






55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77


78
79
80
81
82
83

The connection cache is no longer shared.

## CURL_LOCK_DATA_PSL

The Public Suffix List is no longer shared.

# %PROTOCOLS%

# EXAMPLE

~~~c
int main(void)
{
  CURLSHcode sh;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.
Changes to jni/curl/docs/libcurl/opts/CURLSHOPT_USERDATA.md.
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_USERDATA
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_LOCKFUNC (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All

---

# NAME

CURLSHOPT_USERDATA - pointer passed to the lock and unlock mutex callbacks

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLSHcode curl_share_setopt(CURLSH *share, CURLSHOPT_USERDATA, void *clientp);
~~~

# DESCRIPTION

The *clientp* parameter is held verbatim by libcurl and is passed on as
the *clientp* argument to the callbacks set with
CURLSHOPT_LOCKFUNC(3) and CURLSHOPT_UNLOCKFUNC(3).



# EXAMPLE

~~~c
struct secrets {
  void *custom;
};

int main(void)
{
  CURLSHcode sh;
  struct secrets private_stuff;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_USERDATA, &private_stuff);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# AVAILABILITY

Added in 7.10

# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.













>




















>
>


















|
<
<






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


56
57
58
59
60
61
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLSHOPT_USERDATA
Section: 3
Source: libcurl
See-also:
  - CURLSHOPT_LOCKFUNC (3)
  - curl_share_cleanup (3)
  - curl_share_init (3)
  - curl_share_setopt (3)
Protocol:
  - All
Added-in: 7.10.3
---

# NAME

CURLSHOPT_USERDATA - pointer passed to the lock and unlock mutex callbacks

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLSHcode curl_share_setopt(CURLSH *share, CURLSHOPT_USERDATA, void *clientp);
~~~

# DESCRIPTION

The *clientp* parameter is held verbatim by libcurl and is passed on as
the *clientp* argument to the callbacks set with
CURLSHOPT_LOCKFUNC(3) and CURLSHOPT_UNLOCKFUNC(3).

# %PROTOCOLS%

# EXAMPLE

~~~c
struct secrets {
  void *custom;
};

int main(void)
{
  CURLSHcode sh;
  struct secrets private_stuff;
  CURLSH *share = curl_share_init();
  sh = curl_share_setopt(share, CURLSHOPT_USERDATA, &private_stuff);
  if(sh)
    printf("Error: %s\n", curl_share_strerror(sh));
}
~~~

# %AVAILABILITY%



# RETURN VALUE

CURLSHE_OK (zero) means that the option was set properly, non-zero means an
error occurred. See libcurl-errors(3) for the full list with
descriptions.
Changes to jni/curl/docs/libcurl/opts/Makefile.in.
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







154
155
156
157
158
159
160

161
162
163
164
165
166
167
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
311
312
313
314
315
316
317


318
319
320
321
322
323
324
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
808
809
810
811
812
813
814

815
816
817
818
819
820
821
@BUILD_DOCS_TRUE@  CURLOPT_STREAM_DEPENDS_E.3                    \
@BUILD_DOCS_TRUE@  CURLOPT_STREAM_WEIGHT.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_SUPPRESS_CONNECT_HEADERS.3            \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_FASTOPEN.3                        \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_KEEPALIVE.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_KEEPIDLE.3                        \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_KEEPINTVL.3                       \

@BUILD_DOCS_TRUE@  CURLOPT_TCP_NODELAY.3                         \
@BUILD_DOCS_TRUE@  CURLOPT_TELNETOPTIONS.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_TFTP_BLKSIZE.3                        \
@BUILD_DOCS_TRUE@  CURLOPT_TFTP_NO_OPTIONS.3                     \
@BUILD_DOCS_TRUE@  CURLOPT_TIMECONDITION.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_TIMEOUT.3                             \
@BUILD_DOCS_TRUE@  CURLOPT_TIMEOUT_MS.3                          \







>







809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
@BUILD_DOCS_TRUE@  CURLOPT_STREAM_DEPENDS_E.3                    \
@BUILD_DOCS_TRUE@  CURLOPT_STREAM_WEIGHT.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_SUPPRESS_CONNECT_HEADERS.3            \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_FASTOPEN.3                        \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_KEEPALIVE.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_KEEPIDLE.3                        \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_KEEPINTVL.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_KEEPCNT.3                         \
@BUILD_DOCS_TRUE@  CURLOPT_TCP_NODELAY.3                         \
@BUILD_DOCS_TRUE@  CURLOPT_TELNETOPTIONS.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_TFTP_BLKSIZE.3                        \
@BUILD_DOCS_TRUE@  CURLOPT_TFTP_NO_OPTIONS.3                     \
@BUILD_DOCS_TRUE@  CURLOPT_TIMECONDITION.3                       \
@BUILD_DOCS_TRUE@  CURLOPT_TIMEOUT.3                             \
@BUILD_DOCS_TRUE@  CURLOPT_TIMEOUT_MS.3                          \
Changes to jni/curl/docs/libcurl/opts/Makefile.inc.
380
381
382
383
384
385
386

387
388
389
390
391
392
393
  CURLOPT_STREAM_DEPENDS_E.3                    \
  CURLOPT_STREAM_WEIGHT.3                       \
  CURLOPT_SUPPRESS_CONNECT_HEADERS.3            \
  CURLOPT_TCP_FASTOPEN.3                        \
  CURLOPT_TCP_KEEPALIVE.3                       \
  CURLOPT_TCP_KEEPIDLE.3                        \
  CURLOPT_TCP_KEEPINTVL.3                       \

  CURLOPT_TCP_NODELAY.3                         \
  CURLOPT_TELNETOPTIONS.3                       \
  CURLOPT_TFTP_BLKSIZE.3                        \
  CURLOPT_TFTP_NO_OPTIONS.3                     \
  CURLOPT_TIMECONDITION.3                       \
  CURLOPT_TIMEOUT.3                             \
  CURLOPT_TIMEOUT_MS.3                          \







>







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  CURLOPT_STREAM_DEPENDS_E.3                    \
  CURLOPT_STREAM_WEIGHT.3                       \
  CURLOPT_SUPPRESS_CONNECT_HEADERS.3            \
  CURLOPT_TCP_FASTOPEN.3                        \
  CURLOPT_TCP_KEEPALIVE.3                       \
  CURLOPT_TCP_KEEPIDLE.3                        \
  CURLOPT_TCP_KEEPINTVL.3                       \
  CURLOPT_TCP_KEEPCNT.3                         \
  CURLOPT_TCP_NODELAY.3                         \
  CURLOPT_TELNETOPTIONS.3                       \
  CURLOPT_TFTP_BLKSIZE.3                        \
  CURLOPT_TFTP_NO_OPTIONS.3                     \
  CURLOPT_TIMECONDITION.3                       \
  CURLOPT_TIMEOUT.3                             \
  CURLOPT_TIMEOUT_MS.3                          \
Changes to jni/curl/docs/libcurl/symbols-in-versions.
860
861
862
863
864
865
866

867
868
869
870
871
872
873
CURLOPT_STREAM_DEPENDS_E        7.46.0
CURLOPT_STREAM_WEIGHT           7.46.0
CURLOPT_SUPPRESS_CONNECT_HEADERS 7.54.0
CURLOPT_TCP_FASTOPEN            7.49.0
CURLOPT_TCP_KEEPALIVE           7.25.0
CURLOPT_TCP_KEEPIDLE            7.25.0
CURLOPT_TCP_KEEPINTVL           7.25.0

CURLOPT_TCP_NODELAY             7.11.2
CURLOPT_TELNETOPTIONS           7.7
CURLOPT_TFTP_BLKSIZE            7.19.4
CURLOPT_TFTP_NO_OPTIONS         7.48.0
CURLOPT_TIMECONDITION           7.1
CURLOPT_TIMEOUT                 7.1
CURLOPT_TIMEOUT_MS              7.16.2







>







860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
CURLOPT_STREAM_DEPENDS_E        7.46.0
CURLOPT_STREAM_WEIGHT           7.46.0
CURLOPT_SUPPRESS_CONNECT_HEADERS 7.54.0
CURLOPT_TCP_FASTOPEN            7.49.0
CURLOPT_TCP_KEEPALIVE           7.25.0
CURLOPT_TCP_KEEPIDLE            7.25.0
CURLOPT_TCP_KEEPINTVL           7.25.0
CURLOPT_TCP_KEEPCNT             8.9.0
CURLOPT_TCP_NODELAY             7.11.2
CURLOPT_TELNETOPTIONS           7.7
CURLOPT_TFTP_BLKSIZE            7.19.4
CURLOPT_TFTP_NO_OPTIONS         7.48.0
CURLOPT_TIMECONDITION           7.1
CURLOPT_TIMEOUT                 7.1
CURLOPT_TIMEOUT_MS              7.16.2
1064
1065
1066
1067
1068
1069
1070

1071
1072
1073
1074
1075
1076
1077
CURLU_DEFAULT_PORT              7.62.0
CURLU_DEFAULT_SCHEME            7.62.0
CURLU_DISALLOW_USER             7.62.0
CURLU_GET_EMPTY                 8.8.0
CURLU_GUESS_SCHEME              7.62.0
CURLU_NO_AUTHORITY              7.67.0
CURLU_NO_DEFAULT_PORT           7.62.0

CURLU_NON_SUPPORT_SCHEME        7.62.0
CURLU_PATH_AS_IS                7.62.0
CURLU_PUNY2IDN                  8.3.0
CURLU_PUNYCODE                  7.88.0
CURLU_URLDECODE                 7.62.0
CURLU_URLENCODE                 7.62.0
CURLUE_BAD_FILE_URL             7.81.0







>







1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
CURLU_DEFAULT_PORT              7.62.0
CURLU_DEFAULT_SCHEME            7.62.0
CURLU_DISALLOW_USER             7.62.0
CURLU_GET_EMPTY                 8.8.0
CURLU_GUESS_SCHEME              7.62.0
CURLU_NO_AUTHORITY              7.67.0
CURLU_NO_DEFAULT_PORT           7.62.0
CURLU_NO_GUESS_SCHEME           8.9.0
CURLU_NON_SUPPORT_SCHEME        7.62.0
CURLU_PATH_AS_IS                7.62.0
CURLU_PUNY2IDN                  8.3.0
CURLU_PUNYCODE                  7.88.0
CURLU_URLDECODE                 7.62.0
CURLU_URLENCODE                 7.62.0
CURLUE_BAD_FILE_URL             7.81.0
Changes to jni/curl/docs/mk-ca-bundle.md.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: mk-ca-bundle
Section: 1
Source: mk-ca-bundle
See-also:
  - curl (1)

---

# NAME

mk-ca-bundle - convert Mozilla's certificate bundle to PEM format

# SYNOPSIS








>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: mk-ca-bundle
Section: 1
Source: mk-ca-bundle
See-also:
  - curl (1)
Added-in: n/a
---

# NAME

mk-ca-bundle - convert Mozilla's certificate bundle to PEM format

# SYNOPSIS
Changes to jni/curl/docs/options-in-versions.
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

129
130
131
132
133
134
135
--http1.0 (-0)                       7.9.1
--http1.1                            7.33.0
--http2                              7.33.0
--http2-prior-knowledge              7.49.0
--http3                              7.66.0
--http3-only                         7.88.0
--ignore-content-length              7.14.1

--ipfs-gateway                       8.4.0
--include (-i)                       4.8
--insecure (-k)                      7.10
--interface                          7.3
--ipv4 (-4)                          7.10.8
--ipv6 (-6)                          7.10.8
--json                               7.82.0
--junk-session-cookies (-j)          7.9.7

--keepalive-time                     7.18.0
--key                                7.9.3
--key-type                           7.9.3
--krb                                7.3
--libcurl                            7.16.1
--limit-rate                         7.10
--list-only (-l)                     4.0
--local-port                         7.15.2
--location (-L)                      4.9
--location-trusted                   7.10.4
--login-options                      7.34.0
--mail-auth                          7.25.0
--mail-from                          7.20.0
--mail-rcpt                          7.20.0
--mail-rcpt-allowfails               7.69.0
--manual (-M)                        5.2
--max-filesize                       7.10.8
--max-redirs                         7.5
--max-time (-m)                      4.0
--metalink                           7.27.0

--negotiate                          7.10.6
--netrc (-n)                         4.6
--netrc-file                         7.21.5
--netrc-optional                     7.9.8
--next (-:)                          7.36.0
--no-alpn                            7.36.0
--no-buffer (-N)                     6.5







>








>




















>







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
--http1.0 (-0)                       7.9.1
--http1.1                            7.33.0
--http2                              7.33.0
--http2-prior-knowledge              7.49.0
--http3                              7.66.0
--http3-only                         7.88.0
--ignore-content-length              7.14.1
--ip-tos                             8.9.0
--ipfs-gateway                       8.4.0
--include (-i)                       4.8
--insecure (-k)                      7.10
--interface                          7.3
--ipv4 (-4)                          7.10.8
--ipv6 (-6)                          7.10.8
--json                               7.82.0
--junk-session-cookies (-j)          7.9.7
--keepalive-cnt                      8.9.0
--keepalive-time                     7.18.0
--key                                7.9.3
--key-type                           7.9.3
--krb                                7.3
--libcurl                            7.16.1
--limit-rate                         7.10
--list-only (-l)                     4.0
--local-port                         7.15.2
--location (-L)                      4.9
--location-trusted                   7.10.4
--login-options                      7.34.0
--mail-auth                          7.25.0
--mail-from                          7.20.0
--mail-rcpt                          7.20.0
--mail-rcpt-allowfails               7.69.0
--manual (-M)                        5.2
--max-filesize                       7.10.8
--max-redirs                         7.5
--max-time (-m)                      4.0
--metalink                           7.27.0
--mptcp                              8.9.0
--negotiate                          7.10.6
--netrc (-n)                         4.6
--netrc-file                         7.21.5
--netrc-optional                     7.9.8
--next (-:)                          7.36.0
--no-alpn                            7.36.0
--no-buffer (-N)                     6.5
263
264
265
266
267
268
269

270
271
--url-query                          7.87.0
--use-ascii (-B)                     5.0
--user (-u)                          4.0
--user-agent (-A)                    4.5.1
--variable                           8.3.0
--verbose (-v)                       4.0
--version (-V)                       4.0

--write-out (-w)                     6.5
--xattr                              7.21.3







>


266
267
268
269
270
271
272
273
274
275
--url-query                          7.87.0
--use-ascii (-B)                     5.0
--user (-u)                          4.0
--user-agent (-A)                    4.5.1
--variable                           8.3.0
--verbose (-v)                       4.0
--version (-V)                       4.0
--vlan-priority                      8.9.0
--write-out (-w)                     6.5
--xattr                              7.21.3
Changes to jni/curl/include/Makefile.in.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







105
106
107
108
109
110
111

112
113
114
115
116
117
118
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
289
290
291
292
293
294
295


296
297
298
299
300
301
302
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
Changes to jni/curl/include/README.md.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# include

Public include files for libcurl, external users.

They're all placed in the curl subdirectory here for better fit in any kind of
environment. You must include files from here using...

    #include <curl/curl.h>

... style and point the compiler's include path to the directory holding the
curl subdirectory. It makes it more likely to survive future modifications.











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.

SPDX-License-Identifier: curl
-->

# include

Public include files for libcurl, external users.

They are all placed in the curl subdirectory here for better fit in any kind of
environment. You must include files from here using...

    #include <curl/curl.h>

... style and point the compiler's include path to the directory holding the
curl subdirectory. It makes it more likely to survive future modifications.

Changes to jni/curl/include/curl/Makefile.am.
31
32
33
34
35
36
37
38
39
40
41
CS_0 = @echo "  RUN     " $@;
CS_1 =
CS_ = $(CS_0)

checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS)

if CURLDEBUG
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif







|



31
32
33
34
35
36
37
38
39
40
41
CS_0 = @echo "  RUN     " $@;
CS_1 =
CS_ = $(CS_0)

checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS)

if DEBUGBUILD
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif
Changes to jni/curl/include/curl/Makefile.in.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







105
106
107
108
109
110
111

112
113
114
115
116
117
118
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
276
277
278
279
280
281
282


283
284
285
286
287
288
289
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
@CURLDEBUG_FALSE@all-local:
all-am: Makefile $(HEADERS) all-local
installdirs:
	for dir in "$(DESTDIR)$(pkgincludedir)"; do \
	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
	done
install: install-am
install-exec: install-exec-am







|







590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
@DEBUGBUILD_FALSE@all-local:
all-am: Makefile $(HEADERS) all-local
installdirs:
	for dir in "$(DESTDIR)$(pkgincludedir)"; do \
	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
	done
install: install-am
install-exec: install-exec-am
714
715
716
717
718
719
720
721
722
723
724
725
.PRECIOUS: Makefile


checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS)

# for debug builds, we scan the sources on all regular make invokes
@CURLDEBUG_TRUE@all-local: checksrc

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:







|




715
716
717
718
719
720
721
722
723
724
725
726
.PRECIOUS: Makefile


checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(top_srcdir)/include/curl $(pkginclude_HEADERS)

# for debug builds, we scan the sources on all regular make invokes
@DEBUGBUILD_TRUE@all-local: checksrc

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
Changes to jni/curl/include/curl/curl.h.
30
31
32
33
34
35
36
37
38

39
40
41
42






43
44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
 */

#ifdef CURL_NO_OLDIES
#define CURL_STRICTER
#endif

/* Compile-time deprecation macros. */
#if defined(__GNUC__) &&                                                \
  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) &&  \

  !defined(__INTEL_COMPILER) &&                                         \
  !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
#define CURL_DEPRECATED(version, message)                       \
  __attribute__((deprecated("since " # version ". " message)))






#define CURL_IGNORE_DEPRECATION(statements) \
      _Pragma("GCC diagnostic push") \
      _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
      statements \
      _Pragma("GCC diagnostic pop")

#else
#define CURL_DEPRECATED(version, message)
#define CURL_IGNORE_DEPRECATION(statements)     statements
#endif

#include "curlver.h"         /* libcurl version defines   */
#include "system.h"          /* determine things run-time */

#include <stdio.h>
#include <limits.h>

#if defined(__FreeBSD__) || defined(__MidnightBSD__)
/* Needed for __FreeBSD_version or __MidnightBSD_version symbol definition */
#include <sys/param.h>
#endif

/* The include stuff here below is mainly for time_t! */
#include <sys/types.h>
#include <time.h>

#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
      defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
/* The check above prevents the winsock2 inclusion if winsock.h already was
   included, since they can't co-exist without problems */
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#endif

/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
   libc5-based Linux systems. Only include it on systems that are known to







|
|
>




>
>
>
>
>
>





>






|

















|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
 */

#ifdef CURL_NO_OLDIES
#define CURL_STRICTER
#endif

/* Compile-time deprecation macros. */
#if (defined(__GNUC__) &&                                               \
  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) ||  \
  defined(__IAR_SYSTEMS_ICC__)) &&                                      \
  !defined(__INTEL_COMPILER) &&                                         \
  !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
#define CURL_DEPRECATED(version, message)                       \
  __attribute__((deprecated("since " # version ". " message)))
#if defined(__IAR_SYSTEMS_ICC__)
#define CURL_IGNORE_DEPRECATION(statements) \
      _Pragma("diag_suppress=Pe1444") \
      statements \
      _Pragma("diag_default=Pe1444")
#else
#define CURL_IGNORE_DEPRECATION(statements) \
      _Pragma("GCC diagnostic push") \
      _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
      statements \
      _Pragma("GCC diagnostic pop")
#endif
#else
#define CURL_DEPRECATED(version, message)
#define CURL_IGNORE_DEPRECATION(statements)     statements
#endif

#include "curlver.h"         /* libcurl version defines   */
#include "system.h"          /* determine things runtime */

#include <stdio.h>
#include <limits.h>

#if defined(__FreeBSD__) || defined(__MidnightBSD__)
/* Needed for __FreeBSD_version or __MidnightBSD_version symbol definition */
#include <sys/param.h>
#endif

/* The include stuff here below is mainly for time_t! */
#include <sys/types.h>
#include <time.h>

#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
      defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
/* The check above prevents the winsock2 inclusion if winsock.h already was
   included, since they cannot co-exist without problems */
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#endif

/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
   libc5-based Linux systems. Only include it on systems that are known to
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  char *contenttype;                /* Content-Type */
  struct curl_slist *contentheader; /* list of extra headers for this form */
  struct curl_httppost *more;       /* if one field name has more than one
                                       file, this link should link to following
                                       files */
  long flags;                       /* as defined below */

/* specified content is a file name */
#define CURL_HTTPPOST_FILENAME (1<<0)
/* specified content is a file name */
#define CURL_HTTPPOST_READFILE (1<<1)
/* name is only stored pointer do not free in formfree */
#define CURL_HTTPPOST_PTRNAME (1<<2)
/* contents is only stored pointer do not free in formfree */
#define CURL_HTTPPOST_PTRCONTENTS (1<<3)
/* upload file from buffer */
#define CURL_HTTPPOST_BUFFER (1<<4)
/* upload file from pointer contents */
#define CURL_HTTPPOST_PTRBUFFER (1<<5)
/* upload file contents by using the regular read callback to get the data and
   pass the given pointer as custom pointer */
#define CURL_HTTPPOST_CALLBACK (1<<6)
/* use size in 'contentlen', added in 7.46.0 */
#define CURL_HTTPPOST_LARGE (1<<7)

  char *showfilename;               /* The file name to show. If not set, the
                                       actual file name will be used (if this
                                       is a file part) */
  void *userp;                      /* custom pointer used for
                                       HTTPPOST_CALLBACK posts */
  curl_off_t contentlen;            /* alternative length of contents
                                       field. Used if CURL_HTTPPOST_LARGE is
                                       set. Added in 7.46.0 */
};







|

|















|
|







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  char *contenttype;                /* Content-Type */
  struct curl_slist *contentheader; /* list of extra headers for this form */
  struct curl_httppost *more;       /* if one field name has more than one
                                       file, this link should link to following
                                       files */
  long flags;                       /* as defined below */

/* specified content is a filename */
#define CURL_HTTPPOST_FILENAME (1<<0)
/* specified content is a filename */
#define CURL_HTTPPOST_READFILE (1<<1)
/* name is only stored pointer do not free in formfree */
#define CURL_HTTPPOST_PTRNAME (1<<2)
/* contents is only stored pointer do not free in formfree */
#define CURL_HTTPPOST_PTRCONTENTS (1<<3)
/* upload file from buffer */
#define CURL_HTTPPOST_BUFFER (1<<4)
/* upload file from pointer contents */
#define CURL_HTTPPOST_PTRBUFFER (1<<5)
/* upload file contents by using the regular read callback to get the data and
   pass the given pointer as custom pointer */
#define CURL_HTTPPOST_CALLBACK (1<<6)
/* use size in 'contentlen', added in 7.46.0 */
#define CURL_HTTPPOST_LARGE (1<<7)

  char *showfilename;               /* The filename to show. If not set, the
                                       actual filename will be used (if this
                                       is a file part) */
  void *userp;                      /* custom pointer used for
                                       HTTPPOST_CALLBACK posts */
  curl_off_t contentlen;            /* alternative length of contents
                                       field. Used if CURL_HTTPPOST_LARGE is
                                       set. Added in 7.46.0 */
};
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
#define CURL_CHUNK_END_FUNC_OK      0
#define CURL_CHUNK_END_FUNC_FAIL    1 /* tell the lib to end the task */

/* If splitting of data transfer is enabled this callback is called after
   download of an individual chunk finished.
   Note! After this callback was set then it have to be called FOR ALL chunks.
   Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
   This is the reason why we don't need "transfer_info" parameter in this
   callback and we are not interested in "remains" parameter too. */
typedef long (*curl_chunk_end_callback)(void *ptr);

/* return codes for FNMATCHFUNCTION */
#define CURL_FNMATCHFUNC_MATCH    0 /* string corresponds to the pattern */
#define CURL_FNMATCHFUNC_NOMATCH  1 /* pattern doesn't match the string */
#define CURL_FNMATCHFUNC_FAIL     2 /* an error occurred */

/* callback type for wildcard downloading pattern matching. If the
   string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */
typedef int (*curl_fnmatch_callback)(void *ptr,
                                     const char *pattern,
                                     const char *string);

/* These are the return codes for the seek callbacks */
#define CURL_SEEKFUNC_OK       0
#define CURL_SEEKFUNC_FAIL     1 /* fail the entire transfer */
#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
                                    libcurl might try other means instead */
typedef int (*curl_seek_callback)(void *instream,
                                  curl_off_t offset,
                                  int origin); /* 'whence' */

/* This is a return code for the read callback that, when returned, will
   signal libcurl to immediately abort the current transfer. */







|





|











|







354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
#define CURL_CHUNK_END_FUNC_OK      0
#define CURL_CHUNK_END_FUNC_FAIL    1 /* tell the lib to end the task */

/* If splitting of data transfer is enabled this callback is called after
   download of an individual chunk finished.
   Note! After this callback was set then it have to be called FOR ALL chunks.
   Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
   This is the reason why we do not need "transfer_info" parameter in this
   callback and we are not interested in "remains" parameter too. */
typedef long (*curl_chunk_end_callback)(void *ptr);

/* return codes for FNMATCHFUNCTION */
#define CURL_FNMATCHFUNC_MATCH    0 /* string corresponds to the pattern */
#define CURL_FNMATCHFUNC_NOMATCH  1 /* pattern does not match the string */
#define CURL_FNMATCHFUNC_FAIL     2 /* an error occurred */

/* callback type for wildcard downloading pattern matching. If the
   string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */
typedef int (*curl_fnmatch_callback)(void *ptr,
                                     const char *pattern,
                                     const char *string);

/* These are the return codes for the seek callbacks */
#define CURL_SEEKFUNC_OK       0
#define CURL_SEEKFUNC_FAIL     1 /* fail the entire transfer */
#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking cannot be done, so
                                    libcurl might try other means instead */
typedef int (*curl_seek_callback)(void *instream,
                                  curl_off_t offset,
                                  int origin); /* 'whence' */

/* This is a return code for the read callback that, when returned, will
   signal libcurl to immediately abort the current transfer. */
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
                                         int cmd,
                                         void *clientp);

#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
/*
 * The following typedef's are signatures of malloc, free, realloc, strdup and
 * calloc respectively.  Function pointers of these types can be passed to the
 * curl_global_init_mem() function to set user defined memory management
 * callback routines.
 */
typedef void *(*curl_malloc_callback)(size_t size);
typedef void (*curl_free_callback)(void *ptr);
typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
typedef char *(*curl_strdup_callback)(const char *str);







|







455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
                                         int cmd,
                                         void *clientp);

#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
/*
 * The following typedef's are signatures of malloc, free, realloc, strdup and
 * calloc respectively. Function pointers of these types can be passed to the
 * curl_global_init_mem() function to set user defined memory management
 * callback routines.
 */
typedef void *(*curl_malloc_callback)(size_t size);
typedef void (*curl_free_callback)(void *ptr);
typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
typedef char *(*curl_strdup_callback)(const char *str);
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  CURLE_FTP_COULDNT_RETR_FILE,   /* 19 */
  CURLE_OBSOLETE20,              /* 20 - NOT USED */
  CURLE_QUOTE_ERROR,             /* 21 - quote command failure */
  CURLE_HTTP_RETURNED_ERROR,     /* 22 */
  CURLE_WRITE_ERROR,             /* 23 */
  CURLE_OBSOLETE24,              /* 24 - NOT USED */
  CURLE_UPLOAD_FAILED,           /* 25 - failed upload "command" */
  CURLE_READ_ERROR,              /* 26 - couldn't open/read from file */
  CURLE_OUT_OF_MEMORY,           /* 27 */
  CURLE_OPERATION_TIMEDOUT,      /* 28 - the timeout time was reached */
  CURLE_OBSOLETE29,              /* 29 - NOT USED */
  CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
  CURLE_FTP_COULDNT_USE_REST,    /* 31 - the REST command failed */
  CURLE_OBSOLETE32,              /* 32 - NOT USED */
  CURLE_RANGE_ERROR,             /* 33 - RANGE "command" didn't work */
  CURLE_HTTP_POST_ERROR,         /* 34 */
  CURLE_SSL_CONNECT_ERROR,       /* 35 - wrong when connecting with SSL */
  CURLE_BAD_DOWNLOAD_RESUME,     /* 36 - couldn't resume download */
  CURLE_FILE_COULDNT_READ_FILE,  /* 37 */
  CURLE_LDAP_CANNOT_BIND,        /* 38 */
  CURLE_LDAP_SEARCH_FAILED,      /* 39 */
  CURLE_OBSOLETE40,              /* 40 - NOT USED */
  CURLE_FUNCTION_NOT_FOUND,      /* 41 - NOT USED starting with 7.53.0 */
  CURLE_ABORTED_BY_CALLBACK,     /* 42 */
  CURLE_BAD_FUNCTION_ARGUMENT,   /* 43 */







|






|


|







543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  CURLE_FTP_COULDNT_RETR_FILE,   /* 19 */
  CURLE_OBSOLETE20,              /* 20 - NOT USED */
  CURLE_QUOTE_ERROR,             /* 21 - quote command failure */
  CURLE_HTTP_RETURNED_ERROR,     /* 22 */
  CURLE_WRITE_ERROR,             /* 23 */
  CURLE_OBSOLETE24,              /* 24 - NOT USED */
  CURLE_UPLOAD_FAILED,           /* 25 - failed upload "command" */
  CURLE_READ_ERROR,              /* 26 - could not open/read from file */
  CURLE_OUT_OF_MEMORY,           /* 27 */
  CURLE_OPERATION_TIMEDOUT,      /* 28 - the timeout time was reached */
  CURLE_OBSOLETE29,              /* 29 - NOT USED */
  CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
  CURLE_FTP_COULDNT_USE_REST,    /* 31 - the REST command failed */
  CURLE_OBSOLETE32,              /* 32 - NOT USED */
  CURLE_RANGE_ERROR,             /* 33 - RANGE "command" did not work */
  CURLE_HTTP_POST_ERROR,         /* 34 */
  CURLE_SSL_CONNECT_ERROR,       /* 35 - wrong when connecting with SSL */
  CURLE_BAD_DOWNLOAD_RESUME,     /* 36 - could not resume download */
  CURLE_FILE_COULDNT_READ_FILE,  /* 37 */
  CURLE_LDAP_CANNOT_BIND,        /* 38 */
  CURLE_LDAP_SEARCH_FAILED,      /* 39 */
  CURLE_OBSOLETE40,              /* 40 - NOT USED */
  CURLE_FUNCTION_NOT_FOUND,      /* 41 - NOT USED starting with 7.53.0 */
  CURLE_ABORTED_BY_CALLBACK,     /* 42 */
  CURLE_BAD_FUNCTION_ARGUMENT,   /* 43 */
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
  CURLE_SSL_ENGINE_NOTFOUND,     /* 53 - SSL crypto engine not found */
  CURLE_SSL_ENGINE_SETFAILED,    /* 54 - can not set SSL crypto engine as
                                    default */
  CURLE_SEND_ERROR,              /* 55 - failed sending network data */
  CURLE_RECV_ERROR,              /* 56 - failure in receiving network data */
  CURLE_OBSOLETE57,              /* 57 - NOT IN USE */
  CURLE_SSL_CERTPROBLEM,         /* 58 - problem with the local certificate */
  CURLE_SSL_CIPHER,              /* 59 - couldn't use specified cipher */
  CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
                                     wasn't verified fine */
  CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized/bad encoding */
  CURLE_OBSOLETE62,              /* 62 - NOT IN USE since 7.82.0 */
  CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
  CURLE_USE_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
  CURLE_SEND_FAIL_REWIND,        /* 65 - Sending the data requires a rewind
                                    that failed */
  CURLE_SSL_ENGINE_INITFAILED,   /* 66 - failed to initialise ENGINE */







|

|







577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  CURLE_SSL_ENGINE_NOTFOUND,     /* 53 - SSL crypto engine not found */
  CURLE_SSL_ENGINE_SETFAILED,    /* 54 - can not set SSL crypto engine as
                                    default */
  CURLE_SEND_ERROR,              /* 55 - failed sending network data */
  CURLE_RECV_ERROR,              /* 56 - failure in receiving network data */
  CURLE_OBSOLETE57,              /* 57 - NOT IN USE */
  CURLE_SSL_CERTPROBLEM,         /* 58 - problem with the local certificate */
  CURLE_SSL_CIPHER,              /* 59 - could not use specified cipher */
  CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
                                     was not verified fine */
  CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized/bad encoding */
  CURLE_OBSOLETE62,              /* 62 - NOT IN USE since 7.82.0 */
  CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
  CURLE_USE_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
  CURLE_SEND_FAIL_REWIND,        /* 65 - Sending the data requires a rewind
                                    that failed */
  CURLE_SSL_ENGINE_INITFAILED,   /* 66 - failed to initialise ENGINE */
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
  CURLE_SSH,                     /* 79 - error from the SSH layer, somewhat
                                    generic so the error message will be of
                                    interest when this has happened */

  CURLE_SSL_SHUTDOWN_FAILED,     /* 80 - Failed to shut down the SSL
                                    connection */
  CURLE_AGAIN,                   /* 81 - socket is not ready for send/recv,
                                    wait till it's ready and try again (Added
                                    in 7.18.2) */
  CURLE_SSL_CRL_BADFILE,         /* 82 - could not load CRL file, missing or
                                    wrong format (Added in 7.19.0) */
  CURLE_SSL_ISSUER_ERROR,        /* 83 - Issuer check failed.  (Added in
                                    7.19.0) */
  CURLE_FTP_PRET_FAILED,         /* 84 - a PRET command failed */
  CURLE_RTSP_CSEQ_ERROR,         /* 85 - mismatch of RTSP CSeq numbers */







|







608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
  CURLE_SSH,                     /* 79 - error from the SSH layer, somewhat
                                    generic so the error message will be of
                                    interest when this has happened */

  CURLE_SSL_SHUTDOWN_FAILED,     /* 80 - Failed to shut down the SSL
                                    connection */
  CURLE_AGAIN,                   /* 81 - socket is not ready for send/recv,
                                    wait till it is ready and try again (Added
                                    in 7.18.2) */
  CURLE_SSL_CRL_BADFILE,         /* 82 - could not load CRL file, missing or
                                    wrong format (Added in 7.19.0) */
  CURLE_SSL_ISSUER_ERROR,        /* 83 - Issuer check failed.  (Added in
                                    7.19.0) */
  CURLE_FTP_PRET_FAILED,         /* 84 - a PRET command failed */
  CURLE_RTSP_CSEQ_ERROR,         /* 85 - mismatch of RTSP CSeq numbers */
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
} CURLproxycode;

/* This prototype applies to all conversion callbacks */
typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);

typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
                                          void *ssl_ctx, /* actually an OpenSSL
                                                            or WolfSSL SSL_CTX,
                                                            or an mbedTLS
                                                          mbedtls_ssl_config */
                                          void *userptr);

typedef enum {
  CURLPROXY_HTTP = 0,   /* added in 7.10, new in 7.19.4 default is to use
                           CONNECT HTTP/1.1 */
  CURLPROXY_HTTP_1_0 = 1,   /* added in 7.19.4, force to use CONNECT
                               HTTP/1.0  */
  CURLPROXY_HTTPS = 2,  /* HTTPS but stick to HTTP/1 added in 7.52.0 */
  CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.2.0 */
  CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
                           in 7.10 */
  CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
  CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
  CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
                                   host name rather than the IP address. added
                                   in 7.18.0 */
} curl_proxytype;  /* this enum was added in 7.10 */

/*
 * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options:
 *
 * CURLAUTH_NONE         - No HTTP authentication







|
















|







767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
} CURLproxycode;

/* This prototype applies to all conversion callbacks */
typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);

typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
                                          void *ssl_ctx, /* actually an OpenSSL
                                                            or wolfSSL SSL_CTX,
                                                            or an mbedTLS
                                                          mbedtls_ssl_config */
                                          void *userptr);

typedef enum {
  CURLPROXY_HTTP = 0,   /* added in 7.10, new in 7.19.4 default is to use
                           CONNECT HTTP/1.1 */
  CURLPROXY_HTTP_1_0 = 1,   /* added in 7.19.4, force to use CONNECT
                               HTTP/1.0  */
  CURLPROXY_HTTPS = 2,  /* HTTPS but stick to HTTP/1 added in 7.52.0 */
  CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.2.0 */
  CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
                           in 7.10 */
  CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
  CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
  CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
                                   hostname rather than the IP address. added
                                   in 7.18.0 */
} curl_proxytype;  /* this enum was added in 7.10 */

/*
 * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options:
 *
 * CURLAUTH_NONE         - No HTTP authentication
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870

/* this is the set of return values expected from the curl_sshkeycallback
   callback */
enum curl_khstat {
  CURLKHSTAT_FINE_ADD_TO_FILE,
  CURLKHSTAT_FINE,
  CURLKHSTAT_REJECT, /* reject the connection, return an error */
  CURLKHSTAT_DEFER,  /* do not accept it, but we can't answer right now.
                        Causes a CURLE_PEER_FAILED_VERIFICATION error but the
                        connection will be left intact etc */
  CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */
  CURLKHSTAT_LAST    /* not for use, only a marker for last-in-list */
};

/* this is the set of status codes pass in to the callback */







|







864
865
866
867
868
869
870
871
872
873
874
875
876
877
878

/* this is the set of return values expected from the curl_sshkeycallback
   callback */
enum curl_khstat {
  CURLKHSTAT_FINE_ADD_TO_FILE,
  CURLKHSTAT_FINE,
  CURLKHSTAT_REJECT, /* reject the connection, return an error */
  CURLKHSTAT_DEFER,  /* do not accept it, but we cannot answer right now.
                        Causes a CURLE_PEER_FAILED_VERIFICATION error but the
                        connection will be left intact etc */
  CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */
  CURLKHSTAT_LAST    /* not for use, only a marker for last-in-list */
};

/* this is the set of status codes pass in to the callback */
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
   string options from the header file */


#define CURLOPT(na,t,nu) na = t + nu
#define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu

/* CURLOPT aliases that make no run-time difference */

/* 'char *' argument to a string with a trailing zero */
#define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT

/* 'struct curl_slist *' argument */
#define CURLOPTTYPE_SLISTPOINT  CURLOPTTYPE_OBJECTPOINT








|







1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
   string options from the header file */


#define CURLOPT(na,t,nu) na = t + nu
#define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu

/* CURLOPT aliases that make no runtime difference */

/* 'char *' argument to a string with a trailing zero */
#define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT

/* 'struct curl_slist *' argument */
#define CURLOPTTYPE_SLISTPOINT  CURLOPTTYPE_OBJECTPOINT

1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  /* If CURLOPT_READDATA is used, this can be used to inform libcurl about
   * how large the file being sent really is. That allows better error
   * checking and better verifies that the upload was successful. -1 means
   * unknown size.
   *
   * For large file support, there is also a _LARGE version of the key
   * which takes an off_t type, allowing platforms with larger off_t
   * sizes to handle larger files.  See below for INFILESIZE_LARGE.
   */
  CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14),

  /* POST static input fields. */
  CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15),

  /* Set the referrer page (needed by some CGIs) */







|







1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
  /* If CURLOPT_READDATA is used, this can be used to inform libcurl about
   * how large the file being sent really is. That allows better error
   * checking and better verifies that the upload was successful. -1 means
   * unknown size.
   *
   * For large file support, there is also a _LARGE version of the key
   * which takes an off_t type, allowing platforms with larger off_t
   * sizes to handle larger files. See below for INFILESIZE_LARGE.
   */
  CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14),

  /* POST static input fields. */
  CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15),

  /* Set the referrer page (needed by some CGIs) */
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
  /* Set the "low speed time" */
  CURLOPT(CURLOPT_LOW_SPEED_TIME, CURLOPTTYPE_LONG, 20),

  /* Set the continuation offset.
   *
   * Note there is also a _LARGE version of this key which uses
   * off_t types, allowing for large file offsets on platforms which
   * use larger-than-32-bit off_t's.  Look below for RESUME_FROM_LARGE.
   */
  CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21),

  /* Set cookie in request: */
  CURLOPT(CURLOPT_COOKIE, CURLOPTTYPE_STRINGPOINT, 22),

  /* This points to a linked list of headers, struct curl_slist kind. This







|







1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  /* Set the "low speed time" */
  CURLOPT(CURLOPT_LOW_SPEED_TIME, CURLOPTTYPE_LONG, 20),

  /* Set the continuation offset.
   *
   * Note there is also a _LARGE version of this key which uses
   * off_t types, allowing for large file offsets on platforms which
   * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
   */
  CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21),

  /* Set cookie in request: */
  CURLOPT(CURLOPT_COOKIE, CURLOPTTYPE_STRINGPOINT, 22),

  /* This points to a linked list of headers, struct curl_slist kind. This
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328

  /* tunnel non-http operations through an HTTP proxy */
  CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61),

  /* Set the interface string to use as outgoing network interface */
  CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62),

  /* Set the krb4/5 security level, this also enables krb4/5 awareness.  This
   * is a string, 'clear', 'safe', 'confidential' or 'private'.  If the string
   * is set but doesn't match one of these, 'private' will be used.  */
  CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63),

  /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
  CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64),

  /* The CApath or CAfile used to validate the peer certificate
     this option is used only if SSL_VERIFYPEER is true */







|
|
|







1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336

  /* tunnel non-http operations through an HTTP proxy */
  CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61),

  /* Set the interface string to use as outgoing network interface */
  CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62),

  /* Set the krb4/5 security level, this also enables krb4/5 awareness. This
   * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string
   * is set but does not match one of these, 'private' will be used.  */
  CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63),

  /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
  CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64),

  /* The CApath or CAfile used to validate the peer certificate
     this option is used only if SSL_VERIFYPEER is true */
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369

  /* OBSOLETE, do not use! */
  CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72),

  /* 73 = OBSOLETE */

  /* Set to explicitly use a new connection for the upcoming transfer.
     Do not use this unless you're absolutely sure of this, as it makes the
     operation slower and is less friendly for the network. */
  CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74),

  /* Set to explicitly forbid the upcoming transfer's connection to be reused
     when done. Do not use this unless you're absolutely sure of this, as it
     makes the operation slower and is less friendly for the network. */
  CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75),

  /* Set to a file name that contains random data for libcurl to use to
     seed the random engine when doing SSL connects. */
  CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76,
                    7.84.0, "Serves no purpose anymore"),

  /* Set to the Entropy Gathering Daemon socket pathname */
  CURLOPTDEPRECATED(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77,
                    7.84.0, "Serves no purpose anymore"),







|




|



|







1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377

  /* OBSOLETE, do not use! */
  CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72),

  /* 73 = OBSOLETE */

  /* Set to explicitly use a new connection for the upcoming transfer.
     Do not use this unless you are absolutely sure of this, as it makes the
     operation slower and is less friendly for the network. */
  CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74),

  /* Set to explicitly forbid the upcoming transfer's connection to be reused
     when done. Do not use this unless you are absolutely sure of this, as it
     makes the operation slower and is less friendly for the network. */
  CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75),

  /* Set to a filename that contains random data for libcurl to use to
     seed the random engine when doing SSL connects. */
  CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76,
                    7.84.0, "Serves no purpose anymore"),

  /* Set to the Entropy Gathering Daemon socket pathname */
  CURLOPTDEPRECATED(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77,
                    7.84.0, "Serves no purpose anymore"),
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
  CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80),

  /* Set if we should verify the Common name from the peer certificate in ssl
   * handshake, set 1 to check existence, 2 to ensure that it matches the
   * provided hostname. */
  CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81),

  /* Specify which file name to write all known cookies in after completed
     operation. Set file name to "-" (dash) to make it go to stdout. */
  CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82),

  /* Specify which SSL ciphers to use */
  CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83),

  /* Specify which HTTP version to use! This must be set to one of the
     CURL_HTTP_VERSION* enums set below. */







|
|







1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
  CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80),

  /* Set if we should verify the Common name from the peer certificate in ssl
   * handshake, set 1 to check existence, 2 to ensure that it matches the
   * provided hostname. */
  CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81),

  /* Specify which filename to write all known cookies in after completed
     operation. Set filename to "-" (dash) to make it go to stdout. */
  CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82),

  /* Specify which SSL ciphers to use */
  CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83),

  /* Specify which HTTP version to use! This must be set to one of the
     CURL_HTTP_VERSION* enums set below. */
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548

  /* Set this to a bitmask value to enable the particular authentications
     methods you like. Use this in combination with CURLOPT_USERPWD.
     Note that setting multiple bits may cause extra network round-trips. */
  CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107),

  /* Set the ssl context callback function, currently only for OpenSSL or
     WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
     The function must match the curl_ssl_ctx_callback prototype. */
  CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108),

  /* Set the userdata for the ssl context callback function's third
     argument */
  CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_CBPOINT, 109),

  /* FTP Option that causes missing dirs to be created on the remote server.
     In 7.19.4 we introduced the convenience enums for this option using the
     CURLFTP_CREATE_DIR prefix.
  */
  CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110),

  /* Set this to a bitmask value to enable the particular authentications
     methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
     Note that setting multiple bits may cause extra network round-trips. */
  CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111),

  /* Option that changes the timeout, in seconds, associated with getting a
     response.  This is different from transfer timeout time and essentially
     places a demand on the server to acknowledge commands in a timely
     manner. For FTP, SMTP, IMAP and POP3. */
  CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112),

  /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
     tell libcurl to use those IP versions only. This only has effect on
     systems with support for more than one, i.e IPv4 _and_ IPv6. */
  CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),

  /* Set this option to limit the size of a file that will be downloaded from
     an HTTP or FTP server.

     Note there is also _LARGE version which adds large file support for
     platforms which have larger off_t sizes.  See MAXFILESIZE_LARGE below. */
  CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114),

  /* See the comment for INFILESIZE above, but in short, specifies
   * the size of the file being uploaded.  -1 means unknown.
   */
  CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115),

  /* Sets the continuation offset.  There is also a CURLOPTTYPE_LONG version
   * of this; look above for RESUME_FROM.
   */
  CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116),

  /* Sets the maximum size of data that will be downloaded from
   * an HTTP or FTP server.  See MAXFILESIZE above for the LONG version.
   */
  CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117),

  /* Set this option to the file name of your .netrc file you want libcurl
     to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
     a poor attempt to find the user's home directory and check for a .netrc
     file in there. */
  CURLOPT(CURLOPT_NETRC_FILE, CURLOPTTYPE_STRINGPOINT, 118),

  /* Enable SSL/TLS for FTP, pick one of:
     CURLUSESSL_TRY     - try using SSL, proceed anyway otherwise







|



















|













|







|





|



|







1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556

  /* Set this to a bitmask value to enable the particular authentications
     methods you like. Use this in combination with CURLOPT_USERPWD.
     Note that setting multiple bits may cause extra network round-trips. */
  CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107),

  /* Set the ssl context callback function, currently only for OpenSSL or
     wolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
     The function must match the curl_ssl_ctx_callback prototype. */
  CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108),

  /* Set the userdata for the ssl context callback function's third
     argument */
  CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_CBPOINT, 109),

  /* FTP Option that causes missing dirs to be created on the remote server.
     In 7.19.4 we introduced the convenience enums for this option using the
     CURLFTP_CREATE_DIR prefix.
  */
  CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110),

  /* Set this to a bitmask value to enable the particular authentications
     methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
     Note that setting multiple bits may cause extra network round-trips. */
  CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111),

  /* Option that changes the timeout, in seconds, associated with getting a
     response. This is different from transfer timeout time and essentially
     places a demand on the server to acknowledge commands in a timely
     manner. For FTP, SMTP, IMAP and POP3. */
  CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112),

  /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
     tell libcurl to use those IP versions only. This only has effect on
     systems with support for more than one, i.e IPv4 _and_ IPv6. */
  CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),

  /* Set this option to limit the size of a file that will be downloaded from
     an HTTP or FTP server.

     Note there is also _LARGE version which adds large file support for
     platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
  CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114),

  /* See the comment for INFILESIZE above, but in short, specifies
   * the size of the file being uploaded.  -1 means unknown.
   */
  CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115),

  /* Sets the continuation offset. There is also a CURLOPTTYPE_LONG version
   * of this; look above for RESUME_FROM.
   */
  CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116),

  /* Sets the maximum size of data that will be downloaded from
   * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
   */
  CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117),

  /* Set this option to the filename of your .netrc file you want libcurl
     to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
     a poor attempt to find the user's home directory and check for a .netrc
     file in there. */
  CURLOPT(CURLOPT_NETRC_FILE, CURLOPTTYPE_STRINGPOINT, 118),

  /* Enable SSL/TLS for FTP, pick one of:
     CURLUSESSL_TRY     - try using SSL, proceed anyway otherwise
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
  CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_VALUES, 161),

  /* used by scp/sftp to verify the host's public key */
  CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162),

  /* Callback function for opening socket (instead of socket(2)). Optionally,
     callback is able change the address or refuse to connect returning
     CURL_SOCKET_BAD.  The callback should have type
     curl_opensocket_callback */
  CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163),
  CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_CBPOINT, 164),

  /* POST volatile input fields. */
  CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165),








|







1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
  CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_VALUES, 161),

  /* used by scp/sftp to verify the host's public key */
  CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162),

  /* Callback function for opening socket (instead of socket(2)). Optionally,
     callback is able change the address or refuse to connect returning
     CURL_SOCKET_BAD. The callback should have type
     curl_opensocket_callback */
  CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163),
  CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_CBPOINT, 164),

  /* POST volatile input fields. */
  CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165),

1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765

  /* set the bitmask for the protocols that libcurl is allowed to follow to,
     as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
     to be set in both bitmasks to be allowed to get redirected to. */
  CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182,
                    7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"),

  /* set the SSH knownhost file name to use */
  CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183),

  /* set the SSH host key callback, must point to a curl_sshkeycallback
     function */
  CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184),

  /* set the SSH host key callback custom pointer */







|







1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773

  /* set the bitmask for the protocols that libcurl is allowed to follow to,
     as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
     to be set in both bitmasks to be allowed to get redirected to. */
  CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182,
                    7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"),

  /* set the SSH knownhost filename to use */
  CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183),

  /* set the SSH host key callback, must point to a curl_sshkeycallback
     function */
  CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184),

  /* set the SSH host key callback custom pointer */
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846

  /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
     compressed transfer-encoded responses. Set to 0 to disable the use of TE:
     in outgoing requests. The current default is 0, but it might change in a
     future libcurl release.

     libcurl will ask for the compressed methods it knows of, and if that
     isn't any, it will not ask for transfer-encoding at all even if this
     option is set to 1.

  */
  CURLOPT(CURLOPT_TRANSFER_ENCODING, CURLOPTTYPE_LONG, 207),

  /* Callback function for closing socket (instead of close(2)). The callback
     should have type curl_closesocket_callback */







|







1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854

  /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
     compressed transfer-encoded responses. Set to 0 to disable the use of TE:
     in outgoing requests. The current default is 0, but it might change in a
     future libcurl release.

     libcurl will ask for the compressed methods it knows of, and if that
     is not any, it will not ask for transfer-encoding at all even if this
     option is set to 1.

  */
  CURLOPT(CURLOPT_TRANSFER_ENCODING, CURLOPTTYPE_LONG, 207),

  /* Callback function for closing socket (instead of close(2)). The callback
     should have type curl_closesocket_callback */
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948

  /* Proxy Service Name */
  CURLOPT(CURLOPT_PROXY_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 235),

  /* Service Name */
  CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236),

  /* Wait/don't wait for pipe/mutex to clarify */
  CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237),

  /* Set the protocol used when curl is given a URL without a protocol */
  CURLOPT(CURLOPT_DEFAULT_PROTOCOL, CURLOPTTYPE_STRINGPOINT, 238),

  /* Set stream weight, 1 - 256 (default is 16) */
  CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239),







|







1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956

  /* Proxy Service Name */
  CURLOPT(CURLOPT_PROXY_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 235),

  /* Service Name */
  CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236),

  /* Wait/do not wait for pipe/mutex to clarify */
  CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237),

  /* Set the protocol used when curl is given a URL without a protocol */
  CURLOPT(CURLOPT_DEFAULT_PROTOCOL, CURLOPTTYPE_STRINGPOINT, 238),

  /* Set stream weight, 1 - 256 (default is 16) */
  CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239),
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109

  /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */
  CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285),

  /* alt-svc control bitmask */
  CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286),

  /* alt-svc cache file name to possibly read from/write to */
  CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),

  /* maximum age (idle time) of a connection to consider it for reuse
   * (in seconds) */
  CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),

  /* SASL authorization identity */







|







2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117

  /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */
  CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285),

  /* alt-svc control bitmask */
  CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286),

  /* alt-svc cache filename to possibly read from/write to */
  CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),

  /* maximum age (idle time) of a connection to consider it for reuse
   * (in seconds) */
  CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),

  /* SASL authorization identity */
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
   * OpenSSL support via 'set_groups'/'set_curves':
   * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
   */
  CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298),

  /* HSTS bitmask */
  CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299),
  /* HSTS file name */
  CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300),

  /* HSTS read callback */
  CURLOPT(CURLOPT_HSTSREADFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 301),
  CURLOPT(CURLOPT_HSTSREADDATA, CURLOPTTYPE_CBPOINT, 302),

  /* HSTS write callback */







|







2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
   * OpenSSL support via 'set_groups'/'set_curves':
   * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
   */
  CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298),

  /* HSTS bitmask */
  CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299),
  /* HSTS filename */
  CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300),

  /* HSTS read callback */
  CURLOPT(CURLOPT_HSTSREADFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 301),
  CURLOPT(CURLOPT_HSTSREADDATA, CURLOPTTYPE_CBPOINT, 302),

  /* HSTS write callback */
2206
2207
2208
2209
2210
2211
2212
2213
2214



2215
2216
2217
2218
2219
2220
2221

  /* set a specific client IP for HAProxy PROXY protocol header? */
  CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323),

  /* millisecond version */
  CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),

  /* set ECH configuration  */
  CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 325),




  CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
                          the obsolete stuff removed! */








|

>
>
>







2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232

  /* set a specific client IP for HAProxy PROXY protocol header? */
  CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323),

  /* millisecond version */
  CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),

  /* set ECH configuration */
  CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 325),

  /* maximum number of keepalive probes (Linux, *BSD, macOS, etc.) */
  CURLOPT(CURLOPT_TCP_KEEPCNT, CURLOPTTYPE_LONG, 326),

  CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
                          the obsolete stuff removed! */

2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
#define CURL_IPRESOLVE_V6       2 /* uses only IPv6 addresses/connections */

  /* Convenient "aliases" */
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER

  /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
enum {
  CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
                             like the library to choose the best possible
                             for us! */
  CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
  CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2 in the request */
  CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
  CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE,  /* please use HTTP 2 without HTTP/1.1
                                           Upgrade */
  CURL_HTTP_VERSION_3 = 30, /* Use HTTP/3, fallback to HTTP/2 or HTTP/1 if







|
|
|







2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
#define CURL_IPRESOLVE_V6       2 /* uses only IPv6 addresses/connections */

  /* Convenient "aliases" */
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER

  /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
enum {
  CURL_HTTP_VERSION_NONE, /* setting this means we do not care, and that we
                             would like the library to choose the best
                             possible for us! */
  CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
  CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
  CURL_HTTP_VERSION_2_0,  /* please use HTTP 2 in the request */
  CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
  CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE,  /* please use HTTP 2 without HTTP/1.1
                                           Upgrade */
  CURL_HTTP_VERSION_3 = 30, /* Use HTTP/3, fallback to HTTP/2 or HTTP/1 if
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name);

/*
 * NAME curl_mime_filename()
 *
 * DESCRIPTION
 *
 * Set mime part remote file name.
 */
CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part,
                                        const char *filename);

/*
 * NAME curl_mime_type()
 *







|







2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name);

/*
 * NAME curl_mime_filename()
 *
 * DESCRIPTION
 *
 * Set mime part remote filename.
 */
CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part,
                                        const char *filename);

/*
 * NAME curl_mime_type()
 *
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719

/*
 * NAME curl_global_init_mem()
 *
 * DESCRIPTION
 *
 * curl_global_init() or curl_global_init_mem() should be invoked exactly once
 * for each application that uses libcurl.  This function can be used to
 * initialize libcurl and set user defined memory management callback
 * functions.  Users can implement memory management routines to check for
 * memory leaks, check for mis-use of the curl library etc.  User registered
 * callback routines will be invoked by this library instead of the system
 * memory management routines like malloc, free etc.
 */
CURL_EXTERN CURLcode curl_global_init_mem(long flags,
                                          curl_malloc_callback m,
                                          curl_free_callback f,
                                          curl_realloc_callback r,







|

|
|







2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730

/*
 * NAME curl_global_init_mem()
 *
 * DESCRIPTION
 *
 * curl_global_init() or curl_global_init_mem() should be invoked exactly once
 * for each application that uses libcurl. This function can be used to
 * initialize libcurl and set user defined memory management callback
 * functions. Users can implement memory management routines to check for
 * memory leaks, check for mis-use of the curl library etc. User registered
 * callback routines will be invoked by this library instead of the system
 * memory management routines like malloc, free etc.
 */
CURL_EXTERN CURLcode curl_global_init_mem(long flags,
                                          curl_malloc_callback m,
                                          curl_free_callback f,
                                          curl_realloc_callback r,
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
 */
CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);

/* info about the certificate chain, for SSL backends that support it. Asked
   for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
struct curl_certinfo {
  int num_of_certs;             /* number of certificates with information */
  struct curl_slist **certinfo; /* for each index in this array, there's a
                                   linked list with textual information for a
                                   certificate in the format "name:content".
                                   eg "Subject:foo", "Issuer:bar", etc. */
};

/* Information about the SSL library used and the respective internal SSL
   handle, which can be used to obtain further information regarding the







|







2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
 */
CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);

/* info about the certificate chain, for SSL backends that support it. Asked
   for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
struct curl_certinfo {
  int num_of_certs;             /* number of certificates with information */
  struct curl_slist **certinfo; /* for each index in this array, there is a
                                   linked list with textual information for a
                                   certificate in the format "name:content".
                                   eg "Subject:foo", "Issuer:bar", etc. */
};

/* Information about the SSL library used and the respective internal SSL
   handle, which can be used to obtain further information regarding the
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
  CURLSHE_INVALID,    /* 3 */
  CURLSHE_NOMEM,      /* 4 out of memory */
  CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */
  CURLSHE_LAST        /* never use */
} CURLSHcode;

typedef enum {
  CURLSHOPT_NONE,  /* don't use */
  CURLSHOPT_SHARE,   /* specify a data type to share */
  CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
  CURLSHOPT_LOCKFUNC,   /* pass in a 'curl_lock_function' pointer */
  CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
  CURLSHOPT_USERDATA,   /* pass in a user data pointer used in the lock/unlock
                           callback functions */
  CURLSHOPT_LAST  /* never use */







|







3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
  CURLSHE_INVALID,    /* 3 */
  CURLSHE_NOMEM,      /* 4 out of memory */
  CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */
  CURLSHE_LAST        /* never use */
} CURLSHcode;

typedef enum {
  CURLSHOPT_NONE,  /* do not use */
  CURLSHOPT_SHARE,   /* specify a data type to share */
  CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
  CURLSHOPT_LOCKFUNC,   /* pass in a 'curl_lock_function' pointer */
  CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
  CURLSHOPT_USERDATA,   /* pass in a user data pointer used in the lock/unlock
                           callback functions */
  CURLSHOPT_LAST  /* never use */
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198

/*
 * NAME curl_easy_strerror()
 *
 * DESCRIPTION
 *
 * The curl_easy_strerror function may be used to turn a CURLcode value
 * into the equivalent human readable error string.  This is useful
 * for printing meaningful error messages.
 */
CURL_EXTERN const char *curl_easy_strerror(CURLcode);

/*
 * NAME curl_share_strerror()
 *
 * DESCRIPTION
 *
 * The curl_share_strerror function may be used to turn a CURLSHcode value
 * into the equivalent human readable error string.  This is useful
 * for printing meaningful error messages.
 */
CURL_EXTERN const char *curl_share_strerror(CURLSHcode);

/*
 * NAME curl_easy_pause()
 *







|










|







3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209

/*
 * NAME curl_easy_strerror()
 *
 * DESCRIPTION
 *
 * The curl_easy_strerror function may be used to turn a CURLcode value
 * into the equivalent human readable error string. This is useful
 * for printing meaningful error messages.
 */
CURL_EXTERN const char *curl_easy_strerror(CURLcode);

/*
 * NAME curl_share_strerror()
 *
 * DESCRIPTION
 *
 * The curl_share_strerror function may be used to turn a CURLSHcode value
 * into the equivalent human readable error string. This is useful
 * for printing meaningful error messages.
 */
CURL_EXTERN const char *curl_share_strerror(CURLSHcode);

/*
 * NAME curl_easy_pause()
 *
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
#include "multi.h"
#include "urlapi.h"
#include "options.h"
#include "header.h"
#include "websockets.h"
#include "mprintf.h"

/* the typechecker doesn't work in C++ (yet) */
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
    ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
    !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
#include "typecheck-gcc.h"
#else
#if defined(__STDC__) && (__STDC__ >= 1)
/* This preprocessor magic that replaces a call with the exact same call is







|







3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
#include "multi.h"
#include "urlapi.h"
#include "options.h"
#include "header.h"
#include "websockets.h"
#include "mprintf.h"

/* the typechecker does not work in C++ (yet) */
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
    ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
    !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
#include "typecheck-gcc.h"
#else
#if defined(__STDC__) && (__STDC__ >= 1)
/* This preprocessor magic that replaces a call with the exact same call is
Changes to jni/curl/include/curl/curlver.h.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
   a script at release-time. This was made its own header file in 7.11.2 */

/* This is the global package copyright */
#define LIBCURL_COPYRIGHT "Daniel Stenberg, <daniel@haxx.se>."

/* This is the version number of the libcurl package from which this header
   file origins: */
#define LIBCURL_VERSION "8.8.0"

/* The numeric version number is also available "in parts" by using these
   defines: */
#define LIBCURL_VERSION_MAJOR 8
#define LIBCURL_VERSION_MINOR 8
#define LIBCURL_VERSION_PATCH 0

/* This is the numeric version of the libcurl version number, meant for easier
   parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
   always follow this syntax:

         0xXXYYZZ

   Where XX, YY and ZZ are the main version, release and patch numbers in
   hexadecimal (using 8 bits each). All three numbers are always represented
   using two digits.  1.2 would appear as "0x010200" while version 9.11.7
   appears as "0x090b07".

   This 6-digit (24 bits) hexadecimal number does not show pre-release number,
   and it is always a greater number in a more recent release. It makes
   comparisons with greater than and less than work.

   Note: This define is the full hex number and _does not_ use the
   CURL_VERSION_BITS() macro since curl's own configure script greps for it
   and needs it to contain the full number.
*/
#define LIBCURL_VERSION_NUM 0x080800

/*
 * This is the date and time when the full source package was created. The
 * timestamp is not stored in git, as the timestamp is properly set in the
 * tarballs by the maketgz script.
 *
 * The format of the date follows this template:
 *
 * "2007-11-23"
 */
#define LIBCURL_TIMESTAMP "2024-05-22"

#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
#define CURL_AT_LEAST_VERSION(x,y,z) \
  (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))

#endif /* CURLINC_CURLVER_H */







|




|










|










|










|






28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
   a script at release-time. This was made its own header file in 7.11.2 */

/* This is the global package copyright */
#define LIBCURL_COPYRIGHT "Daniel Stenberg, <daniel@haxx.se>."

/* This is the version number of the libcurl package from which this header
   file origins: */
#define LIBCURL_VERSION "8.9.0"

/* The numeric version number is also available "in parts" by using these
   defines: */
#define LIBCURL_VERSION_MAJOR 8
#define LIBCURL_VERSION_MINOR 9
#define LIBCURL_VERSION_PATCH 0

/* This is the numeric version of the libcurl version number, meant for easier
   parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
   always follow this syntax:

         0xXXYYZZ

   Where XX, YY and ZZ are the main version, release and patch numbers in
   hexadecimal (using 8 bits each). All three numbers are always represented
   using two digits. 1.2 would appear as "0x010200" while version 9.11.7
   appears as "0x090b07".

   This 6-digit (24 bits) hexadecimal number does not show pre-release number,
   and it is always a greater number in a more recent release. It makes
   comparisons with greater than and less than work.

   Note: This define is the full hex number and _does not_ use the
   CURL_VERSION_BITS() macro since curl's own configure script greps for it
   and needs it to contain the full number.
*/
#define LIBCURL_VERSION_NUM 0x080900

/*
 * This is the date and time when the full source package was created. The
 * timestamp is not stored in git, as the timestamp is properly set in the
 * tarballs by the maketgz script.
 *
 * The format of the date follows this template:
 *
 * "2007-11-23"
 */
#define LIBCURL_TIMESTAMP "2024-07-24"

#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
#define CURL_AT_LEAST_VERSION(x,y,z) \
  (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))

#endif /* CURLINC_CURLVER_H */
Changes to jni/curl/include/curl/easy.h.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
 * NAME curl_easy_getinfo()
 *
 * DESCRIPTION
 *
 * Request internal information from the curl session with this function.
 * The third argument MUST be pointing to the specific type of the used option
 * which is documented in each man page of the option. The data pointed to
 * will be filled in accordingly and can be relied upon only if the function
 * returns CURLE_OK. This function is intended to get used *AFTER* a performed
 * transfer, all results from this function are undefined until the transfer
 * is completed.
 */
CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);








|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
 * NAME curl_easy_getinfo()
 *
 * DESCRIPTION
 *
 * Request internal information from the curl session with this function.
 * The third argument MUST be pointing to the specific type of the used option
 * which is documented in each manpage of the option. The data pointed to
 * will be filled in accordingly and can be relied upon only if the function
 * returns CURLE_OK. This function is intended to get used *AFTER* a performed
 * transfer, all results from this function are undefined until the transfer
 * is completed.
 */
CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);

Changes to jni/curl/include/curl/mprintf.h.
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
#include <stdio.h> /* needed for FILE */
#include "curl.h"  /* for CURL_EXTERN */

#ifdef  __cplusplus
extern "C" {
#endif

#if (defined(__GNUC__) || defined(__clang__)) &&                        \

  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) &&         \
  !defined(CURL_NO_FMT_CHECKS)
#if defined(__MINGW32__) && !defined(__clang__)
#define CURL_TEMP_PRINTF(fmt, arg) \
  __attribute__((format(gnu_printf, fmt, arg)))
#else
#define CURL_TEMP_PRINTF(fmt, arg) \







|
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h> /* needed for FILE */
#include "curl.h"  /* for CURL_EXTERN */

#ifdef  __cplusplus
extern "C" {
#endif

#if (defined(__GNUC__) || defined(__clang__) ||                         \
  defined(__IAR_SYSTEMS_ICC__)) &&                                      \
  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) &&         \
  !defined(CURL_NO_FMT_CHECKS)
#if defined(__MINGW32__) && !defined(__clang__)
#define CURL_TEMP_PRINTF(fmt, arg) \
  __attribute__((format(gnu_printf, fmt, arg)))
#else
#define CURL_TEMP_PRINTF(fmt, arg) \
Changes to jni/curl/include/curl/multi.h.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
/*
  This is an "external" header file. Don't give away any internals here!

  GOALS

  o Enable a "pull" interface. The application that uses libcurl decides where
    and when to ask libcurl to get/send data.

  o Enable multiple simultaneous transfers in the same thread without making it







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
/*
  This is an "external" header file. Do not give away any internals here!

  GOALS

  o Enable a "pull" interface. The application that uses libcurl decides where
    and when to ask libcurl to get/send data.

  o Enable multiple simultaneous transfers in the same thread without making it
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

typedef enum {
  CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
                                    curl_multi_socket*() soon */
  CURLM_OK,
  CURLM_BAD_HANDLE,      /* the passed-in handle is not a valid CURLM handle */
  CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
  CURLM_OUT_OF_MEMORY,   /* if you ever get this, you're in deep sh*t */
  CURLM_INTERNAL_ERROR,  /* this is a libcurl bug */
  CURLM_BAD_SOCKET,      /* the passed in socket argument did not match */
  CURLM_UNKNOWN_OPTION,  /* curl_multi_setopt() with unsupported option */
  CURLM_ADDED_ALREADY,   /* an easy handle already added to a multi handle was
                            attempted to get added - again */
  CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
                               callback */







|







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

typedef enum {
  CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
                                    curl_multi_socket*() soon */
  CURLM_OK,
  CURLM_BAD_HANDLE,      /* the passed-in handle is not a valid CURLM handle */
  CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
  CURLM_OUT_OF_MEMORY,   /* if you ever get this, you are in deep sh*t */
  CURLM_INTERNAL_ERROR,  /* this is a libcurl bug */
  CURLM_BAD_SOCKET,      /* the passed in socket argument did not match */
  CURLM_UNKNOWN_OPTION,  /* curl_multi_setopt() with unsupported option */
  CURLM_ADDED_ALREADY,   /* an easy handle already added to a multi handle was
                            attempted to get added - again */
  CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
                               callback */
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    void *whatever;    /* message-specific data */
    CURLcode result;   /* return code for transfer */
  } data;
};
typedef struct CURLMsg CURLMsg;

/* Based on poll(2) structure and values.
 * We don't use pollfd and POLL* constants explicitly
 * to cover platforms without poll(). */
#define CURL_WAIT_POLLIN    0x0001
#define CURL_WAIT_POLLPRI   0x0002
#define CURL_WAIT_POLLOUT   0x0004

struct curl_waitfd {
  curl_socket_t fd;







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    void *whatever;    /* message-specific data */
    CURLcode result;   /* return code for transfer */
  } data;
};
typedef struct CURLMsg CURLMsg;

/* Based on poll(2) structure and values.
 * We do not use pollfd and POLL* constants explicitly
 * to cover platforms without poll(). */
#define CURL_WAIT_POLLIN    0x0001
#define CURL_WAIT_POLLPRI   0x0002
#define CURL_WAIT_POLLOUT   0x0004

struct curl_waitfd {
  curl_socket_t fd;
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
 * Returns:  CURLMcode type, general multi error code.
 */
CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);

 /*
  * Name:    curl_multi_perform()
  *
  * Desc:    When the app thinks there's data available for curl it calls this
  *          function to read/write whatever there is right now. This returns
  *          as soon as the reads and writes are done. This function does not
  *          require that there actually is data available for reading or that
  *          data can be written, it can be called just in case. It returns
  *          the number of handles that still transfer data in the second
  *          argument's integer-pointer.
  *







|







201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
 * Returns:  CURLMcode type, general multi error code.
 */
CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);

 /*
  * Name:    curl_multi_perform()
  *
  * Desc:    When the app thinks there is data available for curl it calls this
  *          function to read/write whatever there is right now. This returns
  *          as soon as the reads and writes are done. This function does not
  *          require that there actually is data available for reading or that
  *          data can be written, it can be called just in case. It returns
  *          the number of handles that still transfer data in the second
  *          argument's integer-pointer.
  *
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
  * Returns: CURLMcode type, general multi error code.
  */
CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);

/*
 * Name:    curl_multi_info_read()
 *
 * Desc:    Ask the multi handle if there's any messages/informationals from
 *          the individual transfers. Messages include informationals such as
 *          error code from the transfer or just the fact that a transfer is
 *          completed. More details on these should be written down as well.
 *
 *          Repeated calls to this function will return a new struct each
 *          time, until a special "end of msgs" struct is returned as a signal
 *          that there is no more to get at this point.
 *
 *          The data the returned pointer points to will not survive calling
 *          curl_multi_cleanup().
 *
 *          The 'CURLMsg' struct is meant to be very simple and only contain
 *          very basic information. If more involved information is wanted,
 *          we will provide the particular "transfer handle" in that struct
 *          and that should/could/would be used in subsequent
 *          curl_easy_getinfo() calls (or similar). The point being that we
 *          must never expose complex structs to applications, as then we'll
 *          undoubtably get backwards compatibility problems in the future.
 *
 * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
 *          of structs. It also writes the number of messages left in the
 *          queue (after this read) in the integer the second argument points
 *          to.
 */
CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
                                          int *msgs_in_queue);

/*
 * Name:    curl_multi_strerror()
 *
 * Desc:    The curl_multi_strerror function may be used to turn a CURLMcode
 *          value into the equivalent human readable error string.  This is
 *          useful for printing meaningful error messages.
 *
 * Returns: A pointer to a null-terminated error message.
 */
CURL_EXTERN const char *curl_multi_strerror(CURLMcode);

/*
 * Name:    curl_multi_socket() and
 *          curl_multi_socket_all()
 *
 * Desc:    An alternative version of curl_multi_perform() that allows the
 *          application to pass in one of the file descriptors that have been
 *          detected to have "action" on them and let libcurl perform.
 *          See man page for details.
 */
#define CURL_POLL_NONE   0
#define CURL_POLL_IN     1
#define CURL_POLL_OUT    2
#define CURL_POLL_INOUT  3
#define CURL_POLL_REMOVE 4








|
















|














|













|







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
  * Returns: CURLMcode type, general multi error code.
  */
CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);

/*
 * Name:    curl_multi_info_read()
 *
 * Desc:    Ask the multi handle if there is any messages/informationals from
 *          the individual transfers. Messages include informationals such as
 *          error code from the transfer or just the fact that a transfer is
 *          completed. More details on these should be written down as well.
 *
 *          Repeated calls to this function will return a new struct each
 *          time, until a special "end of msgs" struct is returned as a signal
 *          that there is no more to get at this point.
 *
 *          The data the returned pointer points to will not survive calling
 *          curl_multi_cleanup().
 *
 *          The 'CURLMsg' struct is meant to be very simple and only contain
 *          very basic information. If more involved information is wanted,
 *          we will provide the particular "transfer handle" in that struct
 *          and that should/could/would be used in subsequent
 *          curl_easy_getinfo() calls (or similar). The point being that we
 *          must never expose complex structs to applications, as then we will
 *          undoubtably get backwards compatibility problems in the future.
 *
 * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
 *          of structs. It also writes the number of messages left in the
 *          queue (after this read) in the integer the second argument points
 *          to.
 */
CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
                                          int *msgs_in_queue);

/*
 * Name:    curl_multi_strerror()
 *
 * Desc:    The curl_multi_strerror function may be used to turn a CURLMcode
 *          value into the equivalent human readable error string. This is
 *          useful for printing meaningful error messages.
 *
 * Returns: A pointer to a null-terminated error message.
 */
CURL_EXTERN const char *curl_multi_strerror(CURLMcode);

/*
 * Name:    curl_multi_socket() and
 *          curl_multi_socket_all()
 *
 * Desc:    An alternative version of curl_multi_perform() that allows the
 *          application to pass in one of the file descriptors that have been
 *          detected to have "action" on them and let libcurl perform.
 *          See manpage for details.
 */
#define CURL_POLL_NONE   0
#define CURL_POLL_IN     1
#define CURL_POLL_OUT    2
#define CURL_POLL_INOUT  3
#define CURL_POLL_REMOVE 4

Changes to jni/curl/include/curl/system.h.
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 *
 * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit
 * wide signed integral data type if there is no 64-bit type.
 *
 * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall
 * only be violated if off_t is the only 64-bit data type available and the
 * size of off_t is independent of large file support settings. Keep your
 * build on the safe side avoiding an off_t gating.  If you have a 64-bit
 * off_t then take for sure that another 64-bit data type exists, dig deeper
 * and you will find it.
 *
 */

#if defined(__DJGPP__) || defined(__GO32__)
#  if defined(__DJGPP__) && (__DJGPP__ > 1)







|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 *
 * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit
 * wide signed integral data type if there is no 64-bit type.
 *
 * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall
 * only be violated if off_t is the only 64-bit data type available and the
 * size of off_t is independent of large file support settings. Keep your
 * build on the safe side avoiding an off_t gating. If you have a 64-bit
 * off_t then take for sure that another 64-bit data type exists, dig deeper
 * and you will find it.
 *
 */

#if defined(__DJGPP__) || defined(__GO32__)
#  if defined(__DJGPP__) && (__DJGPP__ > 1)
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
#    define CURL_SUFFIX_CURL_OFF_TU    UL
#  endif
#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
#  define CURL_PULL_SYS_TYPES_H      1
#  define CURL_PULL_SYS_SOCKET_H     1

#else
/* generic "safe guess" on old 32 bit style */
# define CURL_TYPEOF_CURL_OFF_T     long
# define CURL_FORMAT_CURL_OFF_T     "ld"
# define CURL_FORMAT_CURL_OFF_TU    "lu"
# define CURL_SUFFIX_CURL_OFF_T     L
# define CURL_SUFFIX_CURL_OFF_TU    UL
# define CURL_TYPEOF_CURL_SOCKLEN_T int
#endif







|







398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
#    define CURL_SUFFIX_CURL_OFF_TU    UL
#  endif
#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
#  define CURL_PULL_SYS_TYPES_H      1
#  define CURL_PULL_SYS_SOCKET_H     1

#else
/* generic "safe guess" on old 32-bit style */
# define CURL_TYPEOF_CURL_OFF_T     long
# define CURL_FORMAT_CURL_OFF_T     "ld"
# define CURL_FORMAT_CURL_OFF_TU    "lu"
# define CURL_SUFFIX_CURL_OFF_T     L
# define CURL_SUFFIX_CURL_OFF_TU    UL
# define CURL_TYPEOF_CURL_SOCKLEN_T int
#endif
Changes to jni/curl/include/curl/typecheck-gcc.h.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 *   if(curlcheck_sometype_option(_curl_opt))
 *     if(!curlcheck_sometype(value))
 *       _curl_easy_setopt_err_sometype();
 * block and define curlcheck_sometype_option, curlcheck_sometype and
 * _curl_easy_setopt_err_sometype below
 *
 * NOTE: We use two nested 'if' statements here instead of the && operator, in
 *       order to work around gcc bug #32061.  It affects only gcc 4.3.x/4.4.x
 *       when compiling with -Wlogical-op.
 *
 * To add an option that uses the same type as an existing option, you'll just
 * need to extend the appropriate _curl_*_option macro
 */
#define curl_easy_setopt(handle, option, value)                         \
  __extension__({                                                       \
      CURLoption _curl_opt = (option);                                  \
      if(__builtin_constant_p(_curl_opt)) {                             \
        CURL_IGNORE_DEPRECATION(                                        \
          if(curlcheck_long_option(_curl_opt))                          \







|


|
|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 *   if(curlcheck_sometype_option(_curl_opt))
 *     if(!curlcheck_sometype(value))
 *       _curl_easy_setopt_err_sometype();
 * block and define curlcheck_sometype_option, curlcheck_sometype and
 * _curl_easy_setopt_err_sometype below
 *
 * NOTE: We use two nested 'if' statements here instead of the && operator, in
 *       order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x
 *       when compiling with -Wlogical-op.
 *
 * To add an option that uses the same type as an existing option, you will
 * just need to extend the appropriate _curl_*_option macro
 */
#define curl_easy_setopt(handle, option, value)                         \
  __extension__({                                                       \
      CURLoption _curl_opt = (option);                                  \
      if(__builtin_constant_p(_curl_opt)) {                             \
        CURL_IGNORE_DEPRECATION(                                        \
          if(curlcheck_long_option(_curl_opt))                          \
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
  "curl_easy_getinfo expects a pointer to curl_off_t for this info")

/* groups of curl_easy_setops options that take the same type of argument */

/* To add a new option to one of the groups, just add
 *   (option) == CURLOPT_SOMETHING
 * to the or-expression. If the option takes a long or curl_off_t, you don't
 * have to do anything
 */

/* evaluates to true if option takes a long argument */
#define curlcheck_long_option(option)                   \
  (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)








|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
  "curl_easy_getinfo expects a pointer to curl_off_t for this info")

/* groups of curl_easy_setops options that take the same type of argument */

/* To add a new option to one of the groups, just add
 *   (option) == CURLOPT_SOMETHING
 * to the or-expression. If the option takes a long or curl_off_t, you do not
 * have to do anything
 */

/* evaluates to true if option takes a long argument */
#define curlcheck_long_option(option)                   \
  (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)

674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
                                            const void *);
#ifdef HEADER_SSL_H
/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
 * this will of course break if we're included before OpenSSL headers...
 */
typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *);
typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *,
                                            const void *);
#else







|







674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
                                            const void *);
#ifdef HEADER_SSL_H
/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
 * this will of course break if we are included before OpenSSL headers...
 */
typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *);
typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *,
                                            const void *);
#else
Changes to jni/curl/include/curl/urlapi.h.
93
94
95
96
97
98
99
100
101
102
103
104

105
106
107
108
109
110
111
#define CURLU_URLDECODE (1<<6)          /* URL decode on get */
#define CURLU_URLENCODE (1<<7)          /* URL encode on set */
#define CURLU_APPENDQUERY (1<<8)        /* append a form style part */
#define CURLU_GUESS_SCHEME (1<<9)       /* legacy curl-style guessing */
#define CURLU_NO_AUTHORITY (1<<10)      /* Allow empty authority when the
                                           scheme is unknown. */
#define CURLU_ALLOW_SPACE (1<<11)       /* Allow spaces in the URL */
#define CURLU_PUNYCODE (1<<12)          /* get the host name in punycode */
#define CURLU_PUNY2IDN (1<<13)          /* punycode => IDN conversion */
#define CURLU_GET_EMPTY (1<<14)         /* allow empty queries and fragments
                                           when extracting the URL or the
                                           components */


typedef struct Curl_URL CURLU;

/*
 * curl_url() creates a new CURLU handle and returns a pointer to it.
 * Must be freed with curl_url_cleanup().
 */







|




>







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#define CURLU_URLDECODE (1<<6)          /* URL decode on get */
#define CURLU_URLENCODE (1<<7)          /* URL encode on set */
#define CURLU_APPENDQUERY (1<<8)        /* append a form style part */
#define CURLU_GUESS_SCHEME (1<<9)       /* legacy curl-style guessing */
#define CURLU_NO_AUTHORITY (1<<10)      /* Allow empty authority when the
                                           scheme is unknown. */
#define CURLU_ALLOW_SPACE (1<<11)       /* Allow spaces in the URL */
#define CURLU_PUNYCODE (1<<12)          /* get the hostname in punycode */
#define CURLU_PUNY2IDN (1<<13)          /* punycode => IDN conversion */
#define CURLU_GET_EMPTY (1<<14)         /* allow empty queries and fragments
                                           when extracting the URL or the
                                           components */
#define CURLU_NO_GUESS_SCHEME (1<<15)   /* for get, do not accept a guess */

typedef struct Curl_URL CURLU;

/*
 * curl_url() creates a new CURLU handle and returns a pointer to it.
 * Must be freed with curl_url_cleanup().
 */
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
 * a part string, clears that part.
 */
CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
                                   const char *part, unsigned int flags);

/*
 * curl_url_strerror() turns a CURLUcode value into the equivalent human
 * readable error string.  This is useful for printing meaningful error
 * messages.
 */
CURL_EXTERN const char *curl_url_strerror(CURLUcode);

#ifdef __cplusplus
} /* end of extern "C" */
#endif

#endif /* CURLINC_URLAPI_H */







|









139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
 * a part string, clears that part.
 */
CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
                                   const char *part, unsigned int flags);

/*
 * curl_url_strerror() turns a CURLUcode value into the equivalent human
 * readable error string. This is useful for printing meaningful error
 * messages.
 */
CURL_EXTERN const char *curl_url_strerror(CURLUcode);

#ifdef __cplusplus
} /* end of extern "C" */
#endif

#endif /* CURLINC_URLAPI_H */
Changes to jni/curl/lib/CMakeLists.txt.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

if(ENABLE_CURLDEBUG)
  # We must compile these sources separately to avoid memdebug.h redefinitions
  # applying to them.
  set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
endif()

transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)

if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
  CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
  CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
  CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
  CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR

  # FreeBSD comes with the a.out and elf flavours
  # but a.out was supported up to version 3.x and
  # elf from 3.x. I cannot imagine someone running
  # CMake on those ancient systems
  CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR

  CMAKE_SYSTEM_NAME STREQUAL "Haiku")

  math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
  set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")
else()
  unset(CMAKESONAME)
endif()

## Library definition

# Add "_imp" as a suffix before the extension to avoid conflicting with
# the statically linked "libcurl.lib" (typically with MSVC)
if(WIN32 AND
   NOT IMPORT_LIB_SUFFIX AND
   CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX)







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







61
62
63
64
65
66
67























68
69
70
71
72
73
74

if(ENABLE_CURLDEBUG)
  # We must compile these sources separately to avoid memdebug.h redefinitions
  # applying to them.
  set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
endif()
























## Library definition

# Add "_imp" as a suffix before the extension to avoid conflicting with
# the statically linked "libcurl.lib" (typically with MSVC)
if(WIN32 AND
   NOT IMPORT_LIB_SUFFIX AND
   CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX)
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
    set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
  endif()
  if(CURL_HAS_LTO)
    set_target_properties(${LIB_STATIC} PROPERTIES
      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
  endif()
  if(CMAKEVERSION AND CMAKESONAME)
    set_target_properties(${LIB_STATIC} PROPERTIES
      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
  endif()

  target_include_directories(${LIB_STATIC} INTERFACE
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
endif()

if(BUILD_SHARED_LIBS)
  list(APPEND libcurl_export ${LIB_SHARED})
  add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
  add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
  if(WIN32 OR CYGWIN)
    if(CYGWIN)
      # For cygwin always compile dllmain.c as a separate unit since it
      # includes windows.h, which shouldn't be included in other units.
      set_source_files_properties(dllmain.c PROPERTIES
        SKIP_UNITY_BUILD_INCLUSION ON)
    endif()
    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES dllmain.c)
  endif()
  if(WIN32)
    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)







<
<
<
<












|
|







142
143
144
145
146
147
148




149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
    set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
  endif()
  if(CURL_HAS_LTO)
    set_target_properties(${LIB_STATIC} PROPERTIES
      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
  endif()





  target_include_directories(${LIB_STATIC} INTERFACE
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
endif()

if(BUILD_SHARED_LIBS)
  list(APPEND libcurl_export ${LIB_SHARED})
  add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
  add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
  if(WIN32 OR CYGWIN)
    if(CYGWIN)
      # For Cygwin always compile dllmain.c as a separate unit since it
      # includes windows.h, which should not be included in other units.
      set_source_files_properties(dllmain.c PROPERTIES
        SKIP_UNITY_BUILD_INCLUSION ON)
    endif()
    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES dllmain.c)
  endif()
  if(WIN32)
    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223






























224
225
226
227
228
229
230
    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
  endif()
  if(CURL_HAS_LTO)
    set_target_properties(${LIB_SHARED} PROPERTIES
      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
  endif()
  if(CMAKEVERSION AND CMAKESONAME)
    set_target_properties(${LIB_SHARED} PROPERTIES
      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
  endif()

  target_include_directories(${LIB_SHARED} INTERFACE
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)






























endif()

add_library(${LIB_NAME} ALIAS ${LIB_SELECTED})
add_library(${PROJECT_NAME}::${LIB_NAME} ALIAS ${LIB_SELECTED})

if(CURL_ENABLE_EXPORT_TARGET)
  if(BUILD_STATIC_LIBS)







<
<
<
<




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







182
183
184
185
186
187
188




189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
  endif()
  if(CURL_HAS_LTO)
    set_target_properties(${LIB_SHARED} PROPERTIES
      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
  endif()





  target_include_directories(${LIB_SHARED} INTERFACE
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)

  if(CMAKE_DLL_NAME_WITH_SOVERSION OR
    CYGWIN OR
    APPLE OR
    CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
    CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
    CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
    CMAKE_SYSTEM_NAME STREQUAL "Haiku" OR
    CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR
    # FreeBSD comes with the a.out and ELF flavours but a.out was supported
    # up to v3.x and ELF from v3.x. I cannot imagine someone running CMake
    # on those ancient systems.
    CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
    set(soversion_default TRUE)
  else()
    set(soversion_default FALSE)
  endif()

  option(CURL_LIBCURL_SOVERSION "Enable libcurl SOVERSION" ${soversion_default})

  if(CURL_LIBCURL_SOVERSION)
    transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
    include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)

    math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
    set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")

    set_target_properties(${LIB_SHARED} PROPERTIES
      VERSION "${CMAKEVERSION}" SOVERSION "${CMAKESONAME}")
  endif()
endif()

add_library(${LIB_NAME} ALIAS ${LIB_SELECTED})
add_library(${PROJECT_NAME}::${LIB_NAME} ALIAS ${LIB_SELECTED})

if(CURL_ENABLE_EXPORT_TARGET)
  if(BUILD_STATIC_LIBS)
Changes to jni/curl/lib/Makefile.am.
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
CS_ = $(CS_0)

checksrc:
	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir)    \
	-W$(srcdir)/curl_config.h $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch]   \
	$(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch])

if CURLDEBUG
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif

# disable the tests that are mostly causing false positives
TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference -quiet








|







122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
CS_ = $(CS_0)

checksrc:
	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir)    \
	-W$(srcdir)/curl_config.h $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch]   \
	$(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch])

if DEBUGBUILD
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif

# disable the tests that are mostly causing false positives
TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference -quiet

Changes to jni/curl/lib/Makefile.in.
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







164
165
166
167
168
169
170

171
172
173
174
175
176
177
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
962
963
964
965
966
967
968


969
970
971
972
973
974
975
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@







>
>







961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
@CURLDEBUG_FALSE@all-local:
all-am: Makefile $(LTLIBRARIES) curl_config.h all-local
installdirs:
	for dir in "$(DESTDIR)$(libdir)"; do \
	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
	done
install: install-am
install-exec: install-exec-am







|







4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
@DEBUGBUILD_FALSE@all-local:
all-am: Makefile $(LTLIBRARIES) curl_config.h all-local
installdirs:
	for dir in "$(DESTDIR)$(libdir)"; do \
	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
	done
install: install-am
install-exec: install-exec-am
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523

checksrc:
	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir)    \
	-W$(srcdir)/curl_config.h $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch]   \
	$(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch])

# for debug builds, we scan the sources on all regular make invokes
@CURLDEBUG_TRUE@all-local: checksrc

tidy:
	$(TIDY) $(CSOURCES) $(TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H

optiontable:
	perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c

@HAVE_WINDRES_TRUE@.rc.lo:
@HAVE_WINDRES_TRUE@	$(LIBTOOL) --tag=RC --mode=compile $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:







|













5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524

checksrc:
	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir)    \
	-W$(srcdir)/curl_config.h $(srcdir)/*.[ch] $(srcdir)/vauth/*.[ch]   \
	$(srcdir)/vtls/*.[ch] $(srcdir)/vquic/*.[ch] $(srcdir)/vssh/*.[ch])

# for debug builds, we scan the sources on all regular make invokes
@DEBUGBUILD_TRUE@all-local: checksrc

tidy:
	$(TIDY) $(CSOURCES) $(TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H

optiontable:
	perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c

@HAVE_WINDRES_TRUE@.rc.lo:
@HAVE_WINDRES_TRUE@	$(LIBTOOL) --tag=RC --mode=compile $(RC) -I$(top_srcdir)/include $(RCFLAGS) -i $< -o $@

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
Changes to jni/curl/lib/altsvc.c.
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
 * etc.
 */
static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
{
  CURLcode result = CURLE_OK;
  FILE *fp;

  /* we need a private copy of the file name so that the altsvc cache file
     name survives an easy handle reset */
  free(asi->filename);
  asi->filename = strdup(file);
  if(!asi->filename)
    return CURLE_OUT_OF_MEMORY;

  fp = fopen(file, FOPEN_READTEXT);







|







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
 * etc.
 */
static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
{
  CURLcode result = CURLE_OK;
  FILE *fp;

  /* we need a private copy of the filename so that the altsvc cache file
     name survives an easy handle reset */
  free(asi->filename);
  asi->filename = strdup(file);
  if(!asi->filename)
    return CURLE_OUT_OF_MEMORY;

  fp = fopen(file, FOPEN_READTEXT);
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  }
#endif
  fprintf(fp,
          "%s %s%s%s %u "
          "%s %s%s%s %u "
          "\"%d%02d%02d "
          "%02d:%02d:%02d\" "
          "%u %d\n",
          Curl_alpnid2str(as->src.alpnid),
          src6_pre, as->src.host, src6_post,
          as->src.port,

          Curl_alpnid2str(as->dst.alpnid),
          dst6_pre, as->dst.host, dst6_post,
          as->dst.port,







|







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  }
#endif
  fprintf(fp,
          "%s %s%s%s %u "
          "%s %s%s%s %u "
          "\"%d%02d%02d "
          "%02d:%02d:%02d\" "
          "%u %u\n",
          Curl_alpnid2str(as->src.alpnid),
          src6_pre, as->src.host, src6_post,
          as->src.port,

          Curl_alpnid2str(as->dst.alpnid),
          dst6_pre, as->dst.host, dst6_post,
          as->dst.port,
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    return CURLE_OK;

  /* if not new name is given, use the one we stored from the load */
  if(!file && altsvc->filename)
    file = altsvc->filename;

  if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
    /* marked as read-only, no file or zero length file name */
    return CURLE_OK;

  result = Curl_fopen(data, file, &out, &tempstore);
  if(!result) {
    fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
          "# This file was generated by libcurl! Edit at your own risk.\n",
          out);







|







369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    return CURLE_OK;

  /* if not new name is given, use the one we stored from the load */
  if(!file && altsvc->filename)
    file = altsvc->filename;

  if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
    /* marked as read-only, no file or zero length filename */
    return CURLE_OK;

  result = Curl_fopen(data, file, &out, &tempstore);
  if(!result) {
    fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
          "# This file was generated by libcurl! Edit at your own risk.\n",
          out);
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
{
  size_t hlen = strlen(host);
  size_t clen = strlen(check);

  if(hlen && (host[hlen - 1] == '.'))
    hlen--;
  if(hlen != clen)
    /* they can't match if they have different lengths */
    return FALSE;
  return strncasecompare(host, check, hlen);
}

/* altsvc_flush() removes all alternatives for this source origin from the
   list */
static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,







|







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
{
  size_t hlen = strlen(host);
  size_t clen = strlen(check);

  if(hlen && (host[hlen - 1] == '.'))
    hlen--;
  if(hlen != clen)
    /* they cannot match if they have different lengths */
    return FALSE;
  return strncasecompare(host, check, hlen);
}

/* altsvc_flush() removes all alternatives for this source origin from the
   list */
static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
/* to play well with debug builds, we can *set* a fixed time this will
   return */
static time_t altsvc_debugtime(void *unused)
{
  char *timestr = getenv("CURL_TIME");
  (void)unused;
  if(timestr) {
    unsigned long val = strtol(timestr, NULL, 10);
    return (time_t)val;
  }
  return time(NULL);
}
#undef time
#define time(x) altsvc_debugtime(x)
#endif

#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')

/*
 * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
 * the data correctly in the cache.
 *
 * 'value' points to the header *value*. That's contents to the right of the
 * header name.
 *
 * Currently this function rejects invalid data without returning an error.
 * Invalid host name, port number will result in the specific alternative
 * being rejected. Unknown protocols are skipped.
 */
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
                           struct altsvcinfo *asi, const char *value,
                           enum alpnid srcalpnid, const char *srchost,
                           unsigned short srcport)
{







|














|



|







458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
/* to play well with debug builds, we can *set* a fixed time this will
   return */
static time_t altsvc_debugtime(void *unused)
{
  char *timestr = getenv("CURL_TIME");
  (void)unused;
  if(timestr) {
    long val = strtol(timestr, NULL, 10);
    return (time_t)val;
  }
  return time(NULL);
}
#undef time
#define time(x) altsvc_debugtime(x)
#endif

#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')

/*
 * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
 * the data correctly in the cache.
 *
 * 'value' points to the header *value*. That is contents to the right of the
 * header name.
 *
 * Currently this function rejects invalid data without returning an error.
 * Invalid hostname, port number will result in the specific alternative
 * being rejected. Unknown protocols are skipped.
 */
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
                           struct altsvcinfo *asi, const char *value,
                           enum alpnid srcalpnid, const char *srchost,
                           unsigned short srcport)
{
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
        char *end_ptr;
        bool quoted = FALSE;
        time_t maxage = 24 * 3600; /* default is 24 hours */
        bool persist = FALSE;
        bool valid = TRUE;
        p++;
        if(*p != ':') {
          /* host name starts here */
          const char *hostp = p;
          if(*p == '[') {
            /* pass all valid IPv6 letters - does not handle zone id */
            len = strspn(++p, "0123456789abcdefABCDEF:.");
            if(p[len] != ']')
              /* invalid host syntax, bail out */
              break;
            /* we store the IPv6 numerical address *with* brackets */
            len += 2;
            p = &p[len-1];
          }
          else {
            while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
              p++;
            len = p - hostp;
          }
          if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
            infof(data, "Excessive alt-svc host name, ignoring.");
            valid = FALSE;
          }
          else {
            memcpy(namebuf, hostp, len);
            namebuf[len] = 0;
            dsthost = namebuf;
          }







|

















|







527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
        char *end_ptr;
        bool quoted = FALSE;
        time_t maxage = 24 * 3600; /* default is 24 hours */
        bool persist = FALSE;
        bool valid = TRUE;
        p++;
        if(*p != ':') {
          /* hostname starts here */
          const char *hostp = p;
          if(*p == '[') {
            /* pass all valid IPv6 letters - does not handle zone id */
            len = strspn(++p, "0123456789abcdefABCDEF:.");
            if(p[len] != ']')
              /* invalid host syntax, bail out */
              break;
            /* we store the IPv6 numerical address *with* brackets */
            len += 2;
            p = &p[len-1];
          }
          else {
            while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
              p++;
            len = p - hostp;
          }
          if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
            infof(data, "Excessive alt-svc hostname, ignoring.");
            valid = FALSE;
          }
          else {
            memcpy(namebuf, hostp, len);
            namebuf[len] = 0;
            dsthost = namebuf;
          }
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
          else {
            while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
              p++;
          }
          num = strtoul(value_ptr, &end_ptr, 10);
          if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
            if(strcasecompare("ma", option))
              maxage = num;
            else if(strcasecompare("persist", option) && (num == 1))
              persist = TRUE;
          }
        }
        if(dstalpnid && valid) {
          if(!entries++)
            /* Flush cached alternatives for this source origin, if any - when







|







620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
          else {
            while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
              p++;
          }
          num = strtoul(value_ptr, &end_ptr, 10);
          if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
            if(strcasecompare("ma", option))
              maxage = (time_t)num;
            else if(strcasecompare("persist", option) && (num == 1))
              persist = TRUE;
          }
        }
        if(dstalpnid && valid) {
          if(!entries++)
            /* Flush cached alternatives for this source origin, if any - when
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
            infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
                  Curl_alpnid2str(dstalpnid));
          }
        }
      }
      else
        break;
      /* after the double quote there can be a comma if there's another
         string or a semicolon if no more */
      if(*p == ',') {
        /* comma means another alternative is presented */
        p++;
        result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
        if(result)
          break;







|







647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
            infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
                  Curl_alpnid2str(dstalpnid));
          }
        }
      }
      else
        break;
      /* after the double quote there can be a comma if there is another
         string or a semicolon if no more */
      if(*p == ',') {
        /* comma means another alternative is presented */
        p++;
        result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
        if(result)
          break;
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
      Curl_llist_remove(&asi->list, e, NULL);
      altsvc_free(as);
      continue;
    }
    if((as->src.alpnid == srcalpnid) &&
       hostcompare(srchost, as->src.host) &&
       (as->src.port == srcport) &&
       (versions & as->dst.alpnid)) {
      /* match */
      *dstentry = as;
      return TRUE;
    }
  }
  return FALSE;
}

#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */







|









692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
      Curl_llist_remove(&asi->list, e, NULL);
      altsvc_free(as);
      continue;
    }
    if((as->src.alpnid == srcalpnid) &&
       hostcompare(srchost, as->src.host) &&
       (as->src.port == srcport) &&
       (versions & (int)as->dst.alpnid)) {
      /* match */
      *dstentry = as;
      return TRUE;
    }
  }
  return FALSE;
}

#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */
Changes to jni/curl/lib/altsvc.h.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
};

struct altsvc {
  struct althost src;
  struct althost dst;
  time_t expires;
  bool persist;
  int prio;
  struct Curl_llist_element node;
};

struct altsvcinfo {
  char *filename;
  struct Curl_llist list; /* list of entries */
  long flags; /* the publicly set bitmask */







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
};

struct altsvc {
  struct althost src;
  struct althost dst;
  time_t expires;
  bool persist;
  unsigned int prio;
  struct Curl_llist_element node;
};

struct altsvcinfo {
  char *filename;
  struct Curl_llist list; /* list of entries */
  long flags; /* the publicly set bitmask */
Changes to jni/curl/lib/amigaos.c.
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    CloseLibrary(base);
    __CurlISocket = NULL;
  }
}

#ifdef CURLRES_AMIGA
/*
 * Because we need to handle the different cases in hostip4.c at run-time,
 * not at compile-time, based on what was detected in Curl_amiga_init(),
 * we replace it completely with our own as to not complicate the baseline
 * code. Assumes malloc/calloc/free are thread safe because Curl_he2ai()
 * allocates memory also.
 */

struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,







|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    CloseLibrary(base);
    __CurlISocket = NULL;
  }
}

#ifdef CURLRES_AMIGA
/*
 * Because we need to handle the different cases in hostip4.c at runtime,
 * not at compile-time, based on what was detected in Curl_amiga_init(),
 * we replace it completely with our own as to not complicate the baseline
 * code. Assumes malloc/calloc/free are thread safe because Curl_he2ai()
 * allocates memory also.
 */

struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
Changes to jni/curl/lib/arpa_telnet.h.
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#define CURL_xEOF 236 /* End Of File */
#define CURL_SE   240 /* Sub negotiation End */
#define CURL_NOP  241 /* No OPeration */
#define CURL_DM   242 /* Data Mark */
#define CURL_GA   249 /* Go Ahead, reverse the line */
#define CURL_SB   250 /* SuBnegotiation */
#define CURL_WILL 251 /* Our side WILL use this option */
#define CURL_WONT 252 /* Our side WON'T use this option */
#define CURL_DO   253 /* DO use this option! */
#define CURL_DONT 254 /* DON'T use this option! */
#define CURL_IAC  255 /* Interpret As Command */

#ifndef CURL_DISABLE_VERBOSE_STRINGS
/*
 * Then those numbers represented as strings:







|







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#define CURL_xEOF 236 /* End Of File */
#define CURL_SE   240 /* Sub negotiation End */
#define CURL_NOP  241 /* No OPeration */
#define CURL_DM   242 /* Data Mark */
#define CURL_GA   249 /* Go Ahead, reverse the line */
#define CURL_SB   250 /* SuBnegotiation */
#define CURL_WILL 251 /* Our side WILL use this option */
#define CURL_WONT 252 /* Our side will not use this option */
#define CURL_DO   253 /* DO use this option! */
#define CURL_DONT 254 /* DON'T use this option! */
#define CURL_IAC  255 /* Interpret As Command */

#ifndef CURL_DISABLE_VERBOSE_STRINGS
/*
 * Then those numbers represented as strings:
Changes to jni/curl/lib/asyn-ares.c.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "timediff.h"

#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
  defined(_WIN32)
#  define CARES_STATICLIB
#endif
#include <ares.h>
#include <ares_version.h> /* really old c-ares didn't include this by
                             itself */

#if ARES_VERSION >= 0x010500
/* c-ares 1.5.0 or later, the callback proto is modified */
#define HAVE_CARES_CALLBACK_TIMEOUTS 1
#endif








|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "timediff.h"

#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
  defined(_WIN32)
#  define CARES_STATICLIB
#endif
#include <ares.h>
#include <ares_version.h> /* really old c-ares did not include this by
                             itself */

#if ARES_VERSION >= 0x010500
/* c-ares 1.5.0 or later, the callback proto is modified */
#define HAVE_CARES_CALLBACK_TIMEOUTS 1
#endif

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#endif
  char hostname[1];
};

/* How long we are willing to wait for additional parallel responses after
   obtaining a "definitive" one. For old c-ares without getaddrinfo.

   This is intended to equal the c-ares default timeout.  cURL always uses that
   default value.  Unfortunately, c-ares doesn't expose its default timeout in
   its API, but it is officially documented as 5 seconds.

   See query_completed_cb() for an explanation of how this is used.
 */
#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000

#define CARES_TIMEOUT_PER_ATTEMPT 2000

static int ares_ver = 0;

/*
 * Curl_resolver_global_init() - the generic low-level asynchronous name
 * resolve API.  Called from curl_global_init() to initialize global resolver
 * environment.  Initializes ares library.
 */
int Curl_resolver_global_init(void)
{
#ifdef CARES_HAVE_ARES_LIBRARY_INIT
  if(ares_library_init(ARES_LIB_INIT_ALL)) {
    return CURLE_FAILED_INIT;
  }







|
|












|
|







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#endif
  char hostname[1];
};

/* How long we are willing to wait for additional parallel responses after
   obtaining a "definitive" one. For old c-ares without getaddrinfo.

   This is intended to equal the c-ares default timeout. cURL always uses that
   default value. Unfortunately, c-ares does not expose its default timeout in
   its API, but it is officially documented as 5 seconds.

   See query_completed_cb() for an explanation of how this is used.
 */
#define HAPPY_EYEBALLS_DNS_TIMEOUT 5000

#define CARES_TIMEOUT_PER_ATTEMPT 2000

static int ares_ver = 0;

/*
 * Curl_resolver_global_init() - the generic low-level asynchronous name
 * resolve API. Called from curl_global_init() to initialize global resolver
 * environment. Initializes ares library.
 */
int Curl_resolver_global_init(void)
{
#ifdef CARES_HAVE_ARES_LIBRARY_INIT
  if(ares_library_init(ARES_LIB_INIT_ALL)) {
    return CURLE_FAILED_INIT;
  }
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
}

/*
 * Curl_resolver_init()
 *
 * Called from curl_easy_init() -> Curl_open() to initialize resolver
 * URL-state specific environment ('resolver' member of the UrlState
 * structure).  Fills the passed pointer by the initialized ares_channel.
 */
CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
{
  int status;
  struct ares_options options;
  int optmask = ARES_OPT_SOCK_STATE_CB;
  options.sock_state_cb = sock_state_cb;







|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
}

/*
 * Curl_resolver_init()
 *
 * Called from curl_easy_init() -> Curl_open() to initialize resolver
 * URL-state specific environment ('resolver' member of the UrlState
 * structure). Fills the passed pointer by the initialized ares_channel.
 */
CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
{
  int status;
  struct ares_options options;
  int optmask = ARES_OPT_SOCK_STATE_CB;
  options.sock_state_cb = sock_state_cb;
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
}

/*
 * Curl_resolver_cleanup()
 *
 * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
 * URL-state specific environment ('resolver' member of the UrlState
 * structure).  Destroys the ares channel.
 */
void Curl_resolver_cleanup(void *resolver)
{
  ares_destroy((ares_channel)resolver);
}

/*
 * Curl_resolver_duphandle()
 *
 * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
 * environment ('resolver' member of the UrlState structure).  Duplicates the
 * 'from' ares channel and passes the resulting channel to the 'to' pointer.
 */
CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
{
  (void)from;
  /*
   * it would be better to call ares_dup instead, but right now







|










|







207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
}

/*
 * Curl_resolver_cleanup()
 *
 * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
 * URL-state specific environment ('resolver' member of the UrlState
 * structure). Destroys the ares channel.
 */
void Curl_resolver_cleanup(void *resolver)
{
  ares_destroy((ares_channel)resolver);
}

/*
 * Curl_resolver_duphandle()
 *
 * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
 * environment ('resolver' member of the UrlState structure). Duplicates the
 * 'from' ares channel and passes the resulting channel to the 'to' pointer.
 */
CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
{
  (void)from;
  /*
   * it would be better to call ares_dup instead, but right now
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  DEBUGASSERT(data);
  if(data->state.async.resolver)
    ares_cancel((ares_channel)data->state.async.resolver);
  destroy_async_data(&data->state.async);
}

/*
 * We're equivalent to Curl_resolver_cancel() for the c-ares resolver.  We
 * never block.
 */
void Curl_resolver_kill(struct Curl_easy *data)
{
  /* We don't need to check the resolver state because we can be called safely
     at any time and we always do the same thing. */
  Curl_resolver_cancel(data);
}

/*
 * destroy_async_data() cleans up async resolver data.
 */







|




|







246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  DEBUGASSERT(data);
  if(data->state.async.resolver)
    ares_cancel((ares_channel)data->state.async.resolver);
  destroy_async_data(&data->state.async);
}

/*
 * We are equivalent to Curl_resolver_cancel() for the c-ares resolver. We
 * never block.
 */
void Curl_resolver_kill(struct Curl_easy *data)
{
  /* We do not need to check the resolver state because we can be called safely
     at any time and we always do the same thing. */
  Curl_resolver_cancel(data);
}

/*
 * destroy_async_data() cleans up async resolver data.
 */
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    }
    async->tdata = NULL;
  }
}

/*
 * Curl_resolver_getsock() is called when someone from the outside world
 * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
 * with ares. The caller must make sure that this function is only called when
 * we have a working ares channel.
 *
 * Returns: sockets-in-use-bitmap
 */

int Curl_resolver_getsock(struct Curl_easy *data,







|







276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    }
    async->tdata = NULL;
  }
}

/*
 * Curl_resolver_getsock() is called when someone from the outside world
 * (using curl_multi_fdset()) wants to get our fd_set setup and we are talking
 * with ares. The caller must make sure that this function is only called when
 * we have a working ares channel.
 *
 * Returns: sockets-in-use-bitmap
 */

int Curl_resolver_getsock(struct Curl_easy *data,
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
    if(pfd[i].events)
      num++;
    else
      break;
  }

  if(num) {
    nfds = Curl_poll(pfd, num, timeout_ms);
    if(nfds < 0)
      return -1;
  }
  else
    nfds = 0;

  if(!nfds)
    /* Call ares_process() unconditionally here, even if we simply timed out
       above, as otherwise the ares name resolve won't timeout! */
    ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
                    ARES_SOCKET_BAD);
  else {
    /* move through the descriptors and ask for processing on them */
    for(i = 0; i < num; i++)
      ares_process_fd((ares_channel)data->state.async.resolver,
                      (pfd[i].revents & (POLLRDNORM|POLLIN))?







|








|







346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
    if(pfd[i].events)
      num++;
    else
      break;
  }

  if(num) {
    nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
    if(nfds < 0)
      return -1;
  }
  else
    nfds = 0;

  if(!nfds)
    /* Call ares_process() unconditionally here, even if we simply timed out
       above, as otherwise the ares name resolve will not timeout! */
    ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
                    ARES_SOCKET_BAD);
  else {
    /* move through the descriptors and ask for processing on them */
    for(i = 0; i < num; i++)
      ares_process_fd((ares_channel)data->state.async.resolver,
                      (pfd[i].revents & (POLLRDNORM|POLLIN))?
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  DEBUGASSERT(dns);
  *dns = NULL;

  if(waitperform(data, 0) < 0)
    return CURLE_UNRECOVERABLE_POLL;

#ifndef HAVE_CARES_GETADDRINFO
  /* Now that we've checked for any last minute results above, see if there are
     any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
     expires. */
  if(res
     && res->num_pending
     /* This is only set to non-zero if the timer was started. */
     && (res->happy_eyeballs_dns_time.tv_sec
         || res->happy_eyeballs_dns_time.tv_usec)
     && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time)
         >= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
    /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
       running. */
    memset(
      &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));

    /* Cancel the raw c-ares request, which will fire query_completed_cb() with
       ARES_ECANCELLED synchronously for all pending responses.  This will
       leave us with res->num_pending == 0, which is perfect for the next
       block. */
    ares_cancel((ares_channel)data->state.async.resolver);
    DEBUGASSERT(res->num_pending == 0);
  }
#endif








|
|














|







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  DEBUGASSERT(dns);
  *dns = NULL;

  if(waitperform(data, 0) < 0)
    return CURLE_UNRECOVERABLE_POLL;

#ifndef HAVE_CARES_GETADDRINFO
  /* Now that we have checked for any last minute results above, see if there
     are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
     expires. */
  if(res
     && res->num_pending
     /* This is only set to non-zero if the timer was started. */
     && (res->happy_eyeballs_dns_time.tv_sec
         || res->happy_eyeballs_dns_time.tv_usec)
     && (Curl_timediff(Curl_now(), res->happy_eyeballs_dns_time)
         >= HAPPY_EYEBALLS_DNS_TIMEOUT)) {
    /* Remember that the EXPIRE_HAPPY_EYEBALLS_DNS timer is no longer
       running. */
    memset(
      &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));

    /* Cancel the raw c-ares request, which will fire query_completed_cb() with
       ARES_ECANCELLED synchronously for all pending responses. This will
       leave us with res->num_pending == 0, which is perfect for the next
       block. */
    ares_cancel((ares_channel)data->state.async.resolver);
    DEBUGASSERT(res->num_pending == 0);
  }
#endif

519
520
521
522
523
524
525
526
527
528
529
530
531
532
533

  /* Operation complete, if the lookup was successful we now have the entry
     in the cache. */
  if(entry)
    *entry = data->state.async.dns;

  if(result)
    /* close the connection, since we can't return failure here without
       cleaning up this connection properly. */
    connclose(data->conn, "c-ares resolve failed");

  return result;
}

#ifndef HAVE_CARES_GETADDRINFO







|







519
520
521
522
523
524
525
526
527
528
529
530
531
532
533

  /* Operation complete, if the lookup was successful we now have the entry
     in the cache. */
  if(entry)
    *entry = data->state.async.dns;

  if(result)
    /* close the connection, since we cannot return failure here without
       cleaning up this connection properly. */
    connclose(data->conn, "c-ares resolve failed");

  return result;
}

#ifndef HAVE_CARES_GETADDRINFO
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    }
    /* A successful result overwrites any previous error */
    if(res->last_status != ARES_SUCCESS)
      res->last_status = status;

    /* If there are responses still pending, we presume they must be the
       complementary IPv4 or IPv6 lookups that we started in parallel in
       Curl_resolver_getaddrinfo() (for Happy Eyeballs).  If we've got a
       "definitive" response from one of a set of parallel queries, we need to
       think about how long we're willing to wait for more responses. */
    if(res->num_pending
       /* Only these c-ares status values count as "definitive" for these
          purposes.  For example, ARES_ENODATA is what we expect when there is
          no IPv6 entry for a domain name, and that's not a reason to get more
          aggressive in our timeouts for the other response.  Other errors are
          either a result of bad input (which should affect all parallel
          requests), local or network conditions, non-definitive server
          responses, or us cancelling the request. */
       && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
      /* Right now, there can only be up to two parallel queries, so don't
         bother handling any other cases. */
      DEBUGASSERT(res->num_pending == 1);

      /* It's possible that one of these parallel queries could succeed
         quickly, but the other could always fail or timeout (when we're
         talking to a pool of DNS servers that can only successfully resolve
         IPv4 address, for example).

         It's also possible that the other request could always just take
         longer because it needs more time or only the second DNS server can
         fulfill it successfully.  But, to align with the philosophy of Happy
         Eyeballs, we don't want to wait _too_ long or users will think
         requests are slow when IPv6 lookups don't actually work (but IPv4 ones
         do).

         So, now that we have a usable answer (some IPv4 addresses, some IPv6
         addresses, or "no such domain"), we start a timeout for the remaining
         pending responses.  Even though it is typical that this resolved
         request came back quickly, that needn't be the case.  It might be that
         this completing request didn't get a result from the first DNS server
         or even the first round of the whole DNS server pool.  So it could
         already be quite some time after we issued the DNS queries in the
         first place.  Without modifying c-ares, we can't know exactly where in
         its retry cycle we are.  We could guess based on how much time has
         gone by, but it doesn't really matter.  Happy Eyeballs tells us that,
         given usable information in hand, we simply don't want to wait "too
         much longer" after we get a result.

         We simply wait an additional amount of time equal to the default
         c-ares query timeout.  That is enough time for a typical parallel
         response to arrive without being "too long".  Even on a network
         where one of the two types of queries is failing or timing out
         constantly, this will usually mean we wait a total of the default
         c-ares timeout (5 seconds) plus the round trip time for the successful
         request, which seems bearable.  The downside is that c-ares might race
         with us to issue one more retry just before we give up, but it seems
         better to "waste" that request instead of trying to guess the perfect
         timeout to prevent it.  After all, we don't even know where in the
         c-ares retry cycle each request is.
      */
      res->happy_eyeballs_dns_time = Curl_now();
      Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
                  EXPIRE_HAPPY_EYEBALLS_DNS);
    }
  }







|

|


|
|
|




|



|
|



|

|
|
|
|



|
|
|
|
|
|
|
|
|
|


|
|



|


|







599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    }
    /* A successful result overwrites any previous error */
    if(res->last_status != ARES_SUCCESS)
      res->last_status = status;

    /* If there are responses still pending, we presume they must be the
       complementary IPv4 or IPv6 lookups that we started in parallel in
       Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we have got a
       "definitive" response from one of a set of parallel queries, we need to
       think about how long we are willing to wait for more responses. */
    if(res->num_pending
       /* Only these c-ares status values count as "definitive" for these
          purposes. For example, ARES_ENODATA is what we expect when there is
          no IPv6 entry for a domain name, and that is not a reason to get more
          aggressive in our timeouts for the other response. Other errors are
          either a result of bad input (which should affect all parallel
          requests), local or network conditions, non-definitive server
          responses, or us cancelling the request. */
       && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
      /* Right now, there can only be up to two parallel queries, so do not
         bother handling any other cases. */
      DEBUGASSERT(res->num_pending == 1);

      /* it is possible that one of these parallel queries could succeed
         quickly, but the other could always fail or timeout (when we are
         talking to a pool of DNS servers that can only successfully resolve
         IPv4 address, for example).

         it is also possible that the other request could always just take
         longer because it needs more time or only the second DNS server can
         fulfill it successfully. But, to align with the philosophy of Happy
         Eyeballs, we do not want to wait _too_ long or users will think
         requests are slow when IPv6 lookups do not actually work (but IPv4
         ones do).

         So, now that we have a usable answer (some IPv4 addresses, some IPv6
         addresses, or "no such domain"), we start a timeout for the remaining
         pending responses. Even though it is typical that this resolved
         request came back quickly, that needn't be the case. It might be that
         this completing request did not get a result from the first DNS
         server or even the first round of the whole DNS server pool. So it
         could already be quite some time after we issued the DNS queries in
         the first place. Without modifying c-ares, we cannot know exactly
         where in its retry cycle we are. We could guess based on how much
         time has gone by, but it does not really matter. Happy Eyeballs tells
         us that, given usable information in hand, we simply do not want to
         wait "too much longer" after we get a result.

         We simply wait an additional amount of time equal to the default
         c-ares query timeout. That is enough time for a typical parallel
         response to arrive without being "too long". Even on a network
         where one of the two types of queries is failing or timing out
         constantly, this will usually mean we wait a total of the default
         c-ares timeout (5 seconds) plus the round trip time for the successful
         request, which seems bearable. The downside is that c-ares might race
         with us to issue one more retry just before we give up, but it seems
         better to "waste" that request instead of trying to guess the perfect
         timeout to prevent it. After all, we do not even know where in the
         c-ares retry cycle each request is.
      */
      res->happy_eyeballs_dns_time = Curl_now();
      Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
                  EXPIRE_HAPPY_EYEBALLS_DNS);
    }
  }
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
                              char *servers)
{
  CURLcode result = CURLE_NOT_BUILT_IN;
  int ares_result;

  /* If server is NULL or empty, this would purge all DNS servers
   * from ares library, which will cause any and all queries to fail.
   * So, just return OK if none are configured and don't actually make
   * any changes to c-ares.  This lets c-ares use its defaults, which
   * it gets from the OS (for instance from /etc/resolv.conf on Linux).
   */
  if(!(servers && servers[0]))
    return CURLE_OK;

#ifdef HAVE_CARES_SERVERS_CSV
#ifdef HAVE_CARES_PORTS_CSV







|
|







845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
                              char *servers)
{
  CURLcode result = CURLE_NOT_BUILT_IN;
  int ares_result;

  /* If server is NULL or empty, this would purge all DNS servers
   * from ares library, which will cause any and all queries to fail.
   * So, just return OK if none are configured and do not actually make
   * any changes to c-ares. This lets c-ares use its defaults, which
   * it gets from the OS (for instance from /etc/resolv.conf on Linux).
   */
  if(!(servers && servers[0]))
    return CURLE_OK;

#ifdef HAVE_CARES_SERVERS_CSV
#ifdef HAVE_CARES_PORTS_CSV
Changes to jni/curl/lib/asyn-thread.c.
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  curl_mutex_t *mtx;
  int done;
  int port;
  char *hostname;        /* hostname to resolve, Curl_async.hostname
                            duplicate */
#ifndef CURL_DISABLE_SOCKETPAIR
  struct Curl_easy *data;
  curl_socket_t sock_pair[2]; /* socket pair */
#endif
  int sock_error;
  struct Curl_addrinfo *res;
#ifdef HAVE_GETADDRINFO
  struct addrinfo hints;
#endif
  struct thread_data *td; /* for thread-self cleanup */







|







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  curl_mutex_t *mtx;
  int done;
  int port;
  char *hostname;        /* hostname to resolve, Curl_async.hostname
                            duplicate */
#ifndef CURL_DISABLE_SOCKETPAIR
  struct Curl_easy *data;
  curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
#endif
  int sock_error;
  struct Curl_addrinfo *res;
#ifdef HAVE_GETADDRINFO
  struct addrinfo hints;
#endif
  struct thread_data *td; /* for thread-self cleanup */
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  if(!tsd->mtx)
    goto err_exit;

  Curl_mutex_init(tsd->mtx);

#ifndef CURL_DISABLE_SOCKETPAIR
  /* create socket pair or pipe */
  if(wakeup_create(&tsd->sock_pair[0]) < 0) {
    tsd->sock_pair[0] = CURL_SOCKET_BAD;
    tsd->sock_pair[1] = CURL_SOCKET_BAD;
    goto err_exit;
  }
#endif
  tsd->sock_error = CURL_ASYNC_SUCCESS;








|







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  if(!tsd->mtx)
    goto err_exit;

  Curl_mutex_init(tsd->mtx);

#ifndef CURL_DISABLE_SOCKETPAIR
  /* create socket pair or pipe */
  if(wakeup_create(tsd->sock_pair, FALSE) < 0) {
    tsd->sock_pair[0] = CURL_SOCKET_BAD;
    tsd->sock_pair[1] = CURL_SOCKET_BAD;
    goto err_exit;
  }
#endif
  tsd->sock_error = CURL_ASYNC_SUCCESS;

282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304








305
306
307
308
309
310
311
static CURLcode getaddrinfo_complete(struct Curl_easy *data)
{
  struct thread_sync_data *tsd = conn_thread_sync_data(data);
  CURLcode result;

  result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
  /* The tsd->res structure has been copied to async.dns and perhaps the DNS
     cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
  */
  tsd->res = NULL;

  return result;
}

#ifdef _WIN32
static VOID WINAPI
query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
{
  size_t ss_size;
  const ADDRINFOEXW_ *ai;
  struct Curl_addrinfo *ca;
  struct Curl_addrinfo *cafirst = NULL;
  struct Curl_addrinfo *calast = NULL;








#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
#endif
  struct thread_sync_data *tsd =
    CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped);
#ifdef __clang__







|















>
>
>
>
>
>
>
>







282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
static CURLcode getaddrinfo_complete(struct Curl_easy *data)
{
  struct thread_sync_data *tsd = conn_thread_sync_data(data);
  CURLcode result;

  result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
  /* The tsd->res structure has been copied to async.dns and perhaps the DNS
     cache. Set our copy to NULL so destroy_thread_sync_data does not free it.
  */
  tsd->res = NULL;

  return result;
}

#ifdef _WIN32
static VOID WINAPI
query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
{
  size_t ss_size;
  const ADDRINFOEXW_ *ai;
  struct Curl_addrinfo *ca;
  struct Curl_addrinfo *cafirst = NULL;
  struct Curl_addrinfo *calast = NULL;
#ifndef CURL_DISABLE_SOCKETPAIR
#ifdef USE_EVENTFD
  const void *buf;
  const uint64_t val = 1;
#else
  char buf[1];
#endif
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wcast-align"
#endif
  struct thread_sync_data *tsd =
    CONTAINING_RECORD(overlapped, struct thread_sync_data, w8.overlapped);
#ifdef __clang__
417
418
419
420
421
422
423
424
425

426

427


428
429
430
431
432
433
434
435
    /* too late, gotta clean up the mess */
    Curl_mutex_release(tsd->mtx);
    destroy_thread_sync_data(tsd);
    free(td);
  }
  else {
#ifndef CURL_DISABLE_SOCKETPAIR
    char buf[1];
    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {

      /* DNS has been resolved, signal client task */

      buf[0] = 1;


      if(swrite(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
        /* update sock_erro to errno */
        tsd->sock_error = SOCKERRNO;
      }
    }
#endif
    tsd->done = 1;
    Curl_mutex_release(tsd->mtx);







<

>
|
>

>
>
|







425
426
427
428
429
430
431

432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
    /* too late, gotta clean up the mess */
    Curl_mutex_release(tsd->mtx);
    destroy_thread_sync_data(tsd);
    free(td);
  }
  else {
#ifndef CURL_DISABLE_SOCKETPAIR

    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
#ifdef USE_EVENTFD
      buf = &val;
#else
      buf[0] = 1;
#endif
      /* DNS has been resolved, signal client task */
      if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
        /* update sock_erro to errno */
        tsd->sock_error = SOCKERRNO;
      }
    }
#endif
    tsd->done = 1;
    Curl_mutex_release(tsd->mtx);
443
444
445
446
447
448
449






450
451
452
453
454
455
456




457

458
459
460
461
462
463
464

/*
 * getaddrinfo_thread() resolves a name and then exits.
 *
 * For builds without ARES, but with USE_IPV6, create a resolver thread
 * and wait on it.
 */






static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
{
  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  struct thread_data *td = tsd->td;
  char service[12];
  int rc;
#ifndef CURL_DISABLE_SOCKETPAIR




  char buf[1];

#endif

  msnprintf(service, sizeof(service), "%d", tsd->port);

  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);

  if(rc) {







>
>
>
>
>
>
|






>
>
>
>

>







454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486

/*
 * getaddrinfo_thread() resolves a name and then exits.
 *
 * For builds without ARES, but with USE_IPV6, create a resolver thread
 * and wait on it.
 */
static
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
DWORD
#else
unsigned int
#endif
CURL_STDCALL getaddrinfo_thread(void *arg)
{
  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  struct thread_data *td = tsd->td;
  char service[12];
  int rc;
#ifndef CURL_DISABLE_SOCKETPAIR
#ifdef USE_EVENTFD
  const void *buf;
  const uint64_t val = 1;
#else
  char buf[1];
#endif
#endif

  msnprintf(service, sizeof(service), "%d", tsd->port);

  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);

  if(rc) {
476
477
478
479
480
481
482
483


484


485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502






503
504
505
506
507
508
509
510
    Curl_mutex_release(tsd->mtx);
    destroy_thread_sync_data(tsd);
    free(td);
  }
  else {
#ifndef CURL_DISABLE_SOCKETPAIR
    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
      /* DNS has been resolved, signal client task */


      buf[0] = 1;


      if(wakeup_write(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
        /* update sock_erro to errno */
        tsd->sock_error = SOCKERRNO;
      }
    }
#endif
    tsd->done = 1;
    Curl_mutex_release(tsd->mtx);
  }

  return 0;
}

#else /* HAVE_GETADDRINFO */

/*
 * gethostbyname_thread() resolves a name and then exits.
 */






static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
{
  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  struct thread_data *td = tsd->td;

  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);

  if(!tsd->res) {







|
>
>

>
>
|

















>
>
>
>
>
>
|







498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
    Curl_mutex_release(tsd->mtx);
    destroy_thread_sync_data(tsd);
    free(td);
  }
  else {
#ifndef CURL_DISABLE_SOCKETPAIR
    if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
#ifdef USE_EVENTFD
      buf = &val;
#else
      buf[0] = 1;
#endif
      /* DNS has been resolved, signal client task */
      if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
        /* update sock_erro to errno */
        tsd->sock_error = SOCKERRNO;
      }
    }
#endif
    tsd->done = 1;
    Curl_mutex_release(tsd->mtx);
  }

  return 0;
}

#else /* HAVE_GETADDRINFO */

/*
 * gethostbyname_thread() resolves a name and then exits.
 */
static
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
DWORD
#else
unsigned int
#endif
CURL_STDCALL gethostbyname_thread(void *arg)
{
  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
  struct thread_data *td = tsd->td;

  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);

  if(!tsd->res) {
634
635
636
637
638
639
640
641

642
643
644
645
646
647
648
    goto err_exit;

  /* The thread will set this to 1 when complete. */
  td->tsd.done = 0;

#ifdef _WIN32
  if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
     Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW) {

#define MAX_NAME_LEN 256 /* max domain name is 253 chars */
#define MAX_PORT_LEN 8
    WCHAR namebuf[MAX_NAME_LEN];
    WCHAR portbuf[MAX_PORT_LEN];
    /* calculate required length */
    int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname,
                                    -1, NULL, 0);







|
>







666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
    goto err_exit;

  /* The thread will set this to 1 when complete. */
  td->tsd.done = 0;

#ifdef _WIN32
  if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
     Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW &&
     !Curl_win32_impersonating()) {
#define MAX_NAME_LEN 256 /* max domain name is 253 chars */
#define MAX_PORT_LEN 8
    WCHAR namebuf[MAX_NAME_LEN];
    WCHAR portbuf[MAX_PORT_LEN];
    /* calculate required length */
    int w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, hostname,
                                    -1, NULL, 0);
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
          goto err_exit;
        }
        err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS,
                                  NULL, &td->tsd.w8.hints, &td->tsd.w8.res,
                                  NULL, &td->tsd.w8.overlapped,
                                  &query_complete, &td->tsd.w8.cancel_ev);
        if(err != WSA_IO_PENDING)
          query_complete(err, 0, &td->tsd.w8.overlapped);
        return TRUE;
      }
    }
  }
#endif

#ifdef HAVE_GETADDRINFO







|







693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
          goto err_exit;
        }
        err = Curl_GetAddrInfoExW(namebuf, portbuf, NS_DNS,
                                  NULL, &td->tsd.w8.hints, &td->tsd.w8.res,
                                  NULL, &td->tsd.w8.overlapped,
                                  &query_complete, &td->tsd.w8.cancel_ev);
        if(err != WSA_IO_PENDING)
          query_complete((DWORD)err, 0, &td->tsd.w8.overlapped);
        return TRUE;
      }
    }
  }
#endif

#ifdef HAVE_GETADDRINFO
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
 * Until we gain a way to signal the resolver threads to stop early, we must
 * simply wait for them and ignore their results.
 */
void Curl_resolver_kill(struct Curl_easy *data)
{
  struct thread_data *td = data->state.async.tdata;

  /* If we're still resolving, we must wait for the threads to fully clean up,
     unfortunately.  Otherwise, we can simply cancel to clean up any resolver
     data. */
#ifdef _WIN32
  if(td && td->complete_ev) {
    Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
    (void)thread_wait_resolv(data, NULL, FALSE);
  }
  else







|
|







786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
 * Until we gain a way to signal the resolver threads to stop early, we must
 * simply wait for them and ignore their results.
 */
void Curl_resolver_kill(struct Curl_easy *data)
{
  struct thread_data *td = data->state.async.tdata;

  /* If we are still resolving, we must wait for the threads to fully clean up,
     unfortunately. Otherwise, we can simply cancel to clean up any resolver
     data. */
#ifdef _WIN32
  if(td && td->complete_ev) {
    Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
    (void)thread_wait_resolv(data, NULL, FALSE);
  }
  else
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
      return result;
    }
    destroy_async_data(&data->state.async);
    *entry = data->state.async.dns;
  }
  else {
    /* poll for name lookup done with exponential backoff up to 250ms */
    /* should be fine even if this converts to 32 bit */
    timediff_t elapsed = Curl_timediff(Curl_now(),
                                       data->progress.t_startsingle);
    if(elapsed < 0)
      elapsed = 0;

    if(td->poll_interval == 0)
      /* Start at 1ms poll interval */







|







858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
      return result;
    }
    destroy_async_data(&data->state.async);
    *entry = data->state.async.dns;
  }
  else {
    /* poll for name lookup done with exponential backoff up to 250ms */
    /* should be fine even if this converts to 32-bit */
    timediff_t elapsed = Curl_timediff(Curl_now(),
                                       data->progress.t_startsingle);
    if(elapsed < 0)
      elapsed = 0;

    if(td->poll_interval == 0)
      /* Start at 1ms poll interval */
Changes to jni/curl/lib/asyn.h.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 */
void Curl_resolver_global_cleanup(void);

/*
 * Curl_resolver_init()
 * Called from curl_easy_init() -> Curl_open() to initialize resolver
 * URL-state specific environment ('resolver' member of the UrlState
 * structure).  Should fill the passed pointer by the initialized handler.
 * Returning anything else than CURLE_OK fails curl_easy_init() with the
 * correspondent code.
 */
CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver);

/*
 * Curl_resolver_cleanup()
 * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
 * URL-state specific environment ('resolver' member of the UrlState
 * structure).  Should destroy the handler and free all resources connected to
 * it.
 */
void Curl_resolver_cleanup(void *resolver);

/*
 * Curl_resolver_duphandle()
 * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
 * environment ('resolver' member of the UrlState structure).  Should
 * duplicate the 'from' handle and pass the resulting handle to the 'to'
 * pointer.  Returning anything else than CURLE_OK causes failed
 * curl_easy_duphandle() call.
 */
CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
                                 void *from);

/*
 * Curl_resolver_cancel().
 *
 * It is called from inside other functions to cancel currently performing
 * resolver request. Should also free any temporary resources allocated to
 * perform a request.  This never waits for resolver threads to complete.
 *
 * It is safe to call this when conn is in any state.
 */
void Curl_resolver_cancel(struct Curl_easy *data);

/*
 * Curl_resolver_kill().
 *
 * This acts like Curl_resolver_cancel() except it will block until any threads
 * associated with the resolver are complete.  This never blocks for resolvers
 * that do not use threads.  This is intended to be the "last chance" function
 * that cleans up an in-progress resolver completely (before its owner is about
 * to die).
 *
 * It is safe to call this when conn is in any state.
 */
void Curl_resolver_kill(struct Curl_easy *data);








|









|







|

|










|









|
|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 */
void Curl_resolver_global_cleanup(void);

/*
 * Curl_resolver_init()
 * Called from curl_easy_init() -> Curl_open() to initialize resolver
 * URL-state specific environment ('resolver' member of the UrlState
 * structure). Should fill the passed pointer by the initialized handler.
 * Returning anything else than CURLE_OK fails curl_easy_init() with the
 * correspondent code.
 */
CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver);

/*
 * Curl_resolver_cleanup()
 * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
 * URL-state specific environment ('resolver' member of the UrlState
 * structure). Should destroy the handler and free all resources connected to
 * it.
 */
void Curl_resolver_cleanup(void *resolver);

/*
 * Curl_resolver_duphandle()
 * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
 * environment ('resolver' member of the UrlState structure). Should
 * duplicate the 'from' handle and pass the resulting handle to the 'to'
 * pointer. Returning anything else than CURLE_OK causes failed
 * curl_easy_duphandle() call.
 */
CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
                                 void *from);

/*
 * Curl_resolver_cancel().
 *
 * It is called from inside other functions to cancel currently performing
 * resolver request. Should also free any temporary resources allocated to
 * perform a request. This never waits for resolver threads to complete.
 *
 * It is safe to call this when conn is in any state.
 */
void Curl_resolver_cancel(struct Curl_easy *data);

/*
 * Curl_resolver_kill().
 *
 * This acts like Curl_resolver_cancel() except it will block until any threads
 * associated with the resolver are complete. This never blocks for resolvers
 * that do not use threads. This is intended to be the "last chance" function
 * that cleans up an in-progress resolver completely (before its owner is about
 * to die).
 *
 * It is safe to call this when conn is in any state.
 */
void Curl_resolver_kill(struct Curl_easy *data);

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
 */
struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                const char *hostname,
                                                int port,
                                                int *waitp);

#ifndef CURLRES_ASYNCH
/* convert these functions if an asynch resolver isn't used */
#define Curl_resolver_cancel(x) Curl_nop_stmt
#define Curl_resolver_kill(x) Curl_nop_stmt
#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
#define Curl_resolver_duphandle(x,y,z) CURLE_OK
#define Curl_resolver_init(x,y) CURLE_OK
#define Curl_resolver_global_init() CURLE_OK







|







157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
 */
struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                const char *hostname,
                                                int port,
                                                int *waitp);

#ifndef CURLRES_ASYNCH
/* convert these functions if an asynch resolver is not used */
#define Curl_resolver_cancel(x) Curl_nop_stmt
#define Curl_resolver_kill(x) Curl_nop_stmt
#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
#define Curl_resolver_duphandle(x,y,z) CURLE_OK
#define Curl_resolver_init(x,y) CURLE_OK
#define Curl_resolver_global_init() CURLE_OK
Changes to jni/curl/lib/bufref.c.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

#ifdef DEBUGBUILD
  br->signature = SIGNATURE;
#endif
}

/*
 * Free the buffer and re-init the necessary fields. It doesn't touch the
 * 'signature' field and thus this buffer reference can be reused.
 */

void Curl_bufref_free(struct bufref *br)
{
  DEBUGASSERT(br);
  DEBUGASSERT(br->signature == SIGNATURE);







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

#ifdef DEBUGBUILD
  br->signature = SIGNATURE;
#endif
}

/*
 * Free the buffer and re-init the necessary fields. It does not touch the
 * 'signature' field and thus this buffer reference can be reused.
 */

void Curl_bufref_free(struct bufref *br)
{
  DEBUGASSERT(br);
  DEBUGASSERT(br->signature == SIGNATURE);
Changes to jni/curl/lib/c-hyper.c.
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
{
  char *buf = (char *)hyper_buf_bytes(chunk);
  size_t len = hyper_buf_len(chunk);
  struct Curl_easy *data = (struct Curl_easy *)userdata;
  struct SingleRequest *k = &data->req;
  CURLcode result = CURLE_OK;

  if(0 == k->bodywrites) {
#if defined(USE_NTLM)
    struct connectdata *conn = data->conn;
    if(conn->bits.close &&
       (((data->req.httpcode == 401) &&
         (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
        ((data->req.httpcode == 407) &&
         (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {







|







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
{
  char *buf = (char *)hyper_buf_bytes(chunk);
  size_t len = hyper_buf_len(chunk);
  struct Curl_easy *data = (struct Curl_easy *)userdata;
  struct SingleRequest *k = &data->req;
  CURLcode result = CURLE_OK;

  if(!k->bodywritten) {
#if defined(USE_NTLM)
    struct connectdata *conn = data->conn;
    if(conn->bits.close &&
       (((data->req.httpcode == 401) &&
         (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
        ((data->req.httpcode == 407) &&
         (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
static CURLcode empty_header(struct Curl_easy *data)
{
  CURLcode result = Curl_http_size(data);
  if(!result) {
    result = hyper_each_header(data, NULL, 0, NULL, 0) ?
      CURLE_WRITE_ERROR : CURLE_OK;
    if(result)
      failf(data, "hyperstream: couldn't pass blank header");
    /* Hyper does chunked decoding itself. If it was added during
     * response header processing, remove it again. */
    Curl_cwriter_remove_by_name(data, "chunked");
  }
  return result;
}








|







320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
static CURLcode empty_header(struct Curl_easy *data)
{
  CURLcode result = Curl_http_size(data);
  if(!result) {
    result = hyper_each_header(data, NULL, 0, NULL, 0) ?
      CURLE_WRITE_ERROR : CURLE_OK;
    if(result)
      failf(data, "hyperstream: could not pass blank header");
    /* Hyper does chunked decoding itself. If it was added during
     * response header processing, remove it again. */
    Curl_cwriter_remove_by_name(data, "chunked");
  }
  return result;
}

416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    else if(t == HYPER_TASK_EMPTY) {
      void *userdata = hyper_task_userdata(task);
      hyper_task_free(task);
      if((userdata_t)userdata == USERDATA_RESP_BODY) {
        /* end of transfer */
        data->req.done = TRUE;
        infof(data, "hyperstream is done");
        if(!k->bodywrites) {
          /* hyper doesn't always call the body write callback */
          result = Curl_http_firstwrite(data);
        }
        break;
      }
      else {
        /* A background task for hyper; ignore */
        continue;
      }
    }

    DEBUGASSERT(HYPER_TASK_RESPONSE);

    resp = hyper_task_value(task);
    hyper_task_free(task);

    *didwhat = KEEP_RECV;
    if(!resp) {
      failf(data, "hyperstream: couldn't get response");
      return CURLE_RECV_ERROR;
    }

    http_status = hyper_response_status(resp);
    http_version = hyper_response_version(resp);
    reasonp = hyper_response_reason_phrase(resp);
    reason_len = hyper_response_reason_phrase_len(resp);







|
|

















|







416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    else if(t == HYPER_TASK_EMPTY) {
      void *userdata = hyper_task_userdata(task);
      hyper_task_free(task);
      if((userdata_t)userdata == USERDATA_RESP_BODY) {
        /* end of transfer */
        data->req.done = TRUE;
        infof(data, "hyperstream is done");
        if(!k->bodywritten) {
          /* hyper does not always call the body write callback */
          result = Curl_http_firstwrite(data);
        }
        break;
      }
      else {
        /* A background task for hyper; ignore */
        continue;
      }
    }

    DEBUGASSERT(HYPER_TASK_RESPONSE);

    resp = hyper_task_value(task);
    hyper_task_free(task);

    *didwhat = KEEP_RECV;
    if(!resp) {
      failf(data, "hyperstream: could not get response");
      return CURLE_RECV_ERROR;
    }

    http_status = hyper_response_status(resp);
    http_version = hyper_response_version(resp);
    reasonp = hyper_response_reason_phrase(resp);
    reason_len = hyper_response_reason_phrase_len(resp);
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
    result = status_line(data, conn,
                         http_status, http_version, reasonp, reason_len);
    if(result)
      break;

    headers = hyper_response_headers(resp);
    if(!headers) {
      failf(data, "hyperstream: couldn't get response headers");
      result = CURLE_RECV_ERROR;
      break;
    }

    /* the headers are already received */
    hyper_headers_foreach(headers, hyper_each_header, data);
    if(data->state.hresult) {







|







458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
    result = status_line(data, conn,
                         http_status, http_version, reasonp, reason_len);
    if(result)
      break;

    headers = hyper_response_headers(resp);
    if(!headers) {
      failf(data, "hyperstream: could not get response headers");
      result = CURLE_RECV_ERROR;
      break;
    }

    /* the headers are already received */
    hyper_headers_foreach(headers, hyper_each_header, data);
    if(data->state.hresult) {
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
     * if an auth method was picked. */
    result = Curl_http_auth_act(data);
    if(result)
      break;

    resp_body = hyper_response_body(resp);
    if(!resp_body) {
      failf(data, "hyperstream: couldn't get response body");
      result = CURLE_RECV_ERROR;
      break;
    }
    foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
    if(!foreach) {
      failf(data, "hyperstream: body foreach failed");
      result = CURLE_OUT_OF_MEMORY;







|







501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
     * if an auth method was picked. */
    result = Curl_http_auth_act(data);
    if(result)
      break;

    resp_body = hyper_response_body(resp);
    if(!resp_body) {
      failf(data, "hyperstream: could not get response body");
      result = CURLE_RECV_ERROR;
      break;
    }
    foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
    if(!foreach) {
      failf(data, "hyperstream: body foreach failed");
      result = CURLE_OUT_OF_MEMORY;
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
    if(copy)
      *chunk = copy;
    else {
      result = CURLE_OUT_OF_MEMORY;
      goto out;
    }
    /* increasing the writebytecount here is a little premature but we
       don't know exactly when the body is sent */
    data->req.writebytecount += fillcount;
    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
    rc = HYPER_POLL_READY;
  }
  else if(eos) {
    *chunk = NULL;
    rc = HYPER_POLL_READY;







|







665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
    if(copy)
      *chunk = copy;
    else {
      result = CURLE_OUT_OF_MEMORY;
      goto out;
    }
    /* increasing the writebytecount here is a little premature but we
       do not know exactly when the body is sent */
    data->req.writebytecount += fillcount;
    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
    rc = HYPER_POLL_READY;
  }
  else if(eos) {
    *chunk = NULL;
    rc = HYPER_POLL_READY;
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
  reason_len = hyper_response_reason_phrase_len(resp);

  result = status_line(data, data->conn,
                       http_status, http_version, reasonp, reason_len);
  if(!result) {
    headers = hyper_response_headers(resp);
    if(!headers) {
      failf(data, "hyperstream: couldn't get 1xx response headers");
      result = CURLE_RECV_ERROR;
    }
  }
  data->state.hresult = result;

  if(!result) {
    /* the headers are already received */







|







768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
  reason_len = hyper_response_reason_phrase_len(resp);

  result = status_line(data, data->conn,
                       http_status, http_version, reasonp, reason_len);
  if(!result) {
    headers = hyper_response_headers(resp);
    if(!headers) {
      failf(data, "hyperstream: could not get 1xx response headers");
      result = CURLE_RECV_ERROR;
    }
  }
  data->state.hresult = result;

  if(!result) {
    /* the headers are already received */
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
  client = NULL;

  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
    /* HTTP GET/HEAD download */
    Curl_pgrsSetUploadSize(data, 0); /* nothing */
  }

  Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
  conn->datastream = Curl_hyper_stream;

  /* clear userpwd and proxyuserpwd to avoid reusing old credentials
   * from reused connections */
  Curl_safefree(data->state.aptr.userpwd);
#ifndef CURL_DISABLE_PROXY
  Curl_safefree(data->state.aptr.proxyuserpwd);







|







1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
  client = NULL;

  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
    /* HTTP GET/HEAD download */
    Curl_pgrsSetUploadSize(data, 0); /* nothing */
  }

  Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
  conn->datastream = Curl_hyper_stream;

  /* clear userpwd and proxyuserpwd to avoid reusing old credentials
   * from reused connections */
  Curl_safefree(data->state.aptr.userpwd);
#ifndef CURL_DISABLE_PROXY
  Curl_safefree(data->state.aptr.proxyuserpwd);
1202
1203
1204
1205
1206
1207
1208

1209
1210
1211
1212
1213
1214
1215
  Curl_creader_def_read,
  Curl_creader_def_close,
  Curl_creader_def_needs_rewind,
  Curl_creader_def_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  cr_hyper_unpause,

  Curl_creader_def_done,
  sizeof(struct Curl_creader)
};

static CURLcode cr_hyper_add(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;







>







1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
  Curl_creader_def_read,
  Curl_creader_def_close,
  Curl_creader_def_needs_rewind,
  Curl_creader_def_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  cr_hyper_unpause,
  Curl_creader_def_is_paused,
  Curl_creader_def_done,
  sizeof(struct Curl_creader)
};

static CURLcode cr_hyper_add(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;
Changes to jni/curl/lib/cf-h1-proxy.c.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    H1_TUNNEL_RESPONSE, /* CONNECT response received completely */
    H1_TUNNEL_ESTABLISHED,
    H1_TUNNEL_FAILED
} h1_tunnel_state;

/* struct for HTTP CONNECT tunneling */
struct h1_tunnel_state {
  struct HTTP CONNECT;
  struct dynbuf rcvbuf;
  struct dynbuf request_data;
  size_t nsent;
  size_t headerlines;
  struct Curl_chunker ch;
  enum keeponval {
    KEEPON_DONE,







<







61
62
63
64
65
66
67

68
69
70
71
72
73
74
    H1_TUNNEL_RESPONSE, /* CONNECT response received completely */
    H1_TUNNEL_ESTABLISHED,
    H1_TUNNEL_FAILED
} h1_tunnel_state;

/* struct for HTTP CONNECT tunneling */
struct h1_tunnel_state {

  struct dynbuf rcvbuf;
  struct dynbuf request_data;
  size_t nsent;
  size_t headerlines;
  struct Curl_chunker ch;
  enum keeponval {
    KEEPON_DONE,
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    ts->tunnel_state = new_state;
    Curl_dyn_reset(&ts->rcvbuf);
    Curl_dyn_reset(&ts->request_data);
    /* restore the protocol pointer */
    data->info.httpcode = 0; /* clear it as it might've been used for the
                                proxy */
    /* If a proxy-authorization header was used for the proxy, then we should
       make sure that it isn't accidentally used for the document request
       after we've connected. So let's free and clear it here. */
    Curl_safefree(data->state.aptr.proxyuserpwd);
#ifdef USE_HYPER
    data->state.hconnect = FALSE;
#endif
    break;
  }
}







|
|







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
    ts->tunnel_state = new_state;
    Curl_dyn_reset(&ts->rcvbuf);
    Curl_dyn_reset(&ts->request_data);
    /* restore the protocol pointer */
    data->info.httpcode = 0; /* clear it as it might've been used for the
                                proxy */
    /* If a proxy-authorization header was used for the proxy, then we should
       make sure that it is not accidentally used for the document request
       after we have connected. So let's free and clear it here. */
    Curl_safefree(data->state.aptr.proxyuserpwd);
#ifdef USE_HYPER
    data->state.hconnect = FALSE;
#endif
    break;
  }
}
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
                              struct Curl_easy *data,
                              struct h1_tunnel_state *ts)
{
  struct httpreq *req = NULL;
  int http_minor;
  CURLcode result;

    /* This only happens if we've looped here due to authentication
       reasons, and we don't really use the newly cloned URL here
       then. Just free() it. */
  Curl_safefree(data->req.newurl);

  result = Curl_http_proxy_create_CONNECT(&req, cf, data, 1);
  if(result)
    goto out;








|
|







217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
                              struct Curl_easy *data,
                              struct h1_tunnel_state *ts)
{
  struct httpreq *req = NULL;
  int http_minor;
  CURLcode result;

    /* This only happens if we have looped here due to authentication
       reasons, and we do not really use the newly cloned URL here
       then. Just free() it. */
  Curl_safefree(data->req.newurl);

  result = Curl_http_proxy_create_CONNECT(&req, cf, data, 1);
  if(result)
    goto out;

418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
    }

    if(ts->keepon == KEEPON_IGNORE) {
      /* This means we are currently ignoring a response-body */

      if(ts->cl) {
        /* A Content-Length based body: simply count down the counter
           and make sure to break out of the loop when we're done! */
        ts->cl--;
        if(ts->cl <= 0) {
          ts->keepon = KEEPON_DONE;
          break;
        }
      }
      else if(ts->chunked_encoding) {
        /* chunked-encoded body, so we need to do the chunked dance
           properly to know when the end of the body is reached */
        size_t consumed = 0;

        /* now parse the chunked piece of data so that we can
           properly tell when the stream ends */
        result = Curl_httpchunk_read(data, &ts->ch, &byte, 1, &consumed);
        if(result)
          return result;
        if(Curl_httpchunk_is_done(data, &ts->ch)) {
          /* we're done reading chunks! */
          infof(data, "chunk reading DONE");
          ts->keepon = KEEPON_DONE;
        }
      }
      continue;
    }








|

















|







417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    }

    if(ts->keepon == KEEPON_IGNORE) {
      /* This means we are currently ignoring a response-body */

      if(ts->cl) {
        /* A Content-Length based body: simply count down the counter
           and make sure to break out of the loop when we are done! */
        ts->cl--;
        if(ts->cl <= 0) {
          ts->keepon = KEEPON_DONE;
          break;
        }
      }
      else if(ts->chunked_encoding) {
        /* chunked-encoded body, so we need to do the chunked dance
           properly to know when the end of the body is reached */
        size_t consumed = 0;

        /* now parse the chunked piece of data so that we can
           properly tell when the stream ends */
        result = Curl_httpchunk_read(data, &ts->ch, &byte, 1, &consumed);
        if(result)
          return result;
        if(Curl_httpchunk_is_done(data, &ts->ch)) {
          /* we are done reading chunks! */
          infof(data, "chunk reading DONE");
          ts->keepon = KEEPON_DONE;
        }
      }
      continue;
    }

471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
    if(result)
      return result;

    result = Curl_bump_headersize(data, line_len, TRUE);
    if(result)
      return result;

    /* Newlines are CRLF, so the CR is ignored as the line isn't
       really terminated until the LF comes. Treat a following CR
       as end-of-headers as well.*/

    if(('\r' == linep[0]) ||
       ('\n' == linep[0])) {
      /* end of response-headers from the proxy */








|







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
    if(result)
      return result;

    result = Curl_bump_headersize(data, line_len, TRUE);
    if(result)
      return result;

    /* Newlines are CRLF, so the CR is ignored as the line is not
       really terminated until the LF comes. Treat a following CR
       as end-of-headers as well.*/

    if(('\r' == linep[0]) ||
       ('\n' == linep[0])) {
      /* end of response-headers from the proxy */

494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
                " bytes of response-body", ts->cl);
        }
        else if(ts->chunked_encoding) {
          infof(data, "Ignore chunked response-body");
        }
        else {
          /* without content-length or chunked encoding, we
             can't keep the connection alive since the close is
             the end signal so we bail out at once instead */
          CURL_TRC_CF(data, cf, "CONNECT: no content-length or chunked");
          ts->keepon = KEEPON_DONE;
        }
      }
      else {
        ts->keepon = KEEPON_DONE;
      }

      DEBUGASSERT(ts->keepon == KEEPON_IGNORE
                  || ts->keepon == KEEPON_DONE);
      continue;
    }

    result = on_resp_header(cf, data, ts, linep);
    if(result)
      return result;

    Curl_dyn_reset(&ts->rcvbuf);
  } /* while there's buffer left and loop is requested */

  if(error)
    result = CURLE_RECV_ERROR;
  *done = (ts->keepon == KEEPON_DONE);
  if(!result && *done && data->info.httpproxycode/100 != 2) {
    /* Deal with the possibly already received authenticate
       headers. 'newurl' is set to a new URL if we must loop. */







|



















|







493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
                " bytes of response-body", ts->cl);
        }
        else if(ts->chunked_encoding) {
          infof(data, "Ignore chunked response-body");
        }
        else {
          /* without content-length or chunked encoding, we
             cannot keep the connection alive since the close is
             the end signal so we bail out at once instead */
          CURL_TRC_CF(data, cf, "CONNECT: no content-length or chunked");
          ts->keepon = KEEPON_DONE;
        }
      }
      else {
        ts->keepon = KEEPON_DONE;
      }

      DEBUGASSERT(ts->keepon == KEEPON_IGNORE
                  || ts->keepon == KEEPON_DONE);
      continue;
    }

    result = on_resp_header(cf, data, ts, linep);
    if(result)
      return result;

    Curl_dyn_reset(&ts->rcvbuf);
  } /* while there is buffer left and loop is requested */

  if(error)
    result = CURLE_RECV_ERROR;
  *done = (ts->keepon == KEEPON_DONE);
  if(!result && *done && data->info.httpproxycode/100 != 2) {
    /* Deal with the possibly already received authenticate
       headers. 'newurl' is set to a new URL if we must loop. */
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
                              strlen("CONNECT"))) {
    failf(data, "error setting method");
    result = CURLE_OUT_OF_MEMORY;
    goto error;
  }

    /* This only happens if we've looped here due to authentication
       reasons, and we don't really use the newly cloned URL here
       then. Just free() it. */
  Curl_safefree(data->req.newurl);

  result = CONNECT_host(cf, data, &authority, &host_header);
  if(result)
    goto error;








|
|







661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
  if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
                              strlen("CONNECT"))) {
    failf(data, "error setting method");
    result = CURLE_OUT_OF_MEMORY;
    goto error;
  }

    /* This only happens if we have looped here due to authentication
       reasons, and we do not really use the newly cloned URL here
       then. Just free() it. */
  Curl_safefree(data->req.newurl);

  result = CONNECT_host(cf, data, &authority, &host_header);
  if(result)
    goto error;

951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
      break;
    }

  } while(data->req.newurl);

  DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE);
  if(data->info.httpproxycode/100 != 2) {
    /* a non-2xx response and we have no next url to try. */
    Curl_safefree(data->req.newurl);
    /* failure, close this connection to avoid reuse */
    streamclose(conn, "proxy CONNECT failure");
    h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
    failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
    return CURLE_RECV_ERROR;
  }







|







950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
      break;
    }

  } while(data->req.newurl);

  DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE);
  if(data->info.httpproxycode/100 != 2) {
    /* a non-2xx response and we have no next URL to try. */
    Curl_safefree(data->req.newurl);
    /* failure, close this connection to avoid reuse */
    streamclose(conn, "proxy CONNECT failure");
    h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
    failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
    return CURLE_RECV_ERROR;
  }
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
  struct h1_tunnel_state *ts = cf->ctx;

  if(!cf->connected) {
    /* If we are not connected, but the filter "below" is
     * and not waiting on something, we are tunneling. */
    curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
    if(ts) {
      /* when we've sent a CONNECT to a proxy, we should rather either
         wait for the socket to become readable to be able to get the
         response headers or if we're still sending the request, wait
         for write. */
      if(tunnel_want_send(ts))
        Curl_pollset_set_out_only(data, ps, sock);
      else
        Curl_pollset_set_in_only(data, ps, sock);
    }
    else







|

|







1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
  struct h1_tunnel_state *ts = cf->ctx;

  if(!cf->connected) {
    /* If we are not connected, but the filter "below" is
     * and not waiting on something, we are tunneling. */
    curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
    if(ts) {
      /* when we have sent a CONNECT to a proxy, we should rather either
         wait for the socket to become readable to be able to get the
         response headers or if we are still sending the request, wait
         for write. */
      if(tunnel_want_send(ts))
        Curl_pollset_set_out_only(data, ps, sock);
      else
        Curl_pollset_set_in_only(data, ps, sock);
    }
    else
1073
1074
1075
1076
1077
1078
1079

1080
1081
1082
1083
1084
1085
1086
struct Curl_cftype Curl_cft_h1_proxy = {
  "H1-PROXY",
  CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
  0,
  cf_h1_proxy_destroy,
  cf_h1_proxy_connect,
  cf_h1_proxy_close,

  Curl_cf_http_proxy_get_host,
  cf_h1_proxy_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,







>







1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
struct Curl_cftype Curl_cft_h1_proxy = {
  "H1-PROXY",
  CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
  0,
  cf_h1_proxy_destroy,
  cf_h1_proxy_connect,
  cf_h1_proxy_close,
  Curl_cf_def_shutdown,
  Curl_cf_http_proxy_get_host,
  cf_h1_proxy_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
Changes to jni/curl/lib/cf-h2-proxy.c.
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
    data->state.authproxy.multipass = FALSE;
    FALLTHROUGH();
  case H2_TUNNEL_FAILED:
    if(new_state == H2_TUNNEL_FAILED)
      CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id);
    ts->state = new_state;
    /* If a proxy-authorization header was used for the proxy, then we should
       make sure that it isn't accidentally used for the document request
       after we've connected. So let's free and clear it here. */
    Curl_safefree(data->state.aptr.proxyuserpwd);
    break;
  }
}

struct cf_h2_proxy_ctx {
  nghttp2_session *h2;
  /* The easy handle used in the current filter call, cleared at return */
  struct cf_call_data call_data;

  struct bufq inbufq;  /* network receive buffer */
  struct bufq outbufq; /* network send buffer */

  struct tunnel_stream tunnel; /* our tunnel CONNECT stream */
  int32_t goaway_error;
  int32_t last_stream_id;
  BIT(conn_closed);
  BIT(goaway);

  BIT(nw_out_blocked);
};

/* How to access `call_data` from a cf_h2 filter */
#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf)  \
  ((struct cf_h2_proxy_ctx *)(cf)->ctx)->call_data







|
|

















|
>







158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
    data->state.authproxy.multipass = FALSE;
    FALLTHROUGH();
  case H2_TUNNEL_FAILED:
    if(new_state == H2_TUNNEL_FAILED)
      CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id);
    ts->state = new_state;
    /* If a proxy-authorization header was used for the proxy, then we should
       make sure that it is not accidentally used for the document request
       after we have connected. So let's free and clear it here. */
    Curl_safefree(data->state.aptr.proxyuserpwd);
    break;
  }
}

struct cf_h2_proxy_ctx {
  nghttp2_session *h2;
  /* The easy handle used in the current filter call, cleared at return */
  struct cf_call_data call_data;

  struct bufq inbufq;  /* network receive buffer */
  struct bufq outbufq; /* network send buffer */

  struct tunnel_stream tunnel; /* our tunnel CONNECT stream */
  int32_t goaway_error;
  int32_t last_stream_id;
  BIT(conn_closed);
  BIT(rcvd_goaway);
  BIT(sent_goaway);
  BIT(nw_out_blocked);
};

/* How to access `call_data` from a cf_h2 filter */
#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf)  \
  ((struct cf_h2_proxy_ctx *)(cf)->ctx)->call_data
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
       * servers send an explicit WINDOW_UPDATE, but not all seem to do that.
       * To be safe, we UNHOLD a stream in order not to stall. */
      if(CURL_WANT_SEND(data)) {
        drain_tunnel(cf, data, &ctx->tunnel);
      }
      break;
    case NGHTTP2_GOAWAY:
      ctx->goaway = TRUE;
      break;
    default:
      break;
    }
    return 0;
  }








|







691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
       * servers send an explicit WINDOW_UPDATE, but not all seem to do that.
       * To be safe, we UNHOLD a stream in order not to stall. */
      if(CURL_WANT_SEND(data)) {
        drain_tunnel(cf, data, &ctx->tunnel);
      }
      break;
    case NGHTTP2_GOAWAY:
      ctx->rcvd_goaway = TRUE;
      break;
    default:
      break;
    }
    return 0;
  }

1161
1162
1163
1164
1165
1166
1167











































1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184

1185
1186
1187





1188

1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203








1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224

  (void)data;
  if(ctx) {
    cf_h2_proxy_ctx_free(ctx);
    cf->ctx = NULL;
  }
}












































static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf,
                                     const struct Curl_easy *data)
{
  struct cf_h2_proxy_ctx *ctx = cf->ctx;
  if((ctx && !Curl_bufq_is_empty(&ctx->inbufq)) ||
     (ctx && ctx->tunnel.state == H2_TUNNEL_ESTABLISHED &&
      !Curl_bufq_is_empty(&ctx->tunnel.recvbuf)))
    return TRUE;
  return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
}

static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
                                       struct easy_pollset *ps)
{
  struct cf_h2_proxy_ctx *ctx = cf->ctx;

  curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
  bool want_recv, want_send;






  Curl_pollset_check(data, ps, sock, &want_recv, &want_send);

  if(ctx->h2 && (want_recv || want_send)) {
    struct cf_call_data save;
    bool c_exhaust, s_exhaust;

    CF_DATA_SAVE(save, cf, data);
    c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2);
    s_exhaust = ctx->tunnel.stream_id >= 0 &&
                !nghttp2_session_get_stream_remote_window_size(
                   ctx->h2, ctx->tunnel.stream_id);
    want_recv = (want_recv || c_exhaust || s_exhaust);
    want_send = (!s_exhaust && want_send) ||
                (!c_exhaust && nghttp2_session_want_write(ctx->h2));

    Curl_pollset_set(data, ps, sock, want_recv, want_send);
    CF_DATA_RESTORE(cf, save);








  }
}

static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
                                      struct Curl_easy *data,
                                      CURLcode *err)
{
  struct cf_h2_proxy_ctx *ctx = cf->ctx;
  ssize_t rv = 0;

  if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
    CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
                "connection", ctx->tunnel.stream_id);
    connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */
    *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
    return -1;
  }
  else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) {
    failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
          ctx->tunnel.stream_id, nghttp2_http2_strerror(ctx->tunnel.error),
          ctx->tunnel.error);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

















>



>
>
>
>
>
|
>

<













>
>
>
>
>
>
>
>













|







1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240

1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282

  (void)data;
  if(ctx) {
    cf_h2_proxy_ctx_free(ctx);
    cf->ctx = NULL;
  }
}

static CURLcode cf_h2_proxy_shutdown(struct Curl_cfilter *cf,
                                     struct Curl_easy *data, bool *done)
{
  struct cf_h2_proxy_ctx *ctx = cf->ctx;
  struct cf_call_data save;
  CURLcode result;
  int rv;

  if(!cf->connected || !ctx->h2 || cf->shutdown || ctx->conn_closed) {
    *done = TRUE;
    return CURLE_OK;
  }

  CF_DATA_SAVE(save, cf, data);

  if(!ctx->sent_goaway) {
    rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
                               0, 0,
                               (const uint8_t *)"shutown", sizeof("shutown"));
    if(rv) {
      failf(data, "nghttp2_submit_goaway() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      result = CURLE_SEND_ERROR;
      goto out;
    }
    ctx->sent_goaway = TRUE;
  }
  /* GOAWAY submitted, process egress and ingress until nghttp2 is done. */
  result = CURLE_OK;
  if(nghttp2_session_want_write(ctx->h2))
    result = proxy_h2_progress_egress(cf, data);
  if(!result && nghttp2_session_want_read(ctx->h2))
    result = proxy_h2_progress_ingress(cf, data);

  *done = (ctx->conn_closed ||
           (!result && !nghttp2_session_want_write(ctx->h2) &&
            !nghttp2_session_want_read(ctx->h2)));
out:
  CF_DATA_RESTORE(cf, save);
  cf->shutdown = (result || *done);
  return result;
}

static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf,
                                     const struct Curl_easy *data)
{
  struct cf_h2_proxy_ctx *ctx = cf->ctx;
  if((ctx && !Curl_bufq_is_empty(&ctx->inbufq)) ||
     (ctx && ctx->tunnel.state == H2_TUNNEL_ESTABLISHED &&
      !Curl_bufq_is_empty(&ctx->tunnel.recvbuf)))
    return TRUE;
  return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
}

static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
                                       struct easy_pollset *ps)
{
  struct cf_h2_proxy_ctx *ctx = cf->ctx;
  struct cf_call_data save;
  curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
  bool want_recv, want_send;

  if(!cf->connected && ctx->h2) {
    want_send = nghttp2_session_want_write(ctx->h2);
    want_recv = nghttp2_session_want_read(ctx->h2);
  }
  else
    Curl_pollset_check(data, ps, sock, &want_recv, &want_send);

  if(ctx->h2 && (want_recv || want_send)) {

    bool c_exhaust, s_exhaust;

    CF_DATA_SAVE(save, cf, data);
    c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2);
    s_exhaust = ctx->tunnel.stream_id >= 0 &&
                !nghttp2_session_get_stream_remote_window_size(
                   ctx->h2, ctx->tunnel.stream_id);
    want_recv = (want_recv || c_exhaust || s_exhaust);
    want_send = (!s_exhaust && want_send) ||
                (!c_exhaust && nghttp2_session_want_write(ctx->h2));

    Curl_pollset_set(data, ps, sock, want_recv, want_send);
    CF_DATA_RESTORE(cf, save);
  }
  else if(ctx->sent_goaway && !cf->shutdown) {
    /* shutdown in progress */
    CF_DATA_SAVE(save, cf, data);
    want_send = nghttp2_session_want_write(ctx->h2);
    want_recv = nghttp2_session_want_read(ctx->h2);
    Curl_pollset_set(data, ps, sock, want_recv, want_send);
    CF_DATA_RESTORE(cf, save);
  }
}

static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
                                      struct Curl_easy *data,
                                      CURLcode *err)
{
  struct cf_h2_proxy_ctx *ctx = cf->ctx;
  ssize_t rv = 0;

  if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
    CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
                "connection", ctx->tunnel.stream_id);
    connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
    *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
    return -1;
  }
  else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) {
    failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
          ctx->tunnel.stream_id, nghttp2_http2_strerror(ctx->tunnel.error),
          ctx->tunnel.error);
1255
1256
1257
1258
1259
1260
1261

1262
1263
1264
1265
1266
1267
1268
1269

  if(nread < 0) {
    if(ctx->tunnel.closed) {
      nread = h2_handle_tunnel_close(cf, data, err);
    }
    else if(ctx->tunnel.reset ||
            (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||

            (ctx->goaway && ctx->last_stream_id < ctx->tunnel.stream_id)) {
      *err = CURLE_RECV_ERROR;
      nread = -1;
    }
  }
  else if(nread == 0) {
    *err = CURLE_AGAIN;
    nread = -1;







>
|







1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328

  if(nread < 0) {
    if(ctx->tunnel.closed) {
      nread = h2_handle_tunnel_close(cf, data, err);
    }
    else if(ctx->tunnel.reset ||
            (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
            (ctx->rcvd_goaway &&
             ctx->last_stream_id < ctx->tunnel.stream_id)) {
      *err = CURLE_RECV_ERROR;
      nread = -1;
    }
  }
  else if(nread == 0) {
    *err = CURLE_AGAIN;
    nread = -1;
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
    CURL_TRC_CF(data, cf, "[%d] increase window by %zd",
                ctx->tunnel.stream_id, nread);
    nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread);
  }

  result = proxy_h2_progress_egress(cf, data);
  if(result == CURLE_AGAIN) {
    /* pending data to send, need to be called again. Ideally, we'd
     * monitor the socket for POLLOUT, but we might not be in SENDING
     * transfer state any longer and are unable to make this happen.
     */
    CURL_TRC_CF(data, cf, "[%d] egress blocked, DRAIN",
                ctx->tunnel.stream_id);
    drain_tunnel(cf, data, &ctx->tunnel);
  }







|







1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
    CURL_TRC_CF(data, cf, "[%d] increase window by %zd",
                ctx->tunnel.stream_id, nread);
    nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread);
  }

  result = proxy_h2_progress_egress(cf, data);
  if(result == CURLE_AGAIN) {
    /* pending data to send, need to be called again. Ideally, we would
     * monitor the socket for POLLOUT, but we might not be in SENDING
     * transfer state any longer and are unable to make this happen.
     */
    CURL_TRC_CF(data, cf, "[%d] egress blocked, DRAIN",
                ctx->tunnel.stream_id);
    drain_tunnel(cf, data, &ctx->tunnel);
  }
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
    blocked = 1;
  }

  if(blocked) {
    /* Unable to send all data, due to connection blocked or H2 window
     * exhaustion. Data is left in our stream buffer, or nghttp2's internal
     * frame buffer or our network out buffer. */
    size_t rwin = nghttp2_session_get_stream_remote_window_size(
                    ctx->h2, ctx->tunnel.stream_id);
    if(rwin == 0) {
      /* H2 flow window exhaustion.
       * FIXME: there is no way to HOLD all transfers that use this
       * proxy connection AND to UNHOLD all of them again when the
       * window increases.
       * We *could* iterate over all data on this conn maybe? */







|







1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
    blocked = 1;
  }

  if(blocked) {
    /* Unable to send all data, due to connection blocked or H2 window
     * exhaustion. Data is left in our stream buffer, or nghttp2's internal
     * frame buffer or our network out buffer. */
    size_t rwin = (size_t)nghttp2_session_get_stream_remote_window_size(
                    ctx->h2, ctx->tunnel.stream_id);
    if(rwin == 0) {
      /* H2 flow window exhaustion.
       * FIXME: there is no way to HOLD all transfers that use this
       * proxy connection AND to UNHOLD all of them again when the
       * window increases.
       * We *could* iterate over all data on this conn maybe? */
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
  bool alive = TRUE;

  *input_pending = FALSE;
  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    return FALSE;

  if(*input_pending) {
    /* This happens before we've sent off a request and the connection is
       not in use by any other transfer, there shouldn't be any data here,
       only "protocol frames" */
    CURLcode result;
    ssize_t nread = -1;

    *input_pending = FALSE;
    nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
    if(nread != -1) {







|
|







1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
  bool alive = TRUE;

  *input_pending = FALSE;
  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    return FALSE;

  if(*input_pending) {
    /* This happens before we have sent off a request and the connection is
       not in use by any other transfer, there should not be any data here,
       only "protocol frames" */
    CURLcode result;
    ssize_t nread = -1;

    *input_pending = FALSE;
    nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
    if(nread != -1) {
1533
1534
1535
1536
1537
1538
1539

1540
1541
1542
1543
1544
1545
1546
struct Curl_cftype Curl_cft_h2_proxy = {
  "H2-PROXY",
  CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
  CURL_LOG_LVL_NONE,
  cf_h2_proxy_destroy,
  cf_h2_proxy_connect,
  cf_h2_proxy_close,

  Curl_cf_http_proxy_get_host,
  cf_h2_proxy_adjust_pollset,
  cf_h2_proxy_data_pending,
  cf_h2_proxy_send,
  cf_h2_proxy_recv,
  Curl_cf_def_cntrl,
  cf_h2_proxy_is_alive,







>







1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
struct Curl_cftype Curl_cft_h2_proxy = {
  "H2-PROXY",
  CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
  CURL_LOG_LVL_NONE,
  cf_h2_proxy_destroy,
  cf_h2_proxy_connect,
  cf_h2_proxy_close,
  cf_h2_proxy_shutdown,
  Curl_cf_http_proxy_get_host,
  cf_h2_proxy_adjust_pollset,
  cf_h2_proxy_data_pending,
  cf_h2_proxy_send,
  cf_h2_proxy_recv,
  Curl_cf_def_cntrl,
  cf_h2_proxy_is_alive,
Changes to jni/curl/lib/cf-haproxy.c.
190
191
192
193
194
195
196

197
198
199
200
201
202
203
struct Curl_cftype Curl_cft_haproxy = {
  "HAPROXY",
  CF_TYPE_PROXY,
  0,
  cf_haproxy_destroy,
  cf_haproxy_connect,
  cf_haproxy_close,

  Curl_cf_def_get_host,
  cf_haproxy_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,







>







190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
struct Curl_cftype Curl_cft_haproxy = {
  "HAPROXY",
  CF_TYPE_PROXY,
  0,
  cf_haproxy_destroy,
  cf_haproxy_connect,
  cf_haproxy_close,
  Curl_cf_def_shutdown,
  Curl_cf_def_get_host,
  cf_haproxy_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
Changes to jni/curl/lib/cf-https-connect.c.
51
52
53
54
55
56
57
58

59
60
61
62
63
64
65

struct cf_hc_baller {
  const char *name;
  struct Curl_cfilter *cf;
  CURLcode result;
  struct curltime started;
  int reply_ms;
  bool enabled;

};

static void cf_hc_baller_reset(struct cf_hc_baller *b,
                               struct Curl_easy *data)
{
  if(b->cf) {
    Curl_conn_cf_close(b->cf, data);







|
>







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

struct cf_hc_baller {
  const char *name;
  struct Curl_cfilter *cf;
  CURLcode result;
  struct curltime started;
  int reply_ms;
  BIT(enabled);
  BIT(shutdown);
};

static void cf_hc_baller_reset(struct cf_hc_baller *b,
                               struct Curl_easy *data)
{
  if(b->cf) {
    Curl_conn_cf_close(b->cf, data);
317
318
319
320
321
322
323











































324
325
326
327
328
329
330
    break;
  }

out:
  CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
  return result;
}












































static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  struct easy_pollset *ps)
{
  if(!cf->connected) {
    struct cf_hc_ctx *ctx = cf->ctx;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
    break;
  }

out:
  CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
  return result;
}

static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
                               struct Curl_easy *data, bool *done)
{
  struct cf_hc_ctx *ctx = cf->ctx;
  struct cf_hc_baller *ballers[2];
  size_t i;
  CURLcode result = CURLE_OK;

  DEBUGASSERT(data);
  if(cf->connected) {
    *done = TRUE;
    return CURLE_OK;
  }

  /* shutdown all ballers that have not done so already. If one fails,
   * continue shutting down others until all are shutdown. */
  ballers[0] = &ctx->h3_baller;
  ballers[1] = &ctx->h21_baller;
  for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
    struct cf_hc_baller *b = ballers[i];
    bool bdone = FALSE;
    if(!cf_hc_baller_is_active(b) || b->shutdown)
      continue;
    b->result = b->cf->cft->do_shutdown(b->cf, data, &bdone);
    if(b->result || bdone)
      b->shutdown = TRUE; /* treat a failed shutdown as done */
  }

  *done = TRUE;
  for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
    if(ballers[i] && !ballers[i]->shutdown)
      *done = FALSE;
  }
  if(*done) {
    for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
      if(ballers[i] && ballers[i]->result)
        result = ballers[i]->result;
    }
  }
  CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
  return result;
}

static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  struct easy_pollset *ps)
{
  if(!cf->connected) {
    struct cf_hc_ctx *ctx = cf->ctx;
430
431
432
433
434
435
436

437
438
439
440
441
442
443
struct Curl_cftype Curl_cft_http_connect = {
  "HTTPS-CONNECT",
  0,
  CURL_LOG_LVL_NONE,
  cf_hc_destroy,
  cf_hc_connect,
  cf_hc_close,

  Curl_cf_def_get_host,
  cf_hc_adjust_pollset,
  cf_hc_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,







>







474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
struct Curl_cftype Curl_cft_http_connect = {
  "HTTPS-CONNECT",
  0,
  CURL_LOG_LVL_NONE,
  cf_hc_destroy,
  cf_hc_connect,
  cf_hc_close,
  cf_hc_shutdown,
  Curl_cf_def_get_host,
  cf_hc_adjust_pollset,
  cf_hc_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
  (void)remotehost;

  if(!conn->bits.tls_enable_alpn)
    goto out;

  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
    result = Curl_conn_may_http3(data, conn);
    if(result) /* can't do it */
      goto out;
    try_h3 = TRUE;
    try_h21 = FALSE;
  }
  else if(data->state.httpwant >= CURL_HTTP_VERSION_3) {
    /* We assume that silently not even trying H3 is ok here */
    /* TODO: should we fail instead? */







|







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  (void)remotehost;

  if(!conn->bits.tls_enable_alpn)
    goto out;

  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
    result = Curl_conn_may_http3(data, conn);
    if(result) /* cannot do it */
      goto out;
    try_h3 = TRUE;
    try_h21 = FALSE;
  }
  else if(data->state.httpwant >= CURL_HTTP_VERSION_3) {
    /* We assume that silently not even trying H3 is ok here */
    /* TODO: should we fail instead? */
Changes to jni/curl/lib/cf-socket.c.
31
32
33
34
35
36
37



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54





55
56
57
58
59
60
61
#include <sys/un.h> /* for sockaddr_un */
#endif
#ifdef HAVE_LINUX_TCP_H
#include <linux/tcp.h>
#elif defined(HAVE_NETINET_TCP_H)
#include <netinet/tcp.h>
#endif



#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif

#ifdef __VMS
#include <in.h>
#include <inet.h>
#endif






#include "urldata.h"
#include "bufq.h"
#include "sendf.h"
#include "if2ip.h"
#include "strerror.h"
#include "cfilters.h"







>
>
>

















>
>
>
>
>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <sys/un.h> /* for sockaddr_un */
#endif
#ifdef HAVE_LINUX_TCP_H
#include <linux/tcp.h>
#elif defined(HAVE_NETINET_TCP_H)
#include <netinet/tcp.h>
#endif
#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif

#ifdef __VMS
#include <in.h>
#include <inet.h>
#endif

#ifdef __DragonFly__
/* Required for __DragonFly_version */
#include <sys/param.h>
#endif

#include "urldata.h"
#include "bufq.h"
#include "sendf.h"
#include "if2ip.h"
#include "strerror.h"
#include "cfilters.h"
69
70
71
72
73
74
75

76
77
78
79
80
81
82
#include "inet_pton.h"
#include "progress.h"
#include "warnless.h"
#include "conncache.h"
#include "multihandle.h"
#include "rand.h"
#include "share.h"

#include "version_win32.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"








>







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "inet_pton.h"
#include "progress.h"
#include "warnless.h"
#include "conncache.h"
#include "multihandle.h"
#include "rand.h"
#include "share.h"
#include "strdup.h"
#include "version_win32.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

133
134
135
136
137
138
139
140




141
142
143
144
145
146
147
148
#endif
  }
}
#else
#define nosigpipe(x,y) Curl_nop_stmt
#endif

#if defined(__DragonFly__) || defined(USE_WINSOCK)




/* DragonFlyBSD and Windows use millisecond units */
#define KEEPALIVE_FACTOR(x) (x *= 1000)
#else
#define KEEPALIVE_FACTOR(x)
#endif

#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
#define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)







|
>
>
>
>
|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#endif
  }
}
#else
#define nosigpipe(x,y) Curl_nop_stmt
#endif

#if defined(USE_WINSOCK) || \
   (defined(__sun) && !defined(TCP_KEEPIDLE)) || \
   (defined(__DragonFly__) && __DragonFly_version < 500702) || \
   (defined(_WIN32) && !defined(TCP_KEEPIDLE))
/* Solaris < 11.4, DragonFlyBSD < 500702 and Windows < 10.0.16299
 * use millisecond units. */
#define KEEPALIVE_FACTOR(x) (x *= 1000)
#else
#define KEEPALIVE_FACTOR(x)
#endif

#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
#define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
164
165
166
167
168
169
170
171


























172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206










207
208
209
210
211
212
213
214
215






























216
217
218
219
220
221
222
  if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
        (void *)&optval, sizeof(optval)) < 0) {
    infof(data, "Failed to set SO_KEEPALIVE on fd "
          "%" CURL_FORMAT_SOCKET_T ": errno %d",
          sockfd, SOCKERRNO);
  }
  else {
#if defined(SIO_KEEPALIVE_VALS)


























    struct tcp_keepalive vals;
    DWORD dummy;
    vals.onoff = 1;
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    vals.keepalivetime = optval;
    optval = curlx_sltosi(data->set.tcp_keepintvl);
    KEEPALIVE_FACTOR(optval);
    vals.keepaliveinterval = optval;
    if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
                NULL, 0, &dummy, NULL, NULL) != 0) {
      infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
                  "%" CURL_FORMAT_SOCKET_T ": errno %d",
                  sockfd, SOCKERRNO);
    }

#else
#ifdef TCP_KEEPIDLE
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
          (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPIDLE on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
#elif defined(TCP_KEEPALIVE)
    /* Mac OS X style */
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
      (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPALIVE on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }










#endif
#ifdef TCP_KEEPINTVL
    optval = curlx_sltosi(data->set.tcp_keepintvl);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
          (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPINTVL on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);






























    }
#endif
#endif
  }
}

/**







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|


|






>
|



















>
>
>
>
>
>
>
>
>
>









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
        (void *)&optval, sizeof(optval)) < 0) {
    infof(data, "Failed to set SO_KEEPALIVE on fd "
          "%" CURL_FORMAT_SOCKET_T ": errno %d",
          sockfd, SOCKERRNO);
  }
  else {
#if defined(SIO_KEEPALIVE_VALS) /* Windows */
/* Windows 10, version 1709 (10.0.16299) and later versions */
#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
                (const char *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPIDLE on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
    optval = curlx_sltosi(data->set.tcp_keepintvl);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
                (const char *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPINTVL on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
    optval = curlx_sltosi(data->set.tcp_keepcnt);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
                (const char *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPCNT on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
#else /* Windows < 10.0.16299 */
    struct tcp_keepalive vals;
    DWORD dummy;
    vals.onoff = 1;
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    vals.keepalivetime = (u_long)optval;
    optval = curlx_sltosi(data->set.tcp_keepintvl);
    KEEPALIVE_FACTOR(optval);
    vals.keepaliveinterval = (u_long)optval;
    if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
                NULL, 0, &dummy, NULL, NULL) != 0) {
      infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
                  "%" CURL_FORMAT_SOCKET_T ": errno %d",
                  sockfd, SOCKERRNO);
    }
#endif
#else /* !Windows */
#ifdef TCP_KEEPIDLE
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
          (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPIDLE on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
#elif defined(TCP_KEEPALIVE)
    /* Mac OS X style */
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
      (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPALIVE on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
#elif defined(TCP_KEEPALIVE_THRESHOLD)
    /* Solaris <11.4 style */
    optval = curlx_sltosi(data->set.tcp_keepidle);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
      (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
#endif
#ifdef TCP_KEEPINTVL
    optval = curlx_sltosi(data->set.tcp_keepintvl);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
          (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPINTVL on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
#elif defined(TCP_KEEPALIVE_ABORT_THRESHOLD)
    /* Solaris <11.4 style */
    /* TCP_KEEPALIVE_ABORT_THRESHOLD should equal to
     * TCP_KEEPCNT * TCP_KEEPINTVL on other platforms.
     * The default value of TCP_KEEPCNT is 9 on Linux,
     * 8 on *BSD/macOS, 5 or 10 on Windows. We use the
     * default config for Solaris <11.4 because there is
     * no default value for TCP_KEEPCNT on Solaris 11.4.
     *
     * Note that the consequent probes will not be sent
     * at equal intervals on Solaris, but will be sent
     * using the exponential backoff algorithm. */
    optval = curlx_sltosi(data->set.tcp_keepcnt) *
             curlx_sltosi(data->set.tcp_keepintvl);
    KEEPALIVE_FACTOR(optval);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
          (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
#endif
#ifdef TCP_KEEPCNT
    optval = curlx_sltosi(data->set.tcp_keepcnt);
    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
                (void *)&optval, sizeof(optval)) < 0) {
      infof(data, "Failed to set TCP_KEEPCNT on fd "
            "%" CURL_FORMAT_SOCKET_T ": errno %d",
            sockfd, SOCKERRNO);
    }
#endif
#endif
  }
}

/**
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
    dest->protocol = IPPROTO_IP;
    break;
  default: /* UDP and QUIC */
    dest->socktype = SOCK_DGRAM;
    dest->protocol = IPPROTO_UDP;
    break;
  }
  dest->addrlen = ai->ai_addrlen;

  if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
    dest->addrlen = sizeof(struct Curl_sockaddr_storage);
  memcpy(&dest->sa_addr, ai->ai_addr, dest->addrlen);
}

static CURLcode socket_open(struct Curl_easy *data,







|







325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
    dest->protocol = IPPROTO_IP;
    break;
  default: /* UDP and QUIC */
    dest->socktype = SOCK_DGRAM;
    dest->protocol = IPPROTO_UDP;
    break;
  }
  dest->addrlen = (unsigned int)ai->ai_addrlen;

  if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
    dest->addrlen = sizeof(struct Curl_sockaddr_storage);
  memcpy(&dest->sa_addr, ai->ai_addr, dest->addrlen);
}

static CURLcode socket_open(struct Curl_easy *data,
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
                            struct Curl_sockaddr_ex *addr,
                            int transport,
                            curl_socket_t *sockfd)
{
  struct Curl_sockaddr_ex dummy;

  if(!addr)
    /* if the caller doesn't want info back, use a local temp copy */
    addr = &dummy;

  Curl_sock_assign_addr(addr, ai, transport);
  return socket_open(data, addr, sockfd);
}

static int socket_close(struct Curl_easy *data, struct connectdata *conn,







|







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
                            struct Curl_sockaddr_ex *addr,
                            int transport,
                            curl_socket_t *sockfd)
{
  struct Curl_sockaddr_ex dummy;

  if(!addr)
    /* if the caller does not want info back, use a local temp copy */
    addr = &dummy;

  Curl_sock_assign_addr(addr, ai, transport);
  return socket_open(data, addr, sockfd);
}

static int socket_close(struct Curl_easy *data, struct connectdata *conn,
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380

   https://support.microsoft.com/kb/823764

   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
   Buffer Size

   The problem described in this knowledge-base is applied only to pre-Vista
   Windows.  Following function trying to detect OS version and skips
   SO_SNDBUF adjustment for Windows Vista and above.
*/
#define DETECT_OS_NONE 0
#define DETECT_OS_PREVISTA 1
#define DETECT_OS_VISTA_OR_LATER 2

void Curl_sndbufset(curl_socket_t sockfd)
{
  int val = CURL_MAX_WRITE_SIZE + 32;
  int curval = 0;
  int curlen = sizeof(curval);

  static int detectOsState = DETECT_OS_NONE;








|






|







439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460

   https://support.microsoft.com/kb/823764

   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
   Buffer Size

   The problem described in this knowledge-base is applied only to pre-Vista
   Windows. Following function trying to detect OS version and skips
   SO_SNDBUF adjustment for Windows Vista and above.
*/
#define DETECT_OS_NONE 0
#define DETECT_OS_PREVISTA 1
#define DETECT_OS_VISTA_OR_LATER 2

void Curl_sndbuf_init(curl_socket_t sockfd)
{
  int val = CURL_MAX_WRITE_SIZE + 32;
  int curval = 0;
  int curlen = sizeof(curval);

  static int detectOsState = DETECT_OS_NONE;

391
392
393
394
395
396
397
398












































































399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417




418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471

472
473
474

475
476

477
478
479
480
481


482
483
484


485

486
487
488
489
490
491
492
493
494
495
496

497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538

  if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
    if(curval > val)
      return;

  setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
}
#endif













































































#ifndef CURL_DISABLE_BINDLOCAL
static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
                          curl_socket_t sockfd, int af, unsigned int scope)
{
  struct Curl_sockaddr_storage sa;
  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
#ifdef USE_IPV6
  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
#endif

  struct Curl_dns_entry *h = NULL;
  unsigned short port = data->set.localport; /* use this port number, 0 for
                                                "random" */
  /* how many port numbers to try to bind to, increasing one at a time */
  int portnum = data->set.localportrange;
  const char *dev = data->set.str[STRING_DEVICE];




  int error;
#ifdef IP_BIND_ADDRESS_NO_PORT
  int on = 1;
#endif
#ifndef USE_IPV6
  (void)scope;
#endif

  /*************************************************************
   * Select device to bind socket to
   *************************************************************/
  if(!dev && !port)
    /* no local kind of binding was requested */
    return CURLE_OK;

  memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));

  if(dev && (strlen(dev)<255) ) {
    char myhost[256] = "";
    int done = 0; /* -1 for error, 1 for address found */
    bool is_interface = FALSE;
    bool is_host = FALSE;
    static const char *if_prefix = "if!";
    static const char *host_prefix = "host!";

    if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
      dev += strlen(if_prefix);
      is_interface = TRUE;
    }
    else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
      dev += strlen(host_prefix);
      is_host = TRUE;
    }

    /* interface */
    if(!is_host) {
#ifdef SO_BINDTODEVICE
      /*
       * This binds the local socket to a particular interface. This will
       * force even requests to other local interfaces to go out the external
       * interface. Only bind to the interface when specified as interface,
       * not just as a hostname or ip address.
       *
       * The interface might be a VRF, eg: vrf-blue, which means it cannot be
       * converted to an IP address and would fail Curl_if2ip. Simply try to
       * use it straight away.
       */
      if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                    dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
        /* This is often "errno 1, error: Operation not permitted" if you're
         * not running as root or another suitable privileged user. If it
         * succeeds it means the parameter was a valid interface and not an IP
         * address. Return immediately.
         */

        infof(data, "socket successfully bound to interface '%s'", dev);
        return CURLE_OK;
      }

#endif


      switch(Curl_if2ip(af,
#ifdef USE_IPV6
                        scope, conn->scope_id,
#endif
                        dev, myhost, sizeof(myhost))) {


        case IF2IP_NOT_FOUND:
          if(is_interface) {
            /* Do not fall back to treating it as a host name */


            failf(data, "Couldn't bind to interface '%s'", dev);

            return CURLE_INTERFACE_FAILED;
          }
          break;
        case IF2IP_AF_NOT_SUPPORTED:
          /* Signal the caller to try another address family if available */
          return CURLE_UNSUPPORTED_PROTOCOL;
        case IF2IP_FOUND:
          is_interface = TRUE;
          /*
           * We now have the numerical IP address in the 'myhost' buffer
           */

          infof(data, "Local Interface %s is ip %s using address family %i",
                dev, myhost, af);
          done = 1;
          break;
      }
    }
    if(!is_interface) {
      /*
       * This was not an interface, resolve the name as a host name
       * or IP number
       *
       * Temporarily force name resolution to use only the address type
       * of the connection. The resolve functions should really be changed
       * to take a type parameter instead.
       */
      unsigned char ipver = conn->ip_version;
      int rc;

      if(af == AF_INET)
        conn->ip_version = CURL_IPRESOLVE_V4;
#ifdef USE_IPV6
      else if(af == AF_INET6)
        conn->ip_version = CURL_IPRESOLVE_V6;
#endif

      rc = Curl_resolv(data, dev, 80, FALSE, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_resolver_wait_resolv(data, &h);
      conn->ip_version = ipver;

      if(h) {
        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
        Curl_printable_address(h->addr, myhost, sizeof(myhost));
        infof(data, "Name '%s' family %i resolved to '%s' family %i",
              dev, af, myhost, h->addr->ai_family);
        Curl_resolv_unlock(data, h);
        if(af != h->addr->ai_family) {
          /* bad IP version combo, signal the caller to try another address
             family if available */
          return CURLE_UNSUPPORTED_PROTOCOL;
        }
        done = 1;







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



















>
>
>
>











|





|


<
<
<
<
|
<
<
<
|
<
<
<
<
<

<

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|


>

|
>
|

|

|
>
>
|
|
|
>
>
|
>
|
|
|
|
|
|
|
<
|
|
|
>
|
|
|
|
|
<
|

|
















|








|







471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597




598



599





600

601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647

648
649
650
651
652
653
654
655
656

657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692

  if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
    if(curval > val)
      return;

  setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
}
#endif /* USE_WINSOCK */

/*
 * Curl_parse_interface()
 *
 * This is used to parse interface argument in the following formats.
 * In all the examples, `host` can be an IP address or a hostname.
 *
 *   <iface_or_host> - can be either an interface name or a host.
 *   if!<iface> - interface name.
 *   host!<host> - hostname.
 *   ifhost!<iface>!<host> - interface name and hostname.
 *
 * Parameters:
 *
 * input  [in]     - input string.
 * len    [in]     - length of the input string.
 * dev    [in/out] - address where a pointer to newly allocated memory
 *                   holding the interface-or-host will be stored upon
 *                   completion.
 * iface  [in/out] - address where a pointer to newly allocated memory
 *                   holding the interface will be stored upon completion.
 * host   [in/out] - address where a pointer to newly allocated memory
 *                   holding the host will be stored upon completion.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_parse_interface(const char *input, size_t len,
                              char **dev, char **iface, char **host)
{
  static const char if_prefix[] = "if!";
  static const char host_prefix[] = "host!";
  static const char if_host_prefix[] = "ifhost!";

  DEBUGASSERT(dev);
  DEBUGASSERT(iface);
  DEBUGASSERT(host);

  if(strncmp(if_prefix, input, strlen(if_prefix)) == 0) {
    input += strlen(if_prefix);
    if(!*input)
      return CURLE_BAD_FUNCTION_ARGUMENT;
    *iface = Curl_memdup0(input, len - strlen(if_prefix));
    return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
  }
  if(strncmp(host_prefix, input, strlen(host_prefix)) == 0) {
    input += strlen(host_prefix);
    if(!*input)
      return CURLE_BAD_FUNCTION_ARGUMENT;
    *host = Curl_memdup0(input, len - strlen(host_prefix));
    return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
  }
  if(strncmp(if_host_prefix, input, strlen(if_host_prefix)) == 0) {
    const char *host_part;
    input += strlen(if_host_prefix);
    len -= strlen(if_host_prefix);
    host_part = memchr(input, '!', len);
    if(!host_part || !*(host_part + 1))
      return CURLE_BAD_FUNCTION_ARGUMENT;
    *iface = Curl_memdup0(input, host_part - input);
    if(!*iface)
      return CURLE_OUT_OF_MEMORY;
    ++host_part;
    *host = Curl_memdup0(host_part, len - (host_part - input));
    if(!*host) {
      free(*iface);
      *iface = NULL;
      return CURLE_OUT_OF_MEMORY;
    }
    return CURLE_OK;
  }

  if(!*input)
    return CURLE_BAD_FUNCTION_ARGUMENT;
  *dev = Curl_memdup0(input, len);
  return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY;
}

#ifndef CURL_DISABLE_BINDLOCAL
static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
                          curl_socket_t sockfd, int af, unsigned int scope)
{
  struct Curl_sockaddr_storage sa;
  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
#ifdef USE_IPV6
  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
#endif

  struct Curl_dns_entry *h = NULL;
  unsigned short port = data->set.localport; /* use this port number, 0 for
                                                "random" */
  /* how many port numbers to try to bind to, increasing one at a time */
  int portnum = data->set.localportrange;
  const char *dev = data->set.str[STRING_DEVICE];
  const char *iface_input = data->set.str[STRING_INTERFACE];
  const char *host_input = data->set.str[STRING_BINDHOST];
  const char *iface = iface_input ? iface_input : dev;
  const char *host = host_input ? host_input : dev;
  int error;
#ifdef IP_BIND_ADDRESS_NO_PORT
  int on = 1;
#endif
#ifndef USE_IPV6
  (void)scope;
#endif

  /*************************************************************
   * Select device to bind socket to
   *************************************************************/
  if(!iface && !host && !port)
    /* no local kind of binding was requested */
    return CURLE_OK;

  memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));

  if(iface && (strlen(iface)<255) ) {
    char myhost[256] = "";
    int done = 0; /* -1 for error, 1 for address found */




    if2ip_result_t if2ip_result = IF2IP_NOT_FOUND;









    /* interface */

#ifdef SO_BINDTODEVICE
    /*
      * This binds the local socket to a particular interface. This will
      * force even requests to other local interfaces to go out the external
      * interface. Only bind to the interface when specified as interface,
      * not just as a hostname or ip address.
      *
      * The interface might be a VRF, eg: vrf-blue, which means it cannot be
      * converted to an IP address and would fail Curl_if2ip. Simply try to
      * use it straight away.
      */
    if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                  iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
      /* This is often "errno 1, error: Operation not permitted" if you are
        * not running as root or another suitable privileged user. If it
        * succeeds it means the parameter was a valid interface and not an IP
        * address. Return immediately.
        */
      if(!host_input) {
        infof(data, "socket successfully bound to interface '%s'", iface);
        return CURLE_OK;
      }
    }
#endif
    if(!host_input) {
      /* Discover IP from input device, then bind to it */
      if2ip_result = Curl_if2ip(af,
#ifdef USE_IPV6
                      scope, conn->scope_id,
#endif
                      iface, myhost, sizeof(myhost));
    }
    switch(if2ip_result) {
      case IF2IP_NOT_FOUND:
        if(iface_input && !host_input) {
          /* Do not fall back to treating it as a hostname */
          char buffer[STRERROR_LEN];
          data->state.os_errno = error = SOCKERRNO;
          failf(data, "Couldn't bind to interface '%s' with errno %d: %s",
                iface, error, Curl_strerror(error, buffer, sizeof(buffer)));
          return CURLE_INTERFACE_FAILED;
        }
        break;
      case IF2IP_AF_NOT_SUPPORTED:
        /* Signal the caller to try another address family if available */
        return CURLE_UNSUPPORTED_PROTOCOL;
      case IF2IP_FOUND:

        /*
          * We now have the numerical IP address in the 'myhost' buffer
          */
        host = myhost;
        infof(data, "Local Interface %s is ip %s using address family %i",
              iface, host, af);
        done = 1;
        break;
    }

    if(!iface_input || host_input) {
      /*
       * This was not an interface, resolve the name as a hostname
       * or IP number
       *
       * Temporarily force name resolution to use only the address type
       * of the connection. The resolve functions should really be changed
       * to take a type parameter instead.
       */
      unsigned char ipver = conn->ip_version;
      int rc;

      if(af == AF_INET)
        conn->ip_version = CURL_IPRESOLVE_V4;
#ifdef USE_IPV6
      else if(af == AF_INET6)
        conn->ip_version = CURL_IPRESOLVE_V6;
#endif

      rc = Curl_resolv(data, host, 80, FALSE, &h);
      if(rc == CURLRESOLV_PENDING)
        (void)Curl_resolver_wait_resolv(data, &h);
      conn->ip_version = ipver;

      if(h) {
        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
        Curl_printable_address(h->addr, myhost, sizeof(myhost));
        infof(data, "Name '%s' family %i resolved to '%s' family %i",
              host, af, myhost, h->addr->ai_family);
        Curl_resolv_unlock(data, h);
        if(af != h->addr->ai_family) {
          /* bad IP version combo, signal the caller to try another address
             family if available */
          return CURLE_UNSUPPORTED_PROTOCOL;
        }
        done = 1;
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
        if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
          si6->sin6_family = AF_INET6;
          si6->sin6_port = htons(port);
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
          if(scope_ptr) {
            /* The "myhost" string either comes from Curl_if2ip or from
               Curl_printable_address. The latter returns only numeric scope
               IDs and the former returns none at all.  So the scope ID, if
               present, is known to be numeric */
            unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
            if(scope_id > UINT_MAX)
              return CURLE_UNSUPPORTED_PROTOCOL;

            si6->sin6_scope_id = (unsigned int)scope_id;
          }







|







712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
        if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
          si6->sin6_family = AF_INET6;
          si6->sin6_port = htons(port);
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
          if(scope_ptr) {
            /* The "myhost" string either comes from Curl_if2ip or from
               Curl_printable_address. The latter returns only numeric scope
               IDs and the former returns none at all. So the scope ID, if
               present, is known to be numeric */
            unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
            if(scope_id > UINT_MAX)
              return CURLE_UNSUPPORTED_PROTOCOL;

            si6->sin6_scope_id = (unsigned int)scope_id;
          }
585
586
587
588
589
590
591

592

593

594
595
596
597
598
599
600
      }
    }

    if(done < 1) {
      /* errorbuf is set false so failf will overwrite any message already in
         the error buffer, so the user receives this error message instead of a
         generic resolve error. */

      data->state.errorbuf = FALSE;

      failf(data, "Couldn't bind to '%s'", dev);

      return CURLE_INTERFACE_FAILED;
    }
  }
  else {
    /* no device was given, prepare sa to match af's needs */
#ifdef USE_IPV6
    if(af == AF_INET6) {







>

>
|
>







739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
      }
    }

    if(done < 1) {
      /* errorbuf is set false so failf will overwrite any message already in
         the error buffer, so the user receives this error message instead of a
         generic resolve error. */
      char buffer[STRERROR_LEN];
      data->state.errorbuf = FALSE;
      data->state.os_errno = error = SOCKERRNO;
      failf(data, "Couldn't bind to '%s' with errno %d: %s",
            host, error, Curl_strerror(error, buffer, sizeof(buffer)));
      return CURLE_INTERFACE_FAILED;
    }
  }
  else {
    /* no device was given, prepare sa to match af's needs */
#ifdef USE_IPV6
    if(af == AF_INET6) {
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
   * In October 2003 we effectively nullified this function on Windows due to
   * problems with it using all CPU in multi-threaded cases.
   *
   * In May 2004, we bring it back to offer more info back on connect failures.
   * Gisle Vanem could reproduce the former problems with this function, but
   * could avoid them by adding this SleepEx() call below:
   *
   *    "I don't have Rational Quantify, but the hint from his post was
   *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
   *    just Sleep(0) would be enough?) would release whatever
   *    mutex/critical-section the ntdll call is waiting on.
   *
   *    Someone got to verify this on Win-NT 4.0, 2000."
   */

#ifdef _WIN32_WCE
  Sleep(0);
#else
  SleepEx(0, FALSE);
#endif

#endif

  if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
    err = SOCKERRNO;
#ifdef _WIN32_WCE
  /* Old WinCE versions don't support SO_ERROR */
  if(WSAENOPROTOOPT == err) {
    SET_SOCKERRNO(0);
    err = 0;
  }
#endif
#if defined(EBADIOCTL) && defined(__minix)
  /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
  if(EBADIOCTL == err) {
    SET_SOCKERRNO(0);
    err = 0;
  }
#endif
  if((0 == err) || (EISCONN == err))
    /* we are connected, awesome! */
    rc = TRUE;
  else
    /* This wasn't a successful connect */
    rc = FALSE;
  if(error)
    *error = err;
#else
  (void)sockfd;
  if(error)
    *error = SOCKERRNO;







|
|

















|






|









|







820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
   * In October 2003 we effectively nullified this function on Windows due to
   * problems with it using all CPU in multi-threaded cases.
   *
   * In May 2004, we bring it back to offer more info back on connect failures.
   * Gisle Vanem could reproduce the former problems with this function, but
   * could avoid them by adding this SleepEx() call below:
   *
   *    "I do not have Rational Quantify, but the hint from his post was
   *    ntdll::NtRemoveIoCompletion(). I would assume the SleepEx (or maybe
   *    just Sleep(0) would be enough?) would release whatever
   *    mutex/critical-section the ntdll call is waiting on.
   *
   *    Someone got to verify this on Win-NT 4.0, 2000."
   */

#ifdef _WIN32_WCE
  Sleep(0);
#else
  SleepEx(0, FALSE);
#endif

#endif

  if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
    err = SOCKERRNO;
#ifdef _WIN32_WCE
  /* Old WinCE versions do not support SO_ERROR */
  if(WSAENOPROTOOPT == err) {
    SET_SOCKERRNO(0);
    err = 0;
  }
#endif
#if defined(EBADIOCTL) && defined(__minix)
  /* Minix 3.1.x does not support getsockopt on UDP sockets */
  if(EBADIOCTL == err) {
    SET_SOCKERRNO(0);
    err = 0;
  }
#endif
  if((0 == err) || (EISCONN == err))
    /* we are connected, awesome! */
    rc = TRUE;
  else
    /* This was not a successful connect */
    rc = FALSE;
  if(error)
    *error = err;
#else
  (void)sockfd;
  if(error)
    *error = SOCKERRNO;
761
762
763
764
765
766
767
768
769
770
771
772




773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
#define NW_RECV_CHUNKS         1
#define NW_SMALL_READS        (1024)

struct cf_socket_ctx {
  int transport;
  struct Curl_sockaddr_ex addr;      /* address to connect to */
  curl_socket_t sock;                /* current attempt socket */
  struct bufq recvbuf;               /* used when `buffer_recv` is set */
  struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
  struct curltime started_at;        /* when socket was created */
  struct curltime connected_at;      /* when socket connected/got first byte */
  struct curltime first_byte_at;     /* when first byte was recvd */




  int error;                         /* errno of last failure or 0 */
#ifdef DEBUGBUILD
  int wblock_percent;                /* percent of writes doing EAGAIN */
  int wpartial_percent;              /* percent of bytes written in send */
  int rblock_percent;                /* percent of reads doing EAGAIN */
  size_t recv_max;                  /* max enforced read size */
#endif
  BIT(got_first_byte);               /* if first byte was received */
  BIT(accepted);                     /* socket was accepted, not connected */
  BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
  BIT(active);
  BIT(buffer_recv);
};

static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
                               const struct Curl_addrinfo *ai,
                               int transport)
{
  memset(ctx, 0, sizeof(*ctx));
  ctx->sock = CURL_SOCKET_BAD;
  ctx->transport = transport;
  Curl_sock_assign_addr(&ctx->addr, ai, transport);
  Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
#ifdef DEBUGBUILD
  {
    char *p = getenv("CURL_DBG_SOCK_WBLOCK");
    if(p) {
      long l = strtol(p, NULL, 10);
      if(l >= 0 && l <= 100)
        ctx->wblock_percent = (int)l;







<




>
>
>
>











<










<







918
919
920
921
922
923
924

925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943

944
945
946
947
948
949
950
951
952
953

954
955
956
957
958
959
960
#define NW_RECV_CHUNKS         1
#define NW_SMALL_READS        (1024)

struct cf_socket_ctx {
  int transport;
  struct Curl_sockaddr_ex addr;      /* address to connect to */
  curl_socket_t sock;                /* current attempt socket */

  struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
  struct curltime started_at;        /* when socket was created */
  struct curltime connected_at;      /* when socket connected/got first byte */
  struct curltime first_byte_at;     /* when first byte was recvd */
#ifdef USE_WINSOCK
  struct curltime last_sndbuf_query_at;  /* when SO_SNDBUF last queried */
  ULONG sndbuf_size;                     /* the last set SO_SNDBUF size */
#endif
  int error;                         /* errno of last failure or 0 */
#ifdef DEBUGBUILD
  int wblock_percent;                /* percent of writes doing EAGAIN */
  int wpartial_percent;              /* percent of bytes written in send */
  int rblock_percent;                /* percent of reads doing EAGAIN */
  size_t recv_max;                  /* max enforced read size */
#endif
  BIT(got_first_byte);               /* if first byte was received */
  BIT(accepted);                     /* socket was accepted, not connected */
  BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
  BIT(active);

};

static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
                               const struct Curl_addrinfo *ai,
                               int transport)
{
  memset(ctx, 0, sizeof(*ctx));
  ctx->sock = CURL_SOCKET_BAD;
  ctx->transport = transport;
  Curl_sock_assign_addr(&ctx->addr, ai, transport);

#ifdef DEBUGBUILD
  {
    char *p = getenv("CURL_DBG_SOCK_WBLOCK");
    if(p) {
      long l = strtol(p, NULL, 10);
      if(l >= 0 && l <= 100)
        ctx->wblock_percent = (int)l;
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897























898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
      if(l >= 0)
        ctx->recv_max = (size_t)l;
    }
  }
#endif
}

struct reader_ctx {
  struct Curl_cfilter *cf;
  struct Curl_easy *data;
};

static ssize_t nw_in_read(void *reader_ctx,
                           unsigned char *buf, size_t len,
                           CURLcode *err)
{
  struct reader_ctx *rctx = reader_ctx;
  struct cf_socket_ctx *ctx = rctx->cf->ctx;
  ssize_t nread;

  *err = CURLE_OK;
  nread = sread(ctx->sock, buf, len);

  if(-1 == nread) {
    int sockerr = SOCKERRNO;

    if(
#ifdef WSAEWOULDBLOCK
      /* This is how Windows does it */
      (WSAEWOULDBLOCK == sockerr)
#else
      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
         due to its inability to send off data without blocking. We therefore
         treat both error codes the same here */
      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
#endif
      ) {
      /* this is just a case of EWOULDBLOCK */
      *err = CURLE_AGAIN;
      nread = -1;
    }
    else {
      char buffer[STRERROR_LEN];

      failf(rctx->data, "Recv failure: %s",
            Curl_strerror(sockerr, buffer, sizeof(buffer)));
      rctx->data->state.os_errno = sockerr;
      *err = CURLE_RECV_ERROR;
      nread = -1;
    }
  }
  CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu, fd=%"
              CURL_FORMAT_SOCKET_T ") -> %d, err=%d",
              len, ctx->sock, (int)nread, *err);
  return nread;
}

static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;

  if(ctx && CURL_SOCKET_BAD != ctx->sock) {
    CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
                ")", ctx->sock);
    if(ctx->sock == cf->conn->sock[cf->sockindex])
      cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
    socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
    ctx->sock = CURL_SOCKET_BAD;
    if(ctx->active && cf->sockindex == FIRSTSOCKET)
      cf->conn->remote_addr = NULL;
    Curl_bufq_reset(&ctx->recvbuf);
    ctx->active = FALSE;
    ctx->buffer_recv = FALSE;
    memset(&ctx->started_at, 0, sizeof(ctx->started_at));
    memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
  }

  cf->connected = FALSE;
}
























static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;

  cf_socket_close(cf, data);
  CURL_TRC_CF(data, cf, "destroy");
  Curl_bufq_free(&ctx->recvbuf);
  free(ctx);
  cf->ctx = NULL;
}

static CURLcode set_local_ip(struct Curl_cfilter *cf,
                             struct Curl_easy *data)
{







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<













<

<






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







<







977
978
979
980
981
982
983


















































984
985
986
987
988
989
990
991
992
993
994
995
996

997

998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033

1034
1035
1036
1037
1038
1039
1040
      if(l >= 0)
        ctx->recv_max = (size_t)l;
    }
  }
#endif
}



















































static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;

  if(ctx && CURL_SOCKET_BAD != ctx->sock) {
    CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
                ")", ctx->sock);
    if(ctx->sock == cf->conn->sock[cf->sockindex])
      cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
    socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
    ctx->sock = CURL_SOCKET_BAD;
    if(ctx->active && cf->sockindex == FIRSTSOCKET)
      cf->conn->remote_addr = NULL;

    ctx->active = FALSE;

    memset(&ctx->started_at, 0, sizeof(ctx->started_at));
    memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
  }

  cf->connected = FALSE;
}

static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   bool *done)
{
  if(cf->connected) {
    struct cf_socket_ctx *ctx = cf->ctx;

    CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" CURL_FORMAT_SOCKET_T
                ")", ctx->sock);
    /* On TCP, and when the socket looks well and non-blocking mode
     * can be enabled, receive dangling bytes before close to avoid
     * entering RST states unnecessarily. */
    if(ctx->sock != CURL_SOCKET_BAD &&
       ctx->transport == TRNSPRT_TCP &&
       (curlx_nonblock(ctx->sock, TRUE) >= 0)) {
      unsigned char buf[1024];
      (void)sread(ctx->sock, buf, sizeof(buf));
    }
  }
  *done = TRUE;
  return CURLE_OK;
}

static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;

  cf_socket_close(cf, data);
  CURL_TRC_CF(data, cf, "destroy");

  free(ctx);
  cf->ctx = NULL;
}

static CURLcode set_local_ip(struct Curl_cfilter *cf,
                             struct Curl_easy *data)
{
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959

static CURLcode set_remote_ip(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;

  /* store remote address and port used in this connection attempt */
  if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
    char buffer[STRERROR_LEN];

    ctx->error = errno;
    /* malformed address or bug in inet_ntop, try next address */
    failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
          errno, Curl_strerror(errno, buffer, sizeof(buffer)));







|







1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087

static CURLcode set_remote_ip(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;

  /* store remote address and port used in this connection attempt */
  if(!Curl_addr2string(&ctx->addr.sa_addr, (curl_socklen_t)ctx->addr.addrlen,
                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
    char buffer[STRERROR_LEN];

    ctx->error = errno;
    /* malformed address or bug in inet_ntop, try next address */
    failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
970
971
972
973
974
975
976








977





978
979
980
981
982
983
984
  bool isconnected = FALSE;
  CURLcode result = CURLE_COULDNT_CONNECT;
  bool is_tcp;

  (void)data;
  DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
  ctx->started_at = Curl_now();








  result = socket_open(data, &ctx->addr, &ctx->sock);





  if(result)
    goto out;

  result = set_remote_ip(cf, data);
  if(result)
    goto out;








>
>
>
>
>
>
>
>

>
>
>
>
>







1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  bool isconnected = FALSE;
  CURLcode result = CURLE_COULDNT_CONNECT;
  bool is_tcp;

  (void)data;
  DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
  ctx->started_at = Curl_now();
#ifdef SOCK_NONBLOCK
  /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
   * because we would not know how socketype is about to be used in the
   * callback, SOCK_NONBLOCK might get factored out before calling socket().
   */
  if(!data->set.fopensocket)
    ctx->addr.socktype |= SOCK_NONBLOCK;
#endif
  result = socket_open(data, &ctx->addr, &ctx->sock);
#ifdef SOCK_NONBLOCK
  /* Restore the socktype after the socket is created. */
  if(!data->set.fopensocket)
    ctx->addr.socktype &= ~SOCK_NONBLOCK;
#endif
  if(result)
    goto out;

  result = set_remote_ip(cf, data);
  if(result)
    goto out;

1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
           ctx->addr.socktype == SOCK_STREAM;
#endif
  if(is_tcp && data->set.tcp_nodelay)
    tcpnodelay(data, ctx->sock);

  nosigpipe(data, ctx->sock);

  Curl_sndbufset(ctx->sock);

  if(is_tcp && data->set.tcp_keepalive)
    tcpkeepalive(data, ctx->sock);

  if(data->set.fsockopt) {
    /* activate callback for setting socket options */
    Curl_set_in_callback(data, true);







|







1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
           ctx->addr.socktype == SOCK_STREAM;
#endif
  if(is_tcp && data->set.tcp_nodelay)
    tcpnodelay(data, ctx->sock);

  nosigpipe(data, ctx->sock);

  Curl_sndbuf_init(ctx->sock);

  if(is_tcp && data->set.tcp_keepalive)
    tcpkeepalive(data, ctx->sock);

  if(data->set.fsockopt) {
    /* activate callback for setting socket options */
    Curl_set_in_callback(data, true);
1041
1042
1043
1044
1045
1046
1047

1048

1049

















1050
1051
1052
1053
1054
1055
1056
        result = CURLE_COULDNT_CONNECT;
      }
      goto out;
    }
  }
#endif


  /* set socket non-blocking */

  (void)curlx_nonblock(ctx->sock, TRUE);

















  ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
out:
  if(result) {
    if(ctx->sock != CURL_SOCKET_BAD) {
      socket_close(data, cf->conn, TRUE, ctx->sock);
      ctx->sock = CURL_SOCKET_BAD;
    }







>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
        result = CURLE_COULDNT_CONNECT;
      }
      goto out;
    }
  }
#endif

#ifndef SOCK_NONBLOCK
  /* Set socket non-blocking, must be a non-blocking socket for
   * a non-blocking connect. */
  error = curlx_nonblock(ctx->sock, TRUE);
  if(error < 0) {
    result = CURLE_UNSUPPORTED_PROTOCOL;
    ctx->error = SOCKERRNO;
    goto out;
  }
#else
  if(data->set.fopensocket) {
    /* Set socket non-blocking, must be a non-blocking socket for
     * a non-blocking connect. */
    error = curlx_nonblock(ctx->sock, TRUE);
    if(error < 0) {
      result = CURLE_UNSUPPORTED_PROTOCOL;
      ctx->error = SOCKERRNO;
      goto out;
    }
  }
#endif
  ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
out:
  if(result) {
    if(ctx->sock != CURL_SOCKET_BAD) {
      socket_close(data, cf->conn, TRUE, ctx->sock);
      ctx->sock = CURL_SOCKET_BAD;
    }
1110
1111
1112
1113
1114
1115
1116
1117

1118
1119
1120
1121
1122
1123
1124
    if(cf->conn->given->flags & PROTOPT_SSL)
      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
    else
      rc = 0; /* Do nothing */
#endif
  }
  else {
    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);

  }
  return rc;
}

static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               bool blocking, bool *done)







|
>







1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
    if(cf->conn->given->flags & PROTOPT_SSL)
      rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
    else
      rc = 0; /* Do nothing */
#endif
  }
  else {
    rc = connect(ctx->sock, &ctx->addr.sa_addr,
                 (curl_socklen_t)ctx->addr.addrlen);
  }
  return rc;
}

static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               bool blocking, bool *done)
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266


























1267
1268
1269
1270
1271
1272
1273
static bool cf_socket_data_pending(struct Curl_cfilter *cf,
                                   const struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;
  int readable;

  (void)data;
  if(!Curl_bufq_is_empty(&ctx->recvbuf))
    return TRUE;

  readable = SOCKET_READABLE(ctx->sock, 0);
  return (readable > 0 && (readable & CURL_CSELECT_IN));
}



























static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
                              const void *buf, size_t len, CURLcode *err)
{
  struct cf_socket_ctx *ctx = cf->ctx;
  curl_socket_t fdsave;
  ssize_t nwritten;
  size_t orig_len = len;







<
<
<




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1414
1415
1416
1417
1418
1419
1420



1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
static bool cf_socket_data_pending(struct Curl_cfilter *cf,
                                   const struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;
  int readable;

  (void)data;



  readable = SOCKET_READABLE(ctx->sock, 0);
  return (readable > 0 && (readable & CURL_CSELECT_IN));
}

#ifdef USE_WINSOCK

#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
#endif

static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
{
  ULONG ideal;
  DWORD ideallen;
  struct curltime n = Curl_now();

  if(Curl_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
    if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
                  &ideal, sizeof(ideal), &ideallen, 0, 0) &&
       ideal != ctx->sndbuf_size &&
       !setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF,
                   (const char *)&ideal, sizeof(ideal))) {
      ctx->sndbuf_size = ideal;
    }
    ctx->last_sndbuf_query_at = n;
  }
}

#endif /* USE_WINSOCK */

static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
                              const void *buf, size_t len, CURLcode *err)
{
  struct cf_socket_ctx *ctx = cf->ctx;
  curl_socket_t fdsave;
  ssize_t nwritten;
  size_t orig_len = len;
1331
1332
1333
1334
1335
1336
1337





1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383

1384
1385

1386
1387
1388
1389
1390


1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403

1404

1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
      char buffer[STRERROR_LEN];
      failf(data, "Send failure: %s",
            Curl_strerror(sockerr, buffer, sizeof(buffer)));
      data->state.os_errno = sockerr;
      *err = CURLE_SEND_ERROR;
    }
  }






  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
              orig_len, (int)nwritten, *err);
  cf->conn->sock[cf->sockindex] = fdsave;
  return nwritten;
}

static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
                              char *buf, size_t len, CURLcode *err)
{
  struct cf_socket_ctx *ctx = cf->ctx;
  curl_socket_t fdsave;
  ssize_t nread;

  *err = CURLE_OK;

  fdsave = cf->conn->sock[cf->sockindex];
  cf->conn->sock[cf->sockindex] = ctx->sock;

#ifdef DEBUGBUILD
  /* simulate network blocking/partial reads */
  if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
    unsigned char c = 0;
    Curl_rand(data, &c, 1);
    if(c >= ((100-ctx->rblock_percent)*256/100)) {
      CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
      *err = CURLE_AGAIN;
      nread = -1;
      cf->conn->sock[cf->sockindex] = fdsave;
      return nread;
    }
  }
  if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
    size_t orig_len = len;
    len = ctx->recv_max;
    CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
                orig_len, len);
  }
#endif

  if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
    CURL_TRC_CF(data, cf, "recv from buffer");
    nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
  }
  else {
    struct reader_ctx rctx;


    rctx.cf = cf;

    rctx.data = data;

    /* "small" reads may trigger filling our buffer, "large" reads
     * are probably not worth the additional copy */
    if(ctx->buffer_recv && len < NW_SMALL_READS) {


      ssize_t nwritten;
      nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err);
      if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
        /* we have a partial read with an error. need to deliver
         * what we got, return the error later. */
        CURL_TRC_CF(data, cf, "partial read: empty buffer first");
        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
      }
      else if(nwritten < 0) {
        nread = -1;
        goto out;
      }
      else if(nwritten == 0) {

        /* eof */

        *err = CURLE_OK;
        nread = 0;
      }
      else {
        CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
      }
    }
    else {
      nread = nw_in_read(&rctx, (unsigned char *)buf, len, err);
    }
  }

out:
  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
              *err);
  if(nread > 0 && !ctx->got_first_byte) {
    ctx->first_byte_at = Curl_now();
    ctx->got_first_byte = TRUE;
  }
  cf->conn->sock[cf->sockindex] = fdsave;
  return nread;
}

static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;








>
>
>
>
>











<




<
<
<








<
<
|










<
|
|
|
<
|
>

|
>
|
|
|
|
|
>
>
|
<
|
<
|
|
<
|
|
|
<
|
<
>
|
>
|
<
|
<
<
<
|
|
<
<
<
<
<
<






<







1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537

1538
1539
1540
1541



1542
1543
1544
1545
1546
1547
1548
1549


1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560

1561
1562
1563

1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576

1577

1578
1579

1580
1581
1582

1583

1584
1585
1586
1587

1588



1589
1590






1591
1592
1593
1594
1595
1596

1597
1598
1599
1600
1601
1602
1603
      char buffer[STRERROR_LEN];
      failf(data, "Send failure: %s",
            Curl_strerror(sockerr, buffer, sizeof(buffer)));
      data->state.os_errno = sockerr;
      *err = CURLE_SEND_ERROR;
    }
  }

#if defined(USE_WINSOCK)
  if(!*err)
    win_update_sndbuf_size(ctx);
#endif

  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
              orig_len, (int)nwritten, *err);
  cf->conn->sock[cf->sockindex] = fdsave;
  return nwritten;
}

static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
                              char *buf, size_t len, CURLcode *err)
{
  struct cf_socket_ctx *ctx = cf->ctx;

  ssize_t nread;

  *err = CURLE_OK;




#ifdef DEBUGBUILD
  /* simulate network blocking/partial reads */
  if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
    unsigned char c = 0;
    Curl_rand(data, &c, 1);
    if(c >= ((100-ctx->rblock_percent)*256/100)) {
      CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
      *err = CURLE_AGAIN;


      return -1;
    }
  }
  if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
    size_t orig_len = len;
    len = ctx->recv_max;
    CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
                orig_len, len);
  }
#endif


  *err = CURLE_OK;
  nread = sread(ctx->sock, buf, len);


  if(-1 == nread) {
    int sockerr = SOCKERRNO;

    if(
#ifdef WSAEWOULDBLOCK
      /* This is how Windows does it */
      (WSAEWOULDBLOCK == sockerr)
#else
      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
         due to its inability to send off data without blocking. We therefore
         treat both error codes the same here */
      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
#endif

      ) {

      /* this is just a case of EWOULDBLOCK */
      *err = CURLE_AGAIN;

    }
    else {
      char buffer[STRERROR_LEN];



      failf(data, "Recv failure: %s",
            Curl_strerror(sockerr, buffer, sizeof(buffer)));
      data->state.os_errno = sockerr;
      *err = CURLE_RECV_ERROR;

    }



  }







  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
              *err);
  if(nread > 0 && !ctx->got_first_byte) {
    ctx->first_byte_at = Curl_now();
    ctx->got_first_byte = TRUE;
  }

  return nread;
}

static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;

1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
  /* the first socket info gets some specials */
  if(cf->sockindex == FIRSTSOCKET) {
    cf->conn->remote_addr = &ctx->addr;
  #ifdef USE_IPV6
    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
  #endif
    Curl_persistconninfo(data, cf->conn, &ctx->ip);
    /* buffering is currently disabled by default because we have stalls
     * in parallel transfers where not all buffered data is consumed and no
     * socket events happen.
     */
    ctx->buffer_recv = FALSE;
  }
  ctx->active = TRUE;
}

static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                int event, int arg1, void *arg2)







<
<
<
<
<







1611
1612
1613
1614
1615
1616
1617





1618
1619
1620
1621
1622
1623
1624
  /* the first socket info gets some specials */
  if(cf->sockindex == FIRSTSOCKET) {
    cf->conn->remote_addr = &ctx->addr;
  #ifdef USE_IPV6
    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
  #endif
    Curl_persistconninfo(data, cf->conn, &ctx->ip);





  }
  ctx->active = TRUE;
}

static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                int event, int arg1, void *arg2)
1560
1561
1562
1563
1564
1565
1566

1567
1568
1569
1570
1571
1572
1573
struct Curl_cftype Curl_cft_tcp = {
  "TCP",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_socket_destroy,
  cf_tcp_connect,
  cf_socket_close,

  cf_socket_get_host,
  cf_socket_adjust_pollset,
  cf_socket_data_pending,
  cf_socket_send,
  cf_socket_recv,
  cf_socket_cntrl,
  cf_socket_conn_is_alive,







>







1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
struct Curl_cftype Curl_cft_tcp = {
  "TCP",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_socket_destroy,
  cf_tcp_connect,
  cf_socket_close,
  cf_socket_shutdown,
  cf_socket_get_host,
  cf_socket_adjust_pollset,
  cf_socket_data_pending,
  cf_socket_send,
  cf_socket_recv,
  cf_socket_cntrl,
  cf_socket_conn_is_alive,
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614



1615
1616
1617
1618
1619
1620
1621
1622
1623
1624

1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636



1637

1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655








1656
1657
1658
1659
1660
1661
1662
    Curl_safefree(ctx);
  }

  return result;
}

static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
                               struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;
  int rc;




  /* QUIC needs a connected socket, nonblocking */
  DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);

#if defined(__APPLE__) && defined(USE_OPENSSL_QUIC)
  (void)rc;
  /* On macOS OpenSSL QUIC fails on connected sockets.
   * see: <https://github.com/openssl/openssl/issues/23251> */
#else
  rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);

  if(-1 == rc) {
    return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
  }
  ctx->sock_connected = TRUE;
#endif
  set_local_ip(cf, data);
  CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
              " connected: [%s:%d] -> [%s:%d]",
              (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
              ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
              ctx->ip.remote_ip, ctx->ip.remote_port);




  (void)curlx_nonblock(ctx->sock, TRUE);

  switch(ctx->addr.family) {
#if defined(__linux__) && defined(IP_MTU_DISCOVER)
  case AF_INET: {
    int val = IP_PMTUDISC_DO;
    (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
                     sizeof(val));
    break;
  }
#endif
#if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
  case AF_INET6: {
    int val = IPV6_PMTUDISC_DO;
    (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
                     sizeof(val));
    break;
  }
#endif
  }








  return CURLE_OK;
}

static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               bool blocking, bool *done)
{







|



>
>
>




<
<
<
<
<
|
>




<







>
>
>
|
>


















>
>
>
>
>
>
>
>







1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788





1789
1790
1791
1792
1793
1794

1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
    Curl_safefree(ctx);
  }

  return result;
}

static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
                                  struct Curl_easy *data)
{
  struct cf_socket_ctx *ctx = cf->ctx;
  int rc;
  int one = 1;

  (void)one;

  /* QUIC needs a connected socket, nonblocking */
  DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);






  rc = connect(ctx->sock, &ctx->addr.sa_addr,
               (curl_socklen_t)ctx->addr.addrlen);
  if(-1 == rc) {
    return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
  }
  ctx->sock_connected = TRUE;

  set_local_ip(cf, data);
  CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
              " connected: [%s:%d] -> [%s:%d]",
              (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
              ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
              ctx->ip.remote_ip, ctx->ip.remote_port);

  /* Currently, cf->ctx->sock is always non-blocking because the only
   * caller to cf_udp_setup_quic() is cf_udp_connect() that passes the
   * non-blocking socket created by cf_socket_open() to it. Thus, we
   * do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
   */
  switch(ctx->addr.family) {
#if defined(__linux__) && defined(IP_MTU_DISCOVER)
  case AF_INET: {
    int val = IP_PMTUDISC_DO;
    (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
                     sizeof(val));
    break;
  }
#endif
#if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
  case AF_INET6: {
    int val = IPV6_PMTUDISC_DO;
    (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
                     sizeof(val));
    break;
  }
#endif
  }

#if defined(__linux__) && defined(UDP_GRO) &&                                 \
  (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) &&                        \
  ((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
  (void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
                   (socklen_t)sizeof(one));
#endif

  return CURLE_OK;
}

static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               bool blocking, bool *done)
{
1698
1699
1700
1701
1702
1703
1704

1705
1706
1707
1708
1709
1710
1711
struct Curl_cftype Curl_cft_udp = {
  "UDP",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_socket_destroy,
  cf_udp_connect,
  cf_socket_close,

  cf_socket_get_host,
  cf_socket_adjust_pollset,
  cf_socket_data_pending,
  cf_socket_send,
  cf_socket_recv,
  cf_socket_cntrl,
  cf_socket_conn_is_alive,







>







1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
struct Curl_cftype Curl_cft_udp = {
  "UDP",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_socket_destroy,
  cf_udp_connect,
  cf_socket_close,
  cf_socket_shutdown,
  cf_socket_get_host,
  cf_socket_adjust_pollset,
  cf_socket_data_pending,
  cf_socket_send,
  cf_socket_recv,
  cf_socket_cntrl,
  cf_socket_conn_is_alive,
1749
1750
1751
1752
1753
1754
1755

1756
1757
1758
1759
1760
1761
1762
struct Curl_cftype Curl_cft_unix = {
  "UNIX",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_socket_destroy,
  cf_tcp_connect,
  cf_socket_close,

  cf_socket_get_host,
  cf_socket_adjust_pollset,
  cf_socket_data_pending,
  cf_socket_send,
  cf_socket_recv,
  cf_socket_cntrl,
  cf_socket_conn_is_alive,







>







1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
struct Curl_cftype Curl_cft_unix = {
  "UNIX",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_socket_destroy,
  cf_tcp_connect,
  cf_socket_close,
  cf_socket_shutdown,
  cf_socket_get_host,
  cf_socket_adjust_pollset,
  cf_socket_data_pending,
  cf_socket_send,
  cf_socket_recv,
  cf_socket_cntrl,
  cf_socket_conn_is_alive,
1813
1814
1815
1816
1817
1818
1819

1820
1821
1822
1823
1824
1825
1826
struct Curl_cftype Curl_cft_tcp_accept = {
  "TCP-ACCEPT",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_socket_destroy,
  cf_tcp_accept_connect,
  cf_socket_close,

  cf_socket_get_host,              /* TODO: not accurate */
  cf_socket_adjust_pollset,
  cf_socket_data_pending,
  cf_socket_send,
  cf_socket_recv,
  cf_socket_cntrl,
  cf_socket_conn_is_alive,







>







1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
struct Curl_cftype Curl_cft_tcp_accept = {
  "TCP-ACCEPT",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_socket_destroy,
  cf_tcp_accept_connect,
  cf_socket_close,
  cf_socket_shutdown,
  cf_socket_get_host,              /* TODO: not accurate */
  cf_socket_adjust_pollset,
  cf_socket_data_pending,
  cf_socket_send,
  cf_socket_recv,
  cf_socket_cntrl,
  cf_socket_conn_is_alive,
Changes to jni/curl/lib/cf-socket.h.
50
51
52
53
54
55
56





57
58
59
60
61
62
63
  union {
    struct sockaddr addr;
    struct Curl_sockaddr_storage buff;
  } _sa_ex_u;
};
#define sa_addr _sa_ex_u.addr







/*
 * Create a socket based on info from 'conn' and 'ai'.
 *
 * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open
 * socket callback is set, used that!
 *







>
>
>
>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  union {
    struct sockaddr addr;
    struct Curl_sockaddr_storage buff;
  } _sa_ex_u;
};
#define sa_addr _sa_ex_u.addr

/*
 * Parse interface option, and return the interface name and the host part.
*/
CURLcode Curl_parse_interface(const char *input, size_t len,
                              char **dev, char **iface, char **host);

/*
 * Create a socket based on info from 'conn' and 'ai'.
 *
 * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open
 * socket callback is set, used that!
 *
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

   https://support.microsoft.com/kb/823764

   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
   Buffer Size

*/
void Curl_sndbufset(curl_socket_t sockfd);
#else
#define Curl_sndbufset(y) Curl_nop_stmt
#endif

/**
 * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
 * set the transport used.
 */
void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,







|

|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

   https://support.microsoft.com/kb/823764

   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
   Buffer Size

*/
void Curl_sndbuf_init(curl_socket_t sockfd);
#else
#define Curl_sndbuf_init(y) Curl_nop_stmt
#endif

/**
 * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
 * set the transport used.
 */
void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
Changes to jni/curl/lib/cfilters.c.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56









57
58
59
60
61
62
63
#include "curl_memory.h"
#include "memdebug.h"

#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif

#ifdef DEBUGBUILD
/* used by unit2600.c */
void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  cf->connected = FALSE;
  if(cf->next)
    cf->next->cft->do_close(cf->next, data);
}
#endif










static void conn_report_connect_stats(struct Curl_easy *data,
                                      struct connectdata *conn);

void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
                          const char **phost, const char **pdisplay_host,
                          int *pport)







|








>
>
>
>
>
>
>
>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "curl_memory.h"
#include "memdebug.h"

#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif

#ifdef UNITTESTS
/* used by unit2600.c */
void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  cf->connected = FALSE;
  if(cf->next)
    cf->next->cft->do_close(cf->next, data);
}
#endif

CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
                              struct Curl_easy *data, bool *done)
{
  (void)cf;
  (void)data;
  *done = TRUE;
  return CURLE_OK;
}

static void conn_report_connect_stats(struct Curl_easy *data,
                                      struct connectdata *conn);

void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
                          const char **phost, const char **pdisplay_host,
                          int *pport)
162
163
164
165
166
167
168























































169
170
171
172
173
174
175

  DEBUGASSERT(data->conn);
  /* it is valid to call that without filters being present */
  cf = data->conn->cfilter[index];
  if(cf) {
    cf->cft->do_close(cf, data);
  }























































}

ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
                     size_t len, CURLcode *code)
{
  struct Curl_cfilter *cf;








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239

  DEBUGASSERT(data->conn);
  /* it is valid to call that without filters being present */
  cf = data->conn->cfilter[index];
  if(cf) {
    cf->cft->do_close(cf, data);
  }
  Curl_shutdown_clear(data, index);
}

CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
{
  struct Curl_cfilter *cf;
  CURLcode result = CURLE_OK;
  timediff_t timeout_ms;
  struct curltime now;

  DEBUGASSERT(data->conn);
  /* Get the first connected filter that is not shut down already. */
  cf = data->conn->cfilter[sockindex];
  while(cf && (!cf->connected || cf->shutdown))
    cf = cf->next;

  if(!cf) {
    *done = TRUE;
    return CURLE_OK;
  }

  *done = FALSE;
  now = Curl_now();
  if(!Curl_shutdown_started(data, sockindex)) {
    DEBUGF(infof(data, "shutdown start on%s connection",
           sockindex? " secondary" : ""));
    Curl_shutdown_start(data, sockindex, &now);
  }
  else {
    timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
    if(timeout_ms < 0) {
      failf(data, "SSL shutdown timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }
  }

  while(cf) {
    if(!cf->shutdown) {
      bool cfdone = FALSE;
      result = cf->cft->do_shutdown(cf, data, &cfdone);
      if(result) {
        CURL_TRC_CF(data, cf, "shut down failed with %d", result);
        return result;
      }
      else if(!cfdone) {
        CURL_TRC_CF(data, cf, "shut down not done yet");
        return CURLE_OK;
      }
      CURL_TRC_CF(data, cf, "shut down successfully");
      cf->shutdown = TRUE;
    }
    cf = cf->next;
  }
  *done = (!result);
  return result;
}

ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
                     size_t len, CURLcode *code)
{
  struct Curl_cfilter *cf;

341
342
343
344
345
346
347
348

349

350
351
352
353
354
355
356
  CURLcode result = CURLE_OK;

  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);

  cf = data->conn->cfilter[sockindex];
  DEBUGASSERT(cf);
  if(!cf)

    return CURLE_FAILED_INIT;


  *done = cf->connected;
  if(!*done) {
    result = cf->cft->do_connect(cf, data, blocking, done);
    if(!result && *done) {
      Curl_conn_ev_update_info(data, data->conn);
      conn_report_connect_stats(data, data->conn);







|
>

>







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
  CURLcode result = CURLE_OK;

  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);

  cf = data->conn->cfilter[sockindex];
  DEBUGASSERT(cf);
  if(!cf) {
    *done = FALSE;
    return CURLE_FAILED_INIT;
  }

  *done = cf->connected;
  if(!*done) {
    result = cf->cft->do_connect(cf, data, blocking, done);
    if(!result && *done) {
      Curl_conn_ev_update_info(data, data->conn);
      conn_report_connect_stats(data, data->conn);
437
438
439
440
441
442
443



444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463




































464
465
466
467
468
469
470

void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 struct easy_pollset *ps)
{
  /* Get the lowest not-connected filter, if there are any */
  while(cf && !cf->connected && cf->next && !cf->next->connected)



    cf = cf->next;
  /* From there on, give all filters a chance to adjust the pollset.
   * Lower filters are called later, so they may override */
  while(cf) {
    cf->cft->adjust_pollset(cf, data, ps);
    cf = cf->next;
  }
}

void Curl_conn_adjust_pollset(struct Curl_easy *data,
                               struct easy_pollset *ps)
{
  int i;

  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);
  for(i = 0; i < 2; ++i) {
    Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
  }
}





































void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
                        const char **phost, const char **pdisplay_host,
                        int *pport)
{
  struct Curl_cfilter *cf;








>
>
>




















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575

void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 struct easy_pollset *ps)
{
  /* Get the lowest not-connected filter, if there are any */
  while(cf && !cf->connected && cf->next && !cf->next->connected)
    cf = cf->next;
  /* Skip all filters that have already shut down */
  while(cf && cf->shutdown)
    cf = cf->next;
  /* From there on, give all filters a chance to adjust the pollset.
   * Lower filters are called later, so they may override */
  while(cf) {
    cf->cft->adjust_pollset(cf, data, ps);
    cf = cf->next;
  }
}

void Curl_conn_adjust_pollset(struct Curl_easy *data,
                               struct easy_pollset *ps)
{
  int i;

  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);
  for(i = 0; i < 2; ++i) {
    Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
  }
}

int Curl_conn_cf_poll(struct Curl_cfilter *cf,
                      struct Curl_easy *data,
                      timediff_t timeout_ms)
{
  struct easy_pollset ps;
  struct pollfd pfds[MAX_SOCKSPEREASYHANDLE];
  unsigned int i, npfds = 0;

  DEBUGASSERT(cf);
  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);
  memset(&ps, 0, sizeof(ps));
  memset(pfds, 0, sizeof(pfds));

  Curl_conn_cf_adjust_pollset(cf, data, &ps);
  DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE);
  for(i = 0; i < ps.num; ++i) {
    short events = 0;
    if(ps.actions[i] & CURL_POLL_IN) {
      events |= POLLIN;
    }
    if(ps.actions[i] & CURL_POLL_OUT) {
      events |= POLLOUT;
    }
    if(events) {
      pfds[npfds].fd = ps.sockets[i];
      pfds[npfds].events = events;
      ++npfds;
    }
  }

  if(!npfds)
    DEBUGF(infof(data, "no sockets to poll!"));
  return Curl_poll(pfds, npfds, timeout_ms);
}

void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
                        const char **phost, const char **pdisplay_host,
                        int *pport)
{
  struct Curl_cfilter *cf;

714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
  struct connectdata *conn;

  DEBUGASSERT(sockindex >= 0 && sockindex < 2);
  DEBUGASSERT(pnwritten);
  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);
  conn = data->conn;
#ifdef CURLDEBUG
  {
    /* Allow debug builds to override this logic to force short sends
    */
    char *p = getenv("CURL_SMALLSENDS");
    if(p) {
      size_t altsize = (size_t)strtoul(p, NULL, 10);
      if(altsize)







|







819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
  struct connectdata *conn;

  DEBUGASSERT(sockindex >= 0 && sockindex < 2);
  DEBUGASSERT(pnwritten);
  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);
  conn = data->conn;
#ifdef DEBUGBUILD
  {
    /* Allow debug builds to override this logic to force short sends
    */
    char *p = getenv("CURL_SMALLSENDS");
    if(p) {
      size_t altsize = (size_t)strtoul(p, NULL, 10);
      if(altsize)
Changes to jni/curl/lib/cfilters.h.
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38

39
40







41
42
43
44
45
46
47
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/



struct Curl_cfilter;
struct Curl_easy;
struct Curl_dns_entry;
struct connectdata;

/* Callback to destroy resources held by this filter instance.
 * Implementations MUST NOT chain calls to cf->next.
 */
typedef void     Curl_cft_destroy_this(struct Curl_cfilter *cf,
                                       struct Curl_easy *data);


typedef void     Curl_cft_close(struct Curl_cfilter *cf,
                                struct Curl_easy *data);








typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  bool blocking, bool *done);

/* Return the hostname and port the connection goes to.
 * This may change with the connection state of filters when tunneling







>












>


>
>
>
>
>
>
>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "timediff.h"

struct Curl_cfilter;
struct Curl_easy;
struct Curl_dns_entry;
struct connectdata;

/* Callback to destroy resources held by this filter instance.
 * Implementations MUST NOT chain calls to cf->next.
 */
typedef void     Curl_cft_destroy_this(struct Curl_cfilter *cf,
                                       struct Curl_easy *data);

/* Callback to close the connection immediately. */
typedef void     Curl_cft_close(struct Curl_cfilter *cf,
                                struct Curl_easy *data);

/* Callback to close the connection filter gracefully, non-blocking.
 * Implementations MUST NOT chain calls to cf->next.
 */
typedef CURLcode Curl_cft_shutdown(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   bool *done);

typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  bool blocking, bool *done);

/* Return the hostname and port the connection goes to.
 * This may change with the connection state of filters when tunneling
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
 * actions. If a "lower" filter is unable to write, it needs to be able
 * to disallow POLL_OUT.
 *
 * A filter without own restrictions/preferences should not modify
 * the pollset. Filters, whose filter "below" is not connected, should
 * also do no adjustments.
 *
 * Examples: a TLS handshake, while ongoing, might remove POLL_IN
 * when it needs to write, or vice versa. A HTTP/2 filter might remove
 * POLL_OUT when a stream window is exhausted and a WINDOW_UPDATE needs
 * to be received first and add instead POLL_IN.
 *
 * @param cf     the filter to ask
 * @param data   the easy handle the pollset is about
 * @param ps     the pollset (inout) for the easy handle
 */
typedef void     Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
                                          struct Curl_easy *data,







|
|
|
|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
 * actions. If a "lower" filter is unable to write, it needs to be able
 * to disallow POLL_OUT.
 *
 * A filter without own restrictions/preferences should not modify
 * the pollset. Filters, whose filter "below" is not connected, should
 * also do no adjustments.
 *
 * Examples: a TLS handshake, while ongoing, might remove POLL_IN when it
 * needs to write, or vice versa. An HTTP/2 filter might remove POLL_OUT when
 * a stream window is exhausted and a WINDOW_UPDATE needs to be received first
 * and add instead POLL_IN.
 *
 * @param cf     the filter to ask
 * @param data   the easy handle the pollset is about
 * @param ps     the pollset (inout) for the easy handle
 */
typedef void     Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
                                          struct Curl_easy *data,
190
191
192
193
194
195
196

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

216
217
218
219
220
221
222
struct Curl_cftype {
  const char *name;                       /* name of the filter type */
  int flags;                              /* flags of filter type */
  int log_level;                          /* log level for such filters */
  Curl_cft_destroy_this *destroy;         /* destroy resources of this cf */
  Curl_cft_connect *do_connect;           /* establish connection */
  Curl_cft_close *do_close;               /* close conn */

  Curl_cft_get_host *get_host;            /* host filter talks to */
  Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
  Curl_cft_data_pending *has_data_pending;/* conn has data pending */
  Curl_cft_send *do_send;                 /* send data */
  Curl_cft_recv *do_recv;                 /* receive data */
  Curl_cft_cntrl *cntrl;                  /* events/control */
  Curl_cft_conn_is_alive *is_alive;       /* FALSE if conn is dead, Jim! */
  Curl_cft_conn_keep_alive *keep_alive;   /* try to keep it alive */
  Curl_cft_query *query;                  /* query filter chain */
};

/* A connection filter instance, e.g. registered at a connection */
struct Curl_cfilter {
  const struct Curl_cftype *cft; /* the type providing implementation */
  struct Curl_cfilter *next;     /* next filter in chain */
  void *ctx;                     /* filter type specific settings */
  struct connectdata *conn;      /* the connection this filter belongs to */
  int sockindex;                 /* the index the filter is installed at */
  BIT(connected);                /* != 0 iff this filter is connected */

};

/* Default implementations for the type functions, implementing nop. */
void Curl_cf_def_destroy_this(struct Curl_cfilter *cf,
                              struct Curl_easy *data);

/* Default implementations for the type functions, implementing pass-through







>



















>







199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
struct Curl_cftype {
  const char *name;                       /* name of the filter type */
  int flags;                              /* flags of filter type */
  int log_level;                          /* log level for such filters */
  Curl_cft_destroy_this *destroy;         /* destroy resources of this cf */
  Curl_cft_connect *do_connect;           /* establish connection */
  Curl_cft_close *do_close;               /* close conn */
  Curl_cft_shutdown *do_shutdown;         /* shutdown conn */
  Curl_cft_get_host *get_host;            /* host filter talks to */
  Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
  Curl_cft_data_pending *has_data_pending;/* conn has data pending */
  Curl_cft_send *do_send;                 /* send data */
  Curl_cft_recv *do_recv;                 /* receive data */
  Curl_cft_cntrl *cntrl;                  /* events/control */
  Curl_cft_conn_is_alive *is_alive;       /* FALSE if conn is dead, Jim! */
  Curl_cft_conn_keep_alive *keep_alive;   /* try to keep it alive */
  Curl_cft_query *query;                  /* query filter chain */
};

/* A connection filter instance, e.g. registered at a connection */
struct Curl_cfilter {
  const struct Curl_cftype *cft; /* the type providing implementation */
  struct Curl_cfilter *next;     /* next filter in chain */
  void *ctx;                     /* filter type specific settings */
  struct connectdata *conn;      /* the connection this filter belongs to */
  int sockindex;                 /* the index the filter is installed at */
  BIT(connected);                /* != 0 iff this filter is connected */
  BIT(shutdown);                 /* != 0 iff this filter has shut down */
};

/* Default implementations for the type functions, implementing nop. */
void Curl_cf_def_destroy_this(struct Curl_cfilter *cf,
                              struct Curl_easy *data);

/* Default implementations for the type functions, implementing pass-through
240
241
242
243
244
245
246


247
248
249
250
251
252
253
                                   struct Curl_easy *data,
                                   bool *input_pending);
CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
                                     struct Curl_easy *data);
CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
                           struct Curl_easy *data,
                           int query, int *pres1, void *pres2);



/**
 * Create a new filter instance, unattached to the filter chain.
 * Use Curl_conn_cf_add() to add it to the chain.
 * @param pcf  on success holds the created instance
 * @param cft   the filter type
 * @param ctx  the type specific context to use







>
>







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
                                   struct Curl_easy *data,
                                   bool *input_pending);
CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
                                     struct Curl_easy *data);
CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
                           struct Curl_easy *data,
                           int query, int *pres1, void *pres2);
CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
                              struct Curl_easy *data, bool *done);

/**
 * Create a new filter instance, unattached to the filter chain.
 * Use Curl_conn_cf_add() to add it to the chain.
 * @param pcf  on success holds the created instance
 * @param cft   the filter type
 * @param ctx  the type specific context to use
367
368
369
370
371
372
373







374
375
376
377
378
379
380

/**
 * Close the filter chain at `sockindex` for connection `data->conn`.
  * Filters remain in place and may be connected again afterwards.
 */
void Curl_conn_close(struct Curl_easy *data, int sockindex);








/**
 * Return if data is pending in some connection filter at chain
 * `sockindex` for connection `data->conn`.
 */
bool Curl_conn_data_pending(struct Curl_easy *data,
                            int sockindex);








>
>
>
>
>
>
>







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400

/**
 * Close the filter chain at `sockindex` for connection `data->conn`.
  * Filters remain in place and may be connected again afterwards.
 */
void Curl_conn_close(struct Curl_easy *data, int sockindex);

/**
 * Shutdown the connection at `sockindex` non-blocking, using timeout
 * from `data->set.shutdowntimeout`, default DEFAULT_SHUTDOWN_TIMEOUT_MS.
 * Will return CURLE_OK and *done == FALSE if not finished.
 */
CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done);

/**
 * Return if data is pending in some connection filter at chain
 * `sockindex` for connection `data->conn`.
 */
bool Curl_conn_data_pending(struct Curl_easy *data,
                            int sockindex);

398
399
400
401
402
403
404









405
406
407
408
409
410
411

/**
 * Adjust pollset from filters installed at transfer's connection.
 */
void Curl_conn_adjust_pollset(struct Curl_easy *data,
                               struct easy_pollset *ps);










/**
 * Receive data through the filter chain at `sockindex` for connection
 * `data->conn`. Copy at most `len` bytes into `buf`. Return the
 * actual number of bytes copied or a negative value on error.
 * The error code is placed into `*code`.
 */
ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,







>
>
>
>
>
>
>
>
>







418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440

/**
 * Adjust pollset from filters installed at transfer's connection.
 */
void Curl_conn_adjust_pollset(struct Curl_easy *data,
                               struct easy_pollset *ps);

/**
 * Curl_poll() the filter chain at `cf` with timeout `timeout_ms`.
 * Returns 0 on timeout, negative on error or number of sockets
 * with requested poll events.
 */
int Curl_conn_cf_poll(struct Curl_cfilter *cf,
                      struct Curl_easy *data,
                      timediff_t timeout_ms);

/**
 * Receive data through the filter chain at `sockindex` for connection
 * `data->conn`. Copy at most `len` bytes into `buf`. Return the
 * actual number of bytes copied or a negative value on error.
 * The error code is placed into `*code`.
 */
ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
482
483
484
485
486
487
488

489

490
491
492
493
494
495
496
/**
 * Try to upkeep the connection filters at sockindex.
 */
CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
                              struct connectdata *conn,
                              int sockindex);


void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);

void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
                        const char **phost, const char **pdisplay_host,
                        int *pport);

/**
 * Get the maximum number of parallel transfers the connection
 * expects to be able to handle at `sockindex`.







>

>







511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
/**
 * Try to upkeep the connection filters at sockindex.
 */
CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
                              struct connectdata *conn,
                              int sockindex);

#ifdef UNITTESTS
void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
#endif
void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
                        const char **phost, const char **pdisplay_host,
                        int *pport);

/**
 * Get the maximum number of parallel transfers the connection
 * expects to be able to handle at `sockindex`.
Changes to jni/curl/lib/config-os400.h.
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

/* Define if you have the `timeval' struct. */
#define HAVE_STRUCT_TIMEVAL

/* Define if you have the <io.h> header file. */
#undef HAVE_IO_H

/* Define if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET

/* Define if you have GSS API. */
#define HAVE_GSSAPI

/* Define if you have the GNU gssapi libraries */
#undef HAVE_GSSGNU

/* Define if you need the malloc.h header file even with stdlib.h  */







<
<
<







103
104
105
106
107
108
109



110
111
112
113
114
115
116

/* Define if you have the `timeval' struct. */
#define HAVE_STRUCT_TIMEVAL

/* Define if you have the <io.h> header file. */
#undef HAVE_IO_H




/* Define if you have GSS API. */
#define HAVE_GSSAPI

/* Define if you have the GNU gssapi libraries */
#undef HAVE_GSSGNU

/* Define if you need the malloc.h header file even with stdlib.h  */
Changes to jni/curl/lib/config-riscos.h.
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

/* Define if you have the `timeval' struct. */
#define HAVE_STRUCT_TIMEVAL

/* Define if you have the <io.h> header file. */
#undef HAVE_IO_H

/* Define if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET

/* Define if you need the malloc.h header file even with stdlib.h  */
/* #define NEED_MALLOC_H 1 */

/* Define if you have the <netdb.h> header file. */
#define HAVE_NETDB_H

/* Define if you have the <netinet/in.h> header file. */







<
<
<







104
105
106
107
108
109
110



111
112
113
114
115
116
117

/* Define if you have the `timeval' struct. */
#define HAVE_STRUCT_TIMEVAL

/* Define if you have the <io.h> header file. */
#undef HAVE_IO_H




/* Define if you need the malloc.h header file even with stdlib.h  */
/* #define NEED_MALLOC_H 1 */

/* Define if you have the <netdb.h> header file. */
#define HAVE_NETDB_H

/* Define if you have the <netinet/in.h> header file. */
Changes to jni/curl/lib/conncache.c.
25
26
27
28
29
30
31

32
33
34
35


36
37
38

39
40
41
42
43
44
45
46
47


















48
49
50
51
52
53
54

#include "curl_setup.h"

#include <curl/curl.h>

#include "urldata.h"
#include "url.h"

#include "progress.h"
#include "multiif.h"
#include "sendf.h"
#include "conncache.h"


#include "share.h"
#include "sigpipe.h"
#include "connect.h"

#include "strcase.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

#define HASHKEY_SIZE 128



















static CURLcode bundle_create(struct connectbundle **bundlep)
{
  DEBUGASSERT(*bundlep == NULL);
  *bundlep = malloc(sizeof(struct connectbundle));
  if(!*bundlep)
    return CURLE_OUT_OF_MEMORY;








>




>
>



>









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

#include "curl_setup.h"

#include <curl/curl.h>

#include "urldata.h"
#include "url.h"
#include "cfilters.h"
#include "progress.h"
#include "multiif.h"
#include "sendf.h"
#include "conncache.h"
#include "http_negotiate.h"
#include "http_ntlm.h"
#include "share.h"
#include "sigpipe.h"
#include "connect.h"
#include "select.h"
#include "strcase.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

#define HASHKEY_SIZE 128

static void connc_discard_conn(struct conncache *connc,
                               struct Curl_easy *last_data,
                               struct connectdata *conn,
                               bool aborted);
static void connc_disconnect(struct Curl_easy *data,
                             struct connectdata *conn,
                             struct conncache *connc,
                             bool do_shutdown);
static void connc_run_conn_shutdown(struct Curl_easy *data,
                                    struct connectdata *conn,
                                    bool *done);
static void connc_run_conn_shutdown_handler(struct Curl_easy *data,
                                            struct connectdata *conn);
static CURLMcode connc_update_shutdown_ev(struct Curl_multi *multi,
                                          struct Curl_easy *data,
                                          struct connectdata *conn);
static void connc_shutdown_all(struct conncache *connc, int timeout_ms);

static CURLcode bundle_create(struct connectbundle **bundlep)
{
  DEBUGASSERT(*bundlep == NULL);
  *bundlep = malloc(sizeof(struct connectbundle));
  if(!*bundlep)
    return CURLE_OUT_OF_MEMORY;

96
97
98
99
100
101
102
103

104
105
106
107
108
109




110
111
112
113


114
115
116
117
118
119
120
121



122
123
124
125
126
127
128
static void free_bundle_hash_entry(void *freethis)
{
  struct connectbundle *b = (struct connectbundle *) freethis;

  bundle_destroy(b);
}

int Curl_conncache_init(struct conncache *connc, size_t size)

{
  /* allocate a new easy handle to use when closing cached connections */
  connc->closure_handle = curl_easy_init();
  if(!connc->closure_handle)
    return 1; /* bad */
  connc->closure_handle->state.internal = true;





  Curl_hash_init(&connc->hash, size, Curl_hash_str,
                 Curl_str_key_compare, free_bundle_hash_entry);
  connc->closure_handle->state.conn_cache = connc;



  return 0; /* good */
}

void Curl_conncache_destroy(struct conncache *connc)
{
  if(connc)
    Curl_hash_destroy(&connc->hash);



}

/* creates a key to find a bundle for this connection */
static void hashkey(struct connectdata *conn, char *buf, size_t len)
{
  const char *hostname;
  long port = conn->remote_port;







|
>






>
>
>
>




>
>






|

>
>
>







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
static void free_bundle_hash_entry(void *freethis)
{
  struct connectbundle *b = (struct connectbundle *) freethis;

  bundle_destroy(b);
}

int Curl_conncache_init(struct conncache *connc,
                        struct Curl_multi *multi, size_t size)
{
  /* allocate a new easy handle to use when closing cached connections */
  connc->closure_handle = curl_easy_init();
  if(!connc->closure_handle)
    return 1; /* bad */
  connc->closure_handle->state.internal = true;
 #ifdef DEBUGBUILD
  if(getenv("CURL_DEBUG"))
    connc->closure_handle->set.verbose = true;
#endif

  Curl_hash_init(&connc->hash, size, Curl_hash_str,
                 Curl_str_key_compare, free_bundle_hash_entry);
  connc->closure_handle->state.conn_cache = connc;
  connc->multi = multi;
  Curl_llist_init(&connc->shutdowns.conn_list, NULL);

  return 0; /* good */
}

void Curl_conncache_destroy(struct conncache *connc)
{
  if(connc) {
    Curl_hash_destroy(&connc->hash);
    connc->multi = NULL;
    DEBUGASSERT(!Curl_llist_count(&connc->shutdowns.conn_list));
  }
}

/* creates a key to find a bundle for this connection */
static void hashkey(struct connectdata *conn, char *buf, size_t len)
{
  const char *hostname;
  long port = conn->remote_port;
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    hashkey(conn, key, sizeof(key));
    bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
  }

  return bundle;
}

static void *conncache_add_bundle(struct conncache *connc,
                                  char *key,
                                  struct connectbundle *bundle)
{
  return Curl_hash_add(&connc->hash, key, strlen(key), bundle);
}

static void conncache_remove_bundle(struct conncache *connc,
                                    struct connectbundle *bundle)
{
  struct Curl_hash_iterator iter;
  struct Curl_hash_element *he;

  if(!connc)
    return;








|
<
|




|
|







208
209
210
211
212
213
214
215

216
217
218
219
220
221
222
223
224
225
226
227
228
229
    hashkey(conn, key, sizeof(key));
    bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
  }

  return bundle;
}

static void *connc_add_bundle(struct conncache *connc,

                              char *key, struct connectbundle *bundle)
{
  return Curl_hash_add(&connc->hash, key, strlen(key), bundle);
}

static void connc_remove_bundle(struct conncache *connc,
                                struct connectbundle *bundle)
{
  struct Curl_hash_iterator iter;
  struct Curl_hash_element *he;

  if(!connc)
    return;

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

















254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
    result = bundle_create(&bundle);
    if(result) {
      goto unlock;
    }

    hashkey(conn, key, sizeof(key));

    if(!conncache_add_bundle(data->state.conn_cache, key, bundle)) {
      bundle_destroy(bundle);
      result = CURLE_OUT_OF_MEMORY;
      goto unlock;
    }
  }

  bundle_add_conn(bundle, conn);
  conn->connection_id = connc->next_connection_id++;
  connc->num_conn++;

  DEBUGF(infof(data, "Added connection %" CURL_FORMAT_CURL_OFF_T ". "
               "The cache now contains %zu members",
               conn->connection_id, connc->num_conn));

unlock:
  CONNCACHE_UNLOCK(data);

  return result;
}


















/*
 * Removes the connectdata object from the connection cache, but the transfer
 * still owns this connection.
 *
 * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
 * already holds the lock or not.
 */
void Curl_conncache_remove_conn(struct Curl_easy *data,
                                struct connectdata *conn, bool lock)
{
  struct connectbundle *bundle = conn->bundle;
  struct conncache *connc = data->state.conn_cache;

  /* The bundle pointer can be NULL, since this function can be called
     due to a failed connection attempt, before being added to a bundle */
  if(bundle) {
    if(lock) {
      CONNCACHE_LOCK(data);
    }
    bundle_remove_conn(bundle, conn);
    if(bundle->num_connections == 0)
      conncache_remove_bundle(connc, bundle);
    conn->bundle = NULL; /* removed from it */

    if(connc) {
      connc->num_conn--;
      DEBUGF(infof(data, "The cache now contains %zu members",
                   connc->num_conn));
    }
    if(lock) {
      CONNCACHE_UNLOCK(data);
    }
  }
}

/* This function iterates the entire connection cache and calls the function
   func() with the connection pointer as the first argument and the supplied
   'param' argument as the other.

   The conncache lock is still held when the callback is called. It needs it,







|



















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











<


<
<
<
|
|
<
|
|
<
<
>
|
<
|
|
<
<
<
<
<







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312

313
314



315
316

317
318


319
320

321
322





323
324
325
326
327
328
329
    result = bundle_create(&bundle);
    if(result) {
      goto unlock;
    }

    hashkey(conn, key, sizeof(key));

    if(!connc_add_bundle(data->state.conn_cache, key, bundle)) {
      bundle_destroy(bundle);
      result = CURLE_OUT_OF_MEMORY;
      goto unlock;
    }
  }

  bundle_add_conn(bundle, conn);
  conn->connection_id = connc->next_connection_id++;
  connc->num_conn++;

  DEBUGF(infof(data, "Added connection %" CURL_FORMAT_CURL_OFF_T ". "
               "The cache now contains %zu members",
               conn->connection_id, connc->num_conn));

unlock:
  CONNCACHE_UNLOCK(data);

  return result;
}

static void connc_remove_conn(struct conncache *connc,
                              struct connectdata *conn)
{
  struct connectbundle *bundle = conn->bundle;

  /* The bundle pointer can be NULL, since this function can be called
     due to a failed connection attempt, before being added to a bundle */
  if(bundle) {
    bundle_remove_conn(bundle, conn);
    if(connc && bundle->num_connections == 0)
      connc_remove_bundle(connc, bundle);
    conn->bundle = NULL; /* removed from it */
    if(connc)
      connc->num_conn--;
  }
}

/*
 * Removes the connectdata object from the connection cache, but the transfer
 * still owns this connection.
 *
 * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
 * already holds the lock or not.
 */
void Curl_conncache_remove_conn(struct Curl_easy *data,
                                struct connectdata *conn, bool lock)
{

  struct conncache *connc = data->state.conn_cache;




  if(lock)
    CONNCACHE_LOCK(data);

  connc_remove_conn(connc, conn);
  if(lock)


    CONNCACHE_UNLOCK(data);
  if(connc)

    DEBUGF(infof(data, "The cache now contains %zu members",
                 connc->num_conn));





}

/* This function iterates the entire connection cache and calls the function
   func() with the connection pointer as the first argument and the supplied
   'param' argument as the other.

   The conncache lock is still held when the callback is called. It needs it,
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/* Return the first connection found in the cache. Used when closing all
   connections.

   NOTE: no locking is done here as this is presumably only done when cleaning
   up a cache!
*/
static struct connectdata *
conncache_find_first_connection(struct conncache *connc)
{
  struct Curl_hash_iterator iter;
  struct Curl_hash_element *he;
  struct connectbundle *bundle;

  Curl_hash_start_iterate(&connc->hash, &iter);








|







377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
/* Return the first connection found in the cache. Used when closing all
   connections.

   NOTE: no locking is done here as this is presumably only done when cleaning
   up a cache!
*/
static struct connectdata *
connc_find_first_connection(struct conncache *connc)
{
  struct Curl_hash_iterator iter;
  struct Curl_hash_element *he;
  struct connectbundle *bundle;

  Curl_hash_start_iterate(&connc->hash, &iter);

390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
    if(conn_candidate) {
      /* Use the closure handle for this disconnect so that anything that
         happens during the disconnect is not stored and associated with the
         'data' handle which already just finished a transfer and it is
         important that details from this (unrelated) disconnect does not
         taint meta-data in the data handle. */
      struct conncache *connc = data->state.conn_cache;
      Curl_disconnect(connc->closure_handle, conn_candidate,
                      /* dead_connection */ FALSE);
    }
  }

  return (conn_candidate == conn) ? FALSE : TRUE;

}








|
<







426
427
428
429
430
431
432
433

434
435
436
437
438
439
440
    if(conn_candidate) {
      /* Use the closure handle for this disconnect so that anything that
         happens during the disconnect is not stored and associated with the
         'data' handle which already just finished a transfer and it is
         important that details from this (unrelated) disconnect does not
         taint meta-data in the data handle. */
      struct conncache *connc = data->state.conn_cache;
      connc_disconnect(NULL, conn_candidate, connc, TRUE);

    }
  }

  return (conn_candidate == conn) ? FALSE : TRUE;

}

512
513
514
515
516
517
518






















519
520

521

522
523

524
525

526
527

528
529
530
531
532
533

















































































































































































































































































































































































































































































































































534


535

536
537
538
539

540
541
542
543
544
545
546
547
548
549
550
                 connc->num_conn));
  }
  CONNCACHE_UNLOCK(data);

  return conn_candidate;
}























void Curl_conncache_close_all_connections(struct conncache *connc)
{

  struct connectdata *conn;

  SIGPIPE_VARIABLE(pipe_st);
  if(!connc->closure_handle)

    return;


  conn = conncache_find_first_connection(connc);
  while(conn) {

    sigpipe_ignore(connc->closure_handle, &pipe_st);
    /* This will remove the connection from the cache */
    connclose(conn, "kill all");
    Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
    Curl_disconnect(connc->closure_handle, conn, FALSE);
    sigpipe_restore(&pipe_st);




















































































































































































































































































































































































































































































































































    conn = conncache_find_first_connection(connc);

  }

  sigpipe_ignore(connc->closure_handle, &pipe_st);


  Curl_hostcache_clean(connc->closure_handle,
                       connc->closure_handle->dns.hostcache);
  Curl_close(&connc->closure_handle);
  sigpipe_restore(&pipe_st);
}

#if 0
/* Useful for debugging the connection cache */
void Curl_conncache_print(struct conncache *connc)
{
  struct Curl_hash_iterator iter;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|

>

>

|
>


>
|

>
|



|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
|
>
|
|
<

>
|
<
<
<







547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131

1132
1133
1134



1135
1136
1137
1138
1139
1140
1141
                 connc->num_conn));
  }
  CONNCACHE_UNLOCK(data);

  return conn_candidate;
}

static void connc_shutdown_discard_all(struct conncache *connc)
{
  struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
  struct connectdata *conn;

  if(!e)
    return;

  DEBUGF(infof(connc->closure_handle, "conncache_shutdown_discard_all"));
  DEBUGASSERT(!connc->shutdowns.iter_locked);
  connc->shutdowns.iter_locked = TRUE;
  while(e) {
    conn = e->ptr;
    Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
    DEBUGF(infof(connc->closure_handle, "discard connection #%"
                 CURL_FORMAT_CURL_OFF_T, conn->connection_id));
    connc_disconnect(NULL, conn, connc, FALSE);
    e = connc->shutdowns.conn_list.head;
  }
  connc->shutdowns.iter_locked = FALSE;
}

static void connc_close_all(struct conncache *connc)
{
  struct Curl_easy *data = connc->closure_handle;
  struct connectdata *conn;
  int timeout_ms = 0;
  SIGPIPE_VARIABLE(pipe_st);

  if(!data)
    return;

  /* Move all connections to the shutdown list */
  conn = connc_find_first_connection(connc);
  while(conn) {
    connc_remove_conn(connc, conn);
    sigpipe_ignore(data, &pipe_st);
    /* This will remove the connection from the cache */
    connclose(conn, "kill all");
    Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
    connc_discard_conn(connc, connc->closure_handle, conn, FALSE);
    sigpipe_restore(&pipe_st);

    conn = connc_find_first_connection(connc);
  }

    /* Just for testing, run graceful shutdown */
#ifdef DEBUGBUILD
  {
    char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
    if(p) {
      long l = strtol(p, NULL, 10);
      if(l > 0 && l < INT_MAX)
        timeout_ms = (int)l;
    }
  }
#endif
  connc_shutdown_all(connc, timeout_ms);

  /* discard all connections in the shutdown list */
  connc_shutdown_discard_all(connc);

  sigpipe_ignore(data, &pipe_st);
  Curl_hostcache_clean(data, data->dns.hostcache);
  Curl_close(&data);
  sigpipe_restore(&pipe_st);
}

void Curl_conncache_close_all_connections(struct conncache *connc)
{
  connc_close_all(connc);
}

static void connc_shutdown_discard_oldest(struct conncache *connc)
{
  struct Curl_llist_element *e;
  struct connectdata *conn;
  SIGPIPE_VARIABLE(pipe_st);

  DEBUGASSERT(!connc->shutdowns.iter_locked);
  if(connc->shutdowns.iter_locked)
    return;

  e = connc->shutdowns.conn_list.head;
  if(e) {
    conn = e->ptr;
    Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
    sigpipe_ignore(connc->closure_handle, &pipe_st);
    connc_disconnect(NULL, conn, connc, FALSE);
    sigpipe_restore(&pipe_st);
  }
}

static void connc_discard_conn(struct conncache *connc,
                               struct Curl_easy *last_data,
                               struct connectdata *conn,
                               bool aborted)
{
  /* `last_data`, if present, is the transfer that last worked with
   * the connection. It is present when the connection is being shut down
   * via `Curl_conncache_discard_conn()`, e.g. when the transfer failed
   * or does not allow connection reuse.
   * Using the original handle is necessary for shutting down the protocol
   * handler belonging to the connection. Protocols like 'file:' rely on
   * being invoked to clean up their allocations in the easy handle.
   * When a connection comes from the cache, the transfer is no longer
   * there and we use the cache is own closure handle.
   */
  struct Curl_easy *data = last_data? last_data : connc->closure_handle;
  bool done = FALSE;

  DEBUGASSERT(data);
  DEBUGASSERT(connc);
  DEBUGASSERT(!conn->bundle);

  /*
   * If this connection is not marked to force-close, leave it open if there
   * are other users of it
   */
  if(CONN_INUSE(conn) && !aborted) {
    DEBUGF(infof(data, "[CCACHE] not discarding #%" CURL_FORMAT_CURL_OFF_T
                       " still in use by %zu transfers", conn->connection_id,
                       CONN_INUSE(conn)));
    return;
  }

  /* treat the connection as aborted in CONNECT_ONLY situations, we do
   * not know what the APP did with it. */
  if(conn->connect_only)
    aborted = TRUE;
  conn->bits.aborted = aborted;

  /* We do not shutdown dead connections. The term 'dead' can be misleading
   * here, as we also mark errored connections/transfers as 'dead'.
   * If we do a shutdown for an aborted transfer, the server might think
   * it was successful otherwise (for example an ftps: upload). This is
   * not what we want. */
  if(aborted)
    done = TRUE;
  if(!done) {
    /* Attempt to shutdown the connection right away. */
    Curl_attach_connection(data, conn);
    connc_run_conn_shutdown(data, conn, &done);
    DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
                       ", done=%d",conn->connection_id, done));
    Curl_detach_connection(data);
  }

  if(done) {
    connc_disconnect(data, conn, connc, FALSE);
    return;
  }

  DEBUGASSERT(!connc->shutdowns.iter_locked);
  if(connc->shutdowns.iter_locked) {
    DEBUGF(infof(data, "[CCACHE] discarding #%" CURL_FORMAT_CURL_OFF_T
                       ", list locked", conn->connection_id));
    connc_disconnect(data, conn, connc, FALSE);
    return;
  }

  /* Add the connection to our shutdown list for non-blocking shutdown
   * during multi processing. */
  if(data->multi && data->multi->max_shutdown_connections > 0 &&
     (data->multi->max_shutdown_connections >=
      (long)Curl_llist_count(&connc->shutdowns.conn_list))) {
    DEBUGF(infof(data, "[CCACHE] discarding oldest shutdown connection "
                       "due to limit of %ld",
                       data->multi->max_shutdown_connections));
    connc_shutdown_discard_oldest(connc);
  }

  if(data->multi && data->multi->socket_cb) {
    DEBUGASSERT(connc == &data->multi->conn_cache);
    /* Start with an empty shutdown pollset, so out internal closure handle
     * is added to the sockets. */
    memset(&conn->shutdown_poll, 0, sizeof(conn->shutdown_poll));
    if(connc_update_shutdown_ev(data->multi, connc->closure_handle, conn)) {
      DEBUGF(infof(data, "[CCACHE] update events for shutdown failed, "
                         "discarding #%" CURL_FORMAT_CURL_OFF_T,
                         conn->connection_id));
      connc_disconnect(data, conn, connc, FALSE);
      return;
    }
  }

  Curl_llist_append(&connc->shutdowns.conn_list, conn, &conn->bundle_node);
  DEBUGF(infof(data, "[CCACHE] added #%" CURL_FORMAT_CURL_OFF_T
                     " to shutdown list of length %zu", conn->connection_id,
                     Curl_llist_count(&connc->shutdowns.conn_list)));
}

void Curl_conncache_disconnect(struct Curl_easy *data,
                               struct connectdata *conn,
                               bool aborted)
{
  DEBUGASSERT(data);
  /* Connection must no longer be in and connection cache */
  DEBUGASSERT(!conn->bundle);

  if(data->multi) {
    /* Add it to the multi's conncache for shutdown handling */
    infof(data, "%s connection #%" CURL_FORMAT_CURL_OFF_T,
          aborted? "closing" : "shutting down", conn->connection_id);
    connc_discard_conn(&data->multi->conn_cache, data, conn, aborted);
  }
  else {
    /* No multi available. Make a best-effort shutdown + close */
    infof(data, "closing connection #%" CURL_FORMAT_CURL_OFF_T,
          conn->connection_id);
    DEBUGASSERT(!conn->bundle);
    connc_run_conn_shutdown_handler(data, conn);
    connc_disconnect(data, conn, NULL, !aborted);
  }
}

static void connc_run_conn_shutdown_handler(struct Curl_easy *data,
                                            struct connectdata *conn)
{
  if(!conn->bits.shutdown_handler) {
    if(conn->dns_entry) {
      Curl_resolv_unlock(data, conn->dns_entry);
      conn->dns_entry = NULL;
    }

    /* Cleanup NTLM connection-related data */
    Curl_http_auth_cleanup_ntlm(conn);

    /* Cleanup NEGOTIATE connection-related data */
    Curl_http_auth_cleanup_negotiate(conn);

    if(conn->handler && conn->handler->disconnect) {
      /* This is set if protocol-specific cleanups should be made */
      DEBUGF(infof(data, "connection #%" CURL_FORMAT_CURL_OFF_T
                   ", shutdown protocol handler (aborted=%d)",
                   conn->connection_id, conn->bits.aborted));
      conn->handler->disconnect(data, conn, conn->bits.aborted);
    }

    /* possible left-overs from the async name resolvers */
    Curl_resolver_cancel(data);

    conn->bits.shutdown_handler = TRUE;
  }
}

static void connc_run_conn_shutdown(struct Curl_easy *data,
                                    struct connectdata *conn,
                                    bool *done)
{
  CURLcode r1, r2;
  bool done1, done2;

  /* We expect to be attached when called */
  DEBUGASSERT(data->conn == conn);

  connc_run_conn_shutdown_handler(data, conn);

  if(conn->bits.shutdown_filters) {
    *done = TRUE;
    return;
  }

  if(!conn->connect_only && Curl_conn_is_connected(conn, FIRSTSOCKET))
    r1 = Curl_conn_shutdown(data, FIRSTSOCKET, &done1);
  else {
    r1 = CURLE_OK;
    done1 = TRUE;
  }

  if(!conn->connect_only && Curl_conn_is_connected(conn, SECONDARYSOCKET))
    r2 = Curl_conn_shutdown(data, SECONDARYSOCKET, &done2);
  else {
    r2 = CURLE_OK;
    done2 = TRUE;
  }

  /* we are done when any failed or both report success */
  *done = (r1 || r2 || (done1 && done2));
  if(*done)
    conn->bits.shutdown_filters = TRUE;
}

CURLcode Curl_conncache_add_pollfds(struct conncache *connc,
                                    struct curl_pollfds *cpfds)
{
  CURLcode result = CURLE_OK;

  DEBUGASSERT(!connc->shutdowns.iter_locked);
  connc->shutdowns.iter_locked = TRUE;
  if(connc->shutdowns.conn_list.head) {
    struct Curl_llist_element *e;
    struct easy_pollset ps;
    struct connectdata *conn;

    for(e = connc->shutdowns.conn_list.head; e; e = e->next) {
      conn = e->ptr;
      memset(&ps, 0, sizeof(ps));
      Curl_attach_connection(connc->closure_handle, conn);
      Curl_conn_adjust_pollset(connc->closure_handle, &ps);
      Curl_detach_connection(connc->closure_handle);

      result = Curl_pollfds_add_ps(cpfds, &ps);
      if(result) {
        Curl_pollfds_cleanup(cpfds);
        goto out;
      }
    }
  }
out:
  connc->shutdowns.iter_locked = FALSE;
  return result;
}

CURLcode Curl_conncache_add_waitfds(struct conncache *connc,
                                    struct curl_waitfds *cwfds)
{
  CURLcode result = CURLE_OK;

  DEBUGASSERT(!connc->shutdowns.iter_locked);
  connc->shutdowns.iter_locked = TRUE;
  if(connc->shutdowns.conn_list.head) {
    struct Curl_llist_element *e;
    struct easy_pollset ps;
    struct connectdata *conn;

    for(e = connc->shutdowns.conn_list.head; e; e = e->next) {
      conn = e->ptr;
      memset(&ps, 0, sizeof(ps));
      Curl_attach_connection(connc->closure_handle, conn);
      Curl_conn_adjust_pollset(connc->closure_handle, &ps);
      Curl_detach_connection(connc->closure_handle);

      result = Curl_waitfds_add_ps(cwfds, &ps);
      if(result)
        goto out;
    }
  }
out:
  connc->shutdowns.iter_locked = FALSE;
  return result;
}

static void connc_perform(struct conncache *connc)
{
  struct Curl_easy *data = connc->closure_handle;
  struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
  struct Curl_llist_element *enext;
  struct connectdata *conn;
  bool done;

  if(!e)
    return;

  DEBUGASSERT(data);
  DEBUGASSERT(!connc->shutdowns.iter_locked);
  DEBUGF(infof(data, "[CCACHE] perform, %zu connections being shutdown",
               Curl_llist_count(&connc->shutdowns.conn_list)));
  connc->shutdowns.iter_locked = TRUE;
  while(e) {
    enext = e->next;
    conn = e->ptr;
    Curl_attach_connection(data, conn);
    connc_run_conn_shutdown(data, conn, &done);
    DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
                 ", done=%d", conn->connection_id, done));
    Curl_detach_connection(data);
    if(done) {
      Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
      connc_disconnect(NULL, conn, connc, FALSE);
    }
    e = enext;
  }
  connc->shutdowns.iter_locked = FALSE;
}

void Curl_conncache_multi_perform(struct Curl_multi *multi)
{
  connc_perform(&multi->conn_cache);
}


/*
 * Disconnects the given connection. Note the connection may not be the
 * primary connection, like when freeing room in the connection cache or
 * killing of a dead old connection.
 *
 * A connection needs an easy handle when closing down. We support this passed
 * in separately since the connection to get closed here is often already
 * disassociated from an easy handle.
 *
 * This function MUST NOT reset state in the Curl_easy struct if that
 * is not strictly bound to the life-time of *this* particular connection.
 *
 */
static void connc_disconnect(struct Curl_easy *data,
                             struct connectdata *conn,
                             struct conncache *connc,
                             bool do_shutdown)
{
  bool done;

  /* there must be a connection to close */
  DEBUGASSERT(conn);
  /* it must be removed from the connection cache */
  DEBUGASSERT(!conn->bundle);
  /* there must be an associated transfer */
  DEBUGASSERT(data || connc);
  if(!data)
    data = connc->closure_handle;

  /* the transfer must be detached from the connection */
  DEBUGASSERT(data && !data->conn);

  Curl_attach_connection(data, conn);

  if(connc && connc->multi && connc->multi->socket_cb) {
    struct easy_pollset ps;
    /* With an empty pollset, all previously polled sockets will be removed
     * via the multi_socket API callback. */
    memset(&ps, 0, sizeof(ps));
    (void)Curl_multi_pollset_ev(connc->multi, data, &ps, &conn->shutdown_poll);
  }

  connc_run_conn_shutdown_handler(data, conn);
  if(do_shutdown) {
    /* Make a last attempt to shutdown handlers and filters, if
     * not done so already. */
    connc_run_conn_shutdown(data, conn, &done);
  }

  if(connc)
    DEBUGF(infof(data, "[CCACHE] closing #%" CURL_FORMAT_CURL_OFF_T,
                 conn->connection_id));
  else
    DEBUGF(infof(data, "closing connection #%" CURL_FORMAT_CURL_OFF_T,
                 conn->connection_id));
  Curl_conn_close(data, SECONDARYSOCKET);
  Curl_conn_close(data, FIRSTSOCKET);
  Curl_detach_connection(data);

  Curl_conn_free(data, conn);
}


static CURLMcode connc_update_shutdown_ev(struct Curl_multi *multi,
                                          struct Curl_easy *data,
                                          struct connectdata *conn)
{
  struct easy_pollset ps;
  CURLMcode mresult;

  DEBUGASSERT(data);
  DEBUGASSERT(multi);
  DEBUGASSERT(multi->socket_cb);

  memset(&ps, 0, sizeof(ps));
  Curl_attach_connection(data, conn);
  Curl_conn_adjust_pollset(data, &ps);
  Curl_detach_connection(data);

  mresult = Curl_multi_pollset_ev(multi, data, &ps, &conn->shutdown_poll);

  if(!mresult) /* Remember for next time */
    memcpy(&conn->shutdown_poll, &ps, sizeof(ps));
  return mresult;
}

void Curl_conncache_multi_socket(struct Curl_multi *multi,
                                 curl_socket_t s, int ev_bitmask)
{
  struct conncache *connc = &multi->conn_cache;
  struct Curl_easy *data = connc->closure_handle;
  struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
  struct connectdata *conn;
  bool done;

  (void)ev_bitmask;
  DEBUGASSERT(multi->socket_cb);
  if(!e)
    return;

  connc->shutdowns.iter_locked = TRUE;
  while(e) {
    conn = e->ptr;
    if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
      Curl_attach_connection(data, conn);
      connc_run_conn_shutdown(data, conn, &done);
      DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
                   ", done=%d", conn->connection_id, done));
      Curl_detach_connection(data);
      if(done || connc_update_shutdown_ev(multi, data, conn)) {
        Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
        connc_disconnect(NULL, conn, connc, FALSE);
      }
      break;
    }
    e = e->next;
  }
  connc->shutdowns.iter_locked = FALSE;
}

void Curl_conncache_multi_close_all(struct Curl_multi *multi)
{
  connc_close_all(&multi->conn_cache);
}


#define NUM_POLLS_ON_STACK 10

static CURLcode connc_shutdown_wait(struct conncache *connc, int timeout_ms)
{
  struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
  struct curl_pollfds cpfds;
  CURLcode result;

  Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);

  result = Curl_conncache_add_pollfds(connc, &cpfds);
  if(result)
    goto out;

  Curl_poll(cpfds.pfds, cpfds.n, CURLMIN(timeout_ms, 1000));

out:
  Curl_pollfds_cleanup(&cpfds);
  return result;
}

static void connc_shutdown_all(struct conncache *connc, int timeout_ms)
{
  struct Curl_easy *data = connc->closure_handle;
  struct connectdata *conn;
  struct curltime started = Curl_now();

  if(!data)
    return;
  (void)data;

  DEBUGF(infof(data, "conncache shutdown all"));

  /* Move all connections into the shutdown queue */
  conn = connc_find_first_connection(connc);
  while(conn) {
    /* This will remove the connection from the cache */
    DEBUGF(infof(data, "moving connection %" CURL_FORMAT_CURL_OFF_T
                 " to shutdown queue", conn->connection_id));
    connc_remove_conn(connc, conn);
    connc_discard_conn(connc, NULL, conn, FALSE);
    conn = connc_find_first_connection(connc);
  }

  DEBUGASSERT(!connc->shutdowns.iter_locked);
  while(connc->shutdowns.conn_list.head) {
    timediff_t timespent;
    int remain_ms;

    connc_perform(connc);

    if(!connc->shutdowns.conn_list.head) {
      DEBUGF(infof(data, "conncache shutdown ok"));
      break;
    }

    /* wait for activity, timeout or "nothing" */
    timespent = Curl_timediff(Curl_now(), started);
    if(timespent >= (timediff_t)timeout_ms) {
      DEBUGF(infof(data, "conncache shutdown %s",
                   (timeout_ms > 0)? "timeout" : "best effort done"));
      break;
    }

    remain_ms = timeout_ms - (int)timespent;
    if(connc_shutdown_wait(connc, remain_ms)) {
      DEBUGF(infof(data, "conncache shutdown all, abort"));
      break;
    }
  }


  /* Due to errors/timeout, we might come here without being full ydone. */
  connc_shutdown_discard_all(connc);



}

#if 0
/* Useful for debugging the connection cache */
void Curl_conncache_print(struct conncache *connc)
{
  struct Curl_hash_iterator iter;
Changes to jni/curl/lib/conncache.h.
31
32
33
34
35
36
37








38
39
40
41
42
43
44

45
46

47
48
49
50
51
52
53
54
55
56
57
58
59
60
 * be shared.
 */

#include <curl/curl.h>
#include "timeval.h"

struct connectdata;









struct conncache {
  struct Curl_hash hash;
  size_t num_conn;
  curl_off_t next_connection_id;
  curl_off_t next_easy_id;
  struct curltime last_cleanup;

  /* handle used for closing cached connections */
  struct Curl_easy *closure_handle;

};

#define BUNDLE_NO_MULTIUSE -1
#define BUNDLE_UNKNOWN     0  /* initial value */
#define BUNDLE_MULTIPLEX   2

#ifdef CURLDEBUG
/* the debug versions of these macros make extra certain that the lock is
   never doubly locked or unlocked */
#define CONNCACHE_LOCK(x)                                               \
  do {                                                                  \
    if((x)->share) {                                                    \
      Curl_share_lock((x), CURL_LOCK_DATA_CONNECT,                      \
                      CURL_LOCK_ACCESS_SINGLE);                         \







>
>
>
>
>
>
>
>







>


>






|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 * be shared.
 */

#include <curl/curl.h>
#include "timeval.h"

struct connectdata;
struct curl_pollfds;
struct curl_waitfds;
struct Curl_multi;

struct connshutdowns {
  struct Curl_llist conn_list;  /* The connectdata to shut down */
  BIT(iter_locked);  /* TRUE while iterating the list */
};

struct conncache {
  struct Curl_hash hash;
  size_t num_conn;
  curl_off_t next_connection_id;
  curl_off_t next_easy_id;
  struct curltime last_cleanup;
  struct connshutdowns shutdowns;
  /* handle used for closing cached connections */
  struct Curl_easy *closure_handle;
  struct Curl_multi *multi; /* Optional, set if cache belongs to multi */
};

#define BUNDLE_NO_MULTIUSE -1
#define BUNDLE_UNKNOWN     0  /* initial value */
#define BUNDLE_MULTIPLEX   2

#ifdef DEBUGBUILD
/* the debug versions of these macros make extra certain that the lock is
   never doubly locked or unlocked */
#define CONNCACHE_LOCK(x)                                               \
  do {                                                                  \
    if((x)->share) {                                                    \
      Curl_share_lock((x), CURL_LOCK_DATA_CONNECT,                      \
                      CURL_LOCK_ACCESS_SINGLE);                         \
80
81
82
83
84
85
86

87

88


89
90
91
92
93
94
95

struct connectbundle {
  int multiuse;                 /* supports multi-use */
  size_t num_connections;       /* Number of connections in the bundle */
  struct Curl_llist conn_list;  /* The connectdata members of the bundle */
};


/* returns 1 on error, 0 is fine */

int Curl_conncache_init(struct conncache *, size_t size);


void Curl_conncache_destroy(struct conncache *connc);

/* return the correct bundle, to a host or a proxy */
struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data,
                                                 struct connectdata *conn,
                                                 struct conncache *connc);
/* returns number of connections currently held in the connection cache */







>
|
>
|
>
>







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

struct connectbundle {
  int multiuse;                 /* supports multi-use */
  size_t num_connections;       /* Number of connections in the bundle */
  struct Curl_llist conn_list;  /* The connectdata members of the bundle */
};

/* Init the cache, pass multi only if cache is owned by it.
 * returns 1 on error, 0 is fine.
 */
int Curl_conncache_init(struct conncache *,
                        struct Curl_multi *multi,
                        size_t size);
void Curl_conncache_destroy(struct conncache *connc);

/* return the correct bundle, to a host or a proxy */
struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data,
                                                 struct connectdata *conn,
                                                 struct conncache *connc);
/* returns number of connections currently held in the connection cache */
115
116
117
118
119
120
121




























122
Curl_conncache_extract_bundle(struct Curl_easy *data,
                              struct connectbundle *bundle);
struct connectdata *
Curl_conncache_extract_oldest(struct Curl_easy *data);
void Curl_conncache_close_all_connections(struct conncache *connc);
void Curl_conncache_print(struct conncache *connc);





























#endif /* HEADER_CURL_CONNCACHE_H */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
Curl_conncache_extract_bundle(struct Curl_easy *data,
                              struct connectbundle *bundle);
struct connectdata *
Curl_conncache_extract_oldest(struct Curl_easy *data);
void Curl_conncache_close_all_connections(struct conncache *connc);
void Curl_conncache_print(struct conncache *connc);

/**
 * Tear down the connection. If `aborted` is FALSE, the connection
 * will be shut down first before discarding. If the shutdown
 * is not immediately complete, the connection
 * will be placed into the cache is shutdown queue.
 */
void Curl_conncache_disconnect(struct Curl_easy *data,
                               struct connectdata *conn,
                               bool aborted);

/**
 * Add sockets and POLLIN/OUT flags for connections handled by the cache.
 */
CURLcode Curl_conncache_add_pollfds(struct conncache *connc,
                                    struct curl_pollfds *cpfds);
CURLcode Curl_conncache_add_waitfds(struct conncache *connc,
                                    struct curl_waitfds *cwfds);

/**
 * Perform maintenance on connections in the cache. Specifically,
 * progress the shutdown of connections in the queue.
 */
void Curl_conncache_multi_perform(struct Curl_multi *multi);

void Curl_conncache_multi_socket(struct Curl_multi *multi,
                                 curl_socket_t s, int ev_bitmask);
void Curl_conncache_multi_close_all(struct Curl_multi *multi);

#endif /* HEADER_CURL_CONNCACHE_H */
Changes to jni/curl/lib/connect.c.
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif

/*
 * Curl_timeleft() returns the amount of milliseconds left allowed for the
 * transfer/connection. If the value is 0, there's no timeout (ie there's
 * infinite time left). If the value is negative, the timeout time has already
 * elapsed.
 * @param data the transfer to check on
 * @param nowp timestamp to use for calculation, NULL to use Curl_now()
 * @param duringconnect TRUE iff connect timeout is also taken into account.
 * @unittest: 1303
 */







|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif

/*
 * Curl_timeleft() returns the amount of milliseconds left allowed for the
 * transfer/connection. If the value is 0, there is no timeout (ie there is
 * infinite time left). If the value is negative, the timeout time has already
 * elapsed.
 * @param data the transfer to check on
 * @param nowp timestamp to use for calculation, NULL to use Curl_now()
 * @param duringconnect TRUE iff connect timeout is also taken into account.
 * @unittest: 1303
 */
137
138
139
140
141
142
143











































144
145
146
147
148
149
150
      ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
    if(!timeleft_ms)
      return ctimeleft_ms; /* no general timeout, this is it */
  }
  /* return minimal time left or max amount already expired */
  return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms;
}












































/* Copies connection info into the transfer handle to make it available when
   the transfer handle is no longer associated with the connection. */
void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
                          struct ip_quadruple *ip)
{
  if(ip)







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
      ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
    if(!timeleft_ms)
      return ctimeleft_ms; /* no general timeout, this is it */
  }
  /* return minimal time left or max amount already expired */
  return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms;
}

void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
                         struct curltime *nowp)
{
  struct curltime now;

  DEBUGASSERT(data->conn);
  if(!nowp) {
    now = Curl_now();
    nowp = &now;
  }
  data->conn->shutdown.start[sockindex] = *nowp;
  data->conn->shutdown.timeout_ms = (data->set.shutdowntimeout > 0) ?
    data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS;
}

timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
                                  struct curltime *nowp)
{
  struct curltime now;

  if(!conn->shutdown.start[sockindex].tv_sec || !conn->shutdown.timeout_ms)
    return 0; /* not started or no limits */

  if(!nowp) {
    now = Curl_now();
    nowp = &now;
  }
  return conn->shutdown.timeout_ms -
         Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
}

void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
{
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
  memset(pt, 0, sizeof(*pt));
}

bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
{
  struct curltime *pt = &data->conn->shutdown.start[sockindex];
  return (pt->tv_sec > 0) || (pt->tv_usec > 0);
}

/* Copies connection info into the transfer handle to make it available when
   the transfer handle is no longer associated with the connection. */
void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
                          struct ip_quadruple *ip)
{
  if(ip)
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
void Curl_conncontrol(struct connectdata *conn,
                      int ctrl /* see defines in header */
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
                      , const char *reason
#endif
  )
{
  /* close if a connection, or a stream that isn't multiplexed. */
  /* This function will be called both before and after this connection is
     associated with a transfer. */
  bool closeit, is_multiplex;
  DEBUGASSERT(conn);
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void)reason; /* useful for debugging */
#endif







|







356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
void Curl_conncontrol(struct connectdata *conn,
                      int ctrl /* see defines in header */
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
                      , const char *reason
#endif
  )
{
  /* close if a connection, or a stream that is not multiplexed. */
  /* This function will be called both before and after this connection is
     associated with a transfer. */
  bool closeit, is_multiplex;
  DEBUGASSERT(conn);
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void)reason; /* useful for debugging */
#endif
354
355
356
357
358
359
360

361
362
363
364
365
366
367
  expire_id timeout_id;              /* ID for Curl_expire() */
  CURLcode result;
  int error;
  BIT(rewinded);                     /* if we rewinded the addr list */
  BIT(has_started);                  /* attempts have started */
  BIT(is_done);                      /* out of addresses/time */
  BIT(connected);                    /* cf has connected */

  BIT(inconclusive);                 /* connect was not a hard failure, we
                                      * might talk to a restarting server */
};


typedef enum {
  SCFST_INIT,







>







397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  expire_id timeout_id;              /* ID for Curl_expire() */
  CURLcode result;
  int error;
  BIT(rewinded);                     /* if we rewinded the addr list */
  BIT(has_started);                  /* attempts have started */
  BIT(is_done);                      /* out of addresses/time */
  BIT(connected);                    /* cf has connected */
  BIT(shutdown);                     /* cf has shutdown */
  BIT(inconclusive);                 /* connect was not a hard failure, we
                                      * might talk to a restarting server */
};


typedef enum {
  SCFST_INIT,
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
{
  struct cf_he_ctx *ctx = cf->ctx;
  struct Curl_cfilter *cf_prev = baller->cf;
  struct Curl_cfilter *wcf;
  CURLcode result;


  /* Don't close a previous cfilter yet to ensure that the next IP's
     socket gets a different file descriptor, which can prevent bugs when
     the curl_multi_socket_action interface is used with certain select()
     replacements such as kqueue. */
  result = baller->cf_create(&baller->cf, data, cf->conn, baller->addr,
                             ctx->transport);
  if(result)
    goto out;







|







504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
{
  struct cf_he_ctx *ctx = cf->ctx;
  struct Curl_cfilter *cf_prev = baller->cf;
  struct Curl_cfilter *wcf;
  CURLcode result;


  /* Do not close a previous cfilter yet to ensure that the next IP's
     socket gets a different file descriptor, which can prevent bugs when
     the curl_multi_socket_action interface is used with certain select()
     replacements such as kqueue. */
  result = baller->cf_create(&baller->cf, data, cf->conn, baller->addr,
                             ctx->transport);
  if(result)
    goto out;
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
    result = CURLE_OPERATION_TIMEDOUT;
#endif

  return result;
}

/*
 * Connect to the given host with timeout, proxy or remote doesn't matter.
 * There might be more than one IP address to try out.
 */
static CURLcode start_connect(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              const struct Curl_dns_entry *remotehost)
{
  struct cf_he_ctx *ctx = cf->ctx;







|







784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
    result = CURLE_OPERATION_TIMEDOUT;
#endif

  return result;
}

/*
 * Connect to the given host with timeout, proxy or remote does not matter.
 * There might be more than one IP address to try out.
 */
static CURLcode start_connect(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              const struct Curl_dns_entry *remotehost)
{
  struct cf_he_ctx *ctx = cf->ctx;
852
853
854
855
856
857
858








































859
860
861
862
863
864
865
  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
    baller_free(ctx->baller[i], data);
    ctx->baller[i] = NULL;
  }
  baller_free(ctx->winner, data);
  ctx->winner = NULL;
}









































static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  struct easy_pollset *ps)
{
  struct cf_he_ctx *ctx = cf->ctx;
  size_t i;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
    baller_free(ctx->baller[i], data);
    ctx->baller[i] = NULL;
  }
  baller_free(ctx->winner, data);
  ctx->winner = NULL;
}

static CURLcode cf_he_shutdown(struct Curl_cfilter *cf,
                               struct Curl_easy *data, bool *done)
{
  struct cf_he_ctx *ctx = cf->ctx;
  size_t i;
  CURLcode result = CURLE_OK;

  DEBUGASSERT(data);
  if(cf->connected) {
    *done = TRUE;
    return CURLE_OK;
  }

  /* shutdown all ballers that have not done so already. If one fails,
   * continue shutting down others until all are shutdown. */
  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
    struct eyeballer *baller = ctx->baller[i];
    bool bdone = FALSE;
    if(!baller || !baller->cf || baller->shutdown)
      continue;
    baller->result = baller->cf->cft->do_shutdown(baller->cf, data, &bdone);
    if(baller->result || bdone)
      baller->shutdown = TRUE; /* treat a failed shutdown as done */
  }

  *done = TRUE;
  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
    if(ctx->baller[i] && !ctx->baller[i]->shutdown)
      *done = FALSE;
  }
  if(*done) {
    for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
      if(ctx->baller[i] && ctx->baller[i]->result)
        result = ctx->baller[i]->result;
    }
  }
  CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
  return result;
}

static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  struct easy_pollset *ps)
{
  struct cf_he_ctx *ctx = cf->ctx;
  size_t i;
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
        cf->next = ctx->winner->cf;
        ctx->winner->cf = NULL;
        cf_he_ctx_clear(cf, data);
        Curl_conn_cf_cntrl(cf->next, data, TRUE,
                           CF_CTRL_CONN_INFO_UPDATE, 0, NULL);

        if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
          Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
        Curl_verboseconnect(data, cf->conn, cf->sockindex);
        data->info.numconnects++; /* to track the # of connections made */
      }
      break;
    case SCFST_DONE:
      *done = TRUE;
      break;







|







997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
        cf->next = ctx->winner->cf;
        ctx->winner->cf = NULL;
        cf_he_ctx_clear(cf, data);
        Curl_conn_cf_cntrl(cf->next, data, TRUE,
                           CF_CTRL_CONN_INFO_UPDATE, 0, NULL);

        if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
          Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */
        Curl_verboseconnect(data, cf->conn, cf->sockindex);
        data->info.numconnects++; /* to track the # of connections made */
      }
      break;
    case SCFST_DONE:
      *done = TRUE;
      break;
1048
1049
1050
1051
1052
1053
1054

1055
1056
1057
1058
1059
1060
1061
struct Curl_cftype Curl_cft_happy_eyeballs = {
  "HAPPY-EYEBALLS",
  0,
  CURL_LOG_LVL_NONE,
  cf_he_destroy,
  cf_he_connect,
  cf_he_close,

  Curl_cf_def_get_host,
  cf_he_adjust_pollset,
  cf_he_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,







>







1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
struct Curl_cftype Curl_cft_happy_eyeballs = {
  "HAPPY-EYEBALLS",
  0,
  CURL_LOG_LVL_NONE,
  cf_he_destroy,
  cf_he_connect,
  cf_he_close,
  cf_he_shutdown,
  Curl_cf_def_get_host,
  cf_he_adjust_pollset,
  cf_he_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122

struct transport_provider {
  int transport;
  cf_ip_connect_create *cf_create;
};

static
#ifndef DEBUGBUILD
const
#endif
struct transport_provider transport_providers[] = {
  { TRNSPRT_TCP, Curl_cf_tcp_create },
#ifdef USE_HTTP3
  { TRNSPRT_QUIC, Curl_cf_quic_create },
#endif







|







1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207

struct transport_provider {
  int transport;
  cf_ip_connect_create *cf_create;
};

static
#ifndef UNITTESTS
const
#endif
struct transport_provider transport_providers[] = {
  { TRNSPRT_TCP, Curl_cf_tcp_create },
#ifdef USE_HTTP3
  { TRNSPRT_QUIC, Curl_cf_quic_create },
#endif
1312
1313
1314
1315
1316
1317
1318

1319
1320
1321
1322
1323
1324
1325
struct Curl_cftype Curl_cft_setup = {
  "SETUP",
  0,
  CURL_LOG_LVL_NONE,
  cf_setup_destroy,
  cf_setup_connect,
  cf_setup_close,

  Curl_cf_def_get_host,
  Curl_cf_def_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,







>







1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
struct Curl_cftype Curl_cft_setup = {
  "SETUP",
  0,
  CURL_LOG_LVL_NONE,
  cf_setup_destroy,
  cf_setup_connect,
  cf_setup_close,
  Curl_cf_def_shutdown,
  Curl_cf_def_get_host,
  Curl_cf_def_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
  if(result)
    goto out;
  Curl_conn_cf_add(data, conn, sockindex, cf);
out:
  return result;
}

#ifdef DEBUGBUILD
/* used by unit2600.c */
void Curl_debug_set_transport_provider(int transport,
                                       cf_ip_connect_create *cf_create)
{
  size_t i;
  for(i = 0; i < ARRAYSIZE(transport_providers); ++i) {
    if(transport == transport_providers[i].transport) {
      transport_providers[i].cf_create = cf_create;
      return;
    }
  }
}
#endif /* DEBUGBUILD */

CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
                                    struct Curl_easy *data,
                                    const struct Curl_dns_entry *remotehost,
                                    int transport,
                                    int ssl_mode)
{







|












|







1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
  if(result)
    goto out;
  Curl_conn_cf_add(data, conn, sockindex, cf);
out:
  return result;
}

#ifdef UNITTESTS
/* used by unit2600.c */
void Curl_debug_set_transport_provider(int transport,
                                       cf_ip_connect_create *cf_create)
{
  size_t i;
  for(i = 0; i < ARRAYSIZE(transport_providers); ++i) {
    if(transport == transport_providers[i].transport) {
      transport_providers[i].cf_create = cf_create;
      return;
    }
  }
}
#endif /* UNITTESTS */

CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
                                    struct Curl_easy *data,
                                    const struct Curl_dns_entry *remotehost,
                                    int transport,
                                    int ssl_mode)
{
Changes to jni/curl/lib/connect.h.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42















43
44
45
46
47
48
49
#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
#include "sockaddr.h"
#include "timeval.h"

struct Curl_dns_entry;
struct ip_quadruple;

/* generic function that returns how much time there's left to run, according
   to the timeouts set */
timediff_t Curl_timeleft(struct Curl_easy *data,
                         struct curltime *nowp,
                         bool duringconnect);

#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
















/*
 * Used to extract socket and connectdata struct for the most recent
 * transfer on the given Curl_easy.
 *
 * The returned socket will be CURL_SOCKET_BAD in case of failure!
 */
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,







|







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
#include "sockaddr.h"
#include "timeval.h"

struct Curl_dns_entry;
struct ip_quadruple;

/* generic function that returns how much time there is left to run, according
   to the timeouts set */
timediff_t Curl_timeleft(struct Curl_easy *data,
                         struct curltime *nowp,
                         bool duringconnect);

#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */

#define DEFAULT_SHUTDOWN_TIMEOUT_MS   (2 * 1000)

void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
                         struct curltime *nowp);

/* return how much time there is left to shutdown the connection at
 * sockindex. */
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
                                  struct curltime *nowp);

void Curl_shutdown_clear(struct Curl_easy *data, int sockindex);

/* TRUE iff shutdown has been started */
bool Curl_shutdown_started(struct Curl_easy *data, int sockindex);

/*
 * Used to extract socket and connectdata struct for the most recent
 * transfer on the given Curl_easy.
 *
 * The returned socket will be CURL_SOCKET_BAD in case of failure!
 */
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
121
122
123
124
125
126
127
128
129
130
131
132
133
                         int sockindex,
                         const struct Curl_dns_entry *remotehost,
                         int ssl_mode);

extern struct Curl_cftype Curl_cft_happy_eyeballs;
extern struct Curl_cftype Curl_cft_setup;

#ifdef DEBUGBUILD
void Curl_debug_set_transport_provider(int transport,
                                       cf_ip_connect_create *cf_create);
#endif

#endif /* HEADER_CURL_CONNECT_H */







|





136
137
138
139
140
141
142
143
144
145
146
147
148
                         int sockindex,
                         const struct Curl_dns_entry *remotehost,
                         int ssl_mode);

extern struct Curl_cftype Curl_cft_happy_eyeballs;
extern struct Curl_cftype Curl_cft_setup;

#ifdef UNITTESTS
void Curl_debug_set_transport_provider(int transport,
                                       cf_ip_connect_create *cf_create);
#endif

#endif /* HEADER_CURL_CONNECT_H */
Changes to jni/curl/lib/content_encoding.c.
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#define GZIP_MAGIC_0 0x1f
#define GZIP_MAGIC_1 0x8b

/* gzip flag byte */
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
#define COMMENT      0x10 /* bit 4 set: file comment present */
#define RESERVED     0xE0 /* bits 5..7: reserved */

typedef enum {
  ZLIB_UNINIT,               /* uninitialized */
  ZLIB_INIT,                 /* initialized */
  ZLIB_INFLATING,            /* inflating started. */







|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#define GZIP_MAGIC_0 0x1f
#define GZIP_MAGIC_1 0x8b

/* gzip flag byte */
#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
#define ORIG_NAME    0x08 /* bit 3 set: original filename present */
#define COMMENT      0x10 /* bit 4 set: file comment present */
#define RESERVED     0xE0 /* bits 5..7: reserved */

typedef enum {
  ZLIB_UNINIT,               /* uninitialized */
  ZLIB_INIT,                 /* initialized */
  ZLIB_INFLATING,            /* inflating started. */
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  /* Check state. */
  if(zp->zlib_init != ZLIB_INIT &&
     zp->zlib_init != ZLIB_INFLATING &&
     zp->zlib_init != ZLIB_INIT_GZIP &&
     zp->zlib_init != ZLIB_GZIP_INFLATING)
    return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);

  /* Dynamically allocate a buffer for decompression because it's uncommonly
     large to hold on the stack */
  decomp = malloc(DSIZ);
  if(!decomp)
    return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);

  /* because the buffer size is fixed, iteratively decompress and transfer to
     the client via next_write function. */







|







188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  /* Check state. */
  if(zp->zlib_init != ZLIB_INIT &&
     zp->zlib_init != ZLIB_INFLATING &&
     zp->zlib_init != ZLIB_INIT_GZIP &&
     zp->zlib_init != ZLIB_GZIP_INFLATING)
    return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);

  /* Dynamically allocate a buffer for decompression because it is uncommonly
     large to hold on the stack */
  decomp = malloc(DSIZ);
  if(!decomp)
    return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);

  /* because the buffer size is fixed, iteratively decompress and transfer to
     the client via next_write function. */
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
      result = process_trailer(data, zp);
      break;
    case Z_DATA_ERROR:
      /* some servers seem to not generate zlib headers, so this is an attempt
         to fix and continue anyway */
      if(zp->zlib_init == ZLIB_INIT) {
        /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */
        (void) inflateEnd(z);     /* don't care about the return code */
        if(inflateInit2(z, -MAX_WBITS) == Z_OK) {
          z->next_in = orig_in;
          z->avail_in = nread;
          zp->zlib_init = ZLIB_INFLATING;
          zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */
          done = FALSE;
          break;
        }
        zp->zlib_init = ZLIB_UNINIT;    /* inflateEnd() already called. */
      }
      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
      break;
    default:
      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
      break;
    }
  }
  free(decomp);

  /* We're about to leave this call so the `nread' data bytes won't be seen
     again. If we are in a state that would wrongly allow restart in raw mode
     at the next call, assume output has already started. */
  if(nread && zp->zlib_init == ZLIB_INIT)
    zp->zlib_init = started;      /* Cannot restart anymore. */

  return result;
}







|



















|







242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
      result = process_trailer(data, zp);
      break;
    case Z_DATA_ERROR:
      /* some servers seem to not generate zlib headers, so this is an attempt
         to fix and continue anyway */
      if(zp->zlib_init == ZLIB_INIT) {
        /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */
        (void) inflateEnd(z);     /* do not care about the return code */
        if(inflateInit2(z, -MAX_WBITS) == Z_OK) {
          z->next_in = orig_in;
          z->avail_in = nread;
          zp->zlib_init = ZLIB_INFLATING;
          zp->trailerlen = 4; /* Tolerate up to 4 unknown trailer bytes. */
          done = FALSE;
          break;
        }
        zp->zlib_init = ZLIB_UNINIT;    /* inflateEnd() already called. */
      }
      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
      break;
    default:
      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
      break;
    }
  }
  free(decomp);

  /* We are about to leave this call so the `nread' data bytes will not be seen
     again. If we are in a state that would wrongly allow restart in raw mode
     at the next call, assume output has already started. */
  if(nread && zp->zlib_init == ZLIB_INIT)
    zp->zlib_init = started;      /* Cannot restart anymore. */

  return result;
}
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
    return GZIP_BAD;

  method = data[2];
  flags = data[3];

  if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
    /* Can't handle this compression method or unknown flag */
    return GZIP_BAD;
  }

  /* Skip over time, xflags, OS code and all previous bytes */
  len -= 10;
  data += 10;








|







384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
    return GZIP_BAD;

  method = data[2];
  flags = data[3];

  if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
    /* cannot handle this compression method or unknown flag */
    return GZIP_BAD;
  }

  /* Skip over time, xflags, OS code and all previous bytes */
  len -= 10;
  data += 10;

408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
      return GZIP_UNDERFLOW;

    len -= (extra_len + 2);
    data += (extra_len + 2);
  }

  if(flags & ORIG_NAME) {
    /* Skip over NUL-terminated file name */
    while(len && *data) {
      --len;
      ++data;
    }
    if(!len || *data)
      return GZIP_UNDERFLOW;








|







408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
      return GZIP_UNDERFLOW;

    len -= (extra_len + 2);
    data += (extra_len + 2);
  }

  if(flags & ORIG_NAME) {
    /* Skip over NUL-terminated filename */
    while(len && *data) {
      --len;
      ++data;
    }
    if(!len || *data)
      return GZIP_UNDERFLOW;

470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

#ifndef OLD_ZLIB_SUPPORT
  /* Support for old zlib versions is compiled away and we are running with
     an old version, so return an error. */
  return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);

#else
  /* This next mess is to get around the potential case where there isn't
   * enough data passed in to skip over the gzip header.  If that happens, we
   * malloc a block and copy what we have then wait for the next call.  If
   * there still isn't enough (this is definitely a worst-case scenario), we
   * make the block bigger, copy the next part in and keep waiting.
   *
   * This is only required with zlib versions < 1.2.0.4 as newer versions
   * can handle the gzip header themselves.
   */

  switch(zp->zlib_init) {







|
|
|
|







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

#ifndef OLD_ZLIB_SUPPORT
  /* Support for old zlib versions is compiled away and we are running with
     an old version, so return an error. */
  return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);

#else
  /* This next mess is to get around the potential case where there is not
   * enough data passed in to skip over the gzip header. If that happens, we
   * malloc a block and copy what we have then wait for the next call. If
   * there still is not enough (this is definitely a worst-case scenario), we
   * make the block bigger, copy the next part in and keep waiting.
   *
   * This is only required with zlib versions < 1.2.0.4 as newer versions
   * can handle the gzip header themselves.
   */

  switch(zp->zlib_init) {
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
    case GZIP_OK:
      z->next_in = (Bytef *) buf + hlen;
      z->avail_in = (uInt) (nbytes - hlen);
      zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We need more data so we can find the end of the gzip header.  It's
       * possible that the memory block we malloc here will never be freed if
       * the transfer abruptly aborts after this point.  Since it's unlikely
       * that circumstances will be right for this code path to be followed in
       * the first place, and it's even more unlikely for a transfer to fail
       * immediately afterwards, it should seldom be a problem.
       */
      z->avail_in = (uInt) nbytes;
      z->next_in = malloc(z->avail_in);
      if(!z->next_in) {
        return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
      }
      memcpy(z->next_in, buf, z->avail_in);
      zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
      /* We don't have any data to inflate yet */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
    }








|

|

|









|







495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
    case GZIP_OK:
      z->next_in = (Bytef *) buf + hlen;
      z->avail_in = (uInt) (nbytes - hlen);
      zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We need more data so we can find the end of the gzip header. it is
       * possible that the memory block we malloc here will never be freed if
       * the transfer abruptly aborts after this point. Since it is unlikely
       * that circumstances will be right for this code path to be followed in
       * the first place, and it is even more unlikely for a transfer to fail
       * immediately afterwards, it should seldom be a problem.
       */
      z->avail_in = (uInt) nbytes;
      z->next_in = malloc(z->avail_in);
      if(!z->next_in) {
        return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
      }
      memcpy(z->next_in, buf, z->avail_in);
      zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
      /* We do not have any data to inflate yet */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
    }

532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
    z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
    if(!z->next_in) {
      return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
    }
    /* Append the new block of data to the previous one */
    memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);

    switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
    case GZIP_OK:
      /* This is the zlib stream data */
      free(z->next_in);
      /* Don't point into the malloced block since we just freed it */
      z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
      z->avail_in = (uInt) (z->avail_in - hlen);
      zp->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We still don't have any data to inflate! */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
    }








|



|

|




|







532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
    z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
    if(!z->next_in) {
      return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
    }
    /* Append the new block of data to the previous one */
    memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);

    switch(check_gzip_header(z->next_in, (ssize_t)z->avail_in, &hlen)) {
    case GZIP_OK:
      /* This is the zlib stream data */
      free(z->next_in);
      /* Do not point into the malloced block since we just freed it */
      z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
      z->avail_in = z->avail_in - (uInt)hlen;
      zp->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
      break;

    case GZIP_UNDERFLOW:
      /* We still do not have any data to inflate! */
      return CURLE_OK;

    case GZIP_BAD:
    default:
      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
    }

568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
    /* Inflating stream state */
    z->next_in = (Bytef *) buf;
    z->avail_in = (uInt) nbytes;
    break;
  }

  if(z->avail_in == 0) {
    /* We don't have any data to inflate; wait until next time */
    return CURLE_OK;
  }

  /* We've parsed the header, now uncompress the data */
  return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING);
#endif
}

static void gzip_do_close(struct Curl_easy *data,
                              struct Curl_cwriter *writer)
{







|



|







568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
    /* Inflating stream state */
    z->next_in = (Bytef *) buf;
    z->avail_in = (uInt) nbytes;
    break;
  }

  if(z->avail_in == 0) {
    /* We do not have any data to inflate; wait until next time */
    return CURLE_OK;
  }

  /* We have parsed the header, now uncompress the data */
  return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING);
#endif
}

static void gzip_do_close(struct Curl_easy *data,
                              struct Curl_cwriter *writer)
{
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
    if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
       (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
      return ce;
  }
  return NULL;
}

/* Set-up the unencoding stack from the Content-Encoding header value.
 * See RFC 7231 section 3.1.2.2. */
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                     const char *enclist, int is_transfer)
{
  Curl_cwriter_phase phase = is_transfer?
                             CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE;
  CURLcode result;







|







962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
    if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
       (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
      return ce;
  }
  return NULL;
}

/* Setup the unencoding stack from the Content-Encoding header value.
 * See RFC 7231 section 3.1.2.2. */
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                     const char *enclist, int is_transfer)
{
  Curl_cwriter_phase phase = is_transfer?
                             CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE;
  CURLcode result;
990
991
992
993
994
995
996


997
998
999
1000
1001
1002
1003


1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020

1021
1022
1023
1024
1025
1026
1027
      if(!ISSPACE(*enclist))
        namelen = enclist - name + 1;

    if(namelen) {
      const struct Curl_cwtype *cwt;
      struct Curl_cwriter *writer;



      is_chunked = (is_transfer && (namelen == 7) &&
                    strncasecompare(name, "chunked", 7));
      /* if we skip the decoding in this phase, do not look further.
       * Exception is "chunked" transfer-encoding which always must happen */
      if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
         (!is_transfer && data->set.http_ce_skip)) {
        /* not requested, ignore */


        return CURLE_OK;
      }

      if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) {
        failf(data, "Reject response due to more than %u content encodings",
              MAX_ENCODE_STACK);
        return CURLE_BAD_CONTENT_ENCODING;
      }

      cwt = find_unencode_writer(name, namelen, phase);
      if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) {
        /* A 'chunked' transfer encoding has already been added.
         * Ignore duplicates. See #13451.
         * Also RFC 9112, ch. 6.1:
         * "A sender MUST NOT apply the chunked transfer coding more than
         *  once to a message body."
         */

        return CURLE_OK;
      }

      if(is_transfer && !is_chunked &&
         Curl_cwriter_get_by_name(data, "chunked")) {
        /* RFC 9112, ch. 6.1:
         * "If any transfer coding other than chunked is applied to a







>
>







>
>

















>







990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
      if(!ISSPACE(*enclist))
        namelen = enclist - name + 1;

    if(namelen) {
      const struct Curl_cwtype *cwt;
      struct Curl_cwriter *writer;

      CURL_TRC_WRITE(data, "looking for %s decoder: %.*s",
                     is_transfer? "transfer" : "content", (int)namelen, name);
      is_chunked = (is_transfer && (namelen == 7) &&
                    strncasecompare(name, "chunked", 7));
      /* if we skip the decoding in this phase, do not look further.
       * Exception is "chunked" transfer-encoding which always must happen */
      if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
         (!is_transfer && data->set.http_ce_skip)) {
        /* not requested, ignore */
        CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s",
                       (int)namelen, name);
        return CURLE_OK;
      }

      if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) {
        failf(data, "Reject response due to more than %u content encodings",
              MAX_ENCODE_STACK);
        return CURLE_BAD_CONTENT_ENCODING;
      }

      cwt = find_unencode_writer(name, namelen, phase);
      if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) {
        /* A 'chunked' transfer encoding has already been added.
         * Ignore duplicates. See #13451.
         * Also RFC 9112, ch. 6.1:
         * "A sender MUST NOT apply the chunked transfer coding more than
         *  once to a message body."
         */
        CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder");
        return CURLE_OK;
      }

      if(is_transfer && !is_chunked &&
         Curl_cwriter_get_by_name(data, "chunked")) {
        /* RFC 9112, ch. 6.1:
         * "If any transfer coding other than chunked is applied to a
1036
1037
1038
1039
1040
1041
1042


1043
1044
1045
1046
1047
1048
1049
        return CURLE_BAD_CONTENT_ENCODING;
      }

      if(!cwt)
        cwt = &error_writer;  /* Defer error at use. */

      result = Curl_cwriter_create(&writer, data, cwt, phase);


      if(result)
        return result;

      result = Curl_cwriter_add(data, writer);
      if(result) {
        Curl_cwriter_free(data, writer);
        return result;







>
>







1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
        return CURLE_BAD_CONTENT_ENCODING;
      }

      if(!cwt)
        cwt = &error_writer;  /* Defer error at use. */

      result = Curl_cwriter_create(&writer, data, cwt, phase);
      CURL_TRC_WRITE(data, "added %s decoder %s -> %d",
                     is_transfer? "transfer" : "content", cwt->name, result);
      if(result)
        return result;

      result = Curl_cwriter_add(data, writer);
      if(result) {
        Curl_cwriter_free(data, writer);
        return result;
Changes to jni/curl/lib/cookie.c.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
                                    char *host, char *path, bool secure);

        For a given host and path, return a linked list of cookies that
        the client should send to the server if used now. The secure
        boolean informs the cookie if a secure connection is achieved or
        not.

        It shall only return cookies that haven't expired.


Example set of cookies:

    Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
    Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
    domain=.fidelity.com; path=/ftgw; secure







|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
                                    char *host, char *path, bool secure);

        For a given host and path, return a linked list of cookies that
        the client should send to the server if used now. The secure
        boolean informs the cookie if a secure connection is achieved or
        not.

        It shall only return cookies that have not expired.


Example set of cookies:

    Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
    Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
    domain=.fidelity.com; path=/ftgw; secure
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    return TRUE;
  if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
    return TRUE;
  return FALSE;
}

/*
 * matching cookie path and url path
 * RFC6265 5.1.4 Paths and Path-Match
 */
static bool pathmatch(const char *cookie_path, const char *request_uri)
{
  size_t cookie_path_len;
  size_t uri_path_len;
  char *uri_path = NULL;







|







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
    return TRUE;
  if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
    return TRUE;
  return FALSE;
}

/*
 * matching cookie path and URL path
 * RFC6265 5.1.4 Paths and Path-Match
 */
static bool pathmatch(const char *cookie_path, const char *request_uri)
{
  size_t cookie_path_len;
  size_t uri_path_len;
  char *uri_path = NULL;
258
259
260
261
262
263
264

265
266
267
268
269
270
271
272
273
 */
static size_t cookie_hash_domain(const char *domain, const size_t len)
{
  const char *end = domain + len;
  size_t h = 5381;

  while(domain < end) {

    h += h << 5;
    h ^= Curl_raw_toupper(*domain++);
  }

  return (h % COOKIE_HASH_SIZE);
}

#if defined(_MSC_VER) && (_MSC_VER == 1900)
#pragma optimize("", on)







>

|







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
 */
static size_t cookie_hash_domain(const char *domain, const size_t len)
{
  const char *end = domain + len;
  size_t h = 5381;

  while(domain < end) {
    size_t j = (size_t)Curl_raw_toupper(*domain++);
    h += h << 5;
    h ^= j;
  }

  return (h % COOKIE_HASH_SIZE);
}

#if defined(_MSC_VER) && (_MSC_VER == 1900)
#pragma optimize("", on)
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
}

/*
 * remove_expired
 *
 * Remove expired cookies from the hash by inspecting the expires timestamp on
 * each cookie in the hash, freeing and deleting any where the timestamp is in
 * the past.  If the cookiejar has recorded the next timestamp at which one or
 * more cookies expire, then processing will exit early in case this timestamp
 * is in the future.
 */
static void remove_expired(struct CookieInfo *cookies)
{
  struct Cookie *co, *nx;
  curl_off_t now = (curl_off_t)time(NULL);
  unsigned int i;

  /*
   * If the earliest expiration timestamp in the jar is in the future we can
   * skip scanning the whole jar and instead exit early as there won't be any
   * cookies to evict.  If we need to evict however, reset the next_expiration
   * counter in order to track the next one. In case the recorded first
   * expiration is the max offset, then perform the safe fallback of checking
   * all cookies.
   */
  if(now < cookies->next_expiration &&
      cookies->next_expiration != CURL_OFF_T_MAX)
    return;
  else
    cookies->next_expiration = CURL_OFF_T_MAX;








|











|
|
|
|
|







370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
}

/*
 * remove_expired
 *
 * Remove expired cookies from the hash by inspecting the expires timestamp on
 * each cookie in the hash, freeing and deleting any where the timestamp is in
 * the past. If the cookiejar has recorded the next timestamp at which one or
 * more cookies expire, then processing will exit early in case this timestamp
 * is in the future.
 */
static void remove_expired(struct CookieInfo *cookies)
{
  struct Cookie *co, *nx;
  curl_off_t now = (curl_off_t)time(NULL);
  unsigned int i;

  /*
   * If the earliest expiration timestamp in the jar is in the future we can
   * skip scanning the whole jar and instead exit early as there will not be
   * any cookies to evict. If we need to evict however, reset the
   * next_expiration counter in order to track the next one. In case the
   * recorded first expiration is the max offset, then perform the safe
   * fallback of checking all cookies.
   */
  if(now < cookies->next_expiration &&
      cookies->next_expiration != CURL_OFF_T_MAX)
    return;
  else
    cookies->next_expiration = CURL_OFF_T_MAX;

410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
          pv->next = co->next;
        }
        cookies->numcookies--;
        freecookie(co);
      }
      else {
        /*
         * If this cookie has an expiration timestamp earlier than what we've
         * seen so far then record it for the next round of expirations.
         */
        if(co->expires && co->expires < cookies->next_expiration)
          cookies->next_expiration = co->expires;
        pv = co;
      }
      co = nx;







|







411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
          pv->next = co->next;
        }
        cookies->numcookies--;
        freecookie(co);
      }
      else {
        /*
         * If this cookie has an expiration timestamp earlier than what we have
         * seen so far then record it for the next round of expirations.
         */
        if(co->expires && co->expires < cookies->next_expiration)
          cookies->next_expiration = co->expires;
        pv = co;
      }
      co = nx;
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  return (p[len] != '\0');
}

/*
 * Curl_cookie_add
 *
 * Add a single cookie line to the cookie keeping object. Be aware that
 * sometimes we get an IP-only host name, and that might also be a numerical
 * IPv6 address.
 *
 * Returns NULL on out of memory or invalid cookie. This is suboptimal,
 * as they should be treated separately.
 */
struct Cookie *
Curl_cookie_add(struct Curl_easy *data,







|







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
  return (p[len] != '\0');
}

/*
 * Curl_cookie_add
 *
 * Add a single cookie line to the cookie keeping object. Be aware that
 * sometimes we get an IP-only hostname, and that might also be a numerical
 * IPv6 address.
 *
 * Returns NULL on out of memory or invalid cookie. This is suboptimal,
 * as they should be treated separately.
 */
struct Cookie *
Curl_cookie_add(struct Curl_easy *data,
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
  DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */
  if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT)
    return NULL;

  /* First, alloc and init a new struct for it */
  co = calloc(1, sizeof(struct Cookie));
  if(!co)
    return NULL; /* bail out if we're this low on memory */

  if(httpheader) {
    /* This line was read off an HTTP-header */
    const char *ptr;

    size_t linelength = strlen(lineptr);
    if(linelength > MAX_COOKIE_LINE) {







|







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
  DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */
  if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT)
    return NULL;

  /* First, alloc and init a new struct for it */
  co = calloc(1, sizeof(struct Cookie));
  if(!co)
    return NULL; /* bail out if we are this low on memory */

  if(httpheader) {
    /* This line was read off an HTTP-header */
    const char *ptr;

    size_t linelength = strlen(lineptr);
    if(linelength > MAX_COOKIE_LINE) {
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
              badcookie = TRUE;
              break;
            }
          }
          else if((nlen == 8) && strncasecompare("httponly", namep, 8))
            co->httponly = TRUE;
          else if(sep)
            /* there was a '=' so we're not done parsing this field */
            done = FALSE;
        }
        if(done)
          ;
        else if((nlen == 4) && strncasecompare("path", namep, 4)) {
          strstore(&co->path, valuep, vlen);
          if(!co->path) {







|







644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
              badcookie = TRUE;
              break;
            }
          }
          else if((nlen == 8) && strncasecompare("httponly", namep, 8))
            co->httponly = TRUE;
          else if(sep)
            /* there was a '=' so we are not done parsing this field */
            done = FALSE;
        }
        if(done)
          ;
        else if((nlen == 4) && strncasecompare("path", namep, 4)) {
          strstore(&co->path, valuep, vlen);
          if(!co->path) {
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
          if('.' == valuep[0]) {
            valuep++; /* ignore preceding dot */
            vlen--;
          }

#ifndef USE_LIBPSL
          /*
           * Without PSL we don't know when the incoming cookie is set on a
           * TLD or otherwise "protected" suffix. To reduce risk, we require a
           * dot OR the exact host name being "localhost".
           */
          if(bad_domain(valuep, vlen))
            domain = ":";
#endif

          is_ip = Curl_host_is_ipnum(domain ? domain : valuep);








|

|







678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
          if('.' == valuep[0]) {
            valuep++; /* ignore preceding dot */
            vlen--;
          }

#ifndef USE_LIBPSL
          /*
           * Without PSL we do not know when the incoming cookie is set on a
           * TLD or otherwise "protected" suffix. To reduce risk, we require a
           * dot OR the exact hostname being "localhost".
           */
          if(bad_domain(valuep, vlen))
            domain = ":";
#endif

          is_ip = Curl_host_is_ipnum(domain ? domain : valuep);

717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
        else if((nlen == 7) && strncasecompare("version", namep, 7)) {
          /* just ignore */
        }
        else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
          /*
           * Defined in RFC2109:
           *
           * Optional.  The Max-Age attribute defines the lifetime of the
           * cookie, in seconds.  The delta-seconds value is a decimal non-
           * negative integer.  After delta-seconds seconds elapse, the
           * client should discard the cookie.  A value of zero means the
           * cookie should be discarded immediately.
           */
          CURLofft offt;
          const char *maxage = valuep;
          offt = curlx_strtoofft((*maxage == '\"')?
                                 &maxage[1]:&maxage[0], NULL, 10,
                                 &co->expires);







|
|
|
|







718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
        else if((nlen == 7) && strncasecompare("version", namep, 7)) {
          /* just ignore */
        }
        else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
          /*
           * Defined in RFC2109:
           *
           * Optional. The Max-Age attribute defines the lifetime of the
           * cookie, in seconds. The delta-seconds value is a decimal non-
           * negative integer. After delta-seconds seconds elapse, the
           * client should discard the cookie. A value of zero means the
           * cookie should be discarded immediately.
           */
          CURLofft offt;
          const char *maxage = valuep;
          offt = curlx_strtoofft((*maxage == '\"')?
                                 &maxage[1]:&maxage[0], NULL, 10,
                                 &co->expires);
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
              co->expires = 1;
            else if(co->expires < 0)
              co->expires = 0;
          }
        }

        /*
         * Else, this is the second (or more) name we don't know about!
         */
      }
      else {
        /* this is an "illegal" <what>=<this> pair */
      }

      while(*ptr && ISBLANK(*ptr))







|







777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
              co->expires = 1;
            else if(co->expires < 0)
              co->expires = 0;
          }
        }

        /*
         * Else, this is the second (or more) name we do not know about!
         */
      }
      else {
        /* this is an "illegal" <what>=<this> pair */
      }

      while(*ptr && ISBLANK(*ptr))
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
        if(!co->domain)
          badcookie = TRUE;
      }
    }

    if(!badcookie && !co->path && path) {
      /*
       * No path was given in the header line, set the default.  Note that the
       * passed-in path to this function MAY have a '?' and following part that
       * MUST NOT be stored as part of the path.
       */
      char *queryp = strchr(path, '?');

      /*
       * queryp is where the interesting part of the path ends, so now we







|







803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
        if(!co->domain)
          badcookie = TRUE;
      }
    }

    if(!badcookie && !co->path && path) {
      /*
       * No path was given in the header line, set the default. Note that the
       * passed-in path to this function MAY have a '?' and following part that
       * MUST NOT be stored as part of the path.
       */
      char *queryp = strchr(path, '?');

      /*
       * queryp is where the interesting part of the path ends, so now we
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
        }
        else
          badcookie = TRUE;
      }
    }

    /*
     * If we didn't get a cookie name, or a bad one, the this is an illegal
     * line so bail out.
     */
    if(badcookie || !co->name) {
      freecookie(co);
      return NULL;
    }
    data->req.setcookies++;







|







832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
        }
        else
          badcookie = TRUE;
      }
    }

    /*
     * If we did not get a cookie name, or a bad one, the this is an illegal
     * line so bail out.
     */
    if(badcookie || !co->name) {
      freecookie(co);
      return NULL;
    }
    data->req.setcookies++;
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
     */
    if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
      lineptr += 10;
      co->httponly = TRUE;
    }

    if(lineptr[0]=='#') {
      /* don't even try the comments */
      free(co);
      return NULL;
    }
    /* strip off the possible end-of-line characters */
    ptr = strchr(lineptr, '\r');
    if(ptr)
      *ptr = 0; /* clear it */







|







865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
     */
    if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
      lineptr += 10;
      co->httponly = TRUE;
    }

    if(lineptr[0]=='#') {
      /* do not even try the comments */
      free(co);
      return NULL;
    }
    /* strip off the possible end-of-line characters */
    ptr = strchr(lineptr, '\r');
    if(ptr)
      *ptr = 0; /* clear it */
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
         * .domain.com and to false when the domain is complete www.domain.com
         */
        co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
        break;
      case 2:
        /* The file format allows the path field to remain not filled in */
        if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
          /* only if the path doesn't look like a boolean option! */
          co->path = strdup(ptr);
          if(!co->path)
            badcookie = TRUE;
          else {
            co->spath = sanitize_cookie_path(co->path);
            if(!co->spath) {
              badcookie = TRUE; /* out of memory bad */
            }
          }
          break;
        }
        /* this doesn't look like a path, make one up! */
        co->path = strdup("/");
        if(!co->path)
          badcookie = TRUE;
        co->spath = strdup("/");
        if(!co->spath)
          badcookie = TRUE;
        fields++; /* add a field and fall down to secure */







|











|







905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
         * .domain.com and to false when the domain is complete www.domain.com
         */
        co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
        break;
      case 2:
        /* The file format allows the path field to remain not filled in */
        if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
          /* only if the path does not look like a boolean option! */
          co->path = strdup(ptr);
          if(!co->path)
            badcookie = TRUE;
          else {
            co->spath = sanitize_cookie_path(co->path);
            if(!co->spath) {
              badcookie = TRUE; /* out of memory bad */
            }
          }
          break;
        }
        /* this does not look like a path, make one up! */
        co->path = strdup("/");
        if(!co->path)
          badcookie = TRUE;
        co->spath = strdup("/");
        if(!co->spath)
          badcookie = TRUE;
        fields++; /* add a field and fall down to secure */
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
      freecookie(co);
      return NULL;
    }
  }

  if(!c->running &&    /* read from a file */
     c->newsession &&  /* clean session cookies */
     !co->expires) {   /* this is a session cookie since it doesn't expire! */
    freecookie(co);
    return NULL;
  }

  co->livecookie = c->running;
  co->creationtime = ++c->lastct;

  /*
   * Now we have parsed the incoming line, we must now check if this supersedes
   * an already existing cookie, which it may if the previous have the same
   * domain and path as this.
   */

  /* at first, remove expired cookies */
  if(!noexpire)
    remove_expired(c);

#ifdef USE_LIBPSL
  /*
   * Check if the domain is a Public Suffix and if yes, ignore the cookie. We
   * must also check that the data handle isn't NULL since the psl code will
   * dereference it.
   */
  if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
    bool acceptable = FALSE;
    char lcase[256];
    char lcookie[256];
    size_t dlen = strlen(domain);







|




















|







1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
      freecookie(co);
      return NULL;
    }
  }

  if(!c->running &&    /* read from a file */
     c->newsession &&  /* clean session cookies */
     !co->expires) {   /* this is a session cookie since it does not expire! */
    freecookie(co);
    return NULL;
  }

  co->livecookie = c->running;
  co->creationtime = ++c->lastct;

  /*
   * Now we have parsed the incoming line, we must now check if this supersedes
   * an already existing cookie, which it may if the previous have the same
   * domain and path as this.
   */

  /* at first, remove expired cookies */
  if(!noexpire)
    remove_expired(c);

#ifdef USE_LIBPSL
  /*
   * Check if the domain is a Public Suffix and if yes, ignore the cookie. We
   * must also check that the data handle is not NULL since the psl code will
   * dereference it.
   */
  if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
    bool acceptable = FALSE;
    char lcase[256];
    char lcookie[256];
    size_t dlen = strlen(domain);
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
          replace_old = FALSE;
        else if(!clist->spath != !co->spath)
          replace_old = FALSE;
      }

      if(replace_old && !co->livecookie && clist->livecookie) {
        /*
         * Both cookies matched fine, except that the already present cookie is
         * "live", which means it was set from a header, while the new one was
         * read from a file and thus isn't "live". "live" cookies are preferred
         * so the new cookie is freed.
         */
        freecookie(co);
        return NULL;
      }
      if(replace_old) {
        replace_co = co;
        replace_clist = clist;







|
|
|
|







1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
          replace_old = FALSE;
        else if(!clist->spath != !co->spath)
          replace_old = FALSE;
      }

      if(replace_old && !co->livecookie && clist->livecookie) {
        /*
         * Both cookies matched fine, except that the already present cookie
         * is "live", which means it was set from a header, while the new one
         * was read from a file and thus is not "live". "live" cookies are
         * preferred so the new cookie is freed.
         */
        freecookie(co);
        return NULL;
      }
      if(replace_old) {
        replace_co = co;
        replace_clist = clist;
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
      lastc->next = co;
    else
      c->cookies[myhash] = co;
    c->numcookies++; /* one more cookie in the jar */
  }

  /*
   * Now that we've added a new cookie to the jar, update the expiration
   * tracker in case it is the next one to expire.
   */
  if(co->expires && (co->expires < c->next_expiration))
    c->next_expiration = co->expires;

  return co;
}







|







1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
      lastc->next = co;
    else
      c->cookies[myhash] = co;
    c->numcookies++; /* one more cookie in the jar */
  }

  /*
   * Now that we have added a new cookie to the jar, update the expiration
   * tracker in case it is the next one to expire.
   */
  if(co->expires && (co->expires < c->next_expiration))
    c->next_expiration = co->expires;

  return co;
}
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
                                    struct CookieInfo *inc,
                                    bool newsession)
{
  struct CookieInfo *c;
  FILE *handle = NULL;

  if(!inc) {
    /* we didn't get a struct, create one */
    c = calloc(1, sizeof(struct CookieInfo));
    if(!c)
      return NULL; /* failed to get memory */
    /*
     * Initialize the next_expiration time to signal that we don't have enough
     * information yet.
     */
    c->next_expiration = CURL_OFF_T_MAX;
  }
  else {
    /* we got an already existing one, use that */
    c = inc;







|




|







1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
                                    struct CookieInfo *inc,
                                    bool newsession)
{
  struct CookieInfo *c;
  FILE *handle = NULL;

  if(!inc) {
    /* we did not get a struct, create one */
    c = calloc(1, sizeof(struct CookieInfo));
    if(!c)
      return NULL; /* failed to get memory */
    /*
     * Initialize the next_expiration time to signal that we do not have enough
     * information yet.
     */
    c->next_expiration = CURL_OFF_T_MAX;
  }
  else {
    /* we got an already existing one, use that */
    c = inc;
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
      remove_expired(c);

      if(handle)
        fclose(handle);
    }
    data->state.cookie_engine = TRUE;
  }
  c->running = TRUE;          /* now, we're running */

  return c;
}

/*
 * cookie_sort
 *







|







1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
      remove_expired(c);

      if(handle)
        fclose(handle);
    }
    data->state.cookie_engine = TRUE;
  }
  c->running = TRUE;          /* now, we are running */

  return c;
}

/*
 * cookie_sort
 *
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
/*
 * Curl_cookie_getlist
 *
 * For a given host and path, return a linked list of cookies that the client
 * should send to the server if used now. The secure boolean informs the cookie
 * if a secure connection is achieved or not.
 *
 * It shall only return cookies that haven't expired.
 */
struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
                                   struct CookieInfo *c,
                                   const char *host, const char *path,
                                   bool secure)
{
  struct Cookie *newco;







|







1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
/*
 * Curl_cookie_getlist
 *
 * For a given host and path, return a linked list of cookies that the client
 * should send to the server if used now. The secure boolean informs the cookie
 * if a secure connection is achieved or not.
 *
 * It shall only return cookies that have not expired.
 */
struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
                                   struct CookieInfo *c,
                                   const char *host, const char *path,
                                   bool secure)
{
  struct Cookie *newco;
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403

  /* check if host is an IP(v4|v6) address */
  is_ip = Curl_host_is_ipnum(host);

  co = c->cookies[myhash];

  while(co) {
    /* if the cookie requires we're secure we must only continue if we are! */
    if(co->secure?secure:TRUE) {

      /* now check if the domain is correct */
      if(!co->domain ||
         (co->tailmatch && !is_ip &&
          cookie_tailmatch(co->domain, strlen(co->domain), host)) ||
         ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {







|







1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404

  /* check if host is an IP(v4|v6) address */
  is_ip = Curl_host_is_ipnum(host);

  co = c->cookies[myhash];

  while(co) {
    /* if the cookie requires we are secure we must only continue if we are! */
    if(co->secure?secure:TRUE) {

      /* now check if the domain is correct */
      if(!co->domain ||
         (co->tailmatch && !is_ip &&
          cookie_tailmatch(co->domain, strlen(co->domain), host)) ||
         ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
    co->value?co->value:"");
}

/*
 * cookie_output()
 *
 * Writes all internally known cookies to the specified file. Specify
 * "-" as file name to write to stdout.
 *
 * The function returns non-zero on write failure.
 */
static CURLcode cookie_output(struct Curl_easy *data,
                              struct CookieInfo *c, const char *filename)
{
  struct Cookie *co;







|







1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
    co->value?co->value:"");
}

/*
 * cookie_output()
 *
 * Writes all internally known cookies to the specified file. Specify
 * "-" as filename to write to stdout.
 *
 * The function returns non-zero on write failure.
 */
static CURLcode cookie_output(struct Curl_easy *data,
                              struct CookieInfo *c, const char *filename)
{
  struct Cookie *co;
Changes to jni/curl/lib/cookie.h.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
   In the 6265bis draft document section 5.4 it is phrased even stronger: "If
   the sum of the lengths of the name string and the value string is more than
   4096 octets, abort these steps and ignore the set-cookie-string entirely."
*/

/** Limits for INCOMING cookies **/

/* The longest we allow a line to be when reading a cookie from a HTTP header
   or from a cookie jar */
#define MAX_COOKIE_LINE 5000

/* Maximum length of an incoming cookie name or content we deal with. Longer
   cookies are ignored. */
#define MAX_NAME 4096








|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
   In the 6265bis draft document section 5.4 it is phrased even stronger: "If
   the sum of the lengths of the name string and the value string is more than
   4096 octets, abort these steps and ignore the set-cookie-string entirely."
*/

/** Limits for INCOMING cookies **/

/* The longest we allow a line to be when reading a cookie from an HTTP header
   or from a cookie jar */
#define MAX_COOKIE_LINE 5000

/* Maximum length of an incoming cookie name or content we deal with. Longer
   cookies are ignored. */
#define MAX_NAME 4096

Changes to jni/curl/lib/curl_addrinfo.c.
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
 * Curl_getaddrinfo_ex()
 *
 * This is a wrapper function around system's getaddrinfo(), with
 * the only difference that instead of returning a linked list of
 * addrinfo structs this one returns a linked list of Curl_addrinfo
 * ones. The memory allocated by this function *MUST* be free'd with
 * Curl_freeaddrinfo().  For each successful call to this function
 * there must be an associated call later to Curl_freeaddrinfo().
 *
 * There should be no single call to system's getaddrinfo() in the
 * whole library, any such call should be 'routed' through this one.
 */

int







|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
 * Curl_getaddrinfo_ex()
 *
 * This is a wrapper function around system's getaddrinfo(), with
 * the only difference that instead of returning a linked list of
 * addrinfo structs this one returns a linked list of Curl_addrinfo
 * ones. The memory allocated by this function *MUST* be free'd with
 * Curl_freeaddrinfo(). For each successful call to this function
 * there must be an associated call later to Curl_freeaddrinfo().
 *
 * There should be no single call to system's getaddrinfo() in the
 * whole library, any such call should be 'routed' through this one.
 */

int
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
 *
 * This function returns a pointer to the first element of a newly allocated
 * Curl_addrinfo struct linked list filled with the data of a given hostent.
 * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
 * stack, but usable also for IPv4, all hosts and environments.
 *
 * The memory allocated by this function *MUST* be free'd later on calling
 * Curl_freeaddrinfo().  For each successful call to this function there
 * must be an associated call later to Curl_freeaddrinfo().
 *
 *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
 *
 *     struct Curl_addrinfo {
 *       int                   ai_flags;
 *       int                   ai_family;







|







217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
 *
 * This function returns a pointer to the first element of a newly allocated
 * Curl_addrinfo struct linked list filled with the data of a given hostent.
 * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
 * stack, but usable also for IPv4, all hosts and environments.
 *
 * The memory allocated by this function *MUST* be free'd later on calling
 * Curl_freeaddrinfo(). For each successful call to this function there
 * must be an associated call later to Curl_freeaddrinfo().
 *
 *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
 *
 *     struct Curl_addrinfo {
 *       int                   ai_flags;
 *       int                   ai_family;
313
314
315
316
317
318
319



320

321
322
323
324
325
326
327
328



329

330
331
332
333
334
335
336
    /* leave the rest of the struct filled with zero */

    switch(ai->ai_family) {
    case AF_INET:
      addr = (void *)ai->ai_addr; /* storage area for this info */

      memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));



      addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);

      addr->sin_port = htons((unsigned short)port);
      break;

#ifdef USE_IPV6
    case AF_INET6:
      addr6 = (void *)ai->ai_addr; /* storage area for this info */

      memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));



      addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);

      addr6->sin6_port = htons((unsigned short)port);
      break;
#endif
    }

    prevai = ai;
  }







>
>
>

>








>
>
>

>







313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
    /* leave the rest of the struct filled with zero */

    switch(ai->ai_family) {
    case AF_INET:
      addr = (void *)ai->ai_addr; /* storage area for this info */

      memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
#ifdef __MINGW32__
      addr->sin_family = (short)(he->h_addrtype);
#else
      addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
#endif
      addr->sin_port = htons((unsigned short)port);
      break;

#ifdef USE_IPV6
    case AF_INET6:
      addr6 = (void *)ai->ai_addr; /* storage area for this info */

      memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
#ifdef __MINGW32__
      addr6->sin6_family = (short)(he->h_addrtype);
#else
      addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
#endif
      addr6->sin6_port = htons((unsigned short)port);
      break;
#endif
    }

    prevai = ai;
  }
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  char *h_addr_list[2];
};


/*
 * Curl_ip2addr()
 *
 * This function takes an internet address, in binary form, as input parameter
 * along with its address family and the string version of the address, and it
 * returns a Curl_addrinfo chain filled in correctly with information for the
 * given address/host
 */

struct Curl_addrinfo *
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)







|







363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  char *h_addr_list[2];
};


/*
 * Curl_ip2addr()
 *
 * This function takes an Internet address, in binary form, as input parameter
 * along with its address family and the string version of the address, and it
 * returns a Curl_addrinfo chain filled in correctly with information for the
 * given address/host
 */

struct Curl_addrinfo *
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) &&  \
  defined(HAVE_FREEADDRINFO)
/*
 * curl_dbg_freeaddrinfo()
 *
 * This is strictly for memory tracing and are using the same style as the
 * family otherwise present in memdebug.c. I put these ones here since they
 * require a bunch of structs I didn't want to include in memdebug.c
 */

void
curl_dbg_freeaddrinfo(struct addrinfo *freethis,
                      int line, const char *source)
{
  curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n",







|







515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) &&  \
  defined(HAVE_FREEADDRINFO)
/*
 * curl_dbg_freeaddrinfo()
 *
 * This is strictly for memory tracing and are using the same style as the
 * family otherwise present in memdebug.c. I put these ones here since they
 * require a bunch of structs I did not want to include in memdebug.c
 */

void
curl_dbg_freeaddrinfo(struct addrinfo *freethis,
                      int line, const char *source)
{
  curl_dbg_log("ADDR %s:%d freeaddrinfo(%p)\n",
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545

#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
/*
 * curl_dbg_getaddrinfo()
 *
 * This is strictly for memory tracing and are using the same style as the
 * family otherwise present in memdebug.c. I put these ones here since they
 * require a bunch of structs I didn't want to include in memdebug.c
 */

int
curl_dbg_getaddrinfo(const char *hostname,
                    const char *service,
                    const struct addrinfo *hints,
                    struct addrinfo **result,







|







539
540
541
542
543
544
545
546
547
548
549
550
551
552
553

#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
/*
 * curl_dbg_getaddrinfo()
 *
 * This is strictly for memory tracing and are using the same style as the
 * family otherwise present in memdebug.c. I put these ones here since they
 * require a bunch of structs I did not want to include in memdebug.c
 */

int
curl_dbg_getaddrinfo(const char *hostname,
                    const char *service,
                    const struct addrinfo *hints,
                    struct addrinfo **result,
Changes to jni/curl/lib/curl_addrinfo.h.
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#  include <in.h>
#  include <inet.h>
#  include <stdlib.h>
#endif

/*
 * Curl_addrinfo is our internal struct definition that we use to allow
 * consistent internal handling of this data. We use this even when the
 * system provides an addrinfo structure definition. And we use this for
 * all sorts of IPv4 and IPV6 builds.
 */

struct Curl_addrinfo {
  int                   ai_flags;
  int                   ai_family;
  int                   ai_socktype;
  int                   ai_protocol;







|
|
|







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#  include <in.h>
#  include <inet.h>
#  include <stdlib.h>
#endif

/*
 * Curl_addrinfo is our internal struct definition that we use to allow
 * consistent internal handling of this data. We use this even when the system
 * provides an addrinfo structure definition. We use this for all sorts of
 * IPv4 and IPV6 builds.
 */

struct Curl_addrinfo {
  int                   ai_flags;
  int                   ai_family;
  int                   ai_socktype;
  int                   ai_protocol;
Changes to jni/curl/lib/curl_config.h.cmake.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
/* lib/curl_config.h.in.  Generated somehow by cmake.  */

/* Location of default ca bundle */
#cmakedefine CURL_CA_BUNDLE "${CURL_CA_BUNDLE}"

/* define "1" to use built-in ca store of TLS backend */
#cmakedefine CURL_CA_FALLBACK 1








|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
/* lib/curl_config.h.in. Generated somehow by cmake.  */

/* Location of default ca bundle */
#cmakedefine CURL_CA_BUNDLE "${CURL_CA_BUNDLE}"

/* define "1" to use built-in ca store of TLS backend */
#cmakedefine CURL_CA_FALLBACK 1

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383

/* Define to 1 if you have the `idn2' library (-lidn2). */
#cmakedefine HAVE_LIBIDN2 1

/* Define to 1 if you have the idn2.h header file. */
#cmakedefine HAVE_IDN2_H 1

/* Define to 1 if you have the `socket' library (-lsocket). */
#cmakedefine HAVE_LIBSOCKET 1

/* Define to 1 if you have the `ssh2' library (-lssh2). */
#cmakedefine HAVE_LIBSSH2 1

/* if zlib is available */
#cmakedefine HAVE_LIBZ 1

/* if brotli is available */
#cmakedefine HAVE_BROTLI 1

/* if zstd is available */







<
<
<
<
<
<







364
365
366
367
368
369
370






371
372
373
374
375
376
377

/* Define to 1 if you have the `idn2' library (-lidn2). */
#cmakedefine HAVE_LIBIDN2 1

/* Define to 1 if you have the idn2.h header file. */
#cmakedefine HAVE_IDN2_H 1







/* if zlib is available */
#cmakedefine HAVE_LIBZ 1

/* if brotli is available */
#cmakedefine HAVE_BROTLI 1

/* if zstd is available */
414
415
416
417
418
419
420



421
422
423
424
425
426
427
#cmakedefine HAVE_NET_IF_H 1

/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */
#cmakedefine HAVE_OLD_GSSMIT 1

/* Define to 1 if you have the `pipe' function. */
#cmakedefine HAVE_PIPE 1




/* If you have a fine poll */
#cmakedefine HAVE_POLL_FINE 1

/* Define to 1 if you have the <poll.h> header file. */
#cmakedefine HAVE_POLL_H 1








>
>
>







408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#cmakedefine HAVE_NET_IF_H 1

/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */
#cmakedefine HAVE_OLD_GSSMIT 1

/* Define to 1 if you have the `pipe' function. */
#cmakedefine HAVE_PIPE 1

/* Define to 1 if you have the `eventfd' function. */
#cmakedefine HAVE_EVENTFD 1

/* If you have a fine poll */
#cmakedefine HAVE_POLL_FINE 1

/* Define to 1 if you have the <poll.h> header file. */
#cmakedefine HAVE_POLL_H 1

534
535
536
537
538
539
540



541
542
543
544
545
546
547
#cmakedefine HAVE_MEMRCHR 1

/* if struct sockaddr_storage is defined */
#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1

/* Define to 1 if you have the timeval struct. */
#cmakedefine HAVE_STRUCT_TIMEVAL 1




/* Define to 1 if you have the <sys/filio.h> header file. */
#cmakedefine HAVE_SYS_FILIO_H 1

/* Define to 1 if you have the <sys/wait.h> header file. */
#cmakedefine HAVE_SYS_WAIT_H 1








>
>
>







531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
#cmakedefine HAVE_MEMRCHR 1

/* if struct sockaddr_storage is defined */
#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1

/* Define to 1 if you have the timeval struct. */
#cmakedefine HAVE_STRUCT_TIMEVAL 1

/* Define to 1 if you have the <sys/eventfd.h> header file. */
#cmakedefine HAVE_SYS_EVENTFD_H 1

/* Define to 1 if you have the <sys/filio.h> header file. */
#cmakedefine HAVE_SYS_FILIO_H 1

/* Define to 1 if you have the <sys/wait.h> header file. */
#cmakedefine HAVE_SYS_WAIT_H 1

688
689
690
691
692
693
694
695
696
697






698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715



716
717
718
719
720
721
722
723

/* if mbedTLS is enabled */
#cmakedefine USE_MBEDTLS 1

/* if BearSSL is enabled */
#cmakedefine USE_BEARSSL 1

/* if WolfSSL is enabled */
#cmakedefine USE_WOLFSSL 1







/* if libSSH is in use */
#cmakedefine USE_LIBSSH 1

/* if libSSH2 is in use */
#cmakedefine USE_LIBSSH2 1

/* if libPSL is in use */
#cmakedefine USE_LIBPSL 1

/* if you want to use OpenLDAP code instead of legacy ldap implementation */
#cmakedefine USE_OPENLDAP 1

/* if OpenSSL is in use */
#cmakedefine USE_OPENSSL 1

/* if librtmp/rtmpdump is in use */
#cmakedefine USE_LIBRTMP 1




/* Define to 1 if you don't want the OpenSSL configuration to be loaded
   automatically */
#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1

/* to enable NGHTTP2  */
#cmakedefine USE_NGHTTP2 1

/* to enable NGTCP2 */







|


>
>
>
>
>
>
|


|


|











>
>
>
|







688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732

/* if mbedTLS is enabled */
#cmakedefine USE_MBEDTLS 1

/* if BearSSL is enabled */
#cmakedefine USE_BEARSSL 1

/* if wolfSSL is enabled */
#cmakedefine USE_WOLFSSL 1

/* if wolfSSL has the wolfSSL_DES_ecb_encrypt function. */
#cmakedefine HAVE_WOLFSSL_DES_ECB_ENCRYPT 1

/* if wolfSSL has the wolfSSL_BIO_set_shutdown function. */
#cmakedefine HAVE_WOLFSSL_FULL_BIO 1

/* if libssh is in use */
#cmakedefine USE_LIBSSH 1

/* if libssh2 is in use */
#cmakedefine USE_LIBSSH2 1

/* if libpsl is in use */
#cmakedefine USE_LIBPSL 1

/* if you want to use OpenLDAP code instead of legacy ldap implementation */
#cmakedefine USE_OPENLDAP 1

/* if OpenSSL is in use */
#cmakedefine USE_OPENSSL 1

/* if librtmp/rtmpdump is in use */
#cmakedefine USE_LIBRTMP 1

/* if GSASL is in use */
#cmakedefine USE_GSASL 1

/* Define to 1 if you do not want the OpenSSL configuration to be loaded
   automatically */
#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1

/* to enable NGHTTP2  */
#cmakedefine USE_NGHTTP2 1

/* to enable NGTCP2 */
Changes to jni/curl/lib/curl_config.h.in.
213
214
215
216
217
218
219



220
221
222
223
224
225
226
#undef HAVE_DIRENT_H

/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H

/* Define to 1 if you have the <err.h> header file. */
#undef HAVE_ERR_H




/* Define to 1 if you have the fcntl function. */
#undef HAVE_FCNTL

/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H








>
>
>







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#undef HAVE_DIRENT_H

/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H

/* Define to 1 if you have the <err.h> header file. */
#undef HAVE_ERR_H

/* Define to 1 if you have the `eventfd' function. */
#undef HAVE_EVENTFD

/* Define to 1 if you have the fcntl function. */
#undef HAVE_FCNTL

/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H

398
399
400
401
402
403
404
405
406
407
408
409
410
411
412

/* Define to 1 if you have the `idn2' library (-lidn2). */
#undef HAVE_LIBIDN2

/* Define to 1 if you have the <libpsl.h> header file. */
#undef HAVE_LIBPSL_H

/* Define to 1 if using libressl. */
#undef HAVE_LIBRESSL

/* Define to 1 if you have the <librtmp/rtmp.h> header file. */
#undef HAVE_LIBRTMP_RTMP_H

/* Define to 1 if you have the `ssh' library (-lssh). */
#undef HAVE_LIBSSH







|







401
402
403
404
405
406
407
408
409
410
411
412
413
414
415

/* Define to 1 if you have the `idn2' library (-lidn2). */
#undef HAVE_LIBIDN2

/* Define to 1 if you have the <libpsl.h> header file. */
#undef HAVE_LIBPSL_H

/* Define to 1 if using LibreSSL. */
#undef HAVE_LIBRESSL

/* Define to 1 if you have the <librtmp/rtmp.h> header file. */
#undef HAVE_LIBRTMP_RTMP_H

/* Define to 1 if you have the `ssh' library (-lssh). */
#undef HAVE_LIBSSH
664
665
666
667
668
669
670



671
672
673
674
675
676
677
#undef HAVE_STRUCT_SOCKADDR_STORAGE

/* Define to 1 if you have the timeval struct. */
#undef HAVE_STRUCT_TIMEVAL

/* Define to 1 if suseconds_t is an available type. */
#undef HAVE_SUSECONDS_T




/* Define to 1 if you have the <sys/filio.h> header file. */
#undef HAVE_SYS_FILIO_H

/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H








>
>
>







667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
#undef HAVE_STRUCT_SOCKADDR_STORAGE

/* Define to 1 if you have the timeval struct. */
#undef HAVE_STRUCT_TIMEVAL

/* Define to 1 if suseconds_t is an available type. */
#undef HAVE_SUSECONDS_T

/* Define to 1 if you have the <sys/eventfd.h> header file. */
#undef HAVE_SYS_EVENTFD_H

/* Define to 1 if you have the <sys/filio.h> header file. */
#undef HAVE_SYS_FILIO_H

/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H

865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882

/* if libpsl is in use */
#undef USE_LIBPSL

/* if librtmp is in use */
#undef USE_LIBRTMP

/* if libSSH is in use */
#undef USE_LIBSSH

/* if libSSH2 is in use */
#undef USE_LIBSSH2

/* If you want to build curl with the built-in manual */
#undef USE_MANUAL

/* if mbedTLS is enabled */
#undef USE_MBEDTLS







|


|







871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888

/* if libpsl is in use */
#undef USE_LIBPSL

/* if librtmp is in use */
#undef USE_LIBRTMP

/* if libssh is in use */
#undef USE_LIBSSH

/* if libssh2 is in use */
#undef USE_LIBSSH2

/* If you want to build curl with the built-in manual */
#undef USE_MANUAL

/* if mbedTLS is enabled */
#undef USE_MBEDTLS
Changes to jni/curl/lib/curl_des.c.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

#include "curl_des.h"

/*
 * Curl_des_set_odd_parity()
 *
 * This is used to apply odd parity to the given byte array. It is typically
 * used by when a cryptography engine doesn't have its own version.
 *
 * The function is a port of the Java based oddParity() function over at:
 *
 * https://davenport.sourceforge.net/ntlm.html
 *
 * Parameters:
 *







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

#include "curl_des.h"

/*
 * Curl_des_set_odd_parity()
 *
 * This is used to apply odd parity to the given byte array. It is typically
 * used by when a cryptography engine does not have its own version.
 *
 * The function is a port of the Java based oddParity() function over at:
 *
 * https://davenport.sourceforge.net/ntlm.html
 *
 * Parameters:
 *
Changes to jni/curl/lib/curl_endian.c.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

#include "curl_endian.h"

/*
 * Curl_read16_le()
 *
 * This function converts a 16-bit integer from the little endian format, as
 * used in the incoming package to whatever endian format we're using
 * natively.
 *
 * Parameters:
 *
 * buf      [in]     - A pointer to a 2 byte buffer.
 *
 * Returns the integer.
 */
unsigned short Curl_read16_le(const unsigned char *buf)
{
  return (unsigned short)(((unsigned short)buf[0]) |
                          ((unsigned short)buf[1] << 8));
}

/*
 * Curl_read32_le()
 *
 * This function converts a 32-bit integer from the little endian format, as
 * used in the incoming package to whatever endian format we're using
 * natively.
 *
 * Parameters:
 *
 * buf      [in]     - A pointer to a 4 byte buffer.
 *
 * Returns the integer.
 */
unsigned int Curl_read32_le(const unsigned char *buf)
{
  return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
         ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
}

/*
 * Curl_read16_be()
 *
 * This function converts a 16-bit integer from the big endian format, as
 * used in the incoming package to whatever endian format we're using
 * natively.
 *
 * Parameters:
 *
 * buf      [in]     - A pointer to a 2 byte buffer.
 *
 * Returns the integer.
 */
unsigned short Curl_read16_be(const unsigned char *buf)
{
  return (unsigned short)(((unsigned short)buf[0] << 8) |
                          ((unsigned short)buf[1]));
}







|


















|


















|













26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

#include "curl_endian.h"

/*
 * Curl_read16_le()
 *
 * This function converts a 16-bit integer from the little endian format, as
 * used in the incoming package to whatever endian format we are using
 * natively.
 *
 * Parameters:
 *
 * buf      [in]     - A pointer to a 2 byte buffer.
 *
 * Returns the integer.
 */
unsigned short Curl_read16_le(const unsigned char *buf)
{
  return (unsigned short)(((unsigned short)buf[0]) |
                          ((unsigned short)buf[1] << 8));
}

/*
 * Curl_read32_le()
 *
 * This function converts a 32-bit integer from the little endian format, as
 * used in the incoming package to whatever endian format we are using
 * natively.
 *
 * Parameters:
 *
 * buf      [in]     - A pointer to a 4 byte buffer.
 *
 * Returns the integer.
 */
unsigned int Curl_read32_le(const unsigned char *buf)
{
  return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
         ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
}

/*
 * Curl_read16_be()
 *
 * This function converts a 16-bit integer from the big endian format, as
 * used in the incoming package to whatever endian format we are using
 * natively.
 *
 * Parameters:
 *
 * buf      [in]     - A pointer to a 2 byte buffer.
 *
 * Returns the integer.
 */
unsigned short Curl_read16_be(const unsigned char *buf)
{
  return (unsigned short)(((unsigned short)buf[0] << 8) |
                          ((unsigned short)buf[1]));
}
Changes to jni/curl/lib/curl_fnmatch.c.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  parsekey_state state = CURLFNM_PKW_INIT;
#define KEYLEN 10
  char keyword[KEYLEN] = { 0 };
  int i;
  unsigned char *p = *pattern;
  bool found = FALSE;
  for(i = 0; !found; i++) {
    char c = *p++;
    if(i >= KEYLEN)
      return SETCHARSET_FAIL;
    switch(state) {
    case CURLFNM_PKW_INIT:
      if(ISLOWER(c))
        keyword[i] = c;
      else if(c == ':')







|







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  parsekey_state state = CURLFNM_PKW_INIT;
#define KEYLEN 10
  char keyword[KEYLEN] = { 0 };
  int i;
  unsigned char *p = *pattern;
  bool found = FALSE;
  for(i = 0; !found; i++) {
    char c = (char)*p++;
    if(i >= KEYLEN)
      return SETCHARSET_FAIL;
    switch(state) {
    case CURLFNM_PKW_INIT:
      if(ISLOWER(c))
        keyword[i] = c;
      else if(c == ':')
Changes to jni/curl/lib/curl_gethostname.c.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

#include "curl_setup.h"

#include "curl_gethostname.h"

/*
 * Curl_gethostname() is a wrapper around gethostname() which allows
 * overriding the host name that the function would normally return.
 * This capability is used by the test suite to verify exact matching
 * of NTLM authentication, which exercises libcurl's MD4 and DES code
 * as well as by the SMTP module when a hostname is not provided.
 *
 * For libcurl debug enabled builds host name overriding takes place
 * when environment variable CURL_GETHOSTNAME is set, using the value
 * held by the variable to override returned host name.
 *
 * Note: The function always returns the un-qualified hostname rather
 * than being provider dependent.
 *
 * For libcurl shared library release builds the test suite preloads
 * another shared library named libhostname using the LD_PRELOAD
 * mechanism which intercepts, and might override, the gethostname()
 * function call. In this case a given platform must support the
 * LD_PRELOAD mechanism and additionally have environment variable
 * CURL_GETHOSTNAME set in order to override the returned host name.
 *
 * For libcurl static library release builds no overriding takes place.
 */

int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
{
#ifndef HAVE_GETHOSTNAME

  /* Allow compilation and return failure when unavailable */
  (void) name;
  (void) namelen;
  return -1;

#else
  int err;
  char *dot;

#ifdef DEBUGBUILD

  /* Override host name when environment variable CURL_GETHOSTNAME is set */
  const char *force_hostname = getenv("CURL_GETHOSTNAME");
  if(force_hostname) {
    strncpy(name, force_hostname, namelen - 1);
    err = 0;
  }
  else {
    name[0] = '\0';







|




|

|









|



















|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

#include "curl_setup.h"

#include "curl_gethostname.h"

/*
 * Curl_gethostname() is a wrapper around gethostname() which allows
 * overriding the hostname that the function would normally return.
 * This capability is used by the test suite to verify exact matching
 * of NTLM authentication, which exercises libcurl's MD4 and DES code
 * as well as by the SMTP module when a hostname is not provided.
 *
 * For libcurl debug enabled builds hostname overriding takes place
 * when environment variable CURL_GETHOSTNAME is set, using the value
 * held by the variable to override returned hostname.
 *
 * Note: The function always returns the un-qualified hostname rather
 * than being provider dependent.
 *
 * For libcurl shared library release builds the test suite preloads
 * another shared library named libhostname using the LD_PRELOAD
 * mechanism which intercepts, and might override, the gethostname()
 * function call. In this case a given platform must support the
 * LD_PRELOAD mechanism and additionally have environment variable
 * CURL_GETHOSTNAME set in order to override the returned hostname.
 *
 * For libcurl static library release builds no overriding takes place.
 */

int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
{
#ifndef HAVE_GETHOSTNAME

  /* Allow compilation and return failure when unavailable */
  (void) name;
  (void) namelen;
  return -1;

#else
  int err;
  char *dot;

#ifdef DEBUGBUILD

  /* Override hostname when environment variable CURL_GETHOSTNAME is set */
  const char *force_hostname = getenv("CURL_GETHOSTNAME");
  if(force_hostname) {
    strncpy(name, force_hostname, namelen - 1);
    err = 0;
  }
  else {
    name[0] = '\0';
Changes to jni/curl/lib/curl_multibyte.h.
45
46
47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
 * are duplicated via strdup and remain in whatever the passed in encoding is,
 * which is assumed to be UTF-8 but may be other encoding. Therefore the
 * significance of the conversion functions is primarily for UNICODE builds.
 *
 * Allocated memory should be free'd with curlx_unicodefree().
 *
 * Note: Because these are curlx functions their memory usage is not tracked
 * by the curl memory tracker memdebug. You'll notice that curlx function-like
 * macros call free and strdup in parentheses, eg (strdup)(ptr), and that's to
 * ensure that the curl memdebug override macros do not replace them.

 */

#if defined(UNICODE) && defined(_WIN32)

#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))








|
|
|
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
 * are duplicated via strdup and remain in whatever the passed in encoding is,
 * which is assumed to be UTF-8 but may be other encoding. Therefore the
 * significance of the conversion functions is primarily for UNICODE builds.
 *
 * Allocated memory should be free'd with curlx_unicodefree().
 *
 * Note: Because these are curlx functions their memory usage is not tracked
 * by the curl memory tracker memdebug. you will notice that curlx
 * function-like macros call free and strdup in parentheses, eg (strdup)(ptr),
 * and that is to ensure that the curl memdebug override macros do not replace
 * them.
 */

#if defined(UNICODE) && defined(_WIN32)

#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))

Changes to jni/curl/lib/curl_ntlm_core.c.
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#  include <CommonCrypto/CommonDigest.h>

#elif defined(USE_OS400CRYPTO)
#  include "cipher.mih"  /* mih/cipher */
#elif defined(USE_WIN32_CRYPTO)
#  include <wincrypt.h>
#else
#  error "Can't compile NTLM support without a crypto library with DES."
#  define CURL_NTLM_NOT_SUPPORTED
#endif

#include "urldata.h"
#include "strcase.h"
#include "curl_ntlm_core.h"
#include "curl_md5.h"







|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#  include <CommonCrypto/CommonDigest.h>

#elif defined(USE_OS400CRYPTO)
#  include "cipher.mih"  /* mih/cipher */
#elif defined(USE_WIN32_CRYPTO)
#  include <wincrypt.h>
#else
#  error "cannot compile NTLM support without a crypto library with DES."
#  define CURL_NTLM_NOT_SUPPORTED
#endif

#include "urldata.h"
#include "strcase.h"
#include "curl_ntlm_core.h"
#include "curl_md5.h"
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224

#if !defined(CURL_NTLM_NOT_SUPPORTED)
/*
* Turns a 56-bit key into being 64-bit wide.
*/
static void extend_key_56_to_64(const unsigned char *key_56, char *key)
{
  key[0] = key_56[0];
  key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
  key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
  key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
  key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
  key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
  key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
  key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
}
#endif

#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
/*
 * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
 * key schedule ks is also set.
 */
static void setup_des_key(const unsigned char *key_56,
                          DES_key_schedule DESKEYARG(ks))
{
  DES_cblock key;

  /* Expand the 56-bit key to 64-bits */
  extend_key_56_to_64(key_56, (char *) &key);

  /* Set the key parity to odd */
  DES_set_odd_parity(&key);

  /* Set the key */
  DES_set_key_unchecked(&key, ks);
}

#elif defined(USE_GNUTLS)

static void setup_des_key(const unsigned char *key_56,
                          struct des_ctx *des)
{
  char key[8];

  /* Expand the 56-bit key to 64-bits */
  extend_key_56_to_64(key_56, key);

  /* Set the key parity to odd */
  Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));

  /* Set the key */
  des_set_key(des, (const uint8_t *) key);
}

#elif defined(USE_MBEDTLS)

static bool encrypt_des(const unsigned char *in, unsigned char *out,
                        const unsigned char *key_56)
{
  mbedtls_des_context ctx;
  char key[8];

  /* Expand the 56-bit key to 64-bits */
  extend_key_56_to_64(key_56, key);

  /* Set the key parity to odd */
  mbedtls_des_key_set_parity((unsigned char *) key);

  /* Perform the encryption */
  mbedtls_des_init(&ctx);
  mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
  return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
}

#elif defined(USE_SECTRANSP)

static bool encrypt_des(const unsigned char *in, unsigned char *out,
                        const unsigned char *key_56)
{
  char key[8];
  size_t out_len;
  CCCryptorStatus err;

  /* Expand the 56-bit key to 64-bits */
  extend_key_56_to_64(key_56, key);

  /* Set the key parity to odd */
  Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));

  /* Perform the encryption */
  err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key,







|
|
|
|
|
|
|
|





|







|
















|

















|




















|







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224

#if !defined(CURL_NTLM_NOT_SUPPORTED)
/*
* Turns a 56-bit key into being 64-bit wide.
*/
static void extend_key_56_to_64(const unsigned char *key_56, char *key)
{
  key[0] = (char)key_56[0];
  key[1] = (char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
  key[2] = (char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
  key[3] = (char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
  key[4] = (char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
  key[5] = (char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
  key[6] = (char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
  key[7] = (char) ((key_56[6] << 1) & 0xFF);
}
#endif

#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
/*
 * Turns a 56-bit key into a 64-bit, odd parity key and sets the key. The
 * key schedule ks is also set.
 */
static void setup_des_key(const unsigned char *key_56,
                          DES_key_schedule DESKEYARG(ks))
{
  DES_cblock key;

  /* Expand the 56-bit key to 64 bits */
  extend_key_56_to_64(key_56, (char *) &key);

  /* Set the key parity to odd */
  DES_set_odd_parity(&key);

  /* Set the key */
  DES_set_key_unchecked(&key, ks);
}

#elif defined(USE_GNUTLS)

static void setup_des_key(const unsigned char *key_56,
                          struct des_ctx *des)
{
  char key[8];

  /* Expand the 56-bit key to 64 bits */
  extend_key_56_to_64(key_56, key);

  /* Set the key parity to odd */
  Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));

  /* Set the key */
  des_set_key(des, (const uint8_t *) key);
}

#elif defined(USE_MBEDTLS)

static bool encrypt_des(const unsigned char *in, unsigned char *out,
                        const unsigned char *key_56)
{
  mbedtls_des_context ctx;
  char key[8];

  /* Expand the 56-bit key to 64 bits */
  extend_key_56_to_64(key_56, key);

  /* Set the key parity to odd */
  mbedtls_des_key_set_parity((unsigned char *) key);

  /* Perform the encryption */
  mbedtls_des_init(&ctx);
  mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
  return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
}

#elif defined(USE_SECTRANSP)

static bool encrypt_des(const unsigned char *in, unsigned char *out,
                        const unsigned char *key_56)
{
  char key[8];
  size_t out_len;
  CCCryptorStatus err;

  /* Expand the 56-bit key to 64 bits */
  extend_key_56_to_64(key_56, key);

  /* Set the key parity to odd */
  Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));

  /* Perform the encryption */
  err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key,
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  char key[8];
  _CIPHER_Control_T ctl;

  /* Setup the cipher control structure */
  ctl.Func_ID = ENCRYPT_ONLY;
  ctl.Data_Len = sizeof(key);

  /* Expand the 56-bit key to 64-bits */
  extend_key_56_to_64(key_56, ctl.Crypto_Key);

  /* Set the key parity to odd */
  Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len);

  /* Perform the encryption */
  _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in);







|







236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  char key[8];
  _CIPHER_Control_T ctl;

  /* Setup the cipher control structure */
  ctl.Func_ID = ENCRYPT_ONLY;
  ctl.Data_Len = sizeof(key);

  /* Expand the 56-bit key to 64 bits */
  extend_key_56_to_64(key_56, ctl.Crypto_Key);

  /* Set the key parity to odd */
  Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len);

  /* Perform the encryption */
  _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in);
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  /* Setup the key blob structure */
  memset(&blob, 0, sizeof(blob));
  blob.hdr.bType = PLAINTEXTKEYBLOB;
  blob.hdr.bVersion = 2;
  blob.hdr.aiKeyAlg = CALG_DES;
  blob.len = sizeof(blob.key);

  /* Expand the 56-bit key to 64-bits */
  extend_key_56_to_64(key_56, blob.key);

  /* Set the key parity to odd */
  Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key));

  /* Import the key */
  if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) {







|







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  /* Setup the key blob structure */
  memset(&blob, 0, sizeof(blob));
  blob.hdr.bType = PLAINTEXTKEYBLOB;
  blob.hdr.bVersion = 2;
  blob.hdr.aiKeyAlg = CALG_DES;
  blob.len = sizeof(blob.key);

  /* Expand the 56-bit key to 64 bits */
  extend_key_56_to_64(key_56, blob.key);

  /* Set the key parity to odd */
  Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key));

  /* Import the key */
  if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) {
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
  t = (t + CURL_OFF_T_C(11644473600)) * 10000000;
  ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF);
  ft->dwHighDateTime = (unsigned int) (t >> 32);
#else
  unsigned int r, s;
  unsigned int i;

  ft->dwLowDateTime = t & 0xFFFFFFFF;
  ft->dwHighDateTime = 0;

# ifndef HAVE_TIME_T_UNSIGNED
  /* Extend sign if needed. */
  if(ft->dwLowDateTime & 0x80000000)
    ft->dwHighDateTime = ~0;
# endif

  /* Bias seconds to Jan 1, 1601.
     134774 days = 11644473600 seconds = 0x2B6109100 */
  r = ft->dwLowDateTime;
  ft->dwLowDateTime = (ft->dwLowDateTime + 0xB6109100U) & 0xFFFFFFFF;
  ft->dwHighDateTime += ft->dwLowDateTime < r? 0x03: 0x02;







|





|







462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
  t = (t + CURL_OFF_T_C(11644473600)) * 10000000;
  ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF);
  ft->dwHighDateTime = (unsigned int) (t >> 32);
#else
  unsigned int r, s;
  unsigned int i;

  ft->dwLowDateTime = (unsigned int)t & 0xFFFFFFFF;
  ft->dwHighDateTime = 0;

# ifndef HAVE_TIME_T_UNSIGNED
  /* Extend sign if needed. */
  if(ft->dwLowDateTime & 0x80000000)
    ft->dwHighDateTime = ~(unsigned int)0;
# endif

  /* Bias seconds to Jan 1, 1601.
     134774 days = 11644473600 seconds = 0x2B6109100 */
  r = ft->dwLowDateTime;
  ft->dwLowDateTime = (ft->dwLowDateTime + 0xB6109100U) & 0xFFFFFFFF;
  ft->dwHighDateTime += ft->dwLowDateTime < r? 0x03: 0x02;
Changes to jni/curl/lib/curl_ntlm_core.h.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(USE_CURL_NTLM_CORE)

#if defined(USE_OPENSSL)
#  include <openssl/ssl.h>
#elif defined(USE_WOLFSSL)
#  include <wolfssl/options.h>
#  include <wolfssl/openssl/ssl.h>
#endif

/* Helpers to generate function byte arguments in little endian order */
#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
  ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))

void Curl_ntlm_core_lm_resp(const unsigned char *keys,
                            const unsigned char *plaintext,







<
<
<
<
<
<
<







24
25
26
27
28
29
30







31
32
33
34
35
36
37
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(USE_CURL_NTLM_CORE)








/* Helpers to generate function byte arguments in little endian order */
#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
  ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))

void Curl_ntlm_core_lm_resp(const unsigned char *keys,
                            const unsigned char *plaintext,
Changes to jni/curl/lib/curl_rtmp.c.
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
{
  struct connectdata *conn = data->conn;
  RTMP *r = conn->proto.rtmp;
  SET_RCVTIMEO(tv, 10);

  r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];

  /* We have to know if it's a write before we send the
   * connect request packet
   */
  if(data->state.upload)
    r->Link.protocol |= RTMP_FEATURE_WRITE;

  /* For plain streams, use the buffer toggle trick to keep data flowing */
  if(!(r->Link.lFlags & RTMP_LF_LIVE) &&







|







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
{
  struct connectdata *conn = data->conn;
  RTMP *r = conn->proto.rtmp;
  SET_RCVTIMEO(tv, 10);

  r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];

  /* We have to know if it is a write before we send the
   * connect request packet
   */
  if(data->state.upload)
    r->Link.protocol |= RTMP_FEATURE_WRITE;

  /* For plain streams, use the buffer toggle trick to keep data flowing */
  if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  RTMP *r = conn->proto.rtmp;

  if(!RTMP_ConnectStream(r, 0))
    return CURLE_FAILED_INIT;

  if(data->state.upload) {
    Curl_pgrsSetUploadSize(data, data->state.infilesize);
    Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
  }
  else
    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
  *done = TRUE;
  return CURLE_OK;
}

static CURLcode rtmp_done(struct Curl_easy *data, CURLcode status,
                          bool premature)
{







|


|







269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  RTMP *r = conn->proto.rtmp;

  if(!RTMP_ConnectStream(r, 0))
    return CURLE_FAILED_INIT;

  if(data->state.upload) {
    Curl_pgrsSetUploadSize(data, data->state.infilesize);
    Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
  }
  else
    Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
  *done = TRUE;
  return CURLE_OK;
}

static CURLcode rtmp_done(struct Curl_easy *data, CURLcode status,
                          bool premature)
{
Changes to jni/curl/lib/curl_sasl.c.
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
 */
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
{
  /* Have credentials been provided? */
  if(data->state.aptr.user)
    return TRUE;

  /* EXTERNAL can authenticate without a user name and/or password */
  if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
    return TRUE;

  return FALSE;
}

/*







|







324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
 */
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
{
  /* Have credentials been provided? */
  if(data->state.aptr.user)
    return TRUE;

  /* EXTERNAL can authenticate without a username and/or password */
  if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
    return TRUE;

  return FALSE;
}

/*
Changes to jni/curl/lib/curl_setup.h.
36
37
38
39
40
41
42





































43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#endif

/* Set default _WIN32_WINNT */
#ifdef __MINGW32__
#include <_mingw.h>
#endif






































/*
 * Disable Visual Studio warnings:
 * 4127 "conditional expression is constant"
 */
#ifdef _MSC_VER
#pragma warning(disable:4127)
#endif

#ifdef _WIN32
/*
 * Don't include unneeded stuff in Windows headers to avoid compiler
 * warnings and macro clashes.
 * Make sure to define this macro before including any Windows headers.
 */
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN
#  endif
#  ifndef NOGDI







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#endif

/* Set default _WIN32_WINNT */
#ifdef __MINGW32__
#include <_mingw.h>
#endif

/* Workaround for Homebrew gcc 12.4.0, 13.3.0, 14.1.0 and newer (as of 14.1.0)
   that started advertising the `availability` attribute, which then gets used
   by Apple SDK, but, in a way incompatible with gcc, resulting in a misc
   errors inside SDK headers, e.g.:
     error: attributes should be specified before the declarator in a function
            definition
     error: expected ',' or '}' before
   Followed by missing declarations.
   Fix it by overriding the built-in feature-check macro used by the headers
   to enable the problematic attributes. This makes the feature check fail. */
#if defined(__APPLE__) &&                \
  !defined(__clang__) &&                 \
  defined(__GNUC__) && __GNUC__ >= 12 && \
  defined(__has_attribute)
#define availability curl_pp_attribute_disabled
#endif

#if defined(__APPLE__)
#include <sys/types.h>
#include <TargetConditionals.h>
/* Fixup faulty target macro initialization in macOS SDK since v14.4 (as of
   15.0 beta). The SDK target detection in `TargetConditionals.h` correctly
   detects macOS, but fails to set the macro's old name `TARGET_OS_OSX`, then
   continues to set it to a default value of 0. Other parts of the SDK still
   rely on the old name, and with this inconsistency our builds fail due to
   missing declarations. It happens when using mainline llvm older than v18.
   Later versions fixed it by predefining these target macros, avoiding the
   faulty dynamic detection. gcc is not affected (for now) because it lacks
   the necessary dynamic detection features, so the SDK falls back to
   a codepath that sets both the old and new macro to 1. */
#if defined(TARGET_OS_MAC) && TARGET_OS_MAC && \
  defined(TARGET_OS_OSX) && !TARGET_OS_OSX
#undef TARGET_OS_OSX
#define TARGET_OS_OSX TARGET_OS_MAC
#endif
#endif

/*
 * Disable Visual Studio warnings:
 * 4127 "conditional expression is constant"
 */
#ifdef _MSC_VER
#pragma warning(disable:4127)
#endif

#ifdef _WIN32
/*
 * Do not include unneeded stuff in Windows headers to avoid compiler
 * warnings and macro clashes.
 * Make sure to define this macro before including any Windows headers.
 */
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN
#  endif
#  ifndef NOGDI
302
303
304
305
306
307
308













309
310
311
312
313
314
315
316
317
318
319
320
321
322
#define CURL_PRINTF(fmt, arg) \
  __attribute__((format(__printf__, fmt, arg)))
#endif
#else
#define CURL_PRINTF(fmt, arg)
#endif














/*
 * Use getaddrinfo to resolve the IPv4 address literal. If the current network
 * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64,
 * performing this task will result in a synthesized IPv6 address.
 */
#if defined(__APPLE__) && !defined(USE_ARES)
#include <TargetConditionals.h>
#define USE_RESOLVE_ON_IPS 1
#  if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \
     defined(USE_IPV6)
#    define CURL_MACOS_CALL_COPYPROXIES 1
#    undef  CURL_MACOS_CALL_COPYPROXIES
#  endif
#endif







>
>
>
>
>
>
>
>
>
>
>
>
>


|



<







339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364

365
366
367
368
369
370
371
#define CURL_PRINTF(fmt, arg) \
  __attribute__((format(__printf__, fmt, arg)))
#endif
#else
#define CURL_PRINTF(fmt, arg)
#endif

/* Workaround for mainline llvm v16 and earlier missing a built-in macro
   expected by macOS SDK v14 / Xcode v15 (2023) and newer.
   gcc (as of v14) is also missing it. */
#if defined(__APPLE__) &&                                   \
  ((!defined(__apple_build_version__) &&                    \
    defined(__clang__) && __clang_major__ < 17) ||          \
   (defined(__GNUC__) && __GNUC__ <= 14)) &&                \
  defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
  !defined(__ENVIRONMENT_OS_VERSION_MIN_REQUIRED__)
#define __ENVIRONMENT_OS_VERSION_MIN_REQUIRED__             \
  __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
#endif

/*
 * Use getaddrinfo to resolve the IPv4 address literal. If the current network
 * interface does not support IPv4, but supports IPv6, NAT64, and DNS64,
 * performing this task will result in a synthesized IPv6 address.
 */
#if defined(__APPLE__) && !defined(USE_ARES)

#define USE_RESOLVE_ON_IPS 1
#  if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \
     defined(USE_IPV6)
#    define CURL_MACOS_CALL_COPYPROXIES 1
#    undef  CURL_MACOS_CALL_COPYPROXIES
#  endif
#endif
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
#endif

#ifndef LSEEK_ERROR
#  define LSEEK_ERROR (off_t)-1
#endif

#ifndef SIZEOF_TIME_T
/* assume default size of time_t to be 32 bit */
#define SIZEOF_TIME_T 4
#endif

#ifndef SIZEOF_CURL_SOCKET_T
/* configure and cmake check and set the define */
#  ifdef _WIN64
#    define SIZEOF_CURL_SOCKET_T 8







|







493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
#endif

#ifndef LSEEK_ERROR
#  define LSEEK_ERROR (off_t)-1
#endif

#ifndef SIZEOF_TIME_T
/* assume default size of time_t to be 32 bits */
#define SIZEOF_TIME_T 4
#endif

#ifndef SIZEOF_CURL_SOCKET_T
/* configure and cmake check and set the define */
#  ifdef _WIN64
#    define SIZEOF_CURL_SOCKET_T 8
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
#elif defined(__MINGW32__)
#  define CURL_FORMAT_SOCKET_T "zd"
#else
#  define CURL_FORMAT_SOCKET_T "qd"
#endif

/*
 * Default sizeof(off_t) in case it hasn't been defined in config file.
 */

#ifndef SIZEOF_OFF_T
#  if defined(__VMS) && !defined(__VAX)
#    if defined(_LARGEFILE)
#      define SIZEOF_OFF_T 8
#    endif







|







516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
#elif defined(__MINGW32__)
#  define CURL_FORMAT_SOCKET_T "zd"
#else
#  define CURL_FORMAT_SOCKET_T "qd"
#endif

/*
 * Default sizeof(off_t) in case it has not been defined in config file.
 */

#ifndef SIZEOF_OFF_T
#  if defined(__VMS) && !defined(__VAX)
#    if defined(_LARGEFILE)
#      define SIZEOF_OFF_T 8
#    endif
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
#else
#define SIZE_T_MAX 4294967295U
#endif
#endif
#endif

#ifndef SSIZE_T_MAX
/* some limits.h headers have this defined, some don't */
#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
#define SSIZE_T_MAX 9223372036854775807
#else
#define SSIZE_T_MAX 2147483647
#endif
#endif

/*
 * Arg 2 type for gethostname in case it hasn't been defined in config file.
 */

#ifndef GETHOSTNAME_TYPE_ARG2
#  ifdef USE_WINSOCK
#    define GETHOSTNAME_TYPE_ARG2 int
#  else
#    define GETHOSTNAME_TYPE_ARG2 size_t







|








|







594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
#else
#define SIZE_T_MAX 4294967295U
#endif
#endif
#endif

#ifndef SSIZE_T_MAX
/* some limits.h headers have this defined, some do not */
#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
#define SSIZE_T_MAX 9223372036854775807
#else
#define SSIZE_T_MAX 2147483647
#endif
#endif

/*
 * Arg 2 type for gethostname in case it has not been defined in config file.
 */

#ifndef GETHOSTNAME_TYPE_ARG2
#  ifdef USE_WINSOCK
#    define GETHOSTNAME_TYPE_ARG2 int
#  else
#    define GETHOSTNAME_TYPE_ARG2 size_t
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
#  if defined(SOCKET) || defined(USE_WINSOCK)
#    error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
#  endif
#endif

/*
 * shutdown() flags for systems that don't define them
 */

#ifndef SHUT_RD
#define SHUT_RD 0x00
#endif

#ifndef SHUT_WR







|







815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
#  if defined(SOCKET) || defined(USE_WINSOCK)
#    error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
#  endif
#endif

/*
 * shutdown() flags for systems that do not define them
 */

#ifndef SHUT_RD
#define SHUT_RD 0x00
#endif

#ifndef SHUT_WR
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
#define FOPEN_APPENDTEXT "a"
#else
#define FOPEN_READTEXT "r"
#define FOPEN_WRITETEXT "w"
#define FOPEN_APPENDTEXT "a"
#endif

/* for systems that don't detect this in configure */
#ifndef CURL_SA_FAMILY_T
#  if defined(HAVE_SA_FAMILY_T)
#    define CURL_SA_FAMILY_T sa_family_t
#  elif defined(HAVE_ADDRESS_FAMILY)
#    define CURL_SA_FAMILY_T ADDRESS_FAMILY
#  else
/* use a sensible default */







|







863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
#define FOPEN_APPENDTEXT "a"
#else
#define FOPEN_READTEXT "r"
#define FOPEN_WRITETEXT "w"
#define FOPEN_APPENDTEXT "a"
#endif

/* for systems that do not detect this in configure */
#ifndef CURL_SA_FAMILY_T
#  if defined(HAVE_SA_FAMILY_T)
#    define CURL_SA_FAMILY_T sa_family_t
#  elif defined(HAVE_ADDRESS_FAMILY)
#    define CURL_SA_FAMILY_T ADDRESS_FAMILY
#  else
/* use a sensible default */
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
/* Some versions of the Android SDK is missing the declaration */
#if defined(HAVE_GETPWUID_R) && defined(HAVE_DECL_GETPWUID_R_MISSING)
struct passwd;
int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
               size_t buflen, struct passwd **result);
#endif

#ifdef DEBUGBUILD
#define UNITTEST
#else
#define UNITTEST static
#endif

/* Hyper supports HTTP2 also, but Curl's integration with Hyper does not */
#if defined(USE_NGHTTP2)







|







892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
/* Some versions of the Android SDK is missing the declaration */
#if defined(HAVE_GETPWUID_R) && defined(HAVE_DECL_GETPWUID_R_MISSING)
struct passwd;
int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
               size_t buflen, struct passwd **result);
#endif

#ifdef UNITTESTS
#define UNITTEST
#else
#define UNITTEST static
#endif

/* Hyper supports HTTP2 also, but Curl's integration with Hyper does not */
#if defined(USE_NGHTTP2)
Changes to jni/curl/lib/curl_setup_once.h.
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#      define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T
#      undef OLD_APP32_64BIT_OFF_T
#    endif
#  endif
#endif

/*
 * Definition of timeval struct for platforms that don't have it.
 */

#ifndef HAVE_STRUCT_TIMEVAL
struct timeval {
 long tv_sec;
 long tv_usec;
};







|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#      define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T
#      undef OLD_APP32_64BIT_OFF_T
#    endif
#  endif
#endif

/*
 * Definition of timeval struct for platforms that do not have it.
 */

#ifndef HAVE_STRUCT_TIMEVAL
struct timeval {
 long tv_sec;
 long tv_usec;
};
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#define SEND_4TH_ARG MSG_NOSIGNAL
#else
#define SEND_4TH_ARG 0
#endif


#if defined(__minix)
/* Minix doesn't support recv on TCP sockets */
#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
                                   (RECV_TYPE_ARG2)(y), \
                                   (RECV_TYPE_ARG3)(z))

#elif defined(HAVE_RECV)
/*
 * The definitions for the return type and arguments types
 * of functions recv() and send() belong and come from the
 * configuration file. Do not define them in any other place.
 *
 * HAVE_RECV is defined if you have a function named recv()
 * which is used to read incoming data from sockets. If your
 * function has another name then don't define HAVE_RECV.
 *
 * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
 * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
 * be defined.
 *
 * HAVE_SEND is defined if you have a function named send()
 * which is used to write outgoing data on a connected socket.
 * If yours has another name then don't define HAVE_SEND.
 *
 * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
 * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
 * SEND_TYPE_RETV must also be defined.
 */

#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
                                   (RECV_TYPE_ARG2)(y), \
                                   (RECV_TYPE_ARG3)(z), \
                                   (RECV_TYPE_ARG4)(0))
#else /* HAVE_RECV */
#ifndef sread
#error "Missing definition of macro sread!"
#endif
#endif /* HAVE_RECV */


#if defined(__minix)
/* Minix doesn't support send on TCP sockets */
#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
                                    (SEND_TYPE_ARG2)(y), \
                                    (SEND_TYPE_ARG3)(z))

#elif defined(HAVE_SEND)
#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
                                    (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \







|












|







|


















|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#define SEND_4TH_ARG MSG_NOSIGNAL
#else
#define SEND_4TH_ARG 0
#endif


#if defined(__minix)
/* Minix does not support recv on TCP sockets */
#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
                                   (RECV_TYPE_ARG2)(y), \
                                   (RECV_TYPE_ARG3)(z))

#elif defined(HAVE_RECV)
/*
 * The definitions for the return type and arguments types
 * of functions recv() and send() belong and come from the
 * configuration file. Do not define them in any other place.
 *
 * HAVE_RECV is defined if you have a function named recv()
 * which is used to read incoming data from sockets. If your
 * function has another name then do not define HAVE_RECV.
 *
 * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
 * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
 * be defined.
 *
 * HAVE_SEND is defined if you have a function named send()
 * which is used to write outgoing data on a connected socket.
 * If yours has another name then do not define HAVE_SEND.
 *
 * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
 * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
 * SEND_TYPE_RETV must also be defined.
 */

#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
                                   (RECV_TYPE_ARG2)(y), \
                                   (RECV_TYPE_ARG3)(z), \
                                   (RECV_TYPE_ARG4)(0))
#else /* HAVE_RECV */
#ifndef sread
#error "Missing definition of macro sread!"
#endif
#endif /* HAVE_RECV */


#if defined(__minix)
/* Minix does not support send on TCP sockets */
#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
                                    (SEND_TYPE_ARG2)(y), \
                                    (SEND_TYPE_ARG3)(z))

#elif defined(HAVE_SEND)
#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
                                    (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#  define true 1
#  define HAVE_BOOL_T
#endif


/*
 * 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
 * On non-C99 platforms there's no bool, so define an enum for that.
 * On C99 platforms 'false' and 'true' also exist. Enum uses a
 * global namespace though, so use bool_false and bool_true.
 */

#ifndef HAVE_BOOL_T
  typedef enum {
      bool_false = 0,
      bool_true  = 1
  } bool;

/*
 * Use a define to let 'true' and 'false' use those enums.  There
 * are currently no use of true and false in libcurl proper, but
 * there are some in the examples. This will cater for any later
 * code happening to use true and false.
 */
#  define false bool_false
#  define true  bool_true
#  define HAVE_BOOL_T







|











|







222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#  define true 1
#  define HAVE_BOOL_T
#endif


/*
 * 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
 * On non-C99 platforms there is no bool, so define an enum for that.
 * On C99 platforms 'false' and 'true' also exist. Enum uses a
 * global namespace though, so use bool_false and bool_true.
 */

#ifndef HAVE_BOOL_T
  typedef enum {
      bool_false = 0,
      bool_true  = 1
  } bool;

/*
 * Use a define to let 'true' and 'false' use those enums. There
 * are currently no use of true and false in libcurl proper, but
 * there are some in the examples. This will cater for any later
 * code happening to use true and false.
 */
#  define false bool_false
#  define true  bool_true
#  define HAVE_BOOL_T
Changes to jni/curl/lib/curl_sha512_256.c.
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/* Use local implementation */
#define HAS_SHA512_256_IMPLEMENTATION   1

/* ** This implementation of SHA-512/256 hash calculation was originally ** *
 * ** written by Evgeny Grin (Karlson2k) for GNU libmicrohttpd.          ** *
 * ** The author ported the code to libcurl. The ported code is provided ** *
 * ** under curl license.                                                ** *
 * ** This is a minimal version with minimal optimisations. Performance  ** *
 * ** can be significantly improved. Big-endian store and load macros    ** *
 * ** are obvious targets for optimisation.                              ** */

#ifdef __GNUC__
#  if defined(__has_attribute) && defined(__STDC_VERSION__)
#    if __has_attribute(always_inline) && __STDC_VERSION__ >= 199901
#      define MHDX_INLINE inline __attribute__((always_inline))
#    endif
#  endif







|

|







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/* Use local implementation */
#define HAS_SHA512_256_IMPLEMENTATION   1

/* ** This implementation of SHA-512/256 hash calculation was originally ** *
 * ** written by Evgeny Grin (Karlson2k) for GNU libmicrohttpd.          ** *
 * ** The author ported the code to libcurl. The ported code is provided ** *
 * ** under curl license.                                                ** *
 * ** This is a minimal version with minimal optimizations. Performance  ** *
 * ** can be significantly improved. Big-endian store and load macros    ** *
 * ** are obvious targets for optimization.                              ** */

#ifdef __GNUC__
#  if defined(__has_attribute) && defined(__STDC_VERSION__)
#    if __has_attribute(always_inline) && __STDC_VERSION__ >= 199901
#      define MHDX_INLINE inline __attribute__((always_inline))
#    endif
#  endif
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
 * as an argument, the calculation could be done twice. */
static MHDX_INLINE curl_uint64_t
MHDx_rotr64(curl_uint64_t value, unsigned int bits)
{
  bits %= 64;
  if(0 == bits)
    return value;
  /* Defined in a form which modern compiler could optimise. */
  return (value >> bits) | (value << (64 - bits));
}

/* SHA-512/256 specific data */

/**
 * Number of bits in a single SHA-512/256 word.







|







324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
 * as an argument, the calculation could be done twice. */
static MHDX_INLINE curl_uint64_t
MHDx_rotr64(curl_uint64_t value, unsigned int bits)
{
  bits %= 64;
  if(0 == bits)
    return value;
  /* Defined in a form which modern compiler could optimize. */
  return (value >> bits) | (value << (64 - bits));
}

/* SHA-512/256 specific data */

/**
 * Number of bits in a single SHA-512/256 word.
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  curl_uint64_t g = H[6];
  curl_uint64_t h = H[7];

  /* Data buffer, used as a cyclic buffer.
     See FIPS PUB 180-4 section 5.2.2, 6.7, 6.4. */
  curl_uint64_t W[16];

  /* 'Ch' and 'Maj' macro functions are defined with widely-used optimisation.
     See FIPS PUB 180-4 formulae 4.8, 4.9. */
#define Ch(x,y,z)     ( (z) ^ ((x) & ((y) ^ (z))) )
#define Maj(x,y,z)    ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )

  /* Four 'Sigma' macro functions.
     See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
#define SIG0(x)                                                         \
  ( MHDx_rotr64((x), 28) ^ MHDx_rotr64((x), 34) ^ MHDx_rotr64((x), 39) )
#define SIG1(x)                                                         \
  ( MHDx_rotr64((x), 14) ^ MHDx_rotr64((x), 18) ^ MHDx_rotr64((x), 41) )







|

|
|







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
  curl_uint64_t g = H[6];
  curl_uint64_t h = H[7];

  /* Data buffer, used as a cyclic buffer.
     See FIPS PUB 180-4 section 5.2.2, 6.7, 6.4. */
  curl_uint64_t W[16];

  /* 'Ch' and 'Maj' macro functions are defined with widely-used optimization.
     See FIPS PUB 180-4 formulae 4.8, 4.9. */
#define Sha512_Ch(x,y,z)     ( (z) ^ ((x) & ((y) ^ (z))) )
#define Sha512_Maj(x,y,z)    ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )

  /* Four 'Sigma' macro functions.
     See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
#define SIG0(x)                                                         \
  ( MHDx_rotr64((x), 28) ^ MHDx_rotr64((x), 34) ^ MHDx_rotr64((x), 39) )
#define SIG1(x)                                                         \
  ( MHDx_rotr64((x), 14) ^ MHDx_rotr64((x), 18) ^ MHDx_rotr64((x), 41) )
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
       * Note: the first (vH += SIG1(vE) + Ch(vE,vF,vG) + kt + wt) equals T1 in
       FIPS PUB 180-4 section 6.4.2 step 3.
       the second (vH += SIG0(vA) + Maj(vE,vF,vC) equals T1 + T2 in
       FIPS PUB 180-4 section 6.4.2 step 3.
       * Note: 'wt' must be used exactly one time in this macro as macro for
       'wt' calculation may change other data as well every time when
       used. */
#define SHA2STEP64(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do {                  \
      (vD) += ((vH) += SIG1 ((vE)) + Ch ((vE),(vF),(vG)) + (kt) + (wt)); \
      (vH) += SIG0 ((vA)) + Maj ((vA),(vB),(vC)); } while (0)

    /* One step of SHA-512/256 computation with working variables rotation,
       see FIPS PUB 180-4 section 6.4.2 step 3. This macro version reassigns
       all working variables on each step. */
#define SHA2STEP64RV(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do {                \
      curl_uint64_t tmp_h_ = (vH);                                      \
      SHA2STEP64((vA),(vB),(vC),(vD),(vE),(vF),(vG),tmp_h_,(kt),(wt));  \







|
|
|







543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
       * Note: the first (vH += SIG1(vE) + Ch(vE,vF,vG) + kt + wt) equals T1 in
       FIPS PUB 180-4 section 6.4.2 step 3.
       the second (vH += SIG0(vA) + Maj(vE,vF,vC) equals T1 + T2 in
       FIPS PUB 180-4 section 6.4.2 step 3.
       * Note: 'wt' must be used exactly one time in this macro as macro for
       'wt' calculation may change other data as well every time when
       used. */
#define SHA2STEP64(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do {                       \
     (vD) += ((vH) += SIG1((vE)) + Sha512_Ch((vE),(vF),(vG)) + (kt) + (wt)); \
     (vH) += SIG0((vA)) + Sha512_Maj((vA),(vB),(vC)); } while (0)

    /* One step of SHA-512/256 computation with working variables rotation,
       see FIPS PUB 180-4 section 6.4.2 step 3. This macro version reassigns
       all working variables on each step. */
#define SHA2STEP64RV(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do {                \
      curl_uint64_t tmp_h_ = (vH);                                      \
      SHA2STEP64((vA),(vB),(vC),(vD),(vE),(vF),(vG),tmp_h_,(kt),(wt));  \
Changes to jni/curl/lib/curl_sspi.c.
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
 * Curl_create_sspi_identity()
 *
 * This is used to populate a SSPI identity structure based on the supplied
 * username and password.
 *
 * Parameters:
 *
 * userp    [in]     - The user name in the format User or Domain\User.
 * passwdp  [in]     - The user's password.
 * identity [in/out] - The identity structure.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
                                   SEC_WINNT_AUTH_IDENTITY *identity)







|







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
 * Curl_create_sspi_identity()
 *
 * This is used to populate a SSPI identity structure based on the supplied
 * username and password.
 *
 * Parameters:
 *
 * userp    [in]     - The username in the format User or Domain\User.
 * passwdp  [in]     - The user's password.
 * identity [in/out] - The identity structure.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
                                   SEC_WINNT_AUTH_IDENTITY *identity)
Changes to jni/curl/lib/curl_threads.c.
96
97
98
99
100
101
102
103
104






105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  *hnd = curl_thread_t_null;

  return ret;
}

#elif defined(USE_THREADS_WIN32)

/* !checksrc! disable SPACEBEFOREPAREN 1 */
curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),






                                 void *arg)
{
#ifdef _WIN32_WCE
  typedef HANDLE curl_win_thread_handle_t;
#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
  typedef unsigned long curl_win_thread_handle_t;
#else
  typedef uintptr_t curl_win_thread_handle_t;
#endif
  curl_thread_t t;
  curl_win_thread_handle_t thread_handle;
#ifdef _WIN32_WCE
  thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
#else
  thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
#endif
  t = (curl_thread_t)thread_handle;
  if((t == 0) || (t == LongToHandle(-1L))) {
#ifdef _WIN32_WCE







<
|
>
>
>
>
>
>


|








|







96
97
98
99
100
101
102

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  *hnd = curl_thread_t_null;

  return ret;
}

#elif defined(USE_THREADS_WIN32)


curl_thread_t Curl_thread_create(
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
                                 DWORD
#else
                                 unsigned int
#endif
                                 (CURL_STDCALL *func) (void *),
                                 void *arg)
{
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
  typedef HANDLE curl_win_thread_handle_t;
#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
  typedef unsigned long curl_win_thread_handle_t;
#else
  typedef uintptr_t curl_win_thread_handle_t;
#endif
  curl_thread_t t;
  curl_win_thread_handle_t thread_handle;
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
  thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
#else
  thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
#endif
  t = (curl_thread_t)thread_handle;
  if((t == 0) || (t == LongToHandle(-1L))) {
#ifdef _WIN32_WCE
Changes to jni/curl/lib/curl_threads.h.
43
44
45
46
47
48
49
50
51






52
53
54
55
56
57
58
#  define Curl_mutex_acquire(m)  EnterCriticalSection(m)
#  define Curl_mutex_release(m)  LeaveCriticalSection(m)
#  define Curl_mutex_destroy(m)  DeleteCriticalSection(m)
#endif

#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)

/* !checksrc! disable SPACEBEFOREPAREN 1 */
curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),






                                 void *arg);

void Curl_thread_destroy(curl_thread_t hnd);

int Curl_thread_join(curl_thread_t *hnd);

#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */







<
|
>
>
>
>
>
>







43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
#  define Curl_mutex_acquire(m)  EnterCriticalSection(m)
#  define Curl_mutex_release(m)  LeaveCriticalSection(m)
#  define Curl_mutex_destroy(m)  DeleteCriticalSection(m)
#endif

#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)


curl_thread_t Curl_thread_create(
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
                                 DWORD
#else
                                 unsigned int
#endif
                                 (CURL_STDCALL *func) (void *),
                                 void *arg);

void Curl_thread_destroy(curl_thread_t hnd);

int Curl_thread_join(curl_thread_t *hnd);

#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
Changes to jni/curl/lib/cw-out.c.
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    Curl_set_in_callback(data, FALSE);
    CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
                   wlen, (otype == CW_OUT_BODY)? "body" : "header",
                   nwritten);
    if(CURL_WRITEFUNC_PAUSE == nwritten) {
      if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
        /* Protocols that work without network cannot be paused. This is
           actually only FILE:// just now, and it can't pause since the
           transfer isn't done using the "normal" procedure. */
        failf(data, "Write callback asked for PAUSE when not supported");
        return CURLE_WRITE_ERROR;
      }
      /* mark the connection as RECV paused */
      data->req.keepon |= KEEP_RECV_PAUSE;
      ctx->paused = TRUE;
      CURL_TRC_WRITE(data, "cw_out, PAUSE requested by client");







|
|







224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    Curl_set_in_callback(data, FALSE);
    CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
                   wlen, (otype == CW_OUT_BODY)? "body" : "header",
                   nwritten);
    if(CURL_WRITEFUNC_PAUSE == nwritten) {
      if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
        /* Protocols that work without network cannot be paused. This is
           actually only FILE:// just now, and it cannot pause since the
           transfer is not done using the "normal" procedure. */
        failf(data, "Write callback asked for PAUSE when not supported");
        return CURLE_WRITE_ERROR;
      }
      /* mark the connection as RECV paused */
      data->req.keepon |= KEEP_RECV_PAUSE;
      ctx->paused = TRUE;
      CURL_TRC_WRITE(data, "cw_out, PAUSE requested by client");
Changes to jni/curl/lib/dict.c.
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
                   strategy,
                   eword);

    if(result) {
      failf(data, "Failed sending DICT request");
      goto error;
    }
    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
  }
  else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
          strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
          strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {

    word = strchr(path, ':');
    if(word) {







|







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
                   strategy,
                   eword);

    if(result) {
      failf(data, "Failed sending DICT request");
      goto error;
    }
    Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */
  }
  else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
          strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
          strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {

    word = strchr(path, ':');
    if(word) {
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
                   database,
                   eword);

    if(result) {
      failf(data, "Failed sending DICT request");
      goto error;
    }
    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
  }
  else {

    ppath = strchr(path, '/');
    if(ppath) {
      int i;








|







283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
                   database,
                   eword);

    if(result) {
      failf(data, "Failed sending DICT request");
      goto error;
    }
    Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
  }
  else {

    ppath = strchr(path, '/');
    if(ppath) {
      int i;

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
                     "%s\r\n"
                     "QUIT\r\n", ppath);
      if(result) {
        failf(data, "Failed sending DICT request");
        goto error;
      }

      Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
    }
  }

error:
  free(eword);
  free(path);
  return result;
}
#endif /* CURL_DISABLE_DICT */







|









305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
                     "%s\r\n"
                     "QUIT\r\n", ppath);
      if(result) {
        failf(data, "Failed sending DICT request");
        goto error;
      }

      Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
    }
  }

error:
  free(eword);
  free(path);
  return result;
}
#endif /* CURL_DISABLE_DICT */
Changes to jni/curl/lib/doh.c.
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
                            size_t *olen) /* output length */
{
  const size_t hostlen = strlen(host);
  unsigned char *orig = dnsp;
  const char *hostp = host;

  /* The expected output length is 16 bytes more than the length of
   * the QNAME-encoding of the host name.
   *
   * A valid DNS name may not contain a zero-length label, except at
   * the end.  For this reason, a name beginning with a dot, or
   * containing a sequence of two or more consecutive dots, is invalid
   * and cannot be encoded as a QNAME.
   *
   * If the host name ends with a trailing dot, the corresponding
   * QNAME-encoding is one byte longer than the host name. If (as is
   * also valid) the hostname is shortened by the omission of the
   * trailing dot, then its QNAME-encoding will be two bytes longer
   * than the host name.
   *
   * Each [ label, dot ] pair is encoded as [ length, label ],
   * preserving overall length.  A final [ label ] without a dot is
   * also encoded as [ length, label ], increasing overall length
   * by one. The encoding is completed by appending a zero byte,
   * representing the zero-length root label, again increasing
   * the overall length by one.
   */

  size_t expected_len;







|


|



|
|


|


|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
                            size_t *olen) /* output length */
{
  const size_t hostlen = strlen(host);
  unsigned char *orig = dnsp;
  const char *hostp = host;

  /* The expected output length is 16 bytes more than the length of
   * the QNAME-encoding of the hostname.
   *
   * A valid DNS name may not contain a zero-length label, except at
   * the end. For this reason, a name beginning with a dot, or
   * containing a sequence of two or more consecutive dots, is invalid
   * and cannot be encoded as a QNAME.
   *
   * If the hostname ends with a trailing dot, the corresponding
   * QNAME-encoding is one byte longer than the hostname. If (as is
   * also valid) the hostname is shortened by the omission of the
   * trailing dot, then its QNAME-encoding will be two bytes longer
   * than the hostname.
   *
   * Each [ label, dot ] pair is encoded as [ length, label ],
   * preserving overall length. A final [ label ] without a dot is
   * also encoded as [ length, label ], increasing overall length
   * by one. The encoding is completed by appending a zero byte,
   * representing the zero-length root label, again increasing
   * the overall length by one.
   */

  size_t expected_len;
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201

  if(Curl_dyn_addn(mem, contents, realsize))
    return 0;

  return realsize;
}

#if defined(USE_HTTPSRR) && defined(CURLDEBUG)
static void local_print_buf(struct Curl_easy *data,
                            const char *prefix,
                            unsigned char *buf, size_t len)
{
  unsigned char hexstr[LOCAL_PB_HEXMAX];
  size_t hlen = LOCAL_PB_HEXMAX;
  bool truncated = false;







|







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201

  if(Curl_dyn_addn(mem, contents, realsize))
    return 0;

  return realsize;
}

#if defined(USE_HTTPSRR) && defined(DEBUGBUILD)
static void local_print_buf(struct Curl_easy *data,
                            const char *prefix,
                            unsigned char *buf, size_t len)
{
  unsigned char hexstr[LOCAL_PB_HEXMAX];
  size_t hlen = LOCAL_PB_HEXMAX;
  bool truncated = false;
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
    ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
    ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
    ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
#ifdef USE_HTTP2
    ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
    ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
#endif
#ifndef CURLDEBUG
    /* enforce HTTPS if not debug */
    ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
#else
    /* in debug mode, also allow http */
    ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
#endif
    ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);







|







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
    ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
    ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
    ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
#ifdef USE_HTTP2
    ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
    ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
#endif
#ifndef DEBUGBUILD
    /* enforce HTTPS if not debug */
    ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
#else
    /* in debug mode, also allow http */
    ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
#endif
    ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410

struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
                               const char *hostname,
                               int port,
                               int *waitp)
{
  CURLcode result = CURLE_OK;
  int slot;
  struct dohdata *dohp;
  struct connectdata *conn = data->conn;
#ifdef USE_HTTPSRR
  /* for now, this is only used when ECH is enabled */
# ifdef USE_ECH
  char *qname = NULL;
# endif







<







396
397
398
399
400
401
402

403
404
405
406
407
408
409

struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
                               const char *hostname,
                               int port,
                               int *waitp)
{
  CURLcode result = CURLE_OK;

  struct dohdata *dohp;
  struct connectdata *conn = data->conn;
#ifdef USE_HTTPSRR
  /* for now, this is only used when ECH is enabled */
# ifdef USE_ECH
  char *qname = NULL;
# endif
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
#endif

#ifdef USE_HTTPSRR
  /*
   * TODO: Figure out the conditions under which we want to make
   * a request for an HTTPS RR when we are not doing ECH. For now,
   * making this request breaks a bunch of DoH tests, e.g. test2100,
   * where the additional request doesn't match the pre-cooked data
   * files, so there's a bit of work attached to making the request
   * in a non-ECH use-case. For the present, we'll only make the
   * request when ECH is enabled in the build and is being used for
   * the curl operation.
   */
# ifdef USE_ECH
  if(data->set.tls_ech & CURLECH_ENABLE
     || data->set.tls_ech & CURLECH_HARD) {
    if(port == 443)
      qname = strdup(hostname);
    else
      qname = aprintf("_%d._https.%s", port, hostname);
    if(!qname)
      goto error;
    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_HTTPS],
                      DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
                      data->multi, dohp->headers);
    free(qname);
    if(result)
      goto error;
    dohp->pending++;
  }
# endif
#endif
  *waitp = TRUE; /* this never returns synchronously */
  return NULL;

error:
  curl_slist_free_all(dohp->headers);
  data->req.doh->headers = NULL;
  for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
    (void)curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
    Curl_close(&dohp->probe[slot].easy);
  }
  Curl_safefree(data->req.doh);
  return NULL;
}

static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
                         unsigned int *indexp)
{
  unsigned char length;







|
|
|















|










<
<
<
<
<
<
|







450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485






486
487
488
489
490
491
492
493
#endif

#ifdef USE_HTTPSRR
  /*
   * TODO: Figure out the conditions under which we want to make
   * a request for an HTTPS RR when we are not doing ECH. For now,
   * making this request breaks a bunch of DoH tests, e.g. test2100,
   * where the additional request does not match the pre-cooked data
   * files, so there is a bit of work attached to making the request
   * in a non-ECH use-case. For the present, we will only make the
   * request when ECH is enabled in the build and is being used for
   * the curl operation.
   */
# ifdef USE_ECH
  if(data->set.tls_ech & CURLECH_ENABLE
     || data->set.tls_ech & CURLECH_HARD) {
    if(port == 443)
      qname = strdup(hostname);
    else
      qname = aprintf("_%d._https.%s", port, hostname);
    if(!qname)
      goto error;
    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_HTTPS],
                      DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
                      data->multi, dohp->headers);
    Curl_safefree(qname);
    if(result)
      goto error;
    dohp->pending++;
  }
# endif
#endif
  *waitp = TRUE; /* this never returns synchronously */
  return NULL;

error:






  Curl_doh_cleanup(data);
  return NULL;
}

static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
                         unsigned int *indexp)
{
  unsigned char length;
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
    if(dohlen < (*indexp + 1 + length))
      return DOH_DNS_OUT_OF_RANGE;
    *indexp += (unsigned int)(1 + length);
  } while(length);
  return DOH_OK;
}

static unsigned short get16bit(const unsigned char *doh, int index)
{
  return (unsigned short)((doh[index] << 8) | doh[index + 1]);
}

static unsigned int get32bit(const unsigned char *doh, int index)
{
  /* make clang and gcc optimize this to bswap by incrementing
     the pointer first. */
  doh += index;

  /* avoid undefined behavior by casting to unsigned before shifting
     24 bits, possibly into the sign bit. codegen is same, but
     ub sanitizer won't be upset */
  return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) |
         ((unsigned)doh[2] << 8) | doh[3];
}

static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
{
  /* silently ignore addresses over the limit */







|




|







|







507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
    if(dohlen < (*indexp + 1 + length))
      return DOH_DNS_OUT_OF_RANGE;
    *indexp += (unsigned int)(1 + length);
  } while(length);
  return DOH_OK;
}

static unsigned short get16bit(const unsigned char *doh, unsigned int index)
{
  return (unsigned short)((doh[index] << 8) | doh[index + 1]);
}

static unsigned int get32bit(const unsigned char *doh, unsigned int index)
{
  /* make clang and gcc optimize this to bswap by incrementing
     the pointer first. */
  doh += index;

  /* avoid undefined behavior by casting to unsigned before shifting
     24 bits, possibly into the sign bit. codegen is same, but
     ub sanitizer will not be upset */
  return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) |
         ((unsigned)doh[2] << 8) | doh[3];
}

static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
{
  /* silently ignore addresses over the limit */
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
      int newpos;
      /* name pointer, get the new offset (14 bits) */
      if((index + 1) >= dohlen)
        return DOH_DNS_OUT_OF_RANGE;

      /* move to the new index */
      newpos = (length & 0x3f) << 8 | doh[index + 1];
      index = newpos;
      continue;
    }
    else if(length & 0xc0)
      return DOH_DNS_BAD_LABEL; /* bad input */
    else
      index++;








|







595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
      int newpos;
      /* name pointer, get the new offset (14 bits) */
      if((index + 1) >= dohlen)
        return DOH_DNS_OUT_OF_RANGE;

      /* move to the new index */
      newpos = (length & 0x3f) << 8 | doh[index + 1];
      index = (unsigned int)newpos;
      continue;
    }
    else if(length & 0xc0)
      return DOH_DNS_BAD_LABEL; /* bad input */
    else
      index++;

666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  case DNS_TYPE_HTTPS:
    rc = store_https(doh, index, d, rdlength);
    if(rc)
      return rc;
    break;
#endif
  case DNS_TYPE_CNAME:
    rc = store_cname(doh, dohlen, index, d);
    if(rc)
      return rc;
    break;
  case DNS_TYPE_DNAME:
    /* explicit for clarity; just skip; rely on synthesized CNAME  */
    break;
  default:







|







659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
  case DNS_TYPE_HTTPS:
    rc = store_https(doh, index, d, rdlength);
    if(rc)
      return rc;
    break;
#endif
  case DNS_TYPE_CNAME:
    rc = store_cname(doh, dohlen, (unsigned int)index, d);
    if(rc)
      return rc;
    break;
  case DNS_TYPE_DNAME:
    /* explicit for clarity; just skip; rely on synthesized CNAME  */
    break;
  default:
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
      return DOH_DNS_OUT_OF_RANGE;

    rdlength = get16bit(doh, index);
    index += 2;
    if(dohlen < (index + rdlength))
      return DOH_DNS_OUT_OF_RANGE;

    rc = rdata(doh, dohlen, rdlength, type, index, d);
    if(rc)
      return rc; /* bad rdata */
    index += rdlength;
    ancount--;
  }

  nscount = get16bit(doh, 8);







|







760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
      return DOH_DNS_OUT_OF_RANGE;

    rdlength = get16bit(doh, index);
    index += 2;
    if(dohlen < (index + rdlength))
      return DOH_DNS_OUT_OF_RANGE;

    rc = rdata(doh, dohlen, rdlength, type, (int)index, d);
    if(rc)
      return rc; /* bad rdata */
    index += rdlength;
    ancount--;
  }

  nscount = get16bit(doh, 8);
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
        ptr += l;
      }
      infof(data, "%s", buffer);
    }
  }
#ifdef USE_HTTPSRR
  for(i = 0; i < d->numhttps_rrs; i++) {
# ifdef CURLDEBUG
    local_print_buf(data, "DoH HTTPS",
                    d->https_rrs[i].val, d->https_rrs[i].len);
# else
    infof(data, "DoH HTTPS RR: length %d", d->https_rrs[i].len);
# endif
  }
#endif
  for(i = 0; i < d->numcname; i++) {
    infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
  }
}
#else
#define showdoh(x,y)
#endif

/*
 * doh2ai()
 *
 * This function returns a pointer to the first element of a newly allocated
 * Curl_addrinfo struct linked list filled with the data from a set of DoH
 * lookups.  Curl_addrinfo is meant to work like the addrinfo struct does for
 * a IPv6 stack, but usable also for IPv4, all hosts and environments.
 *
 * The memory allocated by this function *MUST* be free'd later on calling
 * Curl_freeaddrinfo().  For each successful call to this function there
 * must be an associated call later to Curl_freeaddrinfo().
 */

static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
                       int port, struct Curl_addrinfo **aip)
{
  struct Curl_addrinfo *ai;







|




















|



|







859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
        ptr += l;
      }
      infof(data, "%s", buffer);
    }
  }
#ifdef USE_HTTPSRR
  for(i = 0; i < d->numhttps_rrs; i++) {
# ifdef DEBUGBUILD
    local_print_buf(data, "DoH HTTPS",
                    d->https_rrs[i].val, d->https_rrs[i].len);
# else
    infof(data, "DoH HTTPS RR: length %d", d->https_rrs[i].len);
# endif
  }
#endif
  for(i = 0; i < d->numcname; i++) {
    infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
  }
}
#else
#define showdoh(x,y)
#endif

/*
 * doh2ai()
 *
 * This function returns a pointer to the first element of a newly allocated
 * Curl_addrinfo struct linked list filled with the data from a set of DoH
 * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
 * a IPv6 stack, but usable also for IPv4, all hosts and environments.
 *
 * The memory allocated by this function *MUST* be free'd later on calling
 * Curl_freeaddrinfo(). For each successful call to this function there
 * must be an associated call later to Curl_freeaddrinfo().
 */

static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
                       int port, struct Curl_addrinfo **aip)
{
  struct Curl_addrinfo *ai;
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
    return CURLE_COULDNT_RESOLVE_HOST;

  for(i = 0; i < de->numaddr; i++) {
    size_t ss_size;
    CURL_SA_FAMILY_T addrtype;
    if(de->addr[i].type == DNS_TYPE_AAAA) {
#ifndef USE_IPV6
      /* we can't handle IPv6 addresses */
      continue;
#else
      ss_size = sizeof(struct sockaddr_in6);
      addrtype = AF_INET6;
#endif
    }
    else {







|







912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
    return CURLE_COULDNT_RESOLVE_HOST;

  for(i = 0; i < de->numaddr; i++) {
    size_t ss_size;
    CURL_SA_FAMILY_T addrtype;
    if(de->addr[i].type == DNS_TYPE_AAAA) {
#ifndef USE_IPV6
      /* we cannot handle IPv6 addresses */
      continue;
#else
      ss_size = sizeof(struct sockaddr_in6);
      addrtype = AF_INET6;
#endif
    }
    else {
963
964
965
966
967
968
969



970

971
972
973
974
975
976
977
978



979

980
981
982
983
984
985
986
    /* leave the rest of the struct filled with zero */

    switch(ai->ai_family) {
    case AF_INET:
      addr = (void *)ai->ai_addr; /* storage area for this info */
      DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
      memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));



      addr->sin_family = addrtype;

      addr->sin_port = htons((unsigned short)port);
      break;

#ifdef USE_IPV6
    case AF_INET6:
      addr6 = (void *)ai->ai_addr; /* storage area for this info */
      DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
      memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));



      addr6->sin6_family = addrtype;

      addr6->sin6_port = htons((unsigned short)port);
      break;
#endif
    }

    prevai = ai;
  }







>
>
>

>








>
>
>

>







956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
    /* leave the rest of the struct filled with zero */

    switch(ai->ai_family) {
    case AF_INET:
      addr = (void *)ai->ai_addr; /* storage area for this info */
      DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
      memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
#ifdef __MINGW32__
      addr->sin_family = (short)addrtype;
#else
      addr->sin_family = addrtype;
#endif
      addr->sin_port = htons((unsigned short)port);
      break;

#ifdef USE_IPV6
    case AF_INET6:
      addr6 = (void *)ai->ai_addr; /* storage area for this info */
      DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
      memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
#ifdef __MINGW32__
      addr6->sin6_family = (short)addrtype;
#else
      addr6->sin6_family = addrtype;
#endif
      addr6->sin6_port = htons((unsigned short)port);
      break;
#endif
    }

    prevai = ai;
  }
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
{
  int i = 0;
  for(i = 0; i < d->numcname; i++) {
    Curl_dyn_free(&d->cname[i]);
  }
#ifdef USE_HTTPSRR
  for(i = 0; i < d->numhttps_rrs; i++)
    free(d->https_rrs[i].val);
#endif
}

#ifdef USE_HTTPSRR

/*
 * @brief decode the DNS name in a binary RRData
 * @param buf points to the buffer (in/out)
 * @param remaining points to the remaining buffer length (in/out)
 * @param dnsname returns the string form name on success
 * @return is 1 for success, error otherwise
 *
 * The encoding here is defined in
 * https://tools.ietf.org/html/rfc1035#section-3.1
 *
 * The input buffer pointer will be modified so it points to
 * just after the end of the DNS name encoding on output. (And
 * that's why it's an "unsigned char **" :-)
 */
static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
                                        char **dnsname)
{
  unsigned char *cp = NULL;
  int rem = 0;
  unsigned char clen = 0; /* chunk len */







|

















|







1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
{
  int i = 0;
  for(i = 0; i < d->numcname; i++) {
    Curl_dyn_free(&d->cname[i]);
  }
#ifdef USE_HTTPSRR
  for(i = 0; i < d->numhttps_rrs; i++)
    Curl_safefree(d->https_rrs[i].val);
#endif
}

#ifdef USE_HTTPSRR

/*
 * @brief decode the DNS name in a binary RRData
 * @param buf points to the buffer (in/out)
 * @param remaining points to the remaining buffer length (in/out)
 * @param dnsname returns the string form name on success
 * @return is 1 for success, error otherwise
 *
 * The encoding here is defined in
 * https://tools.ietf.org/html/rfc1035#section-3.1
 *
 * The input buffer pointer will be modified so it points to
 * just after the end of the DNS name encoding on output. (And
 * that is why it is an "unsigned char **" :-)
 */
static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
                                        char **dnsname)
{
  unsigned char *cp = NULL;
  int rem = 0;
  unsigned char clen = 0; /* chunk len */
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
  /*
   * spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
   * encoding is catenated list of strings each preceded by a one
   * octet length
   * output is comma-sep list of the strings
   * implementations may or may not handle quoting of comma within
   * string values, so we might see a comma within the wire format
   * version of a string, in which case we'll precede that by a
   * backslash - same goes for a backslash character, and of course
   * we need to use two backslashes in strings when we mean one;-)
   */
  int remaining = (int) len;
  char *oval;
  size_t i;
  unsigned char *cp = rrval;







|







1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
  /*
   * spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
   * encoding is catenated list of strings each preceded by a one
   * octet length
   * output is comma-sep list of the strings
   * implementations may or may not handle quoting of comma within
   * string values, so we might see a comma within the wire format
   * version of a string, in which case we will precede that by a
   * backslash - same goes for a backslash character, and of course
   * we need to use two backslashes in strings when we mean one;-)
   */
  int remaining = (int) len;
  char *oval;
  size_t i;
  unsigned char *cp = rrval;
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
  *alpns = oval;
  return CURLE_OK;
err:
  Curl_dyn_free(&dval);
  return CURLE_BAD_CONTENT_ENCODING;
}

#ifdef CURLDEBUG
static CURLcode test_alpn_escapes(void)
{
  /* we'll use an example from draft-ietf-dnsop-svcb, figure 10 */
  static unsigned char example[] = {
    0x08,                                           /* length 8 */
    0x66, 0x5c, 0x6f, 0x6f, 0x2c, 0x62, 0x61, 0x72, /* value "f\\oo,bar" */
    0x02,                                           /* length 2 */
    0x68, 0x32                                      /* value "h2" */
  };
  size_t example_len = sizeof(example);







|


|







1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  *alpns = oval;
  return CURLE_OK;
err:
  Curl_dyn_free(&dval);
  return CURLE_BAD_CONTENT_ENCODING;
}

#ifdef DEBUGBUILD
static CURLcode test_alpn_escapes(void)
{
  /* we will use an example from draft-ietf-dnsop-svcb, figure 10 */
  static unsigned char example[] = {
    0x08,                                           /* length 8 */
    0x66, 0x5c, 0x6f, 0x6f, 0x2c, 0x62, 0x61, 0x72, /* value "f\\oo,bar" */
    0x02,                                           /* length 2 */
    0x68, 0x32                                      /* value "h2" */
  };
  size_t example_len = sizeof(example);
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
{
  size_t remaining = len;
  unsigned char *cp = rrval;
  uint16_t pcode = 0, plen = 0;
  struct Curl_https_rrinfo *lhrr = NULL;
  char *dnsname = NULL;

#ifdef CURLDEBUG
  /* a few tests of escaping, shouldn't be here but ok for now */
  if(test_alpn_escapes() != CURLE_OK)
    return CURLE_OUT_OF_MEMORY;
#endif
  lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
  if(!lhrr)
    return CURLE_OUT_OF_MEMORY;
  lhrr->val = Curl_memdup(rrval, len);







|
|







1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
{
  size_t remaining = len;
  unsigned char *cp = rrval;
  uint16_t pcode = 0, plen = 0;
  struct Curl_https_rrinfo *lhrr = NULL;
  char *dnsname = NULL;

#ifdef DEBUGBUILD
  /* a few tests of escaping, should not be here but ok for now */
  if(test_alpn_escapes() != CURLE_OK)
    return CURLE_OUT_OF_MEMORY;
#endif
  lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
  if(!lhrr)
    return CURLE_OUT_OF_MEMORY;
  lhrr->val = Curl_memdup(rrval, len);
1205
1206
1207
1208
1209
1210
1211


1212
1213
1214
1215
1216
1217


1218
1219
1220
1221
1222
1223


1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241

1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
    if(pcode == HTTPS_RR_CODE_ALPN) {
      if(local_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
        goto err;
    }
    if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
      lhrr->no_def_alpn = TRUE;
    else if(pcode == HTTPS_RR_CODE_IPV4) {


      lhrr->ipv4hints = Curl_memdup(cp, plen);
      if(!lhrr->ipv4hints)
        goto err;
      lhrr->ipv4hints_len = (size_t)plen;
    }
    else if(pcode == HTTPS_RR_CODE_ECH) {


      lhrr->echconfiglist = Curl_memdup(cp, plen);
      if(!lhrr->echconfiglist)
        goto err;
      lhrr->echconfiglist_len = (size_t)plen;
    }
    else if(pcode == HTTPS_RR_CODE_IPV6) {


      lhrr->ipv6hints = Curl_memdup(cp, plen);
      if(!lhrr->ipv6hints)
        goto err;
      lhrr->ipv6hints_len = (size_t)plen;
    }
    if(plen > 0 && plen <= remaining) {
      cp += plen;
      remaining -= plen;
    }
  }
  DEBUGASSERT(!remaining);
  *hrr = lhrr;
  return CURLE_OK;
err:
  if(lhrr) {
    free(lhrr->target);
    free(lhrr->echconfiglist);
    free(lhrr->val);

    free(lhrr);
  }
  return CURLE_OUT_OF_MEMORY;
}

# ifdef CURLDEBUG
static void local_print_httpsrr(struct Curl_easy *data,
                                struct Curl_https_rrinfo *hrr)
{
  DEBUGASSERT(hrr);
  infof(data, "HTTPS RR: priority %d, target: %s",
        hrr->priority, hrr->target);
  if(hrr->alpns)







>
>






>
>






>
>















|
|
|
>
|




|







1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
    if(pcode == HTTPS_RR_CODE_ALPN) {
      if(local_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
        goto err;
    }
    if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
      lhrr->no_def_alpn = TRUE;
    else if(pcode == HTTPS_RR_CODE_IPV4) {
      if(!plen)
        goto err;
      lhrr->ipv4hints = Curl_memdup(cp, plen);
      if(!lhrr->ipv4hints)
        goto err;
      lhrr->ipv4hints_len = (size_t)plen;
    }
    else if(pcode == HTTPS_RR_CODE_ECH) {
      if(!plen)
        goto err;
      lhrr->echconfiglist = Curl_memdup(cp, plen);
      if(!lhrr->echconfiglist)
        goto err;
      lhrr->echconfiglist_len = (size_t)plen;
    }
    else if(pcode == HTTPS_RR_CODE_IPV6) {
      if(!plen)
        goto err;
      lhrr->ipv6hints = Curl_memdup(cp, plen);
      if(!lhrr->ipv6hints)
        goto err;
      lhrr->ipv6hints_len = (size_t)plen;
    }
    if(plen > 0 && plen <= remaining) {
      cp += plen;
      remaining -= plen;
    }
  }
  DEBUGASSERT(!remaining);
  *hrr = lhrr;
  return CURLE_OK;
err:
  if(lhrr) {
    Curl_safefree(lhrr->target);
    Curl_safefree(lhrr->echconfiglist);
    Curl_safefree(lhrr->val);
    Curl_safefree(lhrr->alpns);
    Curl_safefree(lhrr);
  }
  return CURLE_OUT_OF_MEMORY;
}

# ifdef DEBUGBUILD
static void local_print_httpsrr(struct Curl_easy *data,
                                struct Curl_https_rrinfo *hrr)
{
  DEBUGASSERT(hrr);
  infof(data, "HTTPS RR: priority %d, target: %s",
        hrr->priority, hrr->target);
  if(hrr->alpns)
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
    DOHcode rc[DOH_PROBE_SLOTS] = {
      DOH_OK, DOH_OK, DOH_OK
    };
#endif
    struct dohentry de;
    int slot;
    /* remove DoH handles from multi handle and close them */
    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
      curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
      Curl_close(&dohp->probe[slot].easy);
    }
    /* parse the responses, create the struct and return it! */
    de_init(&de);
    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
      struct dnsprobe *p = &dohp->probe[slot];
      if(!p->dnstype)
        continue;
      rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),







<
<
|
<







1314
1315
1316
1317
1318
1319
1320


1321

1322
1323
1324
1325
1326
1327
1328
    DOHcode rc[DOH_PROBE_SLOTS] = {
      DOH_OK, DOH_OK, DOH_OK
    };
#endif
    struct dohentry de;
    int slot;
    /* remove DoH handles from multi handle and close them */


    Curl_doh_close(data);

    /* parse the responses, create the struct and return it! */
    de_init(&de);
    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
      struct dnsprobe *p = &dohp->probe[slot];
      if(!p->dnstype)
        continue;
      rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
    if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) {
      /* we have an address, of one kind or other */
      struct Curl_dns_entry *dns;
      struct Curl_addrinfo *ai;


      if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
        infof(data, "[DoH] Host name: %s", dohp->host);
        showdoh(data, &de);
      }

      result = doh2ai(&de, dohp->host, dohp->port, &ai);
      if(result) {
        de_cleanup(&de);
        return result;







|







1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
    if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) {
      /* we have an address, of one kind or other */
      struct Curl_dns_entry *dns;
      struct Curl_addrinfo *ai;


      if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
        infof(data, "[DoH] hostname: %s", dohp->host);
        showdoh(data, &de);
      }

      result = doh2ai(&de, dohp->host, dohp->port, &ai);
      if(result) {
        de_cleanup(&de);
        return result;
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402




























1403
      result = Curl_doh_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
                                       &hrr);
      if(result) {
        infof(data, "Failed to decode HTTPS RR");
        return result;
      }
      infof(data, "Some HTTPS RR to process");
# ifdef CURLDEBUG
      local_print_httpsrr(data, hrr);
# endif
      (*dnsp)->hinfo = hrr;
    }
#endif

    /* All done */
    de_cleanup(&de);
    Curl_safefree(data->req.doh);
    return result;

  } /* !dohp->pending */

  /* else wait for pending DoH transactions to complete */
  return CURLE_OK;
}





























#endif /* CURL_DISABLE_DOH */







|

















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
      result = Curl_doh_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
                                       &hrr);
      if(result) {
        infof(data, "Failed to decode HTTPS RR");
        return result;
      }
      infof(data, "Some HTTPS RR to process");
# ifdef DEBUGBUILD
      local_print_httpsrr(data, hrr);
# endif
      (*dnsp)->hinfo = hrr;
    }
#endif

    /* All done */
    de_cleanup(&de);
    Curl_safefree(data->req.doh);
    return result;

  } /* !dohp->pending */

  /* else wait for pending DoH transactions to complete */
  return CURLE_OK;
}

void Curl_doh_close(struct Curl_easy *data)
{
  struct dohdata *doh = data->req.doh;
  if(doh) {
    size_t slot;
    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
      if(!doh->probe[slot].easy)
        continue;
      /* data->multi might already be reset at this time */
      if(doh->probe[slot].easy->multi)
        curl_multi_remove_handle(doh->probe[slot].easy->multi,
                                 doh->probe[slot].easy);
      Curl_close(&doh->probe[slot].easy);
    }
  }
}

void Curl_doh_cleanup(struct Curl_easy *data)
{
  struct dohdata *doh = data->req.doh;
  if(doh) {
    Curl_doh_close(data);
    curl_slist_free_all(doh->headers);
    data->req.doh->headers = NULL;
    Curl_safefree(data->req.doh);
  }
}

#endif /* CURL_DISABLE_DOH */
Changes to jni/curl/lib/doh.h.
136
137
138
139
140
141
142


143
144
145
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
161
162
  int numcname;
#ifdef USE_HTTPSRR
  struct dohhttps_rr https_rrs[DOH_MAX_HTTPS];
  int numhttps_rrs;
#endif
};




#ifdef DEBUGBUILD
DOHcode doh_encode(const char *host,
                   DNStype dnstype,
                   unsigned char *dnsp, /* buffer */
                   size_t len,  /* buffer size */
                   size_t *olen); /* output length */
DOHcode doh_decode(const unsigned char *doh,
                   size_t dohlen,
                   DNStype dnstype,
                   struct dohentry *d);

void de_init(struct dohentry *d);
void de_cleanup(struct dohentry *d);
#endif

extern struct curl_trc_feat Curl_doh_trc;

#else /* if DoH is disabled */
#define Curl_doh(a,b,c,d) NULL
#define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST







>
>

|
|
|
|
|
|
|
|
|
|
>
|
|







136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  int numcname;
#ifdef USE_HTTPSRR
  struct dohhttps_rr https_rrs[DOH_MAX_HTTPS];
  int numhttps_rrs;
#endif
};

void Curl_doh_close(struct Curl_easy *data);
void Curl_doh_cleanup(struct Curl_easy *data);

#ifdef UNITTESTS
UNITTEST DOHcode doh_encode(const char *host,
                            DNStype dnstype,
                            unsigned char *dnsp,  /* buffer */
                            size_t len,  /* buffer size */
                            size_t *olen);  /* output length */
UNITTEST DOHcode doh_decode(const unsigned char *doh,
                            size_t dohlen,
                            DNStype dnstype,
                            struct dohentry *d);

UNITTEST void de_init(struct dohentry *d);
UNITTEST void de_cleanup(struct dohentry *d);
#endif

extern struct curl_trc_feat Curl_doh_trc;

#else /* if DoH is disabled */
#define Curl_doh(a,b,c,d) NULL
#define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
Changes to jni/curl/lib/dynbuf.c.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  s->toobig = toobig;
#ifdef DEBUGBUILD
  s->init = DYNINIT;
#endif
}

/*
 * free the buffer and re-init the necessary fields. It doesn't touch the
 * 'init' field and thus this buffer can be reused to add data to again.
 */
void Curl_dyn_free(struct dynbuf *s)
{
  DEBUGASSERT(s);
  Curl_safefree(s->bufr);
  s->leng = s->allc = 0;
}

/*
 * Store/append an chunk of memory to the dynbuf.
 */
static CURLcode dyn_nappend(struct dynbuf *s,
                            const unsigned char *mem, size_t len)
{
  size_t indx = s->leng;
  size_t a = s->allc;
  size_t fit = len + indx + 1; /* new string + old string + zero byte */

  /* try to detect if there's rubbish in the struct */
  DEBUGASSERT(s->init == DYNINIT);
  DEBUGASSERT(s->toobig);
  DEBUGASSERT(indx < s->toobig);
  DEBUGASSERT(!s->leng || s->bufr);
  DEBUGASSERT(a <= s->toobig);
  DEBUGASSERT(!len || mem);








|



















|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  s->toobig = toobig;
#ifdef DEBUGBUILD
  s->init = DYNINIT;
#endif
}

/*
 * free the buffer and re-init the necessary fields. It does not touch the
 * 'init' field and thus this buffer can be reused to add data to again.
 */
void Curl_dyn_free(struct dynbuf *s)
{
  DEBUGASSERT(s);
  Curl_safefree(s->bufr);
  s->leng = s->allc = 0;
}

/*
 * Store/append an chunk of memory to the dynbuf.
 */
static CURLcode dyn_nappend(struct dynbuf *s,
                            const unsigned char *mem, size_t len)
{
  size_t indx = s->leng;
  size_t a = s->allc;
  size_t fit = len + indx + 1; /* new string + old string + zero byte */

  /* try to detect if there is rubbish in the struct */
  DEBUGASSERT(s->init == DYNINIT);
  DEBUGASSERT(s->toobig);
  DEBUGASSERT(indx < s->toobig);
  DEBUGASSERT(!s->leng || s->bufr);
  DEBUGASSERT(a <= s->toobig);
  DEBUGASSERT(!len || mem);

Changes to jni/curl/lib/dynhds.c.
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
}

CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
{
  return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0);
}

#ifdef DEBUGBUILD
/* used by unit2602.c */

bool Curl_dynhds_contains(struct dynhds *dynhds,
                          const char *name, size_t namelen)
{
  return !!Curl_dynhds_get(dynhds, name, namelen);
}







|







271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
}

CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
{
  return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0);
}

#ifdef UNITTESTS
/* used by unit2602.c */

bool Curl_dynhds_contains(struct dynhds *dynhds,
                          const char *name, size_t namelen)
{
  return !!Curl_dynhds_get(dynhds, name, namelen);
}
Changes to jni/curl/lib/dynhds.h.
91
92
93
94
95
96
97



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151
152
153














154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/**
 * Return the 1st header entry of the name or NULL if none exists.
 */
struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds,
                                     const char *name, size_t namelen);
struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name);




/**
 * Return TRUE iff one or more headers with the given name exist.
 */
bool Curl_dynhds_contains(struct dynhds *dynhds,
                          const char *name, size_t namelen);
bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name);

/**
 * Return how often the given name appears in `dynhds`.
 * Names are case-insensitive.
 */
size_t Curl_dynhds_count_name(struct dynhds *dynhds,
                              const char *name, size_t namelen);

/**
 * Return how often the given 0-terminated name appears in `dynhds`.
 * Names are case-insensitive.
 */
size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name);

/**
 * Add a header, name + value, to `dynhds` at the end. Does *not*
 * check for duplicate names.
 */
CURLcode Curl_dynhds_add(struct dynhds *dynhds,
                         const char *name, size_t namelen,
                         const char *value, size_t valuelen);

/**
 * Add a header, c-string name + value, to `dynhds` at the end.
 */
CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
                          const char *name, const char *value);

/**
 * Remove all entries with the given name.
 * Returns number of entries removed.
 */
size_t Curl_dynhds_remove(struct dynhds *dynhds,
                          const char *name, size_t namelen);
size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name);


/**
 * Set the give header name and value, replacing any entries with
 * the same name. The header is added at the end of all (remaining)
 * entries.
 */
CURLcode Curl_dynhds_set(struct dynhds *dynhds,
                         const char *name, size_t namelen,
                         const char *value, size_t valuelen);


CURLcode Curl_dynhds_cset(struct dynhds *dynhds,
                          const char *name, const char *value);

/**














 * Add a single header from a HTTP/1.1 formatted line at the end. Line
 * may contain a delimiting \r\n or just \n. Any characters after
 * that will be ignored.
 */
CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line);

/**
 * Add a single header from a HTTP/1.1 formatted line at the end. Line
 * may contain a delimiting \r\n or just \n. Any characters after
 * that will be ignored.
 */
CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds,
                                 const char *line, size_t line_len);

/**







>
>
>




















<
<
<
<
<
<
<
<
<
<
<
<
<
<

















>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
|






|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120














121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/**
 * Return the 1st header entry of the name or NULL if none exists.
 */
struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds,
                                     const char *name, size_t namelen);
struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name);

#ifdef UNITTESTS
/* used by unit2602.c */

/**
 * Return TRUE iff one or more headers with the given name exist.
 */
bool Curl_dynhds_contains(struct dynhds *dynhds,
                          const char *name, size_t namelen);
bool Curl_dynhds_ccontains(struct dynhds *dynhds, const char *name);

/**
 * Return how often the given name appears in `dynhds`.
 * Names are case-insensitive.
 */
size_t Curl_dynhds_count_name(struct dynhds *dynhds,
                              const char *name, size_t namelen);

/**
 * Return how often the given 0-terminated name appears in `dynhds`.
 * Names are case-insensitive.
 */
size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name);















/**
 * Remove all entries with the given name.
 * Returns number of entries removed.
 */
size_t Curl_dynhds_remove(struct dynhds *dynhds,
                          const char *name, size_t namelen);
size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name);


/**
 * Set the give header name and value, replacing any entries with
 * the same name. The header is added at the end of all (remaining)
 * entries.
 */
CURLcode Curl_dynhds_set(struct dynhds *dynhds,
                         const char *name, size_t namelen,
                         const char *value, size_t valuelen);
#endif

CURLcode Curl_dynhds_cset(struct dynhds *dynhds,
                          const char *name, const char *value);

/**
 * Add a header, name + value, to `dynhds` at the end. Does *not*
 * check for duplicate names.
 */
CURLcode Curl_dynhds_add(struct dynhds *dynhds,
                         const char *name, size_t namelen,
                         const char *value, size_t valuelen);

/**
 * Add a header, c-string name + value, to `dynhds` at the end.
 */
CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
                          const char *name, const char *value);

/**
 * Add a single header from an HTTP/1.1 formatted line at the end. Line
 * may contain a delimiting \r\n or just \n. Any characters after
 * that will be ignored.
 */
CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line);

/**
 * Add a single header from an HTTP/1.1 formatted line at the end. Line
 * may contain a delimiting \r\n or just \n. Any characters after
 * that will be ignored.
 */
CURLcode Curl_dynhds_h1_add_line(struct dynhds *dynhds,
                                 const char *line, size_t line_len);

/**
Changes to jni/curl/lib/easy.c.
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  /* Invalid input, return immediately */
  if(!m || !f || !r || !s || !c)
    return CURLE_FAILED_INIT;

  global_init_lock();

  if(initialized) {
    /* Already initialized, don't do it again, but bump the variable anyway to
       work like curl_global_init() and require the same amount of cleanup
       calls. */
    initialized++;
    global_init_unlock();
    return CURLE_OK;
  }








|







238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
  /* Invalid input, return immediately */
  if(!m || !f || !r || !s || !c)
    return CURLE_FAILED_INIT;

  global_init_lock();

  if(initialized) {
    /* Already initialized, do not do it again, but bump the variable anyway to
       work like curl_global_init() and require the same amount of cleanup
       calls. */
    initialized++;
    global_init_unlock();
    return CURLE_OK;
  }

264
265
266
267
268
269
270
271

272
273
274
275
276
277
278
  global_init_unlock();

  return result;
}

/**
 * curl_global_cleanup() globally cleanups curl, uses the value of
 * "easy_init_flags" to determine what needs to be cleaned up and what doesn't.

 */
void curl_global_cleanup(void)
{
  global_init_lock();

  if(!initialized) {
    global_init_unlock();







|
>







264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  global_init_unlock();

  return result;
}

/**
 * curl_global_cleanup() globally cleanups curl, uses the value of
 * "easy_init_flags" to determine what needs to be cleaned up and what does
 * not.
 */
void curl_global_cleanup(void)
{
  global_init_lock();

  if(!initialized) {
    global_init_unlock();
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
    DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
    return NULL;
  }

  return data;
}

#ifdef CURLDEBUG

struct socketmonitor {
  struct socketmonitor *next; /* the next node in the list or NULL */
  struct pollfd socket; /* socket info of what to monitor */
};

struct events {







|







371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
    DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
    return NULL;
  }

  return data;
}

#ifdef DEBUGBUILD

struct socketmonitor {
  struct socketmonitor *next; /* the next node in the list or NULL */
  struct pollfd socket; /* socket info of what to monitor */
};

struct events {
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
      numfds++;
    }

    /* get the time stamp to use to figure out how long poll takes */
    before = Curl_now();

    /* wait for activity or timeout */
    pollrc = Curl_poll(fds, numfds, ev->ms);
    if(pollrc < 0)
      return CURLE_UNRECOVERABLE_POLL;

    after = Curl_now();

    ev->msbump = FALSE; /* reset here */








|







576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
      numfds++;
    }

    /* get the time stamp to use to figure out how long poll takes */
    before = Curl_now();

    /* wait for activity or timeout */
    pollrc = Curl_poll(fds, (unsigned int)numfds, ev->ms);
    if(pollrc < 0)
      return CURLE_UNRECOVERABLE_POLL;

    after = Curl_now();

    ev->msbump = FALSE; /* reset here */

623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
        }
      }
    }

    if(mcode)
      return CURLE_URL_MALFORMAT;

    /* we don't really care about the "msgs_in_queue" value returned in the
       second argument */
    msg = curl_multi_info_read(multi, &pollrc);
    if(msg) {
      result = msg->data.result;
      done = TRUE;
    }
  }







|







624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
        }
      }
    }

    if(mcode)
      return CURLE_URL_MALFORMAT;

    /* we do not really care about the "msgs_in_queue" value returned in the
       second argument */
    msg = curl_multi_info_read(multi, &pollrc);
    if(msg) {
      result = msg->data.result;
      done = TRUE;
    }
  }
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
  static struct events evs = {2, FALSE, 0, NULL, 0};

  /* if running event-based, do some further multi inits */
  events_setup(multi, &evs);

  return wait_or_timeout(multi, &evs);
}
#else /* CURLDEBUG */
/* when not built with debug, this function doesn't exist */
#define easy_events(x) CURLE_NOT_BUILT_IN
#endif

static CURLcode easy_transfer(struct Curl_multi *multi)
{
  bool done = FALSE;
  CURLMcode mcode = CURLM_OK;







|
|







652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  static struct events evs = {2, FALSE, 0, NULL, 0};

  /* if running event-based, do some further multi inits */
  events_setup(multi, &evs);

  return wait_or_timeout(multi, &evs);
}
#else /* DEBUGBUILD */
/* when not built with debug, this function does not exist */
#define easy_events(x) CURLE_NOT_BUILT_IN
#endif

static CURLcode easy_transfer(struct Curl_multi *multi)
{
  bool done = FALSE;
  CURLMcode mcode = CURLM_OK;
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
 * transfer as previously setup.
 *
 * CONCEPT: This function creates a multi handle, adds the easy handle to it,
 * runs curl_multi_perform() until the transfer is done, then detaches the
 * easy handle, destroys the multi handle and returns the easy handle's return
 * code.
 *
 * REALITY: it can't just create and destroy the multi handle that easily. It
 * needs to keep it around since if this easy handle is used again by this
 * function, the same multi handle must be reused so that the same pools and
 * caches can be used.
 *
 * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
 * instead of curl_multi_perform() and use curl_multi_socket_action().
 */







|







703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
 * transfer as previously setup.
 *
 * CONCEPT: This function creates a multi handle, adds the easy handle to it,
 * runs curl_multi_perform() until the transfer is done, then detaches the
 * easy handle, destroys the multi handle and returns the easy handle's return
 * code.
 *
 * REALITY: it cannot just create and destroy the multi handle that easily. It
 * needs to keep it around since if this easy handle is used again by this
 * function, the same multi handle must be reused so that the same pools and
 * caches can be used.
 *
 * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
 * instead of curl_multi_perform() and use curl_multi_socket_action().
 */
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
  data->multi_easy = multi;

  sigpipe_ignore(data, &pipe_st);

  /* run the transfer */
  result = events ? easy_events(multi) : easy_transfer(multi);

  /* ignoring the return code isn't nice, but atm we can't really handle
     a failure here, room for future improvement! */
  (void)curl_multi_remove_handle(multi, data);

  sigpipe_restore(&pipe_st);

  /* The multi handle is kept alive, owned by the easy handle */
  return result;
}


/*
 * curl_easy_perform() is the external interface that performs a blocking
 * transfer as previously setup.
 */
CURLcode curl_easy_perform(struct Curl_easy *data)
{
  return easy_perform(data, FALSE);
}

#ifdef CURLDEBUG
/*
 * curl_easy_perform_ev() is the external interface that performs a blocking
 * transfer using the event-based API internally.
 */
CURLcode curl_easy_perform_ev(struct Curl_easy *data)
{
  return easy_perform(data, TRUE);







|



















|







765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
  data->multi_easy = multi;

  sigpipe_ignore(data, &pipe_st);

  /* run the transfer */
  result = events ? easy_events(multi) : easy_transfer(multi);

  /* ignoring the return code is not nice, but atm we cannot really handle
     a failure here, room for future improvement! */
  (void)curl_multi_remove_handle(multi, data);

  sigpipe_restore(&pipe_st);

  /* The multi handle is kept alive, owned by the easy handle */
  return result;
}


/*
 * curl_easy_perform() is the external interface that performs a blocking
 * transfer as previously setup.
 */
CURLcode curl_easy_perform(struct Curl_easy *data)
{
  return easy_perform(data, FALSE);
}

#ifdef DEBUGBUILD
/*
 * curl_easy_perform_ev() is the external interface that performs a blocking
 * transfer using the event-based API internally.
 */
CURLcode curl_easy_perform_ev(struct Curl_easy *data)
{
  return easy_perform(data, TRUE);
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  CURLcode result = CURLE_OK;
  int oldstate;
  int newstate;
  bool recursive = FALSE;
  bool keep_changed, unpause_read, not_all_paused;

  if(!GOOD_EASY_HANDLE(data) || !data->conn)
    /* crazy input, don't continue */
    return CURLE_BAD_FUNCTION_ARGUMENT;

  if(Curl_is_in_callback(data))
    recursive = TRUE;
  k = &data->req;
  oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);








|







1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
  CURLcode result = CURLE_OK;
  int oldstate;
  int newstate;
  bool recursive = FALSE;
  bool keep_changed, unpause_read, not_all_paused;

  if(!GOOD_EASY_HANDLE(data) || !data->conn)
    /* crazy input, do not continue */
    return CURLE_BAD_FUNCTION_ARGUMENT;

  if(Curl_is_in_callback(data))
    recursive = TRUE;
  k = &data->req;
  oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);

1137
1138
1139
1140
1141
1142
1143





1144
1145
1146
1147
1148
1149
1150
  }

  if(unpause_read) {
    result = Curl_creader_unpause(data);
    if(result)
      goto out;
  }






out:
  if(!result && !data->state.done && keep_changed)
    /* This transfer may have been moved in or out of the bundle, update the
       corresponding socket callback, if used */
    result = Curl_updatesocket(data);








>
>
>
>
>







1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
  }

  if(unpause_read) {
    result = Curl_creader_unpause(data);
    if(result)
      goto out;
  }

  if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
    Curl_conn_ev_data_pause(data, FALSE);
    result = Curl_cwriter_unpause(data);
  }

out:
  if(!result && !data->state.done && keep_changed)
    /* This transfer may have been moved in or out of the bundle, update the
       corresponding socket callback, if used */
    result = Curl_updatesocket(data);

Changes to jni/curl/lib/easygetopt.c.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    do {
      if(name) {
        if(strcasecompare(o->name, name))
          return o;
      }
      else {
        if((o->id == id) && !(o->flags & CURLOT_FLAG_ALIAS))
          /* don't match alias options */
          return o;
      }
      o++;
    } while(o->name);
  }
  return NULL;
}







|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    do {
      if(name) {
        if(strcasecompare(o->name, name))
          return o;
      }
      else {
        if((o->id == id) && !(o->flags & CURLOT_FLAG_ALIAS))
          /* do not match alias options */
          return o;
      }
      o++;
    } while(o->name);
  }
  return NULL;
}
Changes to jni/curl/lib/easyif.h.
30
31
32
33
34
35
36
37
38
39
40
41
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
                       size_t buflen, size_t *n);

#ifdef USE_WEBSOCKETS
CURLcode Curl_connect_only_attach(struct Curl_easy *data);
#endif

#ifdef CURLDEBUG
CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
#endif

#endif /* HEADER_CURL_EASYIF_H */







|




30
31
32
33
34
35
36
37
38
39
40
41
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
                       size_t buflen, size_t *n);

#ifdef USE_WEBSOCKETS
CURLcode Curl_connect_only_attach(struct Curl_easy *data);
#endif

#ifdef DEBUGBUILD
CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
#endif

#endif /* HEADER_CURL_EASYIF_H */
Changes to jni/curl/lib/easyoptions.c.
324
325
326
327
328
329
330

331
332
333
334
335
336
337
  {"STREAM_DEPENDS", CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0},
  {"STREAM_DEPENDS_E", CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0},
  {"STREAM_WEIGHT", CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0},
  {"SUPPRESS_CONNECT_HEADERS", CURLOPT_SUPPRESS_CONNECT_HEADERS,
   CURLOT_LONG, 0},
  {"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0},
  {"TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE, CURLOT_LONG, 0},

  {"TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE, CURLOT_LONG, 0},
  {"TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL, CURLOT_LONG, 0},
  {"TCP_NODELAY", CURLOPT_TCP_NODELAY, CURLOT_LONG, 0},
  {"TELNETOPTIONS", CURLOPT_TELNETOPTIONS, CURLOT_SLIST, 0},
  {"TFTP_BLKSIZE", CURLOPT_TFTP_BLKSIZE, CURLOT_LONG, 0},
  {"TFTP_NO_OPTIONS", CURLOPT_TFTP_NO_OPTIONS, CURLOT_LONG, 0},
  {"TIMECONDITION", CURLOPT_TIMECONDITION, CURLOT_VALUES, 0},







>







324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  {"STREAM_DEPENDS", CURLOPT_STREAM_DEPENDS, CURLOT_OBJECT, 0},
  {"STREAM_DEPENDS_E", CURLOPT_STREAM_DEPENDS_E, CURLOT_OBJECT, 0},
  {"STREAM_WEIGHT", CURLOPT_STREAM_WEIGHT, CURLOT_LONG, 0},
  {"SUPPRESS_CONNECT_HEADERS", CURLOPT_SUPPRESS_CONNECT_HEADERS,
   CURLOT_LONG, 0},
  {"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0},
  {"TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE, CURLOT_LONG, 0},
  {"TCP_KEEPCNT", CURLOPT_TCP_KEEPCNT, CURLOT_LONG, 0},
  {"TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE, CURLOT_LONG, 0},
  {"TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL, CURLOT_LONG, 0},
  {"TCP_NODELAY", CURLOPT_TCP_NODELAY, CURLOT_LONG, 0},
  {"TELNETOPTIONS", CURLOPT_TELNETOPTIONS, CURLOT_SLIST, 0},
  {"TFTP_BLKSIZE", CURLOPT_TFTP_BLKSIZE, CURLOT_LONG, 0},
  {"TFTP_NO_OPTIONS", CURLOPT_TFTP_NO_OPTIONS, CURLOT_LONG, 0},
  {"TIMECONDITION", CURLOPT_TIMECONDITION, CURLOT_VALUES, 0},
372
373
374
375
376
377
378
379
380
381
#ifdef DEBUGBUILD
/*
 * Curl_easyopts_check() is a debug-only function that returns non-zero
 * if this source file is not in sync with the options listed in curl/curl.h
 */
int Curl_easyopts_check(void)
{
  return ((CURLOPT_LASTENTRY%10000) != (325 + 1));
}
#endif







|


373
374
375
376
377
378
379
380
381
382
#ifdef DEBUGBUILD
/*
 * Curl_easyopts_check() is a debug-only function that returns non-zero
 * if this source file is not in sync with the options listed in curl/curl.h
 */
int Curl_easyopts_check(void)
{
  return ((CURLOPT_LASTENTRY%10000) != (326 + 1));
}
#endif
Changes to jni/curl/lib/escape.c.
66
67
68
69
70
71
72
73

74
75
76
77
78
79
80
  Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH * 3);

  length = (inlength?(size_t)inlength:strlen(string));
  if(!length)
    return strdup("");

  while(length--) {
    unsigned char in = *string++; /* treat the characters unsigned */


    if(ISUNRESERVED(in)) {
      /* append this */
      if(Curl_dyn_addn(&d, &in, 1))
        return NULL;
    }
    else {







|
>







66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH * 3);

  length = (inlength?(size_t)inlength:strlen(string));
  if(!length)
    return strdup("");

  while(length--) {
    /* treat the characters unsigned */
    unsigned char in = (unsigned char)*string++;

    if(ISUNRESERVED(in)) {
      /* append this */
      if(Curl_dyn_addn(&d, &in, 1))
        return NULL;
    }
    else {
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  if(!ns)
    return CURLE_OUT_OF_MEMORY;

  /* store output string */
  *ostring = ns;

  while(alloc) {
    unsigned char in = *string;
    if(('%' == in) && (alloc > 2) &&
       ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
      /* this is two hexadecimal digits following a '%' */
      in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]);

      string += 3;
      alloc -= 3;
    }
    else {
      string++;
      alloc--;
    }

    if(((ctrl == REJECT_CTRL) && (in < 0x20)) ||
       ((ctrl == REJECT_ZERO) && (in == 0))) {
      Curl_safefree(*ostring);
      return CURLE_URL_MALFORMAT;
    }

    *ns++ = in;
  }
  *ns = 0; /* terminate it */

  if(olen)
    /* store output size */
    *olen = ns - *ostring;








|



















|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  if(!ns)
    return CURLE_OUT_OF_MEMORY;

  /* store output string */
  *ostring = ns;

  while(alloc) {
    unsigned char in = (unsigned char)*string;
    if(('%' == in) && (alloc > 2) &&
       ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
      /* this is two hexadecimal digits following a '%' */
      in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]);

      string += 3;
      alloc -= 3;
    }
    else {
      string++;
      alloc--;
    }

    if(((ctrl == REJECT_CTRL) && (in < 0x20)) ||
       ((ctrl == REJECT_ZERO) && (in == 0))) {
      Curl_safefree(*ostring);
      return CURLE_URL_MALFORMAT;
    }

    *ns++ = (char)in;
  }
  *ns = 0; /* terminate it */

  if(olen)
    /* store output size */
    *olen = ns - *ostring;

218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
{
  const char *hex = "0123456789abcdef";
  DEBUGASSERT(src && len && (olen >= 3));
  if(src && len && (olen >= 3)) {
    while(len-- && (olen >= 3)) {
      /* clang-tidy warns on this line without this comment: */
      /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
      *out++ = hex[(*src & 0xF0)>>4];
      *out++ = hex[*src & 0x0F];
      ++src;
      olen -= 2;
    }
    *out = 0;
  }
  else if(olen)
    *out = 0;
}







|
|








219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
{
  const char *hex = "0123456789abcdef";
  DEBUGASSERT(src && len && (olen >= 3));
  if(src && len && (olen >= 3)) {
    while(len-- && (olen >= 3)) {
      /* clang-tidy warns on this line without this comment: */
      /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
      *out++ = (unsigned char)hex[(*src & 0xF0)>>4];
      *out++ = (unsigned char)hex[*src & 0x0F];
      ++src;
      olen -= 2;
    }
    *out = 0;
  }
  else if(olen)
    *out = 0;
}
Changes to jni/curl/lib/file.c.
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    return CURLE_OUT_OF_MEMORY;

  return CURLE_OK;
}

/*
 * file_connect() gets called from Curl_protocol_connect() to allow us to
 * do protocol-specific actions at connect-time.  We emulate a
 * connect-then-transfer protocol and "connect" to the file here
 */
static CURLcode file_connect(struct Curl_easy *data, bool *done)
{
  char *real_path;
  struct FILEPROTO *file = data->req.p.file;
  int fd;







|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    return CURLE_OUT_OF_MEMORY;

  return CURLE_OK;
}

/*
 * file_connect() gets called from Curl_protocol_connect() to allow us to
 * do protocol-specific actions at connect-time. We emulate a
 * connect-then-transfer protocol and "connect" to the file here
 */
static CURLcode file_connect(struct Curl_easy *data, bool *done)
{
  char *real_path;
  struct FILEPROTO *file = data->req.p.file;
  int fd;
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

  result = Curl_urldecode(data->state.up.path, 0, &real_path,
                          &real_path_len, REJECT_ZERO);
  if(result)
    return result;

#ifdef DOS_FILESYSTEM
  /* If the first character is a slash, and there's
     something that looks like a drive at the beginning of
     the path, skip the slash.  If we remove the initial
     slash in all cases, paths without drive letters end up
     relative to the current directory which isn't how
     browsers work.

     Some browsers accept | instead of : as the drive letter
     separator, so we do too.

     On other platforms, we need the slash to indicate an
     absolute pathname.  On Windows, absolute paths start
     with a drive letter.
  */
  actual_path = real_path;
  if((actual_path[0] == '/') &&
      actual_path[1] &&
     (actual_path[2] == ':' || actual_path[2] == '|')) {
    actual_path[2] = ':';







|

|

|






|







173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

  result = Curl_urldecode(data->state.up.path, 0, &real_path,
                          &real_path_len, REJECT_ZERO);
  if(result)
    return result;

#ifdef DOS_FILESYSTEM
  /* If the first character is a slash, and there is
     something that looks like a drive at the beginning of
     the path, skip the slash. If we remove the initial
     slash in all cases, paths without drive letters end up
     relative to the current directory which is not how
     browsers work.

     Some browsers accept | instead of : as the drive letter
     separator, so we do too.

     On other platforms, we need the slash to indicate an
     absolute pathname. On Windows, absolute paths start
     with a drive letter.
  */
  actual_path = real_path;
  if((actual_path[0] == '/') &&
      actual_path[1] &&
     (actual_path[2] == ':' || actual_path[2] == '|')) {
    actual_path[2] = ':';
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  size_t xfer_ulblen;
  curl_off_t bytecount = 0;
  struct_stat file_stat;
  const char *sendbuf;
  bool eos = FALSE;

  /*
   * Since FILE: doesn't do the full init, we need to provide some extra
   * assignments here.
   */

  if(!dir)
    return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */

  if(!dir[1])







|







304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
  size_t xfer_ulblen;
  curl_off_t bytecount = 0;
  struct_stat file_stat;
  const char *sendbuf;
  bool eos = FALSE;

  /*
   * Since FILE: does not do the full init, we need to provide some extra
   * assignments here.
   */

  if(!dir)
    return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */

  if(!dir[1])
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  if(data->state.resume_from)
    mode = MODE_DEFAULT|O_APPEND;
  else
    mode = MODE_DEFAULT|O_TRUNC;

  fd = open(file->path, mode, data->set.new_file_perms);
  if(fd < 0) {
    failf(data, "Can't open %s for writing", file->path);
    return CURLE_WRITE_ERROR;
  }

  if(-1 != data->state.infilesize)
    /* known size of data to "upload" */
    Curl_pgrsSetUploadSize(data, data->state.infilesize);

  /* treat the negative resume offset value as the case of "-" */
  if(data->state.resume_from < 0) {
    if(fstat(fd, &file_stat)) {
      close(fd);
      failf(data, "Can't get the size of %s", file->path);
      return CURLE_WRITE_ERROR;
    }
    data->state.resume_from = (curl_off_t)file_stat.st_size;
  }

  result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
  if(result)







|











|







327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  if(data->state.resume_from)
    mode = MODE_DEFAULT|O_APPEND;
  else
    mode = MODE_DEFAULT|O_TRUNC;

  fd = open(file->path, mode, data->set.new_file_perms);
  if(fd < 0) {
    failf(data, "cannot open %s for writing", file->path);
    return CURLE_WRITE_ERROR;
  }

  if(-1 != data->state.infilesize)
    /* known size of data to "upload" */
    Curl_pgrsSetUploadSize(data, data->state.infilesize);

  /* treat the negative resume offset value as the case of "-" */
  if(data->state.resume_from < 0) {
    if(fstat(fd, &file_stat)) {
      close(fd);
      failf(data, "cannot get the size of %s", file->path);
      return CURLE_WRITE_ERROR;
    }
    data->state.resume_from = (curl_off_t)file_stat.st_size;
  }

  result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
  if(result)
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  return result;
}

/*
 * file_do() is the protocol-specific function for the do-phase, separated
 * from the connect-phase above. Other protocols merely setup the transfer in
 * the do-phase, to have it done in the main transfer loop but since some
 * platforms we support don't allow select()ing etc on file handles (as
 * opposed to sockets) we instead perform the whole do-operation in this
 * function.
 */
static CURLcode file_do(struct Curl_easy *data, bool *done)
{
  /* This implementation ignores the host name in conformance with
     RFC 1738. Only local files (reachable via the standard file system)
     are supported. This means that files on remotely mounted directories
     (via NFS, Samba, NT sharing) can be accessed through a file:// URL
  */
  CURLcode result = CURLE_OK;
  struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
                          Windows version to have a different struct without







|





|







409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  return result;
}

/*
 * file_do() is the protocol-specific function for the do-phase, separated
 * from the connect-phase above. Other protocols merely setup the transfer in
 * the do-phase, to have it done in the main transfer loop but since some
 * platforms we support do not allow select()ing etc on file handles (as
 * opposed to sockets) we instead perform the whole do-operation in this
 * function.
 */
static CURLcode file_do(struct Curl_easy *data, bool *done)
{
  /* This implementation ignores the hostname in conformance with
     RFC 1738. Only local files (reachable via the standard file system)
     are supported. This means that files on remotely mounted directories
     (via NFS, Samba, NT sharing) can be accessed through a file:// URL
  */
  CURLcode result = CURLE_OK;
  struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
                          Windows version to have a different struct without
461
462
463
464
465
466
467
468
469

470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488

489
490
491
492
493
494
495
496
497

498

499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532

  if(fstated) {
    time_t filetime;
    struct tm buffer;
    const struct tm *tm = &buffer;
    char header[80];
    int headerlen;
    char accept_ranges[24]= { "Accept-ranges: bytes\r\n" };
    if(expected_size >= 0) {

      headerlen = msnprintf(header, sizeof(header),
                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
                expected_size);
      result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
      if(result)
        return result;

      result = Curl_client_write(data, CLIENTWRITE_HEADER,
                                 accept_ranges, strlen(accept_ranges));
      if(result != CURLE_OK)
        return result;
    }

    filetime = (time_t)statbuf.st_mtime;
    result = Curl_gmtime(filetime, &buffer);
    if(result)
      return result;

    /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */

    headerlen = msnprintf(header, sizeof(header),
              "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
              Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
              tm->tm_mday,
              Curl_month[tm->tm_mon],
              tm->tm_year + 1900,
              tm->tm_hour,
              tm->tm_min,
              tm->tm_sec,

              data->req.no_body ? "": "\r\n");

    result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
    if(result)
      return result;
    /* set the file size to make it available post transfer */
    Curl_pgrsSetDownloadSize(data, expected_size);
    if(data->req.no_body)
      return result;
  }

  /* Check whether file range has been specified */
  result = Curl_range(data);
  if(result)
    return result;

  /* Adjust the start offset in case we want to get the N last bytes
   * of the stream if the filesize could be determined */
  if(data->state.resume_from < 0) {
    if(!fstated) {
      failf(data, "Can't get the size of file.");
      return CURLE_READ_ERROR;
    }
    data->state.resume_from += (curl_off_t)statbuf.st_size;
  }

  if(data->state.resume_from > 0) {
    /* We check explicitly if we have a start offset, because
     * expected_size may be -1 if we don't know how large the file is,
     * in which case we should not adjust it. */
    if(data->state.resume_from <= expected_size)
      expected_size -= data->state.resume_from;
    else {
      failf(data, "failed to resume file:// transfer");
      return CURLE_BAD_DOWNLOAD_RESUME;
    }







|

>
|
|
|





|










>
|
|
|
|
|
|
|
|
|
>
|
>
|





|











|







|







461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536

  if(fstated) {
    time_t filetime;
    struct tm buffer;
    const struct tm *tm = &buffer;
    char header[80];
    int headerlen;
    static const char accept_ranges[]= { "Accept-ranges: bytes\r\n" };
    if(expected_size >= 0) {
      headerlen =
        msnprintf(header, sizeof(header),
                  "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
                  expected_size);
      result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
      if(result)
        return result;

      result = Curl_client_write(data, CLIENTWRITE_HEADER,
                                 accept_ranges, sizeof(accept_ranges) - 1);
      if(result != CURLE_OK)
        return result;
    }

    filetime = (time_t)statbuf.st_mtime;
    result = Curl_gmtime(filetime, &buffer);
    if(result)
      return result;

    /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
    headerlen =
      msnprintf(header, sizeof(header),
                "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
                Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
                tm->tm_mday,
                Curl_month[tm->tm_mon],
                tm->tm_year + 1900,
                tm->tm_hour,
                tm->tm_min,
                tm->tm_sec);
    result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
    if(!result)
      /* end of headers */
      result = Curl_client_write(data, CLIENTWRITE_HEADER, "\r\n", 2);
    if(result)
      return result;
    /* set the file size to make it available post transfer */
    Curl_pgrsSetDownloadSize(data, expected_size);
    if(data->req.no_body)
      return CURLE_OK;
  }

  /* Check whether file range has been specified */
  result = Curl_range(data);
  if(result)
    return result;

  /* Adjust the start offset in case we want to get the N last bytes
   * of the stream if the filesize could be determined */
  if(data->state.resume_from < 0) {
    if(!fstated) {
      failf(data, "cannot get the size of file.");
      return CURLE_READ_ERROR;
    }
    data->state.resume_from += (curl_off_t)statbuf.st_size;
  }

  if(data->state.resume_from > 0) {
    /* We check explicitly if we have a start offset, because
     * expected_size may be -1 if we do not know how large the file is,
     * in which case we should not adjust it. */
    if(data->state.resume_from <= expected_size)
      expected_size -= data->state.resume_from;
    else {
      failf(data, "failed to resume file:// transfer");
      return CURLE_BAD_DOWNLOAD_RESUME;
    }
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
  result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
  if(result)
    goto out;

  if(!S_ISDIR(statbuf.st_mode)) {
    while(!result) {
      ssize_t nread;
      /* Don't fill a whole buffer if we want less than all data */
      size_t bytestoread;

      if(size_known) {
        bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
          curlx_sotouz(expected_size) : (xfer_blen-1);
      }
      else







|







566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
  if(result)
    goto out;

  if(!S_ISDIR(statbuf.st_mode)) {
    while(!result) {
      ssize_t nread;
      /* Do not fill a whole buffer if we want less than all data */
      size_t bytestoread;

      if(size_known) {
        bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
          curlx_sotouz(expected_size) : (xfer_blen-1);
      }
      else
Changes to jni/curl/lib/fopen.c.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

/*
  The dirslash() function breaks a null-terminated pathname string into
  directory and filename components then returns the directory component up
  to, *AND INCLUDING*, a final '/'.  If there is no directory in the path,
  this instead returns a "" string.

  This function returns a pointer to malloc'ed memory.

  The input path to this function is expected to have a file name part.
*/

#ifdef _WIN32
#define PATHSEP "\\"
#define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
#elif defined(MSDOS) || defined(__EMX__) || defined(OS2)
#define PATHSEP "\\"







|




|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

/*
  The dirslash() function breaks a null-terminated pathname string into
  directory and filename components then returns the directory component up
  to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
  this instead returns a "" string.

  This function returns a pointer to malloc'ed memory.

  The input path to this function is expected to have a filename part.
*/

#ifdef _WIN32
#define PATHSEP "\\"
#define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
#elif defined(MSDOS) || defined(__EMX__) || defined(OS2)
#define PATHSEP "\\"
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  return Curl_dyn_ptr(&out);
}

/*
 * Curl_fopen() opens a file for writing with a temp name, to be renamed
 * to the final name when completed. If there is an existing file using this
 * name at the time of the open, this function will clone the mode from that
 * file.  if 'tempname' is non-NULL, it needs a rename after the file is
 * written.
 */
CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
                    FILE **fh, char **tempname)
{
  CURLcode result = CURLE_WRITE_ERROR;
  unsigned char randbuf[41];







|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  return Curl_dyn_ptr(&out);
}

/*
 * Curl_fopen() opens a file for writing with a temp name, to be renamed
 * to the final name when completed. If there is an existing file using this
 * name at the time of the open, this function will clone the mode from that
 * file. if 'tempname' is non-NULL, it needs a rename after the file is
 * written.
 */
CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
                    FILE **fh, char **tempname)
{
  CURLcode result = CURLE_WRITE_ERROR;
  unsigned char randbuf[41];
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

  result = Curl_rand_alnum(data, randbuf, sizeof(randbuf));
  if(result)
    goto fail;

  dir = dirslash(filename);
  if(dir) {
    /* The temp file name should not end up too long for the target file
       system */
    tempstore = aprintf("%s%s.tmp", dir, randbuf);
    free(dir);
  }

  if(!tempstore) {
    result = CURLE_OUT_OF_MEMORY;







|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

  result = Curl_rand_alnum(data, randbuf, sizeof(randbuf));
  if(result)
    goto fail;

  dir = dirslash(filename);
  if(dir) {
    /* The temp filename should not end up too long for the target file
       system */
    tempstore = aprintf("%s%s.tmp", dir, randbuf);
    free(dir);
  }

  if(!tempstore) {
    result = CURLE_OUT_OF_MEMORY;
Changes to jni/curl/lib/formdata.c.
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  CURLFORMcode return_value = CURL_FORMADD_OK;
  const char *prevtype = NULL;
  struct curl_httppost *post = NULL;
  CURLformoption option;
  struct curl_forms *forms = NULL;
  char *array_value = NULL; /* value read from an array */

  /* This is a state variable, that if TRUE means that we're parsing an
     array that we got passed to us. If FALSE we're parsing the input
     va_list arguments. */
  bool array_state = FALSE;

  /*
   * We need to allocate the first struct to fill in.
   */
  first_form = calloc(1, sizeof(struct FormInfo));







|
|







212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  CURLFORMcode return_value = CURL_FORMADD_OK;
  const char *prevtype = NULL;
  struct curl_httppost *post = NULL;
  CURLformoption option;
  struct curl_forms *forms = NULL;
  char *array_value = NULL; /* value read from an array */

  /* This is a state variable, that if TRUE means that we are parsing an
     array that we got passed to us. If FALSE we are parsing the input
     va_list arguments. */
  bool array_state = FALSE;

  /*
   * We need to allocate the first struct to fill in.
   */
  first_form = calloc(1, sizeof(struct FormInfo));
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
      if(CURLFORM_END == option)
        break;
    }

    switch(option) {
    case CURLFORM_ARRAY:
      if(array_state)
        /* we don't support an array from within an array */
        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
      else {
        forms = va_arg(params, struct curl_forms *);
        if(forms)
          array_state = TRUE;
        else
          return_value = CURL_FORMADD_NULL;







|







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
      if(CURLFORM_END == option)
        break;
    }

    switch(option) {
    case CURLFORM_ARRAY:
      if(array_state)
        /* we do not support an array from within an array */
        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
      else {
        forms = va_arg(params, struct curl_forms *);
        if(forms)
          array_state = TRUE;
        else
          return_value = CURL_FORMADD_NULL;
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

    case CURLFORM_CONTENTLEN:
      current_form->flags |= CURL_HTTPPOST_LARGE;
      current_form->contentslength =
        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
      break;

      /* Get contents from a given file name */
    case CURLFORM_FILECONTENT:
      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
        return_value = CURL_FORMADD_OPTION_TWICE;
      else {
        const char *filename = array_state?
          array_value:va_arg(params, char *);
        if(filename) {







|







323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

    case CURLFORM_CONTENTLEN:
      current_form->flags |= CURL_HTTPPOST_LARGE;
      current_form->contentslength =
        array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
      break;

      /* Get contents from a given filename */
    case CURLFORM_FILECONTENT:
      if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
        return_value = CURL_FORMADD_OPTION_TWICE;
      else {
        const char *filename = array_state?
          array_value:va_arg(params, char *);
        if(filename) {
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
      if(current_form->userp)
        return_value = CURL_FORMADD_OPTION_TWICE;
      else {
        char *userp =
          array_state?array_value:va_arg(params, char *);
        if(userp) {
          current_form->userp = userp;
          current_form->value = userp; /* this isn't strictly true but we
                                          derive a value from this later on
                                          and we need this non-NULL to be
                                          accepted as a fine form part */
        }
        else
          return_value = CURL_FORMADD_NULL;
      }







|







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
      if(current_form->userp)
        return_value = CURL_FORMADD_OPTION_TWICE;
      else {
        char *userp =
          array_state?array_value:va_arg(params, char *);
        if(userp) {
          current_form->userp = userp;
          current_form->value = userp; /* this is not strictly true but we
                                          derive a value from this later on
                                          and we need this non-NULL to be
                                          accepted as a fine form part */
        }
        else
          return_value = CURL_FORMADD_NULL;
      }
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
            break;
          }
        if(return_value != CURL_FORMADD_OK)
          break;
      }
      if(!(form->flags & HTTPPOST_PTRNAME) &&
         (form == first_form) ) {
        /* Note that there's small risk that form->name is NULL here if the
           app passed in a bad combo, so we better check for that first. */
        if(form->name) {
          /* copy name (without strdup; possibly not null-terminated) */
          form->name = Curl_memdup0(form->name, form->namelength?
                                    form->namelength:
                                    strlen(form->name));
        }







|







595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
            break;
          }
        if(return_value != CURL_FORMADD_OK)
          break;
      }
      if(!(form->flags & HTTPPOST_PTRNAME) &&
         (form == first_form) ) {
        /* Note that there is small risk that form->name is NULL here if the
           app passed in a bad combo, so we better check for that first. */
        if(form->name) {
          /* copy name (without strdup; possibly not null-terminated) */
          form->name = Curl_memdup0(form->name, form->namelength?
                                    form->namelength:
                                    strlen(form->name));
        }
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
    if(!(form->flags & HTTPPOST_PTRNAME))
      free(form->name); /* free the name */
    if(!(form->flags &
         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
      )
      free(form->contents); /* free the contents */
    free(form->contenttype); /* free the content type */
    free(form->showfilename); /* free the faked file name */
    free(form);       /* free the struct */
    form = next;
  } while(form); /* continue */
}


/* Set mime part name, taking care of non null-terminated name string. */







|







760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
    if(!(form->flags & HTTPPOST_PTRNAME))
      free(form->name); /* free the name */
    if(!(form->flags &
         (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
      )
      free(form->contents); /* free the contents */
    free(form->contenttype); /* free the content type */
    free(form->showfilename); /* free the faked filename */
    free(form);       /* free the struct */
    form = next;
  } while(form); /* continue */
}


/* Set mime part name, taking care of non null-terminated name string. */
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
        curl_off_t clen = post->contentslength;

        if(post->flags & CURL_HTTPPOST_LARGE)
          clen = post->contentlen;

        if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
          if(!strcmp(file->contents, "-")) {
            /* There are a few cases where the code below won't work; in
               particular, freopen(stdin) by the caller is not guaranteed
               to result as expected. This feature has been kept for backward
               compatibility: use of "-" pseudo file name should be avoided. */
            result = curl_mime_data_cb(part, (curl_off_t) -1,
                                       (curl_read_callback) fread,
                                       fseeko_wrapper,
                                       NULL, (void *) stdin);
          }
          else
            result = curl_mime_filedata(part, file->contents);







|


|







876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
        curl_off_t clen = post->contentslength;

        if(post->flags & CURL_HTTPPOST_LARGE)
          clen = post->contentlen;

        if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
          if(!strcmp(file->contents, "-")) {
            /* There are a few cases where the code below will not work; in
               particular, freopen(stdin) by the caller is not guaranteed
               to result as expected. This feature has been kept for backward
               compatibility: use of "-" pseudo filename should be avoided. */
            result = curl_mime_data_cb(part, (curl_off_t) -1,
                                       (curl_read_callback) fread,
                                       fseeko_wrapper,
                                       NULL, (void *) stdin);
          }
          else
            result = curl_mime_filedata(part, file->contents);
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
            uclen = CURL_ZERO_TERMINATED;
          else
            uclen = (size_t)clen;
          result = curl_mime_data(part, post->contents, uclen);
        }
      }

      /* Set fake file name. */
      if(!result && post->showfilename)
        if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
                                        HTTPPOST_CALLBACK)))
          result = curl_mime_filename(part, post->showfilename);
    }
  }








|







911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
            uclen = CURL_ZERO_TERMINATED;
          else
            uclen = (size_t)clen;
          result = curl_mime_data(part, post->contents, uclen);
        }
      }

      /* Set fake filename. */
      if(!result && post->showfilename)
        if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
                                        HTTPPOST_CALLBACK)))
          result = curl_mime_filename(part, post->showfilename);
    }
  }

Changes to jni/curl/lib/formdata.h.
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  size_t namelength;
  char *value;
  curl_off_t contentslength;
  char *contenttype;
  long flags;
  char *buffer;      /* pointer to existing buffer used for file upload */
  size_t bufferlength;
  char *showfilename; /* The file name to show. If not set, the actual
                         file name will be used */
  char *userp;        /* pointer for the read callback */
  struct curl_slist *contentheader;
  struct FormInfo *more;
  bool name_alloc;
  bool value_alloc;
  bool contenttype_alloc;
  bool showfilename_alloc;







|
|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  size_t namelength;
  char *value;
  curl_off_t contentslength;
  char *contenttype;
  long flags;
  char *buffer;      /* pointer to existing buffer used for file upload */
  size_t bufferlength;
  char *showfilename; /* The filename to show. If not set, the actual
                         filename will be used */
  char *userp;        /* pointer for the read callback */
  struct curl_slist *contentheader;
  struct FormInfo *more;
  bool name_alloc;
  bool value_alloc;
  bool contenttype_alloc;
  bool showfilename_alloc;
Changes to jni/curl/lib/ftp.c.
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
  CURLPROTO_FTPS,                  /* protocol */
  CURLPROTO_FTP,                   /* family */
  PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
  PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
};
#endif

static void close_secondarysocket(struct Curl_easy *data,
                                  struct connectdata *conn)
{
  CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_DSTATE(data));
  Curl_conn_close(data, SECONDARYSOCKET);
  Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
}

/*
 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
 * requests on files respond with headers passed to the client/stdout that
 * looked like HTTP ones.
 *







|
<



|







286
287
288
289
290
291
292
293

294
295
296
297
298
299
300
301
302
303
304
  CURLPROTO_FTPS,                  /* protocol */
  CURLPROTO_FTP,                   /* family */
  PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
  PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY | PROTOPT_WILDCARD /* flags */
};
#endif

static void close_secondarysocket(struct Curl_easy *data)

{
  CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_DSTATE(data));
  Curl_conn_close(data, SECONDARYSOCKET);
  Curl_conn_cf_discard_all(data, data->conn, SECONDARYSOCKET);
}

/*
 * NOTE: back in the old days, we added code in the FTP code that made NOBODY
 * requests on files respond with headers passed to the client/stdout that
 * looked like HTTP ones.
 *
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
    Curl_set_in_callback(data, true);
    error = data->set.fsockopt(data->set.sockopt_client,
                               s,
                               CURLSOCKTYPE_ACCEPT);
    Curl_set_in_callback(data, false);

    if(error) {
      close_secondarysocket(data, conn);
      return CURLE_ABORTED_BY_CALLBACK;
    }
  }

  return CURLE_OK;

}







|







470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
    Curl_set_in_callback(data, true);
    error = data->set.fsockopt(data->set.sockopt_client,
                               s,
                               CURLSOCKTYPE_ACCEPT);
    Curl_set_in_callback(data, false);

    if(error) {
      close_secondarysocket(data);
      return CURLE_ABORTED_BY_CALLBACK;
    }
  }

  return CURLE_OK;

}
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
      return result;
  }
  result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected);
  if(result || !connected)
    return result;

  if(conn->proto.ftpc.state_saved == FTP_STOR) {
    /* When we know we're uploading a specified file, we can get the file
       size prior to the actual upload. */
    Curl_pgrsSetUploadSize(data, data->state.infilesize);

    /* set the SO_SNDBUF for the secondary socket for those who need it */
    Curl_sndbufset(conn->sock[SECONDARYSOCKET]);

    Curl_xfer_setup(data, -1, -1, FALSE, SECONDARYSOCKET);
  }
  else {
    /* FTP download: */
    Curl_xfer_setup(data, SECONDARYSOCKET,
                    conn->proto.ftpc.retr_size_saved, FALSE, -1);
  }

  conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
  ftp_state(data, FTP_STOP);

  return CURLE_OK;
}

/***********************************************************************
 *
 * AllowServerConnect()
 *
 * When we've issue the PORT command, we have told the server to connect to
 * us. This function checks whether data connection is established if so it is
 * accepted.
 *
 */
static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
{
  timediff_t timeout_ms;







|




|

|



|
|












|







644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
      return result;
  }
  result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected);
  if(result || !connected)
    return result;

  if(conn->proto.ftpc.state_saved == FTP_STOR) {
    /* When we know we are uploading a specified file, we can get the file
       size prior to the actual upload. */
    Curl_pgrsSetUploadSize(data, data->state.infilesize);

    /* set the SO_SNDBUF for the secondary socket for those who need it */
    Curl_sndbuf_init(conn->sock[SECONDARYSOCKET]);

    Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE);
  }
  else {
    /* FTP download: */
    Curl_xfer_setup2(data, CURL_XFER_RECV,
                     conn->proto.ftpc.retr_size_saved, TRUE);
  }

  conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
  ftp_state(data, FTP_STOP);

  return CURLE_OK;
}

/***********************************************************************
 *
 * AllowServerConnect()
 *
 * When we have issue the PORT command, we have told the server to connect to
 * us. This function checks whether data connection is established if so it is
 * accepted.
 *
 */
static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
{
  timediff_t timeout_ms;
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816

CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
                             ssize_t *nreadp, /* return number of bytes read */
                             int *ftpcode) /* return the ftp-code */
{
  /*
   * We cannot read just one byte per read() and then go back to select() as
   * the OpenSSL read() doesn't grok that properly.
   *
   * Alas, read as much as possible, split up into lines, use the ending
   * line in a response or continue reading.  */

  struct connectdata *conn = data->conn;
  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
  CURLcode result = CURLE_OK;







|







801
802
803
804
805
806
807
808
809
810
811
812
813
814
815

CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
                             ssize_t *nreadp, /* return number of bytes read */
                             int *ftpcode) /* return the ftp-code */
{
  /*
   * We cannot read just one byte per read() and then go back to select() as
   * the OpenSSL read() does not grok that properly.
   *
   * Alas, read as much as possible, split up into lines, use the ending
   * line in a response or continue reading.  */

  struct connectdata *conn = data->conn;
  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
  CURLcode result = CURLE_OK;
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
    /*
     * Since this function is blocking, we need to wait here for input on the
     * connection and only then we call the response reading function. We do
     * timeout at least every second to make the timeout check run.
     *
     * A caution here is that the ftp_readresp() function has a cache that may
     * contain pieces of a response from the previous invoke and we need to
     * make sure we don't just wait for input while there is unhandled data in
     * that cache. But also, if the cache is there, we call ftp_readresp() and
     * the cache wasn't good enough to continue we must not just busy-loop
     * around this function.
     *
     */

    if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) {
      /*
       * There's a cache left since before. We then skipping the wait for
       * socket action, unless this is the same cache like the previous round
       * as then the cache was deemed not enough to act on and we then need to
       * wait for more data anyway.
       */
    }
    else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
      switch(SOCKET_READABLE(sockfd, interval_ms)) {







|

|






|







844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
    /*
     * Since this function is blocking, we need to wait here for input on the
     * connection and only then we call the response reading function. We do
     * timeout at least every second to make the timeout check run.
     *
     * A caution here is that the ftp_readresp() function has a cache that may
     * contain pieces of a response from the previous invoke and we need to
     * make sure we do not just wait for input while there is unhandled data in
     * that cache. But also, if the cache is there, we call ftp_readresp() and
     * the cache was not good enough to continue we must not just busy-loop
     * around this function.
     *
     */

    if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) {
      /*
       * There is a cache left since before. We then skipping the wait for
       * socket action, unless this is the same cache like the previous round
       * as then the cache was deemed not enough to act on and we then need to
       * wait for more data anyway.
       */
    }
    else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
      switch(SOCKET_READABLE(sockfd, interval_ms)) {
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
    else
      /* when we got data or there is no cache left, we reset the cache skip
         counter */
      cache_skip = 0;

    *nreadp += nread;

  } /* while there's buffer left and loop is requested */

  pp->pending_resp = FALSE;

  return result;
}

static CURLcode ftp_state_user(struct Curl_easy *data,







|







890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
    else
      /* when we got data or there is no cache left, we reset the cache skip
         counter */
      cache_skip = 0;

    *nreadp += nread;

  } /* while there is buffer left and loop is requested */

  pp->pending_resp = FALSE;

  return result;
}

static CURLcode ftp_state_user(struct Curl_easy *data,
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
  /* When in DO_MORE state, we could be either waiting for us to connect to a
   * remote site, or we could wait for that site to connect to us. Or just
   * handle ordinary commands.
   */
  CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_DSTATE(data));

  if(FTP_STOP == ftpc->state) {
    /* if stopped and still in this state, then we're also waiting for a
       connect on the secondary connection */
    DEBUGASSERT(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD ||
               (conn->cfilter[SECONDARYSOCKET] &&
                !Curl_conn_is_connected(conn, SECONDARYSOCKET)));
    socks[0] = conn->sock[FIRSTSOCKET];
    /* An unconnected SECONDARY will add its socket by itself
     * via its adjust_pollset() */







|







943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
  /* When in DO_MORE state, we could be either waiting for us to connect to a
   * remote site, or we could wait for that site to connect to us. Or just
   * handle ordinary commands.
   */
  CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_DSTATE(data));

  if(FTP_STOP == ftpc->state) {
    /* if stopped and still in this state, then we are also waiting for a
       connect on the secondary connection */
    DEBUGASSERT(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD ||
               (conn->cfilter[SECONDARYSOCKET] &&
                !Curl_conn_is_connected(conn, SECONDARYSOCKET)));
    socks[0] = conn->sock[FIRSTSOCKET];
    /* An unconnected SECONDARY will add its socket by itself
     * via its adjust_pollset() */
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
      switch(Curl_if2ip(conn->remote_addr->family,
#ifdef USE_IPV6
                        Curl_ipv6_scope(&conn->remote_addr->sa_addr),
                        conn->scope_id,
#endif
                        ipstr, hbuf, sizeof(hbuf))) {
        case IF2IP_NOT_FOUND:
          /* not an interface, use the given string as host name instead */
          host = ipstr;
          break;
        case IF2IP_AF_NOT_SUPPORTED:
          goto out;
        case IF2IP_FOUND:
          host = hbuf; /* use the hbuf for host name */
          break;
      }
    }
    else
      /* there was only a port(-range) given, default the host */
      host = NULL;
  } /* data->set.ftpport */

  if(!host) {
    const char *r;
    /* not an interface and not a host name, get default by extracting
       the IP from the control connection */
    sslen = sizeof(ss);
    if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
      failf(data, "getsockname() failed: %s",
            Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
      goto out;
    }
    switch(sa->sa_family) {
#ifdef USE_IPV6
    case AF_INET6:
      r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
      break;
#endif
    default:
      r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
      break;
    }
    if(!r) {
      goto out;
    }
    host = hbuf; /* use this host name */
    possibly_non_local = FALSE; /* we know it is local now */
  }

  /* resolv ip/host to ip */
  rc = Curl_resolv(data, host, 0, FALSE, &h);
  if(rc == CURLRESOLV_PENDING)
    (void)Curl_resolver_wait_resolv(data, &h);







|





|










|




















|







1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
      switch(Curl_if2ip(conn->remote_addr->family,
#ifdef USE_IPV6
                        Curl_ipv6_scope(&conn->remote_addr->sa_addr),
                        conn->scope_id,
#endif
                        ipstr, hbuf, sizeof(hbuf))) {
        case IF2IP_NOT_FOUND:
          /* not an interface, use the given string as hostname instead */
          host = ipstr;
          break;
        case IF2IP_AF_NOT_SUPPORTED:
          goto out;
        case IF2IP_FOUND:
          host = hbuf; /* use the hbuf for hostname */
          break;
      }
    }
    else
      /* there was only a port(-range) given, default the host */
      host = NULL;
  } /* data->set.ftpport */

  if(!host) {
    const char *r;
    /* not an interface and not a hostname, get default by extracting
       the IP from the control connection */
    sslen = sizeof(ss);
    if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
      failf(data, "getsockname() failed: %s",
            Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
      goto out;
    }
    switch(sa->sa_family) {
#ifdef USE_IPV6
    case AF_INET6:
      r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
      break;
#endif
    default:
      r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
      break;
    }
    if(!r) {
      goto out;
    }
    host = hbuf; /* use this hostname */
    possibly_non_local = FALSE; /* we know it is local now */
  }

  /* resolv ip/host to ip */
  rc = Curl_resolv(data, host, 0, FALSE, &h);
  if(rc == CURLRESOLV_PENDING)
    (void)Curl_resolver_wait_resolv(data, &h);
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
      sa6->sin6_port = htons(port);
#endif
    /* Try binding the given address. */
    if(bind(portsock, sa, sslen) ) {
      /* It failed. */
      error = SOCKERRNO;
      if(possibly_non_local && (error == EADDRNOTAVAIL)) {
        /* The requested bind address is not local.  Use the address used for
         * the control connection instead and restart the port loop
         */
        infof(data, "bind(port=%hu) on non-local address failed: %s", port,
              Curl_strerror(error, buffer, sizeof(buffer)));

        sslen = sizeof(ss);
        if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
          failf(data, "getsockname() failed: %s",
                Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
          goto out;
        }
        port = port_min;
        possibly_non_local = FALSE; /* don't try this again */
        continue;
      }
      if(error != EADDRINUSE && error != EACCES) {
        failf(data, "bind(port=%hu) failed: %s", port,
              Curl_strerror(error, buffer, sizeof(buffer)));
        goto out;
      }







|












|







1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
      sa6->sin6_port = htons(port);
#endif
    /* Try binding the given address. */
    if(bind(portsock, sa, sslen) ) {
      /* It failed. */
      error = SOCKERRNO;
      if(possibly_non_local && (error == EADDRNOTAVAIL)) {
        /* The requested bind address is not local. Use the address used for
         * the control connection instead and restart the port loop
         */
        infof(data, "bind(port=%hu) on non-local address failed: %s", port,
              Curl_strerror(error, buffer, sizeof(buffer)));

        sslen = sizeof(ss);
        if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
          failf(data, "getsockname() failed: %s",
                Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
          goto out;
        }
        port = port_min;
        possibly_non_local = FALSE; /* do not try this again */
        continue;
      }
      if(error != EADDRINUSE && error != EACCES) {
        failf(data, "bind(port=%hu) failed: %s", port,
              Curl_strerror(error, buffer, sizeof(buffer)));
        goto out;
      }
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
    if(PORT == fcmd) {
      /* large enough for [IP address],[num],[num] */
      char target[sizeof(myhost) + 20];
      char *source = myhost;
      char *dest = target;

      /* translate x.x.x.x to x,x,x,x */
      while(source && *source) {
        if(*source == '.')
          *dest = ',';
        else
          *dest = *source;
        dest++;
        source++;
      }







|







1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
    if(PORT == fcmd) {
      /* large enough for [IP address],[num],[num] */
      char target[sizeof(myhost) + 20];
      char *source = myhost;
      char *dest = target;

      /* translate x.x.x.x to x,x,x,x */
      while(*source) {
        if(*source == '.')
          *dest = ',';
        else
          *dest = *source;
        dest++;
        source++;
      }
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
{
  CURLcode result = CURLE_OK;
  struct FTP *ftp = data->req.p.ftp;
  struct connectdata *conn = data->conn;

  if(ftp->transfer != PPTRANSFER_BODY) {
    /* doesn't transfer any data */

    /* still possibly do PRE QUOTE jobs */
    ftp_state(data, FTP_RETR_PREQUOTE);
    result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
  }
  else if(data->set.ftp_use_port) {
    /* We have chosen to use the PORT (or similar) command */







|







1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
{
  CURLcode result = CURLE_OK;
  struct FTP *ftp = data->req.p.ftp;
  struct connectdata *conn = data->conn;

  if(ftp->transfer != PPTRANSFER_BODY) {
    /* does not transfer any data */

    /* still possibly do PRE QUOTE jobs */
    ftp_state(data, FTP_RETR_PREQUOTE);
    result = ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
  }
  else if(data->set.ftp_use_port) {
    /* We have chosen to use the PORT (or similar) command */
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
  CURLcode result = CURLE_OK;
  struct FTP *ftp = data->req.p.ftp;
  struct ftp_conn *ftpc = &conn->proto.ftpc;

  if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
    /* if a "head"-like request is being made (on a file) */

    /* we know ftpc->file is a valid pointer to a file name */
    result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
    if(!result)
      ftp_state(data, FTP_SIZE);
  }
  else
    result = ftp_state_rest(data, conn);








|







1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
  CURLcode result = CURLE_OK;
  struct FTP *ftp = data->req.p.ftp;
  struct ftp_conn *ftpc = &conn->proto.ftpc;

  if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
    /* if a "head"-like request is being made (on a file) */

    /* we know ftpc->file is a valid pointer to a filename */
    result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
    if(!result)
      ftp_state(data, FTP_SIZE);
  }
  else
    result = ftp_state_rest(data, conn);

1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
    ftp_state(data, FTP_LIST);

  return result;
}

static CURLcode ftp_state_retr_prequote(struct Curl_easy *data)
{
  /* We've sent the TYPE, now we must send the list of prequote strings */
  return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
}

static CURLcode ftp_state_stor_prequote(struct Curl_easy *data)
{
  /* We've sent the TYPE, now we must send the list of prequote strings */
  return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE);
}

static CURLcode ftp_state_type(struct Curl_easy *data)
{
  CURLcode result = CURLE_OK;
  struct FTP *ftp = data->req.p.ftp;
  struct connectdata *conn = data->conn;
  struct ftp_conn *ftpc = &conn->proto.ftpc;

  /* If we have selected NOBODY and HEADER, it means that we only want file
     information. Which in FTP can't be much more than the file size and
     date. */
  if(data->req.no_body && ftpc->file &&
     ftp_need_type(conn, data->state.prefer_ascii)) {
    /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
       may not support it! It is however the only way we have to get a file's
       size! */








|





|











|







1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
    ftp_state(data, FTP_LIST);

  return result;
}

static CURLcode ftp_state_retr_prequote(struct Curl_easy *data)
{
  /* We have sent the TYPE, now we must send the list of prequote strings */
  return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
}

static CURLcode ftp_state_stor_prequote(struct Curl_easy *data)
{
  /* We have sent the TYPE, now we must send the list of prequote strings */
  return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE);
}

static CURLcode ftp_state_type(struct Curl_easy *data)
{
  CURLcode result = CURLE_OK;
  struct FTP *ftp = data->req.p.ftp;
  struct connectdata *conn = data->conn;
  struct ftp_conn *ftpc = &conn->proto.ftpc;

  /* If we have selected NOBODY and HEADER, it means that we only want file
     information. Which in FTP cannot be much more than the file size and
     date. */
  if(data->req.no_body && ftpc->file &&
     ftp_need_type(conn, data->state.prefer_ascii)) {
    /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
       may not support it! It is however the only way we have to get a file's
       size! */

1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
  struct connectdata *conn = data->conn;
  struct FTP *ftp = data->req.p.ftp;
  struct ftp_conn *ftpc = &conn->proto.ftpc;
  bool append = data->set.remote_append;

  if((data->state.resume_from && !sizechecked) ||
     ((data->state.resume_from > 0) && sizechecked)) {
    /* we're about to continue the uploading of a file */
    /* 1. get already existing file's size. We use the SIZE command for this
       which may not exist in the server!  The SIZE command is not in
       RFC959. */

    /* 2. This used to set REST. But since we can do append, we
       don't another ftp command. We just skip the source file
       offset and then we APPEND the rest on the file instead */

    /* 3. pass file-size number of bytes in the source file */
    /* 4. lower the infilesize counter */
    /* => transfer as usual */
    int seekerr = CURL_SEEKFUNC_OK;








|





|







1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
  struct connectdata *conn = data->conn;
  struct FTP *ftp = data->req.p.ftp;
  struct ftp_conn *ftpc = &conn->proto.ftpc;
  bool append = data->set.remote_append;

  if((data->state.resume_from && !sizechecked) ||
     ((data->state.resume_from > 0) && sizechecked)) {
    /* we are about to continue the uploading of a file */
    /* 1. get already existing file's size. We use the SIZE command for this
       which may not exist in the server!  The SIZE command is not in
       RFC959. */

    /* 2. This used to set REST. But since we can do append, we
       do not another ftp command. We just skip the source file
       offset and then we APPEND the rest on the file instead */

    /* 3. pass file-size number of bytes in the source file */
    /* 4. lower the infilesize counter */
    /* => transfer as usual */
    int seekerr = CURL_SEEKFUNC_OK;

1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717

    if(seekerr != CURL_SEEKFUNC_OK) {
      curl_off_t passed = 0;
      if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
        failf(data, "Could not seek stream");
        return CURLE_FTP_COULDNT_USE_REST;
      }
      /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
      do {
        char scratch[4*1024];
        size_t readthisamountnow =
          (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ?
          sizeof(scratch) :
          curlx_sotouz(data->state.resume_from - passed);








|







1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716

    if(seekerr != CURL_SEEKFUNC_OK) {
      curl_off_t passed = 0;
      if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
        failf(data, "Could not seek stream");
        return CURLE_FTP_COULDNT_USE_REST;
      }
      /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
      do {
        char scratch[4*1024];
        size_t readthisamountnow =
          (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ?
          sizeof(scratch) :
          curlx_sotouz(data->state.resume_from - passed);

1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
    if(data->state.infilesize>0) {
      data->state.infilesize -= data->state.resume_from;

      if(data->state.infilesize <= 0) {
        infof(data, "File already completely uploaded");

        /* no data to transfer */
        Curl_xfer_setup(data, -1, -1, FALSE, -1);

        /* Set ->transfer so that we won't get any error in
         * ftp_done() because we didn't transfer anything! */
        ftp->transfer = PPTRANSFER_NONE;

        ftp_state(data, FTP_STOP);
        return CURLE_OK;
      }
    }
    /* we've passed, proceed as normal */
  } /* resume_from */

  result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
                         ftpc->file);
  if(!result)
    ftp_state(data, FTP_STOR);








|

|
|






|







1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
    if(data->state.infilesize>0) {
      data->state.infilesize -= data->state.resume_from;

      if(data->state.infilesize <= 0) {
        infof(data, "File already completely uploaded");

        /* no data to transfer */
        Curl_xfer_setup_nop(data);

        /* Set ->transfer so that we will not get any error in
         * ftp_done() because we did not transfer anything! */
        ftp->transfer = PPTRANSFER_NONE;

        ftp_state(data, FTP_STOP);
        return CURLE_OK;
      }
    }
    /* we have passed, proceed as normal */
  } /* resume_from */

  result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
                         ftpc->file);
  if(!result)
    ftp_state(data, FTP_STOR);

1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
      else {
        if(ftpc->known_filesize != -1) {
          Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
          result = ftp_state_retr(data, ftpc->known_filesize);
        }
        else {
          if(data->set.ignorecl || data->state.prefer_ascii) {
            /* 'ignorecl' is used to support download of growing files.  It
               prevents the state machine from requesting the file size from
               the server.  With an unknown file size the download continues
               until the server terminates it, otherwise the client stops if
               the received byte count exceeds the reported file size.  Set
               option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
               behavior.

               In addition: asking for the size for 'TYPE A' transfers is not
               constructive since servers don't report the converted size. So
               skip it.
            */
            result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
            if(!result)
              ftp_state(data, FTP_RETR);
          }
          else {







|

|

|




|







1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
      else {
        if(ftpc->known_filesize != -1) {
          Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
          result = ftp_state_retr(data, ftpc->known_filesize);
        }
        else {
          if(data->set.ignorecl || data->state.prefer_ascii) {
            /* 'ignorecl' is used to support download of growing files. It
               prevents the state machine from requesting the file size from
               the server. With an unknown file size the download continues
               until the server terminates it, otherwise the client stops if
               the received byte count exceeds the reported file size. Set
               option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
               behavior.

               In addition: asking for the size for 'TYPE A' transfers is not
               constructive since servers do not report the converted size. So
               skip it.
            */
            result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
            if(!result)
              ftp_state(data, FTP_RETR);
          }
          else {
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
  CURLcode result = CURLE_OK;

  if(conn->bits.ipv6
#ifndef CURL_DISABLE_PROXY
     && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
#endif
    ) {
    /* We can't disable EPSV when doing IPv6, so this is instead a fail */
    failf(data, "Failed EPSV attempt, exiting");
    return CURLE_WEIRD_SERVER_REPLY;
  }

  infof(data, "Failed EPSV attempt. Disabling EPSV");
  /* disable it for next transfer */
  conn->bits.ftp_use_epsv = FALSE;







|







1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
  CURLcode result = CURLE_OK;

  if(conn->bits.ipv6
#ifndef CURL_DISABLE_PROXY
     && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
#endif
    ) {
    /* We cannot disable EPSV when doing IPv6, so this is instead a fail */
    failf(data, "Failed EPSV attempt, exiting");
    return CURLE_WEIRD_SERVER_REPLY;
  }

  infof(data, "Failed EPSV attempt. Disabling EPSV");
  /* disable it for next transfer */
  conn->bits.ftp_use_epsv = FALSE;
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
  return result;
}


static char *control_address(struct connectdata *conn)
{
  /* Returns the control connection IP address.
     If a proxy tunnel is used, returns the original host name instead, because
     the effective control connection address is the proxy address,
     not the ftp host. */
#ifndef CURL_DISABLE_PROXY
  if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
    return conn->host.name;
#endif
  return conn->primary.remote_ip;







|







1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
  return result;
}


static char *control_address(struct connectdata *conn)
{
  /* Returns the control connection IP address.
     If a proxy tunnel is used, returns the original hostname instead, because
     the effective control connection address is the proxy address,
     not the ftp host. */
#ifndef CURL_DISABLE_PROXY
  if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
    return conn->host.name;
#endif
  return conn->primary.remote_ip;
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
    return CURLE_FTP_WEIRD_PASV_REPLY;
  }

#ifndef CURL_DISABLE_PROXY
  if(conn->bits.proxy) {
    /*
     * This connection uses a proxy and we need to connect to the proxy again
     * here. We don't want to rely on a former host lookup that might've
     * expired now, instead we remake the lookup here and now!
     */
    const char * const host_name = conn->bits.socksproxy ?
      conn->socks_proxy.host.name : conn->http_proxy.host.name;
    rc = Curl_resolv(data, host_name, conn->primary.remote_port, FALSE, &addr);
    if(rc == CURLRESOLV_PENDING)
      /* BLOCKING, ignores the return code but 'addr' will be NULL in
         case of failure */
      (void)Curl_resolver_wait_resolv(data, &addr);

    /* we connect to the proxy's port */
    connectport = (unsigned short)conn->primary.remote_port;

    if(!addr) {
      failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
      return CURLE_COULDNT_RESOLVE_PROXY;
    }
  }
  else
#endif
  {
    /* normal, direct, ftp connection */







|














|







2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
    return CURLE_FTP_WEIRD_PASV_REPLY;
  }

#ifndef CURL_DISABLE_PROXY
  if(conn->bits.proxy) {
    /*
     * This connection uses a proxy and we need to connect to the proxy again
     * here. We do not want to rely on a former host lookup that might've
     * expired now, instead we remake the lookup here and now!
     */
    const char * const host_name = conn->bits.socksproxy ?
      conn->socks_proxy.host.name : conn->http_proxy.host.name;
    rc = Curl_resolv(data, host_name, conn->primary.remote_port, FALSE, &addr);
    if(rc == CURLRESOLV_PENDING)
      /* BLOCKING, ignores the return code but 'addr' will be NULL in
         case of failure */
      (void)Curl_resolver_wait_resolv(data, &addr);

    /* we connect to the proxy's port */
    connectport = (unsigned short)conn->primary.remote_port;

    if(!addr) {
      failf(data, "cannot resolve proxy host %s:%hu", host_name, connectport);
      return CURLE_COULDNT_RESOLVE_PROXY;
    }
  }
  else
#endif
  {
    /* normal, direct, ftp connection */
2084
2085
2086
2087
2088
2089
2090

2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
    if(rc == CURLRESOLV_PENDING)
      /* BLOCKING */
      (void)Curl_resolver_wait_resolv(data, &addr);

    connectport = ftpc->newport; /* we connect to the remote port */

    if(!addr) {

      failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
      return CURLE_FTP_CANT_GET_HOST;
    }
  }

  result = Curl_conn_setup(data, conn, SECONDARYSOCKET, addr,
                           conn->bits.ftp_use_data_ssl?
                           CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);

  if(result) {
    Curl_resolv_unlock(data, addr); /* we're done using this address */
    if(ftpc->count1 == 0 && ftpcode == 229)
      return ftp_epsv_disable(data, conn);

    return result;
  }


  /*
   * When this is used from the multi interface, this might've returned with
   * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
   * connect to connect.
   */

  if(data->set.verbose)
    /* this just dumps information about this second connection */
    ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);

  Curl_resolv_unlock(data, addr); /* we're done using this address */

  Curl_safefree(conn->secondaryhostname);
  conn->secondary_port = ftpc->newport;
  conn->secondaryhostname = strdup(ftpc->newhost);
  if(!conn->secondaryhostname)
    return CURLE_OUT_OF_MEMORY;








>
|









|

















|







2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
    if(rc == CURLRESOLV_PENDING)
      /* BLOCKING */
      (void)Curl_resolver_wait_resolv(data, &addr);

    connectport = ftpc->newport; /* we connect to the remote port */

    if(!addr) {
      failf(data, "cannot resolve new host %s:%hu",
            ftpc->newhost, connectport);
      return CURLE_FTP_CANT_GET_HOST;
    }
  }

  result = Curl_conn_setup(data, conn, SECONDARYSOCKET, addr,
                           conn->bits.ftp_use_data_ssl?
                           CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);

  if(result) {
    Curl_resolv_unlock(data, addr); /* we are done using this address */
    if(ftpc->count1 == 0 && ftpcode == 229)
      return ftp_epsv_disable(data, conn);

    return result;
  }


  /*
   * When this is used from the multi interface, this might've returned with
   * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
   * connect to connect.
   */

  if(data->set.verbose)
    /* this just dumps information about this second connection */
    ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);

  Curl_resolv_unlock(data, addr); /* we are done using this address */

  Curl_safefree(conn->secondaryhostname);
  conn->secondary_port = ftpc->newport;
  conn->secondaryhostname = strdup(ftpc->newhost);
  if(!conn->secondaryhostname)
    return CURLE_OUT_OF_MEMORY;

2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
   * the body write callback when data->set.include_header is set
   * via CURLOPT_HEADER.
   * For historic reasons, FTP never played this game and expects
   * all its HEADERs to do that always. Set that flag during the
   * call to Curl_client_write() so it does the right thing.
   *
   * Notice that we cannot enable this flag for FTP in general,
   * as an FTP transfer might involve a HTTP proxy connection and
   * headers from CONNECT should not automatically be part of the
   * output. */
  CURLcode result;
  int save = data->set.include_header;
  data->set.include_header = TRUE;
  result = Curl_client_write(data, CLIENTWRITE_HEADER, buf, blen);
  data->set.include_header = save? TRUE:FALSE;







|







2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
   * the body write callback when data->set.include_header is set
   * via CURLOPT_HEADER.
   * For historic reasons, FTP never played this game and expects
   * all its HEADERs to do that always. Set that flag during the
   * call to Curl_client_write() so it does the right thing.
   *
   * Notice that we cannot enable this flag for FTP in general,
   * as an FTP transfer might involve an HTTP proxy connection and
   * headers from CONNECT should not automatically be part of the
   * output. */
  CURLcode result;
  int save = data->set.include_header;
  data->set.include_header = TRUE;
  result = Curl_client_write(data, CLIENTWRITE_HEADER, buf, blen);
  data->set.include_header = save? TRUE:FALSE;
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
  }
  ftp->downloadsize = filesize;

  if(data->state.resume_from) {
    /* We always (attempt to) get the size of downloads, so it is done before
       this even when not doing resumes. */
    if(filesize == -1) {
      infof(data, "ftp server doesn't support SIZE");
      /* We couldn't get the size and therefore we can't know if there really
         is a part of the file left to get, although the server will just
         close the connection when we start the connection so it won't cause
         us any harm, just not make us exit as nicely. */
    }
    else {
      /* We got a file size report, so we check that there actually is a
         part of the file left to get, or else we go home.  */
      if(data->state.resume_from< 0) {
        /* We're supposed to download the last abs(from) bytes */
        if(filesize < -data->state.resume_from) {
          failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
                ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
                data->state.resume_from, filesize);
          return CURLE_BAD_DOWNLOAD_RESUME;
        }
        /* convert to size to download */







|
|

|






|







2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
  }
  ftp->downloadsize = filesize;

  if(data->state.resume_from) {
    /* We always (attempt to) get the size of downloads, so it is done before
       this even when not doing resumes. */
    if(filesize == -1) {
      infof(data, "ftp server does not support SIZE");
      /* We could not get the size and therefore we cannot know if there really
         is a part of the file left to get, although the server will just
         close the connection when we start the connection so it will not cause
         us any harm, just not make us exit as nicely. */
    }
    else {
      /* We got a file size report, so we check that there actually is a
         part of the file left to get, or else we go home.  */
      if(data->state.resume_from< 0) {
        /* We are supposed to download the last abs(from) bytes */
        if(filesize < -data->state.resume_from) {
          failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
                ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
                data->state.resume_from, filesize);
          return CURLE_BAD_DOWNLOAD_RESUME;
        }
        /* convert to size to download */
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
        /* Now store the number of bytes we are expected to download */
        ftp->downloadsize = filesize-data->state.resume_from;
      }
    }

    if(ftp->downloadsize == 0) {
      /* no data to transfer */
      Curl_xfer_setup(data, -1, -1, FALSE, -1);
      infof(data, "File already completely downloaded");

      /* Set ->transfer so that we won't get any error in ftp_done()
       * because we didn't transfer the any file */
      ftp->transfer = PPTRANSFER_NONE;
      ftp_state(data, FTP_STOP);
      return CURLE_OK;
    }

    /* Set resume file transfer offset */
    infof(data, "Instructs server to resume from offset %"







|


|
|







2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
        /* Now store the number of bytes we are expected to download */
        ftp->downloadsize = filesize-data->state.resume_from;
      }
    }

    if(ftp->downloadsize == 0) {
      /* no data to transfer */
      Curl_xfer_setup_nop(data);
      infof(data, "File already completely downloaded");

      /* Set ->transfer so that we will not get any error in ftp_done()
       * because we did not transfer the any file */
      ftp->transfer = PPTRANSFER_NONE;
      ftp_state(data, FTP_STOP);
      return CURLE_OK;
    }

    /* Set resume file transfer offset */
    infof(data, "Instructs server to resume from offset %"
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
     */

    if((instate != FTP_LIST) &&
       !data->state.prefer_ascii &&
       !data->set.ignorecl &&
       (ftp->downloadsize < 1)) {
      /*
       * It seems directory listings either don't show the size or very
       * often uses size 0 anyway. ASCII transfers may very well turn out
       * that the transferred amount of data is not the same as this line
       * tells, why using this number in those cases only confuses us.
       *
       * Example D above makes this parsing a little tricky */
      char *bytes;
      char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);







|







2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
     */

    if((instate != FTP_LIST) &&
       !data->state.prefer_ascii &&
       !data->set.ignorecl &&
       (ftp->downloadsize < 1)) {
      /*
       * It seems directory listings either do not show the size or very
       * often uses size 0 anyway. ASCII transfers may very well turn out
       * that the transferred amount of data is not the same as this line
       * tells, why using this number in those cases only confuses us.
       *
       * Example D above makes this parsing a little tricky */
      char *bytes;
      char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
    }
    else
      return InitiateTransfer(data);
  }
  else {
    if((instate == FTP_LIST) && (ftpcode == 450)) {
      /* simply no matching files in the dir listing */
      ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
      ftp_state(data, FTP_STOP); /* this phase is over */
    }
    else {
      failf(data, "RETR response: %03d", ftpcode);
      return instate == FTP_RETR && ftpcode == 550?
        CURLE_REMOTE_FILE_NOT_FOUND:
        CURLE_FTP_COULDNT_RETR_FILE;







|







2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
    }
    else
      return InitiateTransfer(data);
  }
  else {
    if((instate == FTP_LIST) && (ftpcode == 450)) {
      /* simply no matching files in the dir listing */
      ftp->transfer = PPTRANSFER_NONE; /* do not download anything */
      ftp_state(data, FTP_STOP); /* this phase is over */
    }
    else {
      failf(data, "RETR response: %03d", ftpcode);
      return instate == FTP_RETR && ftpcode == 550?
        CURLE_REMOTE_FILE_NOT_FOUND:
        CURLE_FTP_COULDNT_RETR_FILE;
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
    /* All other response codes, like:

    530 User ... access denied
    (the server denies to log the specified user) */

    if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
       !ftpc->ftp_trying_alternative) {
      /* Ok, USER failed.  Let's try the supplied command. */
      result =
        Curl_pp_sendf(data, &ftpc->pp, "%s",
                      data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
      if(!result) {
        ftpc->ftp_trying_alternative = TRUE;
        ftp_state(data, FTP_USER);
      }







|







2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
    /* All other response codes, like:

    530 User ... access denied
    (the server denies to log the specified user) */

    if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
       !ftpc->ftp_trying_alternative) {
      /* Ok, USER failed. Let's try the supplied command. */
      result =
        Curl_pp_sendf(data, &ftpc->pp, "%s",
                      data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
      if(!result) {
        ftpc->ftp_trying_alternative = TRUE;
        ftp_state(data, FTP_USER);
      }
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
          return CURLE_WEIRD_SERVER_REPLY;
        }
        infof(data, "Authentication successful");
      }
#endif

      if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
        /* We don't have a SSL/TLS control connection yet, but FTPS is
           requested. Try a FTPS connection now */

        ftpc->count3 = 0;
        switch(data->set.ftpsslauth) {
        case CURLFTPAUTH_DEFAULT:
        case CURLFTPAUTH_SSL:
          ftpc->count2 = 1; /* add one to get next */
          ftpc->count1 = 0;
          break;
        case CURLFTPAUTH_TLS:
          ftpc->count2 = -1; /* subtract one to get next */
          ftpc->count1 = 1;
          break;
        default:
          failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
                (int)data->set.ftpsslauth);
          return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
        }
        result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
                               ftpauth[ftpc->count1]);
        if(!result)
          ftp_state(data, FTP_AUTH);
      }
      else







|
















|







2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
          return CURLE_WEIRD_SERVER_REPLY;
        }
        infof(data, "Authentication successful");
      }
#endif

      if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
        /* We do not have a SSL/TLS control connection yet, but FTPS is
           requested. Try a FTPS connection now */

        ftpc->count3 = 0;
        switch(data->set.ftpsslauth) {
        case CURLFTPAUTH_DEFAULT:
        case CURLFTPAUTH_SSL:
          ftpc->count2 = 1; /* add one to get next */
          ftpc->count1 = 0;
          break;
        case CURLFTPAUTH_TLS:
          ftpc->count2 = -1; /* subtract one to get next */
          ftpc->count1 = 1;
          break;
        default:
          failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
                (int)data->set.ftpsslauth);
          return CURLE_UNKNOWN_OPTION; /* we do not know what to do */
        }
        result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
                               ftpauth[ftpc->count1]);
        if(!result)
          ftp_state(data, FTP_AUTH);
      }
      else
2976
2977
2978
2979
2980
2981
2982





2983

2984
2985
2986
2987
2988
2989
2990
      else
        result = ftp_state_pwd(data, conn);
      break;

    case FTP_CCC:
      if(ftpcode < 500) {
        /* First shut down the SSL layer (note: this call will block) */





        result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET);


        if(result)
          failf(data, "Failed to clear the command channel (CCC)");
      }
      if(!result)
        /* Then continue as normal */
        result = ftp_state_pwd(data, conn);







>
>
>
>
>
|
>







2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
      else
        result = ftp_state_pwd(data, conn);
      break;

    case FTP_CCC:
      if(ftpcode < 500) {
        /* First shut down the SSL layer (note: this call will block) */
        /* This has only been tested on the proftpd server, and the mod_tls
         * code sends a close notify alert without waiting for a close notify
         * alert in response. Thus we wait for a close notify alert from the
         * server, but we do not send one. Let's hope other servers do
         * the same... */
        result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET,
          (data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE));

        if(result)
          failf(data, "Failed to clear the command channel (CCC)");
      }
      if(!result)
        /* Then continue as normal */
        result = ftp_state_pwd(data, conn);
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
          Curl_safefree(ftpc->entrypath);
          ftpc->entrypath = dir; /* remember this */
          infof(data, "Entry path is '%s'", ftpc->entrypath);
          /* also save it where getinfo can access it: */
          data->state.most_recent_ftp_entrypath = ftpc->entrypath;
        }
        else {
          /* couldn't get the path */
          Curl_dyn_free(&out);
          infof(data, "Failed to figure out path");
        }
      }
      ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
      CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
      break;







|







3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
          Curl_safefree(ftpc->entrypath);
          ftpc->entrypath = dir; /* remember this */
          infof(data, "Entry path is '%s'", ftpc->entrypath);
          /* also save it where getinfo can access it: */
          data->state.most_recent_ftp_entrypath = ftpc->entrypath;
        }
        else {
          /* could not get the path */
          Curl_dyn_free(&out);
          infof(data, "Failed to figure out path");
        }
      }
      ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
      CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
      break;
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
                                 ftpc->dirs[ftpc->cwdcount - 1]);
          if(!result)
            ftp_state(data, FTP_MKD);
        }
        else {
          /* return failure */
          failf(data, "Server denied you to change to the given directory");
          ftpc->cwdfail = TRUE; /* don't remember this path as we failed
                                   to enter it */
          result = CURLE_REMOTE_ACCESS_DENIED;
        }
      }
      else {
        /* success */
        ftpc->count2 = 0;







|







3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
                                 ftpc->dirs[ftpc->cwdcount - 1]);
          if(!result)
            ftp_state(data, FTP_MKD);
        }
        else {
          /* return failure */
          failf(data, "Server denied you to change to the given directory");
          ftpc->cwdfail = TRUE; /* do not remember this path as we failed
                                   to enter it */
          result = CURLE_REMOTE_ACCESS_DENIED;
        }
      }
      else {
        /* success */
        ftpc->count2 = 0;
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
  case CURLE_PARTIAL_FILE:
  case CURLE_UPLOAD_FAILED:
  case CURLE_REMOTE_ACCESS_DENIED:
  case CURLE_FILESIZE_EXCEEDED:
  case CURLE_REMOTE_FILE_NOT_FOUND:
  case CURLE_WRITE_ERROR:
    /* the connection stays alive fine even though this happened */
  case CURLE_OK: /* doesn't affect the control connection's status */
    if(!premature)
      break;

    /* until we cope better with prematurely ended requests, let them
     * fallback as if in complete failure */
    FALLTHROUGH();
  default:       /* by default, an error means the control connection is







|







3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
  case CURLE_PARTIAL_FILE:
  case CURLE_UPLOAD_FAILED:
  case CURLE_REMOTE_ACCESS_DENIED:
  case CURLE_FILESIZE_EXCEEDED:
  case CURLE_REMOTE_FILE_NOT_FOUND:
  case CURLE_WRITE_ERROR:
    /* the connection stays alive fine even though this happened */
  case CURLE_OK: /* does not affect the control connection's status */
    if(!premature)
      break;

    /* until we cope better with prematurely ended requests, let them
     * fallback as if in complete failure */
    FALLTHROUGH();
  default:       /* by default, an error means the control connection is
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
    if(ftpc->prevpath)
      infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath);
  }

  /* free the dir tree and file parts */
  freedirs(ftpc);

  /* shut down the socket to inform the server we're done */

#ifdef _WIN32_WCE
  shutdown(conn->sock[SECONDARYSOCKET], 2);  /* SD_BOTH */
#endif

  if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
    if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
      /* partial download completed */
      result = Curl_pp_sendf(data, pp, "%s", "ABOR");
      if(result) {
        failf(data, "Failure sending ABOR command: %s",
              curl_easy_strerror(result));
        ftpc->ctl_valid = FALSE; /* mark control connection as bad */
        connclose(conn, "ABOR command failed"); /* connection closure */
      }
    }

    close_secondarysocket(data, conn);
  }

  if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
     pp->pending_resp && !premature) {
    /*
     * Let's see what the server says about the transfer we just performed,
     * but lower the timeout as sometimes this connection has died while the







|

















|







3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
    if(ftpc->prevpath)
      infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath);
  }

  /* free the dir tree and file parts */
  freedirs(ftpc);

  /* shut down the socket to inform the server we are done */

#ifdef _WIN32_WCE
  shutdown(conn->sock[SECONDARYSOCKET], 2);  /* SD_BOTH */
#endif

  if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
    if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
      /* partial download completed */
      result = Curl_pp_sendf(data, pp, "%s", "ABOR");
      if(result) {
        failf(data, "Failure sending ABOR command: %s",
              curl_easy_strerror(result));
        ftpc->ctl_valid = FALSE; /* mark control connection as bad */
        connclose(conn, "ABOR command failed"); /* connection closure */
      }
    }

    close_secondarysocket(data);
  }

  if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
     pp->pending_resp && !premature) {
    /*
     * Let's see what the server says about the transfer we just performed,
     * but lower the timeout as sometimes this connection has died while the
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
      result = CURLE_PARTIAL_FILE;
    }
  }
  else {
    if((-1 != data->req.size) &&
       (data->req.size != data->req.bytecount) &&
#ifdef CURL_DO_LINEEND_CONV
       /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
        * we'll check to see if the discrepancy can be explained by the number
        * of CRLFs we've changed to LFs.
        */
       ((data->req.size + data->state.crlf_conversions) !=
        data->req.bytecount) &&
#endif /* CURL_DO_LINEEND_CONV */
       (data->req.maxdownload != data->req.bytecount)) {
      failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
            " bytes", data->req.bytecount);







|
|
|







3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
      result = CURLE_PARTIAL_FILE;
    }
  }
  else {
    if((-1 != data->req.size) &&
       (data->req.size != data->req.bytecount) &&
#ifdef CURL_DO_LINEEND_CONV
       /* Most FTP servers do not adjust their file SIZE response for CRLFs,
        * so we will check to see if the discrepancy can be explained by the
        * number of CRLFs we have changed to LFs.
        */
       ((data->req.size + data->state.crlf_conversions) !=
        data->req.bytecount) &&
#endif /* CURL_DO_LINEEND_CONV */
       (data->req.maxdownload != data->req.bytecount)) {
      failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
            " bytes", data->req.bytecount);
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
}

/***************************************************************************
 *
 * ftp_pasv_verbose()
 *
 * This function only outputs some informationals about this second connection
 * when we've issued a PASV command before and thus we have connected to a
 * possibly new IP address.
 *
 */
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void
ftp_pasv_verbose(struct Curl_easy *data,
                 struct Curl_addrinfo *ai,







|







3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
}

/***************************************************************************
 *
 * ftp_pasv_verbose()
 *
 * This function only outputs some informationals about this second connection
 * when we have issued a PASV command before and thus we have connected to a
 * possibly new IP address.
 *
 */
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void
ftp_pasv_verbose(struct Curl_easy *data,
                 struct Curl_addrinfo *ai,
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
  bool complete = FALSE;

  /* the ftp struct is inited in ftp_connect(). If we are connecting to an HTTP
   * proxy then the state will not be valid until after that connection is
   * complete */
  struct FTP *ftp = NULL;

  /* if the second connection isn't done yet, wait for it to have
   * connected to the remote host. When using proxy tunneling, this
   * means the tunnel needs to have been establish. However, we
   * can not expect the remote host to talk to us in any way yet.
   * So, when using ftps: the SSL handshake will not start until we
   * tell the remote server that we are there. */
  if(conn->cfilter[SECONDARYSOCKET]) {
    result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected);







|







3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
  bool complete = FALSE;

  /* the ftp struct is inited in ftp_connect(). If we are connecting to an HTTP
   * proxy then the state will not be valid until after that connection is
   * complete */
  struct FTP *ftp = NULL;

  /* if the second connection is not done yet, wait for it to have
   * connected to the remote host. When using proxy tunneling, this
   * means the tunnel needs to have been establish. However, we
   * can not expect the remote host to talk to us in any way yet.
   * So, when using ftps: the SSL handshake will not start until we
   * tell the remote server that we are there. */
  if(conn->cfilter[SECONDARYSOCKET]) {
    result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &connected);
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
  if(ftpc->state) {
    /* already in a state so skip the initial commands.
       They are only done to kickstart the do_more state */
    result = ftp_multi_statemach(data, &complete);

    *completep = (int)complete;

    /* if we got an error or if we don't wait for a data connection return
       immediately */
    if(result || !ftpc->wait_data_conn)
      return result;

    /* if we reach the end of the FTP state machine here, *complete will be
       TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
       data connection and therefore we're not actually complete */
    *completep = 0;
  }

  if(ftp->transfer <= PPTRANSFER_INFO) {
    /* a transfer is about to take place, or if not a file name was given
       so we'll do a SIZE on it later and then we need the right TYPE first */

    if(ftpc->wait_data_conn) {
      bool serv_conned;

      result = ReceivedServerConnect(data, &serv_conned);
      if(result)
        return result; /* Failed to accept data connection */







|






|




|
|







3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
  if(ftpc->state) {
    /* already in a state so skip the initial commands.
       They are only done to kickstart the do_more state */
    result = ftp_multi_statemach(data, &complete);

    *completep = (int)complete;

    /* if we got an error or if we do not wait for a data connection return
       immediately */
    if(result || !ftpc->wait_data_conn)
      return result;

    /* if we reach the end of the FTP state machine here, *complete will be
       TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
       data connection and therefore we are not actually complete */
    *completep = 0;
  }

  if(ftp->transfer <= PPTRANSFER_INFO) {
    /* a transfer is about to take place, or if not a filename was given so we
       will do a SIZE on it later and then we need the right TYPE first */

    if(ftpc->wait_data_conn) {
      bool serv_conned;

      result = ReceivedServerConnect(data, &serv_conned);
      if(result)
        return result; /* Failed to accept data connection */
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
    else {
      /* download */
      ftp->downloadsize = -1; /* unknown as of yet */

      result = Curl_range(data);

      if(result == CURLE_OK && data->req.maxdownload >= 0) {
        /* Don't check for successful transfer */
        ftpc->dont_check = TRUE;
      }

      if(result)
        ;
      else if(data->state.list_only || !ftpc->file) {
        /* The specified path ends with a slash, and therefore we think this







|







3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
    else {
      /* download */
      ftp->downloadsize = -1; /* unknown as of yet */

      result = Curl_range(data);

      if(result == CURLE_OK && data->req.maxdownload >= 0) {
        /* Do not check for successful transfer */
        ftpc->dont_check = TRUE;
      }

      if(result)
        ;
      else if(data->state.list_only || !ftpc->file) {
        /* The specified path ends with a slash, and therefore we think this
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
      result = ftp_multi_statemach(data, &complete);
      *completep = (int)complete;
    }
    return result;
  }

  /* no data to transfer */
  Curl_xfer_setup(data, -1, -1, FALSE, -1);

  if(!ftpc->wait_data_conn) {
    /* no waiting for the data connection so this is now complete */
    *completep = 1;
    CURL_TRC_FTP(data, "[%s] DO-MORE phase ends with %d", FTP_DSTATE(data),
                 (int)result);
  }







|







3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
      result = ftp_multi_statemach(data, &complete);
      *completep = (int)complete;
    }
    return result;
  }

  /* no data to transfer */
  Curl_xfer_setup_nop(data);

  if(!ftpc->wait_data_conn) {
    /* no waiting for the data connection so this is now complete */
    *completep = 1;
    CURL_TRC_FTP(data, "[%s] DO-MORE phase ends with %d", FTP_DSTATE(data),
                 (int)result);
  }
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
  wildcard->ftpwc = ftpwc; /* put it to the WildcardData tmp pointer */
  wildcard->dtor = wc_data_dtor;

  /* wildcard does not support NOCWD option (assert it?) */
  if(data->set.ftp_filemethod == FTPFILE_NOCWD)
    data->set.ftp_filemethod = FTPFILE_MULTICWD;

  /* try to parse ftp url */
  result = ftp_parse_url_path(data);
  if(result) {
    goto fail;
  }

  wildcard->path = strdup(ftp->path);
  if(!wildcard->path) {







|







3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
  wildcard->ftpwc = ftpwc; /* put it to the WildcardData tmp pointer */
  wildcard->dtor = wc_data_dtor;

  /* wildcard does not support NOCWD option (assert it?) */
  if(data->set.ftp_filemethod == FTPFILE_NOCWD)
    data->set.ftp_filemethod = FTPFILE_MULTICWD;

  /* try to parse ftp URL */
  result = ftp_parse_url_path(data);
  if(result) {
    goto fail;
  }

  wildcard->path = strdup(ftp->path);
  if(!wildcard->path) {
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
      if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
        ftpc->known_filesize = finfo->size;

      result = ftp_parse_url_path(data);
      if(result)
        return result;

      /* we don't need the Curl_fileinfo of first file anymore */
      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);

      if(wildcard->filelist.size == 0) { /* remains only one file to down. */
        wildcard->state = CURLWC_CLEAN;
        /* after that will be ftp_do called once again and no transfer
           will be done because of CURLWC_CLEAN state */
        return CURLE_OK;







|







4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
      if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
        ftpc->known_filesize = finfo->size;

      result = ftp_parse_url_path(data);
      if(result)
        return result;

      /* we do not need the Curl_fileinfo of first file anymore */
      Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);

      if(wildcard->filelist.size == 0) { /* remains only one file to down. */
        wildcard->state = CURLWC_CLEAN;
        /* after that will be ftp_do called once again and no transfer
           will be done because of CURLWC_CLEAN state */
        return CURLE_OK;
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
  struct ftp_conn *ftpc = &conn->proto.ftpc;
  struct pingpong *pp = &ftpc->pp;

  /* We cannot send quit unconditionally. If this connection is stale or
     bad in any way, sending quit and waiting around here will make the
     disconnect wait in vain and cause more problems than we need to.

     ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
     will try to send the QUIT command, otherwise it will just return.
  */
  if(dead_connection)
    ftpc->ctl_valid = FALSE;

  /* The FTP session may or may not have been allocated/setup at this point! */
  (void)ftp_quit(data, conn); /* ignore errors on the QUIT */







|







4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
  struct ftp_conn *ftpc = &conn->proto.ftpc;
  struct pingpong *pp = &ftpc->pp;

  /* We cannot send quit unconditionally. If this connection is stale or
     bad in any way, sending quit and waiting around here will make the
     disconnect wait in vain and cause more problems than we need to.

     ftp_quit() will check the state of ftp->ctl_valid. If it is ok it
     will try to send the QUIT command, otherwise it will just return.
  */
  if(dead_connection)
    ftpc->ctl_valid = FALSE;

  /* The FTP session may or may not have been allocated/setup at this point! */
  (void)ftp_quit(data, conn); /* ignore errors on the QUIT */
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
        ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen);
        if(!ftpc->dirs[0]) {
          free(rawPath);
          return CURLE_OUT_OF_MEMORY;
        }

        ftpc->dirdepth = 1; /* we consider it to be a single dir */
        fileName = slashPos + 1; /* rest is file name */
      }
      else
        fileName = rawPath; /* file name only (or empty) */
      break;

    default: /* allow pretty much anything */
    case FTPFILE_MULTICWD: {
      /* current position: begin of next path component */
      const char *curPos = rawPath;








|


|







4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
        ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen);
        if(!ftpc->dirs[0]) {
          free(rawPath);
          return CURLE_OUT_OF_MEMORY;
        }

        ftpc->dirdepth = 1; /* we consider it to be a single dir */
        fileName = slashPos + 1; /* rest is filename */
      }
      else
        fileName = rawPath; /* filename only (or empty) */
      break;

    default: /* allow pretty much anything */
    case FTPFILE_MULTICWD: {
      /* current position: begin of next path component */
      const char *curPos = rawPath;

4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
          size_t compLen = slashPos - curPos;

          /* path starts with a slash: add that as a directory */
          if((compLen == 0) && (ftpc->dirdepth == 0))
            ++compLen;

          /* we skip empty path components, like "x//y" since the FTP command
             CWD requires a parameter and a non-existent parameter a) doesn't
             work on many servers and b) has no effect on the others. */
          if(compLen > 0) {
            char *comp = Curl_memdup0(curPos, compLen);
            if(!comp) {
              free(rawPath);
              return CURLE_OUT_OF_MEMORY;
            }
            ftpc->dirs[ftpc->dirdepth++] = comp;
          }
          curPos = slashPos + 1;
        }
      }
      DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc);
      fileName = curPos; /* the rest is the file name (or empty) */
    }
    break;
  } /* switch */

  if(fileName && *fileName)
    ftpc->file = strdup(fileName);
  else
    ftpc->file = NULL; /* instead of point to a zero byte,
                            we make it a NULL pointer */

  if(data->state.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
    /* We need a file name when uploading. Return error! */
    failf(data, "Uploading to a URL without a file name");
    free(rawPath);
    return CURLE_URL_MALFORMAT;
  }

  ftpc->cwddone = FALSE; /* default to not done */

  if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))







|













|











|
|







4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
          size_t compLen = slashPos - curPos;

          /* path starts with a slash: add that as a directory */
          if((compLen == 0) && (ftpc->dirdepth == 0))
            ++compLen;

          /* we skip empty path components, like "x//y" since the FTP command
             CWD requires a parameter and a non-existent parameter a) does not
             work on many servers and b) has no effect on the others. */
          if(compLen > 0) {
            char *comp = Curl_memdup0(curPos, compLen);
            if(!comp) {
              free(rawPath);
              return CURLE_OUT_OF_MEMORY;
            }
            ftpc->dirs[ftpc->dirdepth++] = comp;
          }
          curPos = slashPos + 1;
        }
      }
      DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc);
      fileName = curPos; /* the rest is the filename (or empty) */
    }
    break;
  } /* switch */

  if(fileName && *fileName)
    ftpc->file = strdup(fileName);
  else
    ftpc->file = NULL; /* instead of point to a zero byte,
                            we make it a NULL pointer */

  if(data->state.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
    /* We need a filename when uploading. Return error! */
    failf(data, "Uploading to a URL without a filename");
    free(rawPath);
    return CURLE_URL_MALFORMAT;
  }

  ftpc->cwddone = FALSE; /* default to not done */

  if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
  struct ftp_conn *ftpc = &conn->proto.ftpc;

  if(connected) {
    int completed;
    CURLcode result = ftp_do_more(data, &completed);

    if(result) {
      close_secondarysocket(data, conn);
      return result;
    }
  }

  if(ftp->transfer != PPTRANSFER_BODY)
    /* no data to transfer */
    Curl_xfer_setup(data, -1, -1, FALSE, -1);
  else if(!connected)
    /* since we didn't connect now, we want do_more to get called */
    conn->bits.do_more = TRUE;

  ftpc->ctl_valid = TRUE; /* seems good */

  return CURLE_OK;
}








|






|

|







4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
  struct ftp_conn *ftpc = &conn->proto.ftpc;

  if(connected) {
    int completed;
    CURLcode result = ftp_do_more(data, &completed);

    if(result) {
      close_secondarysocket(data);
      return result;
    }
  }

  if(ftp->transfer != PPTRANSFER_BODY)
    /* no data to transfer */
    Curl_xfer_setup_nop(data);
  else if(!connected)
    /* since we did not connect now, we want do_more to get called */
    conn->bits.do_more = TRUE;

  ftpc->ctl_valid = TRUE; /* seems good */

  return CURLE_OK;
}

4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
      Curl_safefree(ftpc->account);
      free(ftp);
      return CURLE_OUT_OF_MEMORY;
    }
  }
  data->req.p.ftp = ftp;

  ftp->path = &data->state.up.path[1]; /* don't include the initial slash */

  /* FTP URLs support an extension like ";type=<typecode>" that
   * we'll try to get now! */
  type = strstr(ftp->path, ";type=");

  if(!type)
    type = strstr(conn->host.rawalloc, ";type=");

  if(type) {
    char command;







|


|







4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
      Curl_safefree(ftpc->account);
      free(ftp);
      return CURLE_OUT_OF_MEMORY;
    }
  }
  data->req.p.ftp = ftp;

  ftp->path = &data->state.up.path[1]; /* do not include the initial slash */

  /* FTP URLs support an extension like ";type=<typecode>" that
   * we will try to get now! */
  type = strstr(ftp->path, ";type=");

  if(!type)
    type = strstr(conn->host.rawalloc, ";type=");

  if(type) {
    char command;
Changes to jni/curl/lib/ftp.h.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  FTP_SYST,
  FTP_NAMEFMT,
  FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
  FTP_RETR_PREQUOTE,
  FTP_STOR_PREQUOTE,
  FTP_POSTQUOTE,
  FTP_CWD,  /* change dir */
  FTP_MKD,  /* if the dir didn't exist */
  FTP_MDTM, /* to figure out the datestamp */
  FTP_TYPE, /* to set type when doing a head-like request */
  FTP_LIST_TYPE, /* set type when about to do a dir list */
  FTP_RETR_TYPE, /* set type when about to RETR a file */
  FTP_STOR_TYPE, /* set type when about to STOR a file */
  FTP_SIZE, /* get the remote file's size for head-like request */
  FTP_RETR_SIZE, /* get the remote file's size for RETR */







|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  FTP_SYST,
  FTP_NAMEFMT,
  FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
  FTP_RETR_PREQUOTE,
  FTP_STOR_PREQUOTE,
  FTP_POSTQUOTE,
  FTP_CWD,  /* change dir */
  FTP_MKD,  /* if the dir did not exist */
  FTP_MDTM, /* to figure out the datestamp */
  FTP_TYPE, /* to set type when doing a head-like request */
  FTP_LIST_TYPE, /* set type when about to do a dir list */
  FTP_RETR_TYPE, /* set type when about to RETR a file */
  FTP_STOR_TYPE, /* set type when about to STOR a file */
  FTP_SIZE, /* get the remote file's size for head-like request */
  FTP_RETR_SIZE, /* get the remote file's size for RETR */
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* ftp_conn is used for struct connection-oriented data in the connectdata
   struct */
struct ftp_conn {
  struct pingpong pp;
  char *account;
  char *alternative_to_user;
  char *entrypath; /* the PWD reply when we logged on */
  char *file;    /* url-decoded file name (or path) */
  char **dirs;   /* realloc()ed array for path components */
  char *newhost;
  char *prevpath;   /* url-decoded conn->path from the previous transfer */
  char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
                        and others (A/I or zero) */
  curl_off_t retr_size_saved; /* Size of retrieved file saved */
  char *server_os;     /* The target server operating system. */
  curl_off_t known_filesize; /* file size is different from -1, if wildcard
                                LIST parsing was done and wc_statemach set
                                it */
  int dirdepth;  /* number of entries used in the 'dirs' array */
  int cwdcount;     /* number of CWD commands issued */
  int count1; /* general purpose counter for the state machine */
  int count2; /* general purpose counter for the state machine */
  int count3; /* general purpose counter for the state machine */
  /* newhost is the (allocated) IP addr or host name to connect the data
     connection to */
  unsigned short newport;
  ftpstate state; /* always use ftp.c:state() to change state! */
  ftpstate state_saved; /* transfer type saved to be reloaded after data
                           connection is established */
  unsigned char use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
                              IMAP or POP3 or others! (type: curl_usessl)*/







|















|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* ftp_conn is used for struct connection-oriented data in the connectdata
   struct */
struct ftp_conn {
  struct pingpong pp;
  char *account;
  char *alternative_to_user;
  char *entrypath; /* the PWD reply when we logged on */
  char *file;    /* url-decoded filename (or path) */
  char **dirs;   /* realloc()ed array for path components */
  char *newhost;
  char *prevpath;   /* url-decoded conn->path from the previous transfer */
  char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
                        and others (A/I or zero) */
  curl_off_t retr_size_saved; /* Size of retrieved file saved */
  char *server_os;     /* The target server operating system. */
  curl_off_t known_filesize; /* file size is different from -1, if wildcard
                                LIST parsing was done and wc_statemach set
                                it */
  int dirdepth;  /* number of entries used in the 'dirs' array */
  int cwdcount;     /* number of CWD commands issued */
  int count1; /* general purpose counter for the state machine */
  int count2; /* general purpose counter for the state machine */
  int count3; /* general purpose counter for the state machine */
  /* newhost is the (allocated) IP addr or hostname to connect the data
     connection to */
  unsigned short newport;
  ftpstate state; /* always use ftp.c:state() to change state! */
  ftpstate state_saved; /* transfer type saved to be reloaded after data
                           connection is established */
  unsigned char use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
                              IMAP or POP3 or others! (type: curl_usessl)*/
Changes to jni/curl/lib/getenv.c.
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
{
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) || \
  defined(__ORBIS__) || defined(__PROSPERO__) /* PlayStation 4 and 5 */
  (void)variable;
  return NULL;
#elif defined(_WIN32)
  /* This uses Windows API instead of C runtime getenv() to get the environment
     variable since some changes aren't always visible to the latter. #4774 */
  char *buf = NULL;
  char *tmp;
  DWORD bufsize;
  DWORD rc = 1;
  const DWORD max = 32768; /* max env var size from MSCRT source */

  for(;;) {
    tmp = realloc(buf, rc);
    if(!tmp) {
      free(buf);
      return NULL;
    }

    buf = tmp;
    bufsize = rc;

    /* It's possible for rc to be 0 if the variable was found but empty.
       Since getenv doesn't make that distinction we ignore it as well. */
    rc = GetEnvironmentVariableA(variable, buf, bufsize);
    if(!rc || rc == bufsize || rc > max) {
      free(buf);
      return NULL;
    }

    /* if rc < bufsize then rc is bytes written not including null */







|
















|
|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
{
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) || \
  defined(__ORBIS__) || defined(__PROSPERO__) /* PlayStation 4 and 5 */
  (void)variable;
  return NULL;
#elif defined(_WIN32)
  /* This uses Windows API instead of C runtime getenv() to get the environment
     variable since some changes are not always visible to the latter. #4774 */
  char *buf = NULL;
  char *tmp;
  DWORD bufsize;
  DWORD rc = 1;
  const DWORD max = 32768; /* max env var size from MSCRT source */

  for(;;) {
    tmp = realloc(buf, rc);
    if(!tmp) {
      free(buf);
      return NULL;
    }

    buf = tmp;
    bufsize = rc;

    /* it is possible for rc to be 0 if the variable was found but empty.
       Since getenv does not make that distinction we ignore it as well. */
    rc = GetEnvironmentVariableA(variable, buf, bufsize);
    if(!rc || rc == bufsize || rc > max) {
      free(buf);
      return NULL;
    }

    /* if rc < bufsize then rc is bytes written not including null */
Changes to jni/curl/lib/getinfo.c.
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    unsigned long *to_ulong;
    long          *to_long;
  } lptr;

#ifdef DEBUGBUILD
  char *timestr = getenv("CURL_TIME");
  if(timestr) {
    unsigned long val = strtol(timestr, NULL, 10);
    switch(info) {
    case CURLINFO_LOCAL_PORT:
      *param_longp = (long)val;
      return CURLE_OK;
    default:
      break;
    }
  }
  /* use another variable for this to allow different values */
  timestr = getenv("CURL_DEBUG_SIZE");
  if(timestr) {
    unsigned long val = strtol(timestr, NULL, 10);
    switch(info) {
    case CURLINFO_HEADER_SIZE:
    case CURLINFO_REQUEST_SIZE:
      *param_longp = (long)val;
      return CURLE_OK;
    default:
      break;







|











|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    unsigned long *to_ulong;
    long          *to_long;
  } lptr;

#ifdef DEBUGBUILD
  char *timestr = getenv("CURL_TIME");
  if(timestr) {
    unsigned long val = strtoul(timestr, NULL, 10);
    switch(info) {
    case CURLINFO_LOCAL_PORT:
      *param_longp = (long)val;
      return CURLE_OK;
    default:
      break;
    }
  }
  /* use another variable for this to allow different values */
  timestr = getenv("CURL_DEBUG_SIZE");
  if(timestr) {
    unsigned long val = strtoul(timestr, NULL, 10);
    switch(info) {
    case CURLINFO_HEADER_SIZE:
    case CURLINFO_REQUEST_SIZE:
      *param_longp = (long)val;
      return CURLE_OK;
    default:
      break;
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
    break;
  case CURLINFO_NUM_CONNECTS:
    *param_longp = data->info.numconnects;
    break;
  case CURLINFO_LASTSOCKET:
    sockfd = Curl_getconnectinfo(data, NULL);

    /* note: this is not a good conversion for systems with 64 bit sockets and
       32 bit longs */
    if(sockfd != CURL_SOCKET_BAD)
      *param_longp = (long)sockfd;
    else
      /* this interface is documented to return -1 in case of badness, which
         may not be the same as the CURL_SOCKET_BAD value */
      *param_longp = -1;
    break;







|
|







273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
    break;
  case CURLINFO_NUM_CONNECTS:
    *param_longp = data->info.numconnects;
    break;
  case CURLINFO_LASTSOCKET:
    sockfd = Curl_getconnectinfo(data, NULL);

    /* note: this is not a good conversion for systems with 64-bit sockets and
       32-bit longs */
    if(sockfd != CURL_SOCKET_BAD)
      *param_longp = (long)sockfd;
    else
      /* this interface is documented to return -1 in case of badness, which
         may not be the same as the CURL_SOCKET_BAD value */
      *param_longp = -1;
    break;
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
      break;
    default:
      *param_longp = CURL_HTTP_VERSION_NONE;
      break;
    }
    break;
  case CURLINFO_PROTOCOL:
    *param_longp = data->info.conn_protocol;
    break;
  case CURLINFO_USED_PROXY:
    *param_longp =
#ifdef CURL_DISABLE_PROXY
      0
#else
      data->info.used_proxy







|







331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
      break;
    default:
      *param_longp = CURL_HTTP_VERSION_NONE;
      break;
    }
    break;
  case CURLINFO_PROTOCOL:
    *param_longp = (long)data->info.conn_protocol;
    break;
  case CURLINFO_USED_PROXY:
    *param_longp =
#ifdef CURL_DISABLE_PROXY
      0
#else
      data->info.used_proxy
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371

static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
                             curl_off_t *param_offt)
{
#ifdef DEBUGBUILD
  char *timestr = getenv("CURL_TIME");
  if(timestr) {
    unsigned long val = strtol(timestr, NULL, 10);
    switch(info) {
    case CURLINFO_TOTAL_TIME_T:
    case CURLINFO_NAMELOOKUP_TIME_T:
    case CURLINFO_CONNECT_TIME_T:
    case CURLINFO_APPCONNECT_TIME_T:
    case CURLINFO_PRETRANSFER_TIME_T:
    case CURLINFO_STARTTRANSFER_TIME_T:







|







357
358
359
360
361
362
363
364
365
366
367
368
369
370
371

static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
                             curl_off_t *param_offt)
{
#ifdef DEBUGBUILD
  char *timestr = getenv("CURL_TIME");
  if(timestr) {
    unsigned long val = strtoul(timestr, NULL, 10);
    switch(info) {
    case CURLINFO_TOTAL_TIME_T:
    case CURLINFO_NAMELOOKUP_TIME_T:
    case CURLINFO_CONNECT_TIME_T:
    case CURLINFO_APPCONNECT_TIME_T:
    case CURLINFO_PRETRANSFER_TIME_T:
    case CURLINFO_STARTTRANSFER_TIME_T:
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460

static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
                               double *param_doublep)
{
#ifdef DEBUGBUILD
  char *timestr = getenv("CURL_TIME");
  if(timestr) {
    unsigned long val = strtol(timestr, NULL, 10);
    switch(info) {
    case CURLINFO_TOTAL_TIME:
    case CURLINFO_NAMELOOKUP_TIME:
    case CURLINFO_CONNECT_TIME:
    case CURLINFO_APPCONNECT_TIME:
    case CURLINFO_PRETRANSFER_TIME:
    case CURLINFO_STARTTRANSFER_TIME:







|







446
447
448
449
450
451
452
453
454
455
456
457
458
459
460

static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
                               double *param_doublep)
{
#ifdef DEBUGBUILD
  char *timestr = getenv("CURL_TIME");
  if(timestr) {
    unsigned long val = strtoul(timestr, NULL, 10);
    switch(info) {
    case CURLINFO_TOTAL_TIME:
    case CURLINFO_NAMELOOKUP_TIME:
    case CURLINFO_CONNECT_TIME:
    case CURLINFO_APPCONNECT_TIME:
    case CURLINFO_PRETRANSFER_TIME:
    case CURLINFO_STARTTRANSFER_TIME:
Changes to jni/curl/lib/gopher.c.
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    if(timeout_ms < 0) {
      result = CURLE_OPERATION_TIMEDOUT;
      break;
    }
    if(!timeout_ms)
      timeout_ms = TIMEDIFF_T_MAX;

    /* Don't busyloop. The entire loop thing is a work-around as it causes a
       BLOCKING behavior which is a NO-NO. This function should rather be
       split up in a do and a doing piece where the pieces that aren't
       possible to send now will be sent in the doing function repeatedly
       until the entire request is sent.
    */
    what = SOCKET_WRITABLE(sockfd, timeout_ms);
    if(what < 0) {
      result = CURLE_SEND_ERROR;
      break;







|

|







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    if(timeout_ms < 0) {
      result = CURLE_OPERATION_TIMEDOUT;
      break;
    }
    if(!timeout_ms)
      timeout_ms = TIMEDIFF_T_MAX;

    /* Do not busyloop. The entire loop thing is a work-around as it causes a
       BLOCKING behavior which is a NO-NO. This function should rather be
       split up in a do and a doing piece where the pieces that are not
       possible to send now will be sent in the doing function repeatedly
       until the entire request is sent.
    */
    what = SOCKET_WRITABLE(sockfd, timeout_ms);
    if(what < 0) {
      result = CURLE_SEND_ERROR;
      break;
234
235
236
237
238
239
240
241
242
243
244
    failf(data, "Failed sending Gopher request");
    return result;
  }
  result = Curl_client_write(data, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
  if(result)
    return result;

  Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
  return CURLE_OK;
}
#endif /* CURL_DISABLE_GOPHER */







|



234
235
236
237
238
239
240
241
242
243
244
    failf(data, "Failed sending Gopher request");
    return result;
  }
  result = Curl_client_write(data, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
  if(result)
    return result;

  Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
  return CURLE_OK;
}
#endif /* CURL_DISABLE_GOPHER */
Changes to jni/curl/lib/hash.c.
36
37
38
39
40
41
42



43
44
45
46
47
48
49
50
static void
hash_element_dtor(void *user, void *element)
{
  struct Curl_hash *h = (struct Curl_hash *) user;
  struct Curl_hash_element *e = (struct Curl_hash_element *) element;

  if(e->ptr) {



    h->dtor(e->ptr);
    e->ptr = NULL;
  }

  e->key_len = 0;

  free(e);
}







>
>
>
|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
static void
hash_element_dtor(void *user, void *element)
{
  struct Curl_hash *h = (struct Curl_hash *) user;
  struct Curl_hash_element *e = (struct Curl_hash_element *) element;

  if(e->ptr) {
    if(e->dtor)
      e->dtor(e->key, e->key_len, e->ptr);
    else
      h->dtor(e->ptr);
    e->ptr = NULL;
  }

  e->key_len = 0;

  free(e);
}
73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
  h->comp_func = comparator;
  h->dtor = dtor;
  h->size = 0;
  h->slots = slots;
}

static struct Curl_hash_element *
mk_hash_element(const void *key, size_t key_len, const void *p)

{
  /* allocate the struct plus memory after it to store the key */
  struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) +
                                        key_len);
  if(he) {
    /* copy the key */
    memcpy(he->key, key, key_len);
    he->key_len = key_len;
    he->ptr = (void *) p;

  }
  return he;
}

#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]

/* Insert the data in the hash. If there already was a match in the hash, that
 * data is replaced. This function also "lazily" allocates the table if
 * needed, as it isn't done in the _init function (anymore).
 *
 * @unittest: 1305
 * @unittest: 1602
 * @unittest: 1603
 */
void *
Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)

{
  struct Curl_hash_element  *he;
  struct Curl_llist_element *le;
  struct Curl_llist *l;

  DEBUGASSERT(h);
  DEBUGASSERT(h->slots);







|
>









>






<
<
<
<
<
<
<
<
<
|
>







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100









101
102
103
104
105
106
107
108
109
  h->comp_func = comparator;
  h->dtor = dtor;
  h->size = 0;
  h->slots = slots;
}

static struct Curl_hash_element *
mk_hash_element(const void *key, size_t key_len, const void *p,
                Curl_hash_elem_dtor dtor)
{
  /* allocate the struct plus memory after it to store the key */
  struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) +
                                        key_len);
  if(he) {
    /* copy the key */
    memcpy(he->key, key, key_len);
    he->key_len = key_len;
    he->ptr = (void *) p;
    he->dtor = dtor;
  }
  return he;
}

#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]










void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
                     Curl_hash_elem_dtor dtor)
{
  struct Curl_hash_element  *he;
  struct Curl_llist_element *le;
  struct Curl_llist *l;

  DEBUGASSERT(h);
  DEBUGASSERT(h->slots);
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141














142
143
144
145
146
147
148
    if(h->comp_func(he->key, he->key_len, key, key_len)) {
      Curl_llist_remove(l, le, (void *)h);
      --h->size;
      break;
    }
  }

  he = mk_hash_element(key, key_len, p);
  if(he) {
    Curl_llist_append(l, he, &he->list);
    ++h->size;
    return p; /* return the new entry */
  }

  return NULL; /* failure */
}















/* Remove the identified hash entry.
 * Returns non-zero on failure.
 *
 * @unittest: 1603
 */
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)







|








>
>
>
>
>
>
>
>
>
>
>
>
>
>







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
    if(h->comp_func(he->key, he->key_len, key, key_len)) {
      Curl_llist_remove(l, le, (void *)h);
      --h->size;
      break;
    }
  }

  he = mk_hash_element(key, key_len, p, dtor);
  if(he) {
    Curl_llist_append(l, he, &he->list);
    ++h->size;
    return p; /* return the new entry */
  }

  return NULL; /* failure */
}

/* Insert the data in the hash. If there already was a match in the hash, that
 * data is replaced. This function also "lazily" allocates the table if
 * needed, as it is not done in the _init function (anymore).
 *
 * @unittest: 1305
 * @unittest: 1602
 * @unittest: 1603
 */
void *
Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
{
  return Curl_hash_add2(h, key, key_len, p, NULL);
}

/* Remove the identified hash entry.
 * Returns non-zero on failure.
 *
 * @unittest: 1603
 */
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
255
256
257
258
259
260
261

262
263
264
265
266
267
268
269
270
size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
{
  const char *key_str = (const char *) key;
  const char *end = key_str + key_length;
  size_t h = 5381;

  while(key_str < end) {

    h += h << 5;
    h ^= *key_str++;
  }

  return (h % slots_num);
}

size_t Curl_str_key_compare(void *k1, size_t key1_len,
                            void *k2, size_t key2_len)







>

|







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
{
  const char *key_str = (const char *) key;
  const char *end = key_str + key_length;
  size_t h = 5381;

  while(key_str < end) {
    size_t j = (size_t)*key_str++;
    h += h << 5;
    h ^= j;
  }

  return (h % slots_num);
}

size_t Curl_str_key_compare(void *k1, size_t key1_len,
                            void *k2, size_t key2_len)
Changes to jni/curl/lib/hash.h.
54
55
56
57
58
59
60


61
62
63

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80


81
82
83
84
85
86
87
  /* Comparator function to compare keys */
  comp_function comp_func;
  Curl_hash_dtor   dtor;
  size_t slots;
  size_t size;
};



struct Curl_hash_element {
  struct Curl_llist_element list;
  void   *ptr;

  size_t key_len;
  char   key[1]; /* allocated memory following the struct */
};

struct Curl_hash_iterator {
  struct Curl_hash *hash;
  size_t slot_index;
  struct Curl_llist_element *current_element;
};

void Curl_hash_init(struct Curl_hash *h,
                    size_t slots,
                    hash_function hfunc,
                    comp_function comparator,
                    Curl_hash_dtor dtor);

void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);


int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
#define Curl_hash_count(h) ((h)->size)
void Curl_hash_destroy(struct Curl_hash *h);
void Curl_hash_clean(struct Curl_hash *h);
void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
                                    int (*comp)(void *, void *));







>
>



>

















>
>







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  /* Comparator function to compare keys */
  comp_function comp_func;
  Curl_hash_dtor   dtor;
  size_t slots;
  size_t size;
};

typedef void (*Curl_hash_elem_dtor)(void *key, size_t key_len, void *p);

struct Curl_hash_element {
  struct Curl_llist_element list;
  void   *ptr;
  Curl_hash_elem_dtor dtor;
  size_t key_len;
  char   key[1]; /* allocated memory following the struct */
};

struct Curl_hash_iterator {
  struct Curl_hash *hash;
  size_t slot_index;
  struct Curl_llist_element *current_element;
};

void Curl_hash_init(struct Curl_hash *h,
                    size_t slots,
                    hash_function hfunc,
                    comp_function comparator,
                    Curl_hash_dtor dtor);

void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
                     Curl_hash_elem_dtor dtor);
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
#define Curl_hash_count(h) ((h)->size)
void Curl_hash_destroy(struct Curl_hash *h);
void Curl_hash_clean(struct Curl_hash *h);
void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
                                    int (*comp)(void *, void *));
Changes to jni/curl/lib/headers.c.
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  h->value = hs->value;
  h->amount = amount;
  h->index = index;
  /* this will randomly OR a reserved bit for the sole purpose of making it
     impossible for applications to do == comparisons, as that would otherwise
     be very tempting and then lead to the reserved bits not being reserved
     anymore. */
  h->origin = hs->type | (1<<27);
  h->anchor = e;
}

/* public API */
CURLHcode curl_easy_header(CURL *easy,
                           const char *name,
                           size_t nameindex,







|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  h->value = hs->value;
  h->amount = amount;
  h->index = index;
  /* this will randomly OR a reserved bit for the sole purpose of making it
     impossible for applications to do == comparisons, as that would otherwise
     be very tempting and then lead to the reserved bits not being reserved
     anymore. */
  h->origin = (unsigned int)(hs->type | (1<<27));
  h->anchor = e;
}

/* public API */
CURLHcode curl_easy_header(CURL *easy,
                           const char *name,
                           size_t nameindex,
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
         (hs->type & type) &&
         (hs->request == request) &&
         (match++ == nameindex)) {
        e_pick = e;
        break;
      }
    }
    if(!e) /* this shouldn't happen */
      return CURLHE_MISSING;
  }
  /* this is the name we want */
  copy_header_external(hs, nameindex, amount, e_pick,
                       &data->state.headerout[0]);
  *hout = &data->state.headerout[0];
  return CURLHE_OK;







|







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
         (hs->type & type) &&
         (hs->request == request) &&
         (match++ == nameindex)) {
        e_pick = e;
        break;
      }
    }
    if(!e) /* this should not happen */
      return CURLHE_MISSING;
  }
  /* this is the name we want */
  copy_header_external(hs, nameindex, amount, e_pick,
                       &data->state.headerout[0]);
  *hout = &data->state.headerout[0];
  return CURLHE_OK;
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  hlen = end - header;

  if((header[0] == ' ') || (header[0] == '\t')) {
    if(data->state.prevhead)
      /* line folding, append value to the previous header's value */
      return unfold_value(data, header, hlen);
    else {
      /* Can't unfold without a previous header. Instead of erroring, just
         pass the leading blanks. */
      while(hlen && ISBLANK(*header)) {
        header++;
        hlen--;
      }
      if(!hlen)
        return CURLE_WEIRD_SERVER_REPLY;







|







298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  hlen = end - header;

  if((header[0] == ' ') || (header[0] == '\t')) {
    if(data->state.prevhead)
      /* line folding, append value to the previous header's value */
      return unfold_value(data, header, hlen);
    else {
      /* cannot unfold without a previous header. Instead of erroring, just
         pass the leading blanks. */
      while(hlen && ISBLANK(*header)) {
        header++;
        hlen--;
      }
      if(!hlen)
        return CURLE_WEIRD_SERVER_REPLY;
Changes to jni/curl/lib/hmac.c.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/* The last #include file should be: */
#include "memdebug.h"

/*
 * Generic HMAC algorithm.
 *
 *   This module computes HMAC digests based on any hash function. Parameters
 * and computing procedures are set-up dynamically at HMAC computation context
 * initialization.
 */

static const unsigned char hmac_ipad = 0x36;
static const unsigned char hmac_opad = 0x5C;









|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/* The last #include file should be: */
#include "memdebug.h"

/*
 * Generic HMAC algorithm.
 *
 *   This module computes HMAC digests based on any hash function. Parameters
 * and computing procedures are setup dynamically at HMAC computation context
 * initialization.
 */

static const unsigned char hmac_ipad = 0x36;
static const unsigned char hmac_opad = 0x5C;


Changes to jni/curl/lib/hostip.c.
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
 * hostip.c explained
 * ==================
 *
 * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
 * source file are these:
 *
 * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
 * that. The host may not be able to resolve IPv6, but we don't really have to
 * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
 * defined.
 *
 * CURLRES_ARES - is defined if libcurl is built to use c-ares for
 * asynchronous name resolves. This can be Windows or *nix.
 *
 * CURLRES_THREADED - is defined if libcurl is built to run under (native)
 * Windows, and then the name resolve will be done in a new thread, and the







|
|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
 * hostip.c explained
 * ==================
 *
 * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
 * source file are these:
 *
 * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
 * that. The host may not be able to resolve IPv6, but we do not really have to
 * take that into account. Hosts that are not IPv6-enabled have CURLRES_IPV4
 * defined.
 *
 * CURLRES_ARES - is defined if libcurl is built to use c-ares for
 * asynchronous name resolves. This can be Windows or *nix.
 *
 * CURLRES_THREADED - is defined if libcurl is built to run under (native)
 * Windows, and then the name resolve will be done in a new thread, and the
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
void Curl_hostcache_prune(struct Curl_easy *data)
{
  time_t now;
  /* the timeout may be set -1 (forever) */
  int timeout = data->set.dns_cache_timeout;

  if(!data->dns.hostcache)
    /* NULL hostcache means we can't do it */
    return;

  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

  now = time(NULL);








|







234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
void Curl_hostcache_prune(struct Curl_easy *data)
{
  time_t now;
  /* the timeout may be set -1 (forever) */
  int timeout = data->set.dns_cache_timeout;

  if(!data->dns.hostcache)
    /* NULL hostcache means we cannot do it */
    return;

  if(data->share)
    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

  now = time(NULL);

279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  struct Curl_dns_entry *dns = NULL;
  char entry_id[MAX_HOSTCACHE_LEN];

  /* Create an entry id, based upon the hostname and port */
  size_t entry_len = create_hostcache_id(hostname, 0, port,
                                         entry_id, sizeof(entry_id));

  /* See if it's already in our dns cache */
  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);

  /* No entry found in cache, check if we might have a wildcard entry */
  if(!dns && data->state.wildcard_resolve) {
    entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id));

    /* See if it's already in our dns cache */
    dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
  }

  if(dns && (data->set.dns_cache_timeout != -1)) {
    /* See whether the returned entry is stale. Done before we release lock */
    struct hostcache_prune_data user;








|






|







279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  struct Curl_dns_entry *dns = NULL;
  char entry_id[MAX_HOSTCACHE_LEN];

  /* Create an entry id, based upon the hostname and port */
  size_t entry_len = create_hostcache_id(hostname, 0, port,
                                         entry_id, sizeof(entry_id));

  /* See if it is already in our dns cache */
  dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);

  /* No entry found in cache, check if we might have a wildcard entry */
  if(!dns && data->state.wildcard_resolve) {
    entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id));

    /* See if it is already in our dns cache */
    dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
  }

  if(dns && (data->set.dns_cache_timeout != -1)) {
    /* See whether the returned entry is stale. Done before we release lock */
    struct hostcache_prune_data user;

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
        found = true;
        break;
      }
      addr = addr->ai_next;
    }

    if(!found) {
      infof(data, "Hostname in DNS cache doesn't have needed family, zapped");
      dns = NULL; /* the memory deallocation is being handled by the hash */
      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
    }
  }
  return dns;
}

/*
 * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
 *
 * Curl_resolv() checks initially and multi_runsingle() checks each time
 * it discovers the handle in the state WAITRESOLVE whether the hostname
 * has already been resolved and the address has already been stored in
 * the DNS cache. This short circuits waiting for a lot of pending
 * lookups for the same hostname requested by different handles.
 *
 * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
 *
 * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
 * use, or we'll leak memory!
 */
struct Curl_dns_entry *
Curl_fetch_addr(struct Curl_easy *data,
                const char *hostname,
                int port)
{
  struct Curl_dns_entry *dns = NULL;







|



















|







325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
        found = true;
        break;
      }
      addr = addr->ai_next;
    }

    if(!found) {
      infof(data, "Hostname in DNS cache does not have needed family, zapped");
      dns = NULL; /* the memory deallocation is being handled by the hash */
      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
    }
  }
  return dns;
}

/*
 * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
 *
 * Curl_resolv() checks initially and multi_runsingle() checks each time
 * it discovers the handle in the state WAITRESOLVE whether the hostname
 * has already been resolved and the address has already been stored in
 * the DNS cache. This short circuits waiting for a lot of pending
 * lookups for the same hostname requested by different handles.
 *
 * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
 *
 * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
 * use, or we will leak memory!
 */
struct Curl_dns_entry *
Curl_fetch_addr(struct Curl_easy *data,
                const char *hostname,
                int port)
{
  struct Curl_dns_entry *dns = NULL;
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439

      rnd = malloc(rnd_size);
      if(rnd) {
        /* Fisher-Yates shuffle */
        if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) {
          struct Curl_addrinfo *swap_tmp;
          for(i = num_addrs - 1; i > 0; i--) {
            swap_tmp = nodes[rnd[i] % (i + 1)];
            nodes[rnd[i] % (i + 1)] = nodes[i];
            nodes[i] = swap_tmp;
          }

          /* relink list in the new order */
          for(i = 1; i < num_addrs; i++) {
            nodes[i-1]->ai_next = nodes[i];
          }







|
|







424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439

      rnd = malloc(rnd_size);
      if(rnd) {
        /* Fisher-Yates shuffle */
        if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) {
          struct Curl_addrinfo *swap_tmp;
          for(i = num_addrs - 1; i > 0; i--) {
            swap_tmp = nodes[rnd[i] % (unsigned int)(i + 1)];
            nodes[rnd[i] % (unsigned int)(i + 1)] = nodes[i];
            nodes[i] = swap_tmp;
          }

          /* relink list in the new order */
          for(i = 1; i < num_addrs; i++) {
            nodes[i-1]->ai_next = nodes[i];
          }
532
533
534
535
536
537
538

539
540
541
542
543
544
545
546
547
  if(!ca)
    return NULL;

  sa6.sin6_family = AF_INET6;
  sa6.sin6_port = htons(port16);
  sa6.sin6_flowinfo = 0;
  sa6.sin6_scope_id = 0;

  if(Curl_inet_pton(AF_INET6, "::1", ipv6) < 1)
    return NULL;
  memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));

  ca->ai_flags     = 0;
  ca->ai_family    = AF_INET6;
  ca->ai_socktype  = SOCK_STREAM;
  ca->ai_protocol  = IPPROTO_TCP;
  ca->ai_addrlen   = (curl_socklen_t)ss_size;







>
|
<







532
533
534
535
536
537
538
539
540

541
542
543
544
545
546
547
  if(!ca)
    return NULL;

  sa6.sin6_family = AF_INET6;
  sa6.sin6_port = htons(port16);
  sa6.sin6_flowinfo = 0;
  sa6.sin6_scope_id = 0;

  (void)Curl_inet_pton(AF_INET6, "::1", ipv6);

  memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));

  ca->ai_flags     = 0;
  ca->ai_family    = AF_INET6;
  ca->ai_socktype  = SOCK_STREAM;
  ca->ai_protocol  = IPPROTO_TCP;
  ca->ai_addrlen   = (curl_socklen_t)ss_size;
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
#ifdef USE_IPV6
/*
 * Curl_ipv6works() returns TRUE if IPv6 seems to work.
 */
bool Curl_ipv6works(struct Curl_easy *data)
{
  if(data) {
    /* the nature of most system is that IPv6 status doesn't come and go
       during a program's lifetime so we only probe the first time and then we
       have the info kept for fast reuse */
    DEBUGASSERT(data);
    DEBUGASSERT(data->multi);
    if(data->multi->ipv6_up == IPV6_UNKNOWN) {
      bool works = Curl_ipv6works(NULL);
      data->multi->ipv6_up = works ? IPV6_WORKS : IPV6_DEAD;
    }
    return data->multi->ipv6_up == IPV6_WORKS;
  }
  else {
    int ipv6_works = -1;
    /* probe to see if we have a working IPv6 stack */
    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
    if(s == CURL_SOCKET_BAD)
      /* an IPv6 address was requested but we can't get/use one */
      ipv6_works = 0;
    else {
      ipv6_works = 1;
      sclose(s);
    }
    return (ipv6_works>0)?TRUE:FALSE;
  }







|















|







598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
#ifdef USE_IPV6
/*
 * Curl_ipv6works() returns TRUE if IPv6 seems to work.
 */
bool Curl_ipv6works(struct Curl_easy *data)
{
  if(data) {
    /* the nature of most system is that IPv6 status does not come and go
       during a program's lifetime so we only probe the first time and then we
       have the info kept for fast reuse */
    DEBUGASSERT(data);
    DEBUGASSERT(data->multi);
    if(data->multi->ipv6_up == IPV6_UNKNOWN) {
      bool works = Curl_ipv6works(NULL);
      data->multi->ipv6_up = works ? IPV6_WORKS : IPV6_DEAD;
    }
    return data->multi->ipv6_up == IPV6_WORKS;
  }
  else {
    int ipv6_works = -1;
    /* probe to see if we have a working IPv6 stack */
    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
    if(s == CURL_SOCKET_BAD)
      /* an IPv6 address was requested but we cannot get/use one */
      ipv6_works = 0;
    else {
      ipv6_works = 1;
      sclose(s);
    }
    return (ipv6_works>0)?TRUE:FALSE;
  }
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
    return FALSE;
  return strncasecompare(part, &full[flen - plen], plen);
}

/*
 * Curl_resolv() is the main name resolve function within libcurl. It resolves
 * a name and returns a pointer to the entry in the 'entry' argument (if one
 * is provided). This function might return immediately if we're using asynch
 * resolves. See the return codes.
 *
 * The cache entry we return will get its 'inuse' counter increased when this
 * function is used. You MUST call Curl_resolv_unlock() later (when you're
 * done using this struct) to decrease the counter again.
 *
 * Return codes:
 *
 * CURLRESOLV_ERROR   (-1) = error, no pointer
 * CURLRESOLV_RESOLVED (0) = OK, pointer provided
 * CURLRESOLV_PENDING  (1) = waiting for response, no pointer







|



|







658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
    return FALSE;
  return strncasecompare(part, &full[flen - plen], plen);
}

/*
 * Curl_resolv() is the main name resolve function within libcurl. It resolves
 * a name and returns a pointer to the entry in the 'entry' argument (if one
 * is provided). This function might return immediately if we are using asynch
 * resolves. See the return codes.
 *
 * The cache entry we return will get its 'inuse' counter increased when this
 * function is used. You MUST call Curl_resolv_unlock() later (when you are
 * done using this struct) to decrease the counter again.
 *
 * Return codes:
 *
 * CURLRESOLV_ERROR   (-1) = error, no pointer
 * CURLRESOLV_RESOLVED (0) = OK, pointer provided
 * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
        addr = Curl_getaddrinfo(data, hostname, port, &respwait);
      }
    }
    if(!addr) {
      if(respwait) {
        /* the response to our resolve call will come asynchronously at
           a later time, good or bad */
        /* First, check that we haven't received the info by now */
        result = Curl_resolv_check(data, &dns);
        if(result) /* error detected */
          return CURLRESOLV_ERROR;
        if(dns)
          rc = CURLRESOLV_RESOLVED; /* pointer provided */
        else
          rc = CURLRESOLV_PENDING; /* no info yet */







|







809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
        addr = Curl_getaddrinfo(data, hostname, port, &respwait);
      }
    }
    if(!addr) {
      if(respwait) {
        /* the response to our resolve call will come asynchronously at
           a later time, good or bad */
        /* First, check that we have not received the info by now */
        result = Curl_resolv_check(data, &dns);
        if(result) /* error detected */
          return CURLRESOLV_ERROR;
        if(dns)
          rc = CURLRESOLV_RESOLVED; /* pointer provided */
        else
          rc = CURLRESOLV_PENDING; /* no info yet */
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878

  return rc;
}

#ifdef USE_ALARM_TIMEOUT
/*
 * This signal handler jumps back into the main libcurl code and continues
 * execution.  This effectively causes the remainder of the application to run
 * within a signal handler which is nonportable and could lead to problems.
 */
CURL_NORETURN static
void alarmfunc(int sig)
{
  (void)sig;
  siglongjmp(curl_jmpenv, 1);
}
#endif /* USE_ALARM_TIMEOUT */

/*
 * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
 * timeout.  This function might return immediately if we're using asynch
 * resolves. See the return codes.
 *
 * The cache entry we return will get its 'inuse' counter increased when this
 * function is used. You MUST call Curl_resolv_unlock() later (when you're
 * done using this struct) to decrease the counter again.
 *
 * If built with a synchronous resolver and use of signals is not
 * disabled by the application, then a nonzero timeout will cause a
 * timeout after the specified number of milliseconds. Otherwise, timeout
 * is ignored.
 *







|












|



|







847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878

  return rc;
}

#ifdef USE_ALARM_TIMEOUT
/*
 * This signal handler jumps back into the main libcurl code and continues
 * execution. This effectively causes the remainder of the application to run
 * within a signal handler which is nonportable and could lead to problems.
 */
CURL_NORETURN static
void alarmfunc(int sig)
{
  (void)sig;
  siglongjmp(curl_jmpenv, 1);
}
#endif /* USE_ALARM_TIMEOUT */

/*
 * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
 * timeout. This function might return immediately if we are using asynch
 * resolves. See the return codes.
 *
 * The cache entry we return will get its 'inuse' counter increased when this
 * function is used. You MUST call Curl_resolv_unlock() later (when you are
 * done using this struct) to decrease the counter again.
 *
 * If built with a synchronous resolver and use of signals is not
 * disabled by the application, then a nonzero timeout will cause a
 * timeout after the specified number of milliseconds. Otherwise, timeout
 * is ignored.
 *
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
        timeout);
    return CURLRESOLV_TIMEDOUT;
  }
  /* This allows us to time-out from the name resolver, as the timeout
     will generate a signal and we will siglongjmp() from that here.
     This technique has problems (see alarmfunc).
     This should be the last thing we do before calling Curl_resolv(),
     as otherwise we'd have to worry about variables that get modified
     before we invoke Curl_resolv() (and thus use "volatile"). */
  curl_simple_lock_lock(&curl_jmpenv_lock);

  if(sigsetjmp(curl_jmpenv, 1)) {
    /* this is coming from a siglongjmp() after an alarm signal */
    failf(data, "name lookup timed out");
    rc = CURLRESOLV_ERROR;
    goto clean_up;
  }
  else {
    /*************************************************************
     * Set signal handler to catch SIGALRM
     * Store the old value to be able to set it back later!
     *************************************************************/
#ifdef HAVE_SIGACTION
    sigaction(SIGALRM, NULL, &sigact);
    keep_sigact = sigact;
    keep_copysig = TRUE; /* yes, we have a copy */
    sigact.sa_handler = alarmfunc;
#ifdef SA_RESTART
    /* HPUX doesn't have SA_RESTART but defaults to that behavior! */
    sigact.sa_flags &= ~SA_RESTART;
#endif
    /* now set the new struct */
    sigaction(SIGALRM, &sigact, NULL);
#else /* HAVE_SIGACTION */
    /* no sigaction(), revert to the much lamer signal() */
#ifdef HAVE_SIGNAL







|




















|







930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
        timeout);
    return CURLRESOLV_TIMEDOUT;
  }
  /* This allows us to time-out from the name resolver, as the timeout
     will generate a signal and we will siglongjmp() from that here.
     This technique has problems (see alarmfunc).
     This should be the last thing we do before calling Curl_resolv(),
     as otherwise we would have to worry about variables that get modified
     before we invoke Curl_resolv() (and thus use "volatile"). */
  curl_simple_lock_lock(&curl_jmpenv_lock);

  if(sigsetjmp(curl_jmpenv, 1)) {
    /* this is coming from a siglongjmp() after an alarm signal */
    failf(data, "name lookup timed out");
    rc = CURLRESOLV_ERROR;
    goto clean_up;
  }
  else {
    /*************************************************************
     * Set signal handler to catch SIGALRM
     * Store the old value to be able to set it back later!
     *************************************************************/
#ifdef HAVE_SIGACTION
    sigaction(SIGALRM, NULL, &sigact);
    keep_sigact = sigact;
    keep_copysig = TRUE; /* yes, we have a copy */
    sigact.sa_handler = alarmfunc;
#ifdef SA_RESTART
    /* HPUX does not have SA_RESTART but defaults to that behavior! */
    sigact.sa_flags &= ~SA_RESTART;
#endif
    /* now set the new struct */
    sigaction(SIGALRM, &sigact, NULL);
#else /* HAVE_SIGACTION */
    /* no sigaction(), revert to the much lamer signal() */
#ifdef HAVE_SIGNAL
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
    /* the alarm period is counted in even number of seconds */
    unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs);

    if(!alarm_set ||
       ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
      /* if the alarm time-left reached zero or turned "negative" (counted
         with unsigned values), we should fire off a SIGALRM here, but we
         won't, and zero would be to switch it off so we never set it to
         less than 1! */
      alarm(1);
      rc = CURLRESOLV_TIMEDOUT;
      failf(data, "Previous alarm fired off");
    }
    else
      alarm((unsigned int)alarm_set);







|







1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
    /* the alarm period is counted in even number of seconds */
    unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs);

    if(!alarm_set ||
       ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
      /* if the alarm time-left reached zero or turned "negative" (counted
         with unsigned values), we should fire off a SIGALRM here, but we
         will not, and zero would be to switch it off so we never set it to
         less than 1! */
      alarm(1);
      rc = CURLRESOLV_TIMEDOUT;
      failf(data, "Previous alarm fired off");
    }
    else
      alarm((unsigned int)alarm_set);
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
      }
      /* Create an entry id, based upon the hostname and port */
      entry_len = create_hostcache_id(&hostp->data[1], hlen, (int)num,
                                      entry_id, sizeof(entry_id));
      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* delete entry, ignore if it didn't exist */
      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
    }
    else {
      struct Curl_dns_entry *dns;







|







1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
      }
      /* Create an entry id, based upon the hostname and port */
      entry_len = create_hostcache_id(&hostp->data[1], hlen, (int)num,
                                      entry_id, sizeof(entry_id));
      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* delete entry, ignore if it did not exist */
      Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);

      if(data->share)
        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
    }
    else {
      struct Curl_dns_entry *dns;
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
      /* Create an entry id, based upon the hostname and port */
      entry_len = create_hostcache_id(host_begin, hlen, port,
                                      entry_id, sizeof(entry_id));

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* See if it's already in our dns cache */
      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);

      if(dns) {
        infof(data, "RESOLVE %.*s:%d - old addresses discarded",
              (int)hlen, host_begin, port);
        /* delete old entry, there are two reasons for this
         1. old entry may have different addresses.







|







1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
      /* Create an entry id, based upon the hostname and port */
      entry_len = create_hostcache_id(host_begin, hlen, port,
                                      entry_id, sizeof(entry_id));

      if(data->share)
        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);

      /* See if it is already in our dns cache */
      dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);

      if(dns) {
        infof(data, "RESOLVE %.*s:%d - old addresses discarded",
              (int)hlen, host_begin, port);
        /* delete old entry, there are two reasons for this
         1. old entry may have different addresses.
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
      struct dynbuf *d = &out[(a->ai_family != PF_INET)];
      Curl_printable_address(a, buf, sizeof(buf));
      if(Curl_dyn_len(d))
        result = Curl_dyn_addn(d, ", ", 2);
      if(!result)
        result = Curl_dyn_add(d, buf);
      if(result) {
        infof(data, "too many IP, can't show");
        goto fail;
      }
    }
    a = a->ai_next;
  }

#ifdef CURLRES_IPV6







|







1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
      struct dynbuf *d = &out[(a->ai_family != PF_INET)];
      Curl_printable_address(a, buf, sizeof(buf));
      if(Curl_dyn_len(d))
        result = Curl_dyn_addn(d, ", ", 2);
      if(!result)
        result = Curl_dyn_add(d, buf);
      if(result) {
        infof(data, "too many IP, cannot show");
        goto fail;
      }
    }
    a = a->ai_next;
  }

#ifdef CURLRES_IPV6
Changes to jni/curl/lib/hostip.h.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
   * https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
   */
  uint16_t priority;
  char *target;
  char *alpns; /* keytag = 1 */
  bool no_def_alpn; /* keytag = 2 */
  /*
   * we don't support ports (keytag = 3) as we don't support
   * port-switching yet
   */
  unsigned char *ipv4hints; /* keytag = 4 */
  size_t ipv4hints_len;
  unsigned char *echconfiglist; /* keytag = 5 */
  size_t echconfiglist_len;
  unsigned char *ipv6hints; /* keytag = 6 */
  size_t ipv6hints_len;
};
#endif

struct Curl_dns_entry {
  struct Curl_addrinfo *addr;
#ifdef USE_HTTPSRR
  struct Curl_https_rrinfo *hinfo;
#endif
  /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
  time_t timestamp;
  /* use-counter, use Curl_resolv_unlock to release reference */
  long inuse;
  /* hostname port number that resolved to addr. */
  int hostport;
  /* hostname that resolved to addr. may be NULL (unix domain sockets). */
  char hostname[1];
};

bool Curl_host_is_ipnum(const char *hostname);

/*
 * Curl_resolv() returns an entry with the info for the specified host
 * and port.
 *
 * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
 * use, or we'll leak memory!
 */
/* return codes */
enum resolve_t {
  CURLRESOLV_TIMEDOUT = -2,
  CURLRESOLV_ERROR    = -1,
  CURLRESOLV_RESOLVED =  0,
  CURLRESOLV_PENDING  =  1







|
















|
















|







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
   * https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
   */
  uint16_t priority;
  char *target;
  char *alpns; /* keytag = 1 */
  bool no_def_alpn; /* keytag = 2 */
  /*
   * we do not support ports (keytag = 3) as we do not support
   * port-switching yet
   */
  unsigned char *ipv4hints; /* keytag = 4 */
  size_t ipv4hints_len;
  unsigned char *echconfiglist; /* keytag = 5 */
  size_t echconfiglist_len;
  unsigned char *ipv6hints; /* keytag = 6 */
  size_t ipv6hints_len;
};
#endif

struct Curl_dns_entry {
  struct Curl_addrinfo *addr;
#ifdef USE_HTTPSRR
  struct Curl_https_rrinfo *hinfo;
#endif
  /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (does not time out) */
  time_t timestamp;
  /* use-counter, use Curl_resolv_unlock to release reference */
  long inuse;
  /* hostname port number that resolved to addr. */
  int hostport;
  /* hostname that resolved to addr. may be NULL (unix domain sockets). */
  char hostname[1];
};

bool Curl_host_is_ipnum(const char *hostname);

/*
 * Curl_resolv() returns an entry with the info for the specified host
 * and port.
 *
 * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
 * use, or we will leak memory!
 */
/* return codes */
enum resolve_t {
  CURLRESOLV_TIMEDOUT = -2,
  CURLRESOLV_ERROR    = -1,
  CURLRESOLV_RESOLVED =  0,
  CURLRESOLV_PENDING  =  1
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210

/*
 * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
 *
 * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
 *
 * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
 * use, or we'll leak memory!
 */
struct Curl_dns_entry *
Curl_fetch_addr(struct Curl_easy *data,
                const char *hostname,
                int port);

/*







|







196
197
198
199
200
201
202
203
204
205
206
207
208
209
210

/*
 * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
 *
 * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
 *
 * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
 * use, or we will leak memory!
 */
struct Curl_dns_entry *
Curl_fetch_addr(struct Curl_easy *data,
                const char *hostname,
                int port);

/*
Changes to jni/curl/lib/hostip4.c.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
 * been set and returns TRUE if they are OK.
 */
bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
{
  (void)data;
  if(conn->ip_version == CURL_IPRESOLVE_V6)
    /* An IPv6 address was requested and we can't get/use one */
    return FALSE;

  return TRUE; /* OK, proceed */
}

#ifdef CURLRES_SYNCH








|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
 * been set and returns TRUE if they are OK.
 */
bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
{
  (void)data;
  if(conn->ip_version == CURL_IPRESOLVE_V6)
    /* An IPv6 address was requested and we cannot get/use one */
    return FALSE;

  return TRUE; /* OK, proceed */
}

#ifdef CURLRES_SYNCH

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
                      &h, /* DIFFERENCE */
                      &h_errnop);
  /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
   * sudden this function returns EAGAIN if the given buffer size is too
   * small. Previous versions are known to return ERANGE for the same
   * problem.
   *
   * This wouldn't be such a big problem if older versions wouldn't
   * sometimes return EAGAIN on a common failure case. Alas, we can't
   * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
   * glibc.
   *
   * For now, we do that and thus we may call the function repeatedly and
   * fail for older glibc versions that return EAGAIN, until we run out of
   * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
   *
   * If anyone has a better fix, please tell us!
   *
   * -------------------------------------------------------------------
   *
   * On October 23rd 2003, Dan C dug up more details on the mysteries of
   * gethostbyname_r() in glibc:
   *
   * In glibc 2.2.5 the interface is different (this has also been
   * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
   * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
   * (shipped/upgraded by Redhat 7.2) don't show this behavior!
   *
   * In this "buggy" version, the return code is -1 on error and 'errno'
   * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
   * thread-safe variable.
   */

  if(!h) /* failure */
#elif defined(HAVE_GETHOSTBYNAME_R_3)
  /* AIX, Digital Unix/Tru64, HPUX 10, more? */

  /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
   * the plain fact that it does not return unique full buffers on each
   * call, but instead several of the pointers in the hostent structs will
   * point to the same actual data! This have the unfortunate down-side that
   * our caching system breaks down horribly. Luckily for us though, AIX 4.3
   * and more recent versions have a "completely thread-safe"[*] libc where
   * all the data is stored in thread-specific memory areas making calls to
   * the plain old gethostbyname() work fine even for multi-threaded
   * programs.
   *
   * This AIX 4.3 or later detection is all made in the configure script.
   *
   * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
   *
   * [*] = much later we've found out that it isn't at all "completely
   * thread-safe", but at least the gethostbyname() function is.
   */

  if(CURL_HOSTENT_SIZE >=
     (sizeof(struct hostent) + sizeof(struct hostent_data))) {

    /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
     * that should work! September 20: Richard Prescott worked on the buffer
     * size dilemma.
     */

    res = gethostbyname_r(hostname,
                          (struct hostent *)buf,
                          (struct hostent_data *)((char *)buf +
                                                  sizeof(struct hostent)));
    h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
  }
  else
    res = -1; /* failure, too smallish buffer size */

  if(!res) { /* success */

    h = buf; /* result expected in h */

    /* This is the worst kind of the different gethostbyname_r() interfaces.
     * Since we don't know how big buffer this particular lookup required,
     * we can't realloc down the huge alloc without doing closer analysis of
     * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
     * name lookup. Fixing this would require an extra malloc() and then
     * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
     * memory area to the actually used amount.
     */
  }
  else
#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
  {
    h = NULL; /* set return code to NULL */
    free(buf);
  }
#else /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
          HAVE_GETHOSTBYNAME_R */
  /*
   * Here is code for platforms that don't have a thread safe
   * getaddrinfo() nor gethostbyname_r() function or for which
   * gethostbyname() is the preferred one.
   */
  h = gethostbyname((void *)hostname);
#endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
           HAVE_GETHOSTBYNAME_R */








|
|















|

|










|













|















|









|
|















|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
                      &h, /* DIFFERENCE */
                      &h_errnop);
  /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
   * sudden this function returns EAGAIN if the given buffer size is too
   * small. Previous versions are known to return ERANGE for the same
   * problem.
   *
   * This would not be such a big problem if older versions would not
   * sometimes return EAGAIN on a common failure case. Alas, we cannot
   * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
   * glibc.
   *
   * For now, we do that and thus we may call the function repeatedly and
   * fail for older glibc versions that return EAGAIN, until we run out of
   * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
   *
   * If anyone has a better fix, please tell us!
   *
   * -------------------------------------------------------------------
   *
   * On October 23rd 2003, Dan C dug up more details on the mysteries of
   * gethostbyname_r() in glibc:
   *
   * In glibc 2.2.5 the interface is different (this has also been
   * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I cannot
   * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
   * (shipped/upgraded by Redhat 7.2) do not show this behavior!
   *
   * In this "buggy" version, the return code is -1 on error and 'errno'
   * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
   * thread-safe variable.
   */

  if(!h) /* failure */
#elif defined(HAVE_GETHOSTBYNAME_R_3)
  /* AIX, Digital Unix/Tru64, HPUX 10, more? */

  /* For AIX 4.3 or later, we do not use gethostbyname_r() at all, because of
   * the plain fact that it does not return unique full buffers on each
   * call, but instead several of the pointers in the hostent structs will
   * point to the same actual data! This have the unfortunate down-side that
   * our caching system breaks down horribly. Luckily for us though, AIX 4.3
   * and more recent versions have a "completely thread-safe"[*] libc where
   * all the data is stored in thread-specific memory areas making calls to
   * the plain old gethostbyname() work fine even for multi-threaded
   * programs.
   *
   * This AIX 4.3 or later detection is all made in the configure script.
   *
   * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
   *
   * [*] = much later we have found out that it is not at all "completely
   * thread-safe", but at least the gethostbyname() function is.
   */

  if(CURL_HOSTENT_SIZE >=
     (sizeof(struct hostent) + sizeof(struct hostent_data))) {

    /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
     * that should work! September 20: Richard Prescott worked on the buffer
     * size dilemma.
     */

    res = gethostbyname_r(hostname,
                          (struct hostent *)buf,
                          (struct hostent_data *)((char *)buf +
                                                  sizeof(struct hostent)));
    h_errnop = SOCKERRNO; /* we do not deal with this, but set it anyway */
  }
  else
    res = -1; /* failure, too smallish buffer size */

  if(!res) { /* success */

    h = buf; /* result expected in h */

    /* This is the worst kind of the different gethostbyname_r() interfaces.
     * Since we do not know how big buffer this particular lookup required,
     * we cannot realloc down the huge alloc without doing closer analysis of
     * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
     * name lookup. Fixing this would require an extra malloc() and then
     * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
     * memory area to the actually used amount.
     */
  }
  else
#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
  {
    h = NULL; /* set return code to NULL */
    free(buf);
  }
#else /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
          HAVE_GETHOSTBYNAME_R */
  /*
   * Here is code for platforms that do not have a thread safe
   * getaddrinfo() nor gethostbyname_r() function or for which
   * gethostbyname() is the preferred one.
   */
  h = gethostbyname((void *)hostname);
#endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
           HAVE_GETHOSTBYNAME_R */

Changes to jni/curl/lib/hsts.c.
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#define MAX_HSTS_LINE 4095
#define MAX_HSTS_HOSTLEN 256
#define MAX_HSTS_HOSTLENSTR "256"
#define MAX_HSTS_DATELEN 64
#define MAX_HSTS_DATELENSTR "64"
#define UNLIMITED "unlimited"

#ifdef DEBUGBUILD
/* to play well with debug builds, we can *set* a fixed time this will
   return */
time_t deltatime; /* allow for "adjustments" for unit test purposes */
static time_t hsts_debugtime(void *unused)
{
  char *timestr = getenv("CURL_TIME");
  (void)unused;







|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#define MAX_HSTS_LINE 4095
#define MAX_HSTS_HOSTLEN 256
#define MAX_HSTS_HOSTLENSTR "256"
#define MAX_HSTS_DATELEN 64
#define MAX_HSTS_DATELENSTR "64"
#define UNLIMITED "unlimited"

#if defined(DEBUGBUILD) || defined(UNITTESTS)
/* to play well with debug builds, we can *set* a fixed time this will
   return */
time_t deltatime; /* allow for "adjustments" for unit test purposes */
static time_t hsts_debugtime(void *unused)
{
  char *timestr = getenv("CURL_TIME");
  (void)unused;
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  else
    return hsts_create(h, hostname, subdomains, expires);

  return CURLE_OK;
}

/*
 * Return TRUE if the given host name is currently an HSTS one.
 *
 * The 'subdomain' argument tells the function if subdomain matching should be
 * attempted.
 */
struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
                           bool subdomain)
{







|







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  else
    return hsts_create(h, hostname, subdomains, expires);

  return CURLE_OK;
}

/*
 * Return TRUE if the given hostname is currently an HSTS one.
 *
 * The 'subdomain' argument tells the function if subdomain matching should be
 * attempted.
 */
struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
                           bool subdomain)
{
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
    return CURLE_OK;

  /* if no new name is given, use the one we stored from the load */
  if(!file && h->filename)
    file = h->filename;

  if((h->flags & CURLHSTS_READONLYFILE) || !file || !file[0])
    /* marked as read-only, no file or zero length file name */
    goto skipsave;

  result = Curl_fopen(data, file, &out, &tempstore);
  if(!result) {
    fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n"
          "# This file was generated by libcurl! Edit at your own risk.\n",
          out);







|







364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
    return CURLE_OK;

  /* if no new name is given, use the one we stored from the load */
  if(!file && h->filename)
    file = h->filename;

  if((h->flags & CURLHSTS_READONLYFILE) || !file || !file[0])
    /* marked as read-only, no file or zero length filename */
    goto skipsave;

  result = Curl_fopen(data, file, &out, &tempstore);
  if(!result) {
    fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n"
          "# This file was generated by libcurl! Edit at your own risk.\n",
          out);
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403

    if(result && tempstore)
      unlink(tempstore);
  }
  free(tempstore);
skipsave:
  if(data->set.hsts_write) {
    /* if there's a write callback */
    struct curl_index i; /* count */
    i.total = h->list.size;
    i.index = 0;
    for(e = h->list.head; e; e = n) {
      struct stsentry *sts = e->ptr;
      bool stop;
      n = e->next;







|







389
390
391
392
393
394
395
396
397
398
399
400
401
402
403

    if(result && tempstore)
      unlink(tempstore);
  }
  free(tempstore);
skipsave:
  if(data->set.hsts_write) {
    /* if there is a write callback */
    struct curl_index i; /* count */
    i.total = h->list.size;
    i.index = 0;
    for(e = h->list.head; e; e = n) {
      struct stsentry *sts = e->ptr;
      bool stop;
      n = e->next;
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
      subdomain = TRUE;
    }
    /* only add it if not already present */
    e = Curl_hsts(h, p, subdomain);
    if(!e)
      result = hsts_create(h, p, subdomain, expires);
    else {
      /* the same host name, use the largest expire time */
      if(expires > e->expires)
        e->expires = expires;
    }
    if(result)
      return result;
  }








|







436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
      subdomain = TRUE;
    }
    /* only add it if not already present */
    e = Curl_hsts(h, p, subdomain);
    if(!e)
      result = hsts_create(h, p, subdomain, expires);
    else {
      /* the same hostname, use the largest expire time */
      if(expires > e->expires)
        e->expires = expires;
    }
    if(result)
      return result;
  }

504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
 * etc.
 */
static CURLcode hsts_load(struct hsts *h, const char *file)
{
  CURLcode result = CURLE_OK;
  FILE *fp;

  /* we need a private copy of the file name so that the hsts cache file
     name survives an easy handle reset */
  free(h->filename);
  h->filename = strdup(file);
  if(!h->filename)
    return CURLE_OUT_OF_MEMORY;

  fp = fopen(file, FOPEN_READTEXT);







|







504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
 * etc.
 */
static CURLcode hsts_load(struct hsts *h, const char *file)
{
  CURLcode result = CURLE_OK;
  FILE *fp;

  /* we need a private copy of the filename so that the hsts cache file
     name survives an easy handle reset */
  free(h->filename);
  h->filename = strdup(file);
  if(!h->filename)
    return CURLE_OUT_OF_MEMORY;

  fp = fopen(file, FOPEN_READTEXT);
Changes to jni/curl/lib/hsts.h.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 ***************************************************************************/
#include "curl_setup.h"

#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
#include <curl/curl.h>
#include "llist.h"

#ifdef DEBUGBUILD
extern time_t deltatime;
#endif

struct stsentry {
  struct Curl_llist_element node;
  const char *host;
  bool includeSubDomains;
  curl_off_t expires; /* the timestamp of this entry's expiry */
};

/* The HSTS cache. Needs to be able to tailmatch host names. */
struct hsts {
  struct Curl_llist list;
  char *filename;
  unsigned int flags;
};

struct hsts *Curl_hsts_init(void);







|










|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 ***************************************************************************/
#include "curl_setup.h"

#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
#include <curl/curl.h>
#include "llist.h"

#if defined(DEBUGBUILD) || defined(UNITTESTS)
extern time_t deltatime;
#endif

struct stsentry {
  struct Curl_llist_element node;
  const char *host;
  bool includeSubDomains;
  curl_off_t expires; /* the timestamp of this entry's expiry */
};

/* The HSTS cache. Needs to be able to tailmatch hostnames. */
struct hsts {
  struct Curl_llist list;
  char *filename;
  unsigned int flags;
};

struct hsts *Curl_hsts_init(void);
Changes to jni/curl/lib/http.c.
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#endif

CURLcode Curl_http_setup_conn(struct Curl_easy *data,
                              struct connectdata *conn)
{
  /* allocate the HTTP-specific struct for the Curl_easy, only to survive
     during this request */
  struct HTTP *http;
  DEBUGASSERT(data->req.p.http == NULL);

  http = calloc(1, sizeof(struct HTTP));
  if(!http)
    return CURLE_OUT_OF_MEMORY;

  data->req.p.http = http;
  connkeep(conn, "HTTP default");

  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
    CURLcode result = Curl_conn_may_http3(data, conn);
    if(result)
      return result;
  }







<
<
<
<
<
<
<
<







165
166
167
168
169
170
171








172
173
174
175
176
177
178
#endif

CURLcode Curl_http_setup_conn(struct Curl_easy *data,
                              struct connectdata *conn)
{
  /* allocate the HTTP-specific struct for the Curl_easy, only to survive
     during this request */








  connkeep(conn, "HTTP default");

  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
    CURLcode result = Curl_conn_may_http3(data, conn);
    if(result)
      return result;
  }
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
                                   struct connectdata *conn)
{
  curl_off_t bytessent = data->req.writebytecount;
  curl_off_t expectsend = Curl_creader_total_length(data);
  curl_off_t upload_remain = (expectsend >= 0)? (expectsend - bytessent) : -1;
  bool little_upload_remains = (upload_remain >= 0 && upload_remain < 2000);
  bool needs_rewind = Curl_creader_needs_rewind(data);
  /* By default, we'd like to abort the transfer when little or
   * unknown amount remains. But this may be overridden by authentications
   * further below! */
  bool abort_upload = (!data->req.upload_done && !little_upload_remains);
  const char *ongoing_auth = NULL;

  /* We need a rewind before uploading client read data again. The
   * checks below just influence of the upload is to be continued
   * or aborted early.
   * This depends on how much remains to be sent and in what state







|
|
|







406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
                                   struct connectdata *conn)
{
  curl_off_t bytessent = data->req.writebytecount;
  curl_off_t expectsend = Curl_creader_total_length(data);
  curl_off_t upload_remain = (expectsend >= 0)? (expectsend - bytessent) : -1;
  bool little_upload_remains = (upload_remain >= 0 && upload_remain < 2000);
  bool needs_rewind = Curl_creader_needs_rewind(data);
  /* By default, we would like to abort the transfer when little or unknown
   * amount remains. This may be overridden by authentications further
   * below! */
  bool abort_upload = (!data->req.upload_done && !little_upload_remains);
  const char *ongoing_auth = NULL;

  /* We need a rewind before uploading client read data again. The
   * checks below just influence of the upload is to be continued
   * or aborted early.
   * This depends on how much remains to be sent and in what state
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
      infof(data, "%s%sclose instead of sending unknown amount "
        "of more bytes",
        ongoing_auth? ongoing_auth : "",
        ongoing_auth? " send, " : "");
    /* We decided to abort the ongoing transfer */
    streamclose(conn, "Mid-auth HTTP and much data left to send");
    /* FIXME: questionable manipulation here, can we do this differently? */
    data->req.size = 0; /* don't download any more than 0 bytes */
  }
  return CURLE_OK;
}

/*
 * Curl_http_auth_act() gets called when all HTTP headers have been received
 * and it checks what authentication methods that are available and decides







|







471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
      infof(data, "%s%sclose instead of sending unknown amount "
        "of more bytes",
        ongoing_auth? ongoing_auth : "",
        ongoing_auth? " send, " : "");
    /* We decided to abort the ongoing transfer */
    streamclose(conn, "Mid-auth HTTP and much data left to send");
    /* FIXME: questionable manipulation here, can we do this differently? */
    data->req.size = 0; /* do not download any more than 0 bytes */
  }
  return CURLE_OK;
}

/*
 * Curl_http_auth_act() gets called when all HTTP headers have been received
 * and it checks what authentication methods that are available and decides
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
  }
  else if((data->req.httpcode < 300) &&
          (!data->state.authhost.done) &&
          data->req.authneg) {
    /* no (known) authentication available,
       authentication is not "done" yet and
       no authentication seems to be required and
       we didn't try HEAD or GET */
    if((data->state.httpreq != HTTPREQ_GET) &&
       (data->state.httpreq != HTTPREQ_HEAD)) {
      data->req.newurl = strdup(data->state.url); /* clone URL */
      if(!data->req.newurl)
        return CURLE_OUT_OF_MEMORY;
      data->state.authhost.done = TRUE;
    }







|







544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  }
  else if((data->req.httpcode < 300) &&
          (!data->state.authhost.done) &&
          data->req.authneg) {
    /* no (known) authentication available,
       authentication is not "done" yet and
       no authentication seems to be required and
       we did not try HEAD or GET */
    if((data->state.httpreq != HTTPREQ_GET) &&
       (data->state.httpreq != HTTPREQ_HEAD)) {
      data->req.newurl = strdup(data->state.url); /* clone URL */
      if(!data->req.newurl)
        return CURLE_OUT_OF_MEMORY;
      data->state.authhost.done = TRUE;
    }
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
    authproxy->done = TRUE;
    return CURLE_OK; /* no authentication with no user or password */
  }

  if(authhost->want && !authhost->picked)
    /* The app has selected one or more methods, but none has been picked
       so far by a server round-trip. Then we set the picked one to the
       want one, and if this is one single bit it'll be used instantly. */
    authhost->picked = authhost->want;

  if(authproxy->want && !authproxy->picked)
    /* The app has selected one or more methods, but none has been picked so
       far by a proxy round-trip. Then we set the picked one to the want one,
       and if this is one single bit it'll be used instantly. */
    authproxy->picked = authproxy->want;

#ifndef CURL_DISABLE_PROXY
  /* Send proxy authentication header if needed */
  if(conn->bits.httpproxy &&
     (conn->bits.tunnel_proxy == (bit)proxytunnel)) {
    result = output_auth_headers(data, conn, authproxy, request, path, TRUE);
    if(result)
      return result;
  }
  else
#else
  (void)proxytunnel;
#endif /* CURL_DISABLE_PROXY */
    /* we have no proxy so let's pretend we're done authenticating
       with it */
    authproxy->done = TRUE;

  /* To prevent the user+password to get sent to other than the original host
     due to a location-follow */
  if(Curl_auth_allowed_to_host(data)
#ifndef CURL_DISABLE_NETRC







|





|














|







734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
    authproxy->done = TRUE;
    return CURLE_OK; /* no authentication with no user or password */
  }

  if(authhost->want && !authhost->picked)
    /* The app has selected one or more methods, but none has been picked
       so far by a server round-trip. Then we set the picked one to the
       want one, and if this is one single bit it will be used instantly. */
    authhost->picked = authhost->want;

  if(authproxy->want && !authproxy->picked)
    /* The app has selected one or more methods, but none has been picked so
       far by a proxy round-trip. Then we set the picked one to the want one,
       and if this is one single bit it will be used instantly. */
    authproxy->picked = authproxy->want;

#ifndef CURL_DISABLE_PROXY
  /* Send proxy authentication header if needed */
  if(conn->bits.httpproxy &&
     (conn->bits.tunnel_proxy == (bit)proxytunnel)) {
    result = output_auth_headers(data, conn, authproxy, request, path, TRUE);
    if(result)
      return result;
  }
  else
#else
  (void)proxytunnel;
#endif /* CURL_DISABLE_PROXY */
    /* we have no proxy so let's pretend we are done authenticating
       with it */
    authproxy->done = TRUE;

  /* To prevent the user+password to get sent to other than the original host
     due to a location-follow */
  if(Curl_auth_allowed_to_host(data)
#ifndef CURL_DISABLE_NETRC
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
          else if(Curl_auth_is_digest_supported()) {
            CURLcode result;

            *availp |= CURLAUTH_DIGEST;
            authp->avail |= CURLAUTH_DIGEST;

            /* We call this function on input Digest headers even if Digest
             * authentication isn't activated yet, as we need to store the
             * incoming data from this header in case we are going to use
             * Digest */
            result = Curl_input_digest(data, proxy, auth);
            if(result) {
              infof(data, "Authentication problem. Ignoring this.");
              data->state.authproblem = TRUE;
            }
          }
        }
        else
#endif
#ifndef CURL_DISABLE_BASIC_AUTH
          if(checkprefix("Basic", auth) &&
             is_valid_auth_separator(auth[5])) {
            *availp |= CURLAUTH_BASIC;
            authp->avail |= CURLAUTH_BASIC;
            if(authp->picked == CURLAUTH_BASIC) {
              /* We asked for Basic authentication but got a 40X back
                 anyway, which basically means our name+password isn't
                 valid. */
              authp->avail = CURLAUTH_NONE;
              infof(data, "Authentication problem. Ignoring this.");
              data->state.authproblem = TRUE;
            }
          }
          else
#endif
#ifndef CURL_DISABLE_BEARER_AUTH
            if(checkprefix("Bearer", auth) &&
               is_valid_auth_separator(auth[6])) {
              *availp |= CURLAUTH_BEARER;
              authp->avail |= CURLAUTH_BEARER;
              if(authp->picked == CURLAUTH_BEARER) {
                /* We asked for Bearer authentication but got a 40X back
                  anyway, which basically means our token isn't valid. */
                authp->avail = CURLAUTH_NONE;
                infof(data, "Authentication problem. Ignoring this.");
                data->state.authproblem = TRUE;
              }
            }
#else
            {
              /*
               * Empty block to terminate the if-else chain correctly.
               *
               * A semicolon would yield the same result here, but can cause a
               * compiler warning when -Wextra is enabled.
               */
            }
#endif

    /* there may be multiple methods on one line, so keep reading */
    while(*auth && *auth != ',') /* read up to the next comma */
      auth++;
    if(*auth == ',') /* if we're on a comma, skip it */
      auth++;
    while(*auth && ISSPACE(*auth))
      auth++;
  }

  return CURLE_OK;
}







|


















|















|



















|







929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
          else if(Curl_auth_is_digest_supported()) {
            CURLcode result;

            *availp |= CURLAUTH_DIGEST;
            authp->avail |= CURLAUTH_DIGEST;

            /* We call this function on input Digest headers even if Digest
             * authentication is not activated yet, as we need to store the
             * incoming data from this header in case we are going to use
             * Digest */
            result = Curl_input_digest(data, proxy, auth);
            if(result) {
              infof(data, "Authentication problem. Ignoring this.");
              data->state.authproblem = TRUE;
            }
          }
        }
        else
#endif
#ifndef CURL_DISABLE_BASIC_AUTH
          if(checkprefix("Basic", auth) &&
             is_valid_auth_separator(auth[5])) {
            *availp |= CURLAUTH_BASIC;
            authp->avail |= CURLAUTH_BASIC;
            if(authp->picked == CURLAUTH_BASIC) {
              /* We asked for Basic authentication but got a 40X back
                 anyway, which basically means our name+password is not
                 valid. */
              authp->avail = CURLAUTH_NONE;
              infof(data, "Authentication problem. Ignoring this.");
              data->state.authproblem = TRUE;
            }
          }
          else
#endif
#ifndef CURL_DISABLE_BEARER_AUTH
            if(checkprefix("Bearer", auth) &&
               is_valid_auth_separator(auth[6])) {
              *availp |= CURLAUTH_BEARER;
              authp->avail |= CURLAUTH_BEARER;
              if(authp->picked == CURLAUTH_BEARER) {
                /* We asked for Bearer authentication but got a 40X back
                  anyway, which basically means our token is not valid. */
                authp->avail = CURLAUTH_NONE;
                infof(data, "Authentication problem. Ignoring this.");
                data->state.authproblem = TRUE;
              }
            }
#else
            {
              /*
               * Empty block to terminate the if-else chain correctly.
               *
               * A semicolon would yield the same result here, but can cause a
               * compiler warning when -Wextra is enabled.
               */
            }
#endif

    /* there may be multiple methods on one line, so keep reading */
    while(*auth && *auth != ',') /* read up to the next comma */
      auth++;
    if(*auth == ',') /* if we are on a comma, skip it */
      auth++;
    while(*auth && ISSPACE(*auth))
      auth++;
  }

  return CURLE_OK;
}
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
 */
static bool http_should_fail(struct Curl_easy *data, int httpcode)
{
  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);

  /*
  ** If we haven't been asked to fail on error,
  ** don't fail.
  */
  if(!data->set.http_fail_on_error)
    return FALSE;

  /*
  ** Any code < 400 is never terminal.
  */
  if(httpcode < 400)
    return FALSE;

  /*
  ** A 416 response to a resume request is presumably because the file is
  ** already completely downloaded and thus not actually a fail.
  */
  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
     httpcode == 416)
    return FALSE;

  /*
  ** Any code >= 400 that's not 401 or 407 is always
  ** a terminal error
  */
  if((httpcode != 401) && (httpcode != 407))
    return TRUE;

  /*
  ** All we have left to deal with is 401 and 407
  */
  DEBUGASSERT((httpcode == 401) || (httpcode == 407));

  /*
  ** Examine the current authentication state to see if this
  ** is an error.  The idea is for this function to get
  ** called after processing all the headers in a response
  ** message.  So, if we've been to asked to authenticate a
  ** particular stage, and we've done it, we're OK.  But, if
  ** we're already completely authenticated, it's not OK to
  ** get another 401 or 407.
  **
  ** It is possible for authentication to go stale such that
  ** the client needs to reauthenticate.  Once that info is
  ** available, use it here.
  */

  /*
  ** Either we're not authenticating, or we're supposed to
  ** be authenticating something else.  This is an error.
  */
  if((httpcode == 401) && !data->state.aptr.user)
    return TRUE;
#ifndef CURL_DISABLE_PROXY
  if((httpcode == 407) && !data->conn->bits.proxy_user_passwd)
    return TRUE;
#endif







|
|



















|











|
<
|
|
|
<
|

|
<
|



|
|







1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047

1048
1049
1050

1051
1052
1053

1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
 */
static bool http_should_fail(struct Curl_easy *data, int httpcode)
{
  DEBUGASSERT(data);
  DEBUGASSERT(data->conn);

  /*
  ** If we have not been asked to fail on error,
  ** do not fail.
  */
  if(!data->set.http_fail_on_error)
    return FALSE;

  /*
  ** Any code < 400 is never terminal.
  */
  if(httpcode < 400)
    return FALSE;

  /*
  ** A 416 response to a resume request is presumably because the file is
  ** already completely downloaded and thus not actually a fail.
  */
  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
     httpcode == 416)
    return FALSE;

  /*
  ** Any code >= 400 that is not 401 or 407 is always
  ** a terminal error
  */
  if((httpcode != 401) && (httpcode != 407))
    return TRUE;

  /*
  ** All we have left to deal with is 401 and 407
  */
  DEBUGASSERT((httpcode == 401) || (httpcode == 407));

  /*
  ** Examine the current authentication state to see if this is an error. The

  ** idea is for this function to get called after processing all the headers
  ** in a response message. So, if we have been to asked to authenticate a
  ** particular stage, and we have done it, we are OK. If we are already

  ** completely authenticated, it is not OK to get another 401 or 407.
  **
  ** It is possible for authentication to go stale such that the client needs

  ** to reauthenticate. Once that info is available, use it here.
  */

  /*
  ** Either we are not authenticating, or we are supposed to be authenticating
  ** something else. This is an error.
  */
  if((httpcode == 401) && !data->state.aptr.user)
    return TRUE;
#ifndef CURL_DISABLE_PROXY
  if((httpcode == 407) && !data->conn->bits.proxy_user_passwd)
    return TRUE;
#endif
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
  const char *end;
  DEBUGASSERT(hlen);
  DEBUGASSERT(clen);
  DEBUGASSERT(header);
  DEBUGASSERT(content);

  if(!strncasecompare(headerline, header, hlen))
    return FALSE; /* doesn't start with header */

  /* pass the header */
  start = &headerline[hlen];

  /* pass all whitespace */
  while(*start && ISSPACE(*start))
    start++;

  /* find the end of the header line */
  end = strchr(start, '\r'); /* lines end with CRLF */
  if(!end) {
    /* in case there's a non-standard compliant line here */
    end = strchr(start, '\n');

    if(!end)
      /* hm, there's no line ending here, use the zero byte! */
      end = strchr(start, '\0');
  }

  len = end-start; /* length of the content part of the input line */

  /* find the content string in the rest of the line */
  for(; len >= clen; len--, start++) {







|











|



|







1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
  const char *end;
  DEBUGASSERT(hlen);
  DEBUGASSERT(clen);
  DEBUGASSERT(header);
  DEBUGASSERT(content);

  if(!strncasecompare(headerline, header, hlen))
    return FALSE; /* does not start with header */

  /* pass the header */
  start = &headerline[hlen];

  /* pass all whitespace */
  while(*start && ISSPACE(*start))
    start++;

  /* find the end of the header line */
  end = strchr(start, '\r'); /* lines end with CRLF */
  if(!end) {
    /* in case there is a non-standard compliant line here */
    end = strchr(start, '\n');

    if(!end)
      /* hm, there is no line ending here, use the zero byte! */
      end = strchr(start, '\0');
  }

  len = end-start; /* length of the content part of the input line */

  /* find the content string in the rest of the line */
  for(; len >= clen; len--, start++) {
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
     function to make the reuse checks properly be able to check this bit. */
  connkeep(conn, "HTTP default");

  return Curl_conn_connect(data, FIRSTSOCKET, FALSE, done);
}

/* this returns the socket to wait for in the DO and DOING state for the multi
   interface and then we're always _sending_ a request and thus we wait for
   the single socket to become writable only */
int Curl_http_getsock_do(struct Curl_easy *data,
                         struct connectdata *conn,
                         curl_socket_t *socks)
{
  /* write mode */
  (void)conn;
  socks[0] = Curl_conn_get_socket(data, FIRSTSOCKET);
  return GETSOCK_WRITESOCK(0);
}

/*
 * Curl_http_done() gets called after a single HTTP request has been
 * performed.
 */

CURLcode Curl_http_done(struct Curl_easy *data,
                        CURLcode status, bool premature)
{
  struct connectdata *conn = data->conn;
  struct HTTP *http = data->req.p.http;

  /* Clear multipass flag. If authentication isn't done yet, then it will get
   * a chance to be set back to true when we output the next auth header */
  data->state.authhost.multipass = FALSE;
  data->state.authproxy.multipass = FALSE;

  if(!http)
    return CURLE_OK;

  Curl_dyn_reset(&data->state.headerb);
  Curl_hyper_done(data);

  if(status)
    return status;

  if(!premature && /* this check is pointless when DONE is called before the
                      entire operation is complete */
     !conn->bits.retry &&
     !data->set.connect_only &&
     (data->req.bytecount +
      data->req.headerbytecount -
      data->req.deductheadercount) <= 0) {
    /* If this connection isn't simply closed to be retried, AND nothing was
       read from the HTTP server (that counts), this can't be right so we
       return an error here */
    failf(data, "Empty reply from server");
    /* Mark it as closed to avoid the "left intact" message */
    streamclose(conn, "Empty reply from server");
    return CURLE_GOT_NOTHING;
  }








|




















<

|




<
<
<













|
|







1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165

1166
1167
1168
1169
1170
1171



1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
     function to make the reuse checks properly be able to check this bit. */
  connkeep(conn, "HTTP default");

  return Curl_conn_connect(data, FIRSTSOCKET, FALSE, done);
}

/* this returns the socket to wait for in the DO and DOING state for the multi
   interface and then we are always _sending_ a request and thus we wait for
   the single socket to become writable only */
int Curl_http_getsock_do(struct Curl_easy *data,
                         struct connectdata *conn,
                         curl_socket_t *socks)
{
  /* write mode */
  (void)conn;
  socks[0] = Curl_conn_get_socket(data, FIRSTSOCKET);
  return GETSOCK_WRITESOCK(0);
}

/*
 * Curl_http_done() gets called after a single HTTP request has been
 * performed.
 */

CURLcode Curl_http_done(struct Curl_easy *data,
                        CURLcode status, bool premature)
{
  struct connectdata *conn = data->conn;


  /* Clear multipass flag. If authentication is not done yet, then it will get
   * a chance to be set back to true when we output the next auth header */
  data->state.authhost.multipass = FALSE;
  data->state.authproxy.multipass = FALSE;




  Curl_dyn_reset(&data->state.headerb);
  Curl_hyper_done(data);

  if(status)
    return status;

  if(!premature && /* this check is pointless when DONE is called before the
                      entire operation is complete */
     !conn->bits.retry &&
     !data->set.connect_only &&
     (data->req.bytecount +
      data->req.headerbytecount -
      data->req.deductheadercount) <= 0) {
    /* If this connection is not simply closed to be retried, AND nothing was
       read from the HTTP server (that counts), this cannot be right so we
       return an error here */
    failf(data, "Empty reply from server");
    /* Mark it as closed to avoid the "left intact" message */
    streamclose(conn, "Empty reply from server");
    return CURLE_GOT_NOTHING;
  }

1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
           * ignore this for now */
          continue;
        }
      }

      DEBUGASSERT(name && value);
      if(data->state.aptr.host &&
         /* a Host: header was sent already, don't pass on any custom Host:
            header as that will produce *two* in the same request! */
         hd_name_eq(name, namelen, STRCONST("Host:")))
        ;
      else if(data->state.httpreq == HTTPREQ_POST_FORM &&
              /* this header (extended by formdata.c) is sent later */
              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
        ;
      else if(data->state.httpreq == HTTPREQ_POST_MIME &&
              /* this header is sent later */
              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
        ;
      else if(data->req.authneg &&
              /* while doing auth neg, don't allow the custom length since
                 we will force length zero then */
              hd_name_eq(name, namelen, STRCONST("Content-Length:")))
        ;
      else if(data->state.aptr.te &&
              /* when asking for Transfer-Encoding, don't pass on a custom
                 Connection: */
              hd_name_eq(name, namelen, STRCONST("Connection:")))
        ;
      else if((conn->httpversion >= 20) &&
              hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
        /* HTTP/2 doesn't support chunked requests */
        ;
      else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) ||
               hd_name_eq(name, namelen, STRCONST("Cookie:"))) &&
              /* be careful of sending this potentially sensitive header to
                 other hosts */
              !Curl_auth_allowed_to_host(data))
        ;







|












|




|





|







1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
           * ignore this for now */
          continue;
        }
      }

      DEBUGASSERT(name && value);
      if(data->state.aptr.host &&
         /* a Host: header was sent already, do not pass on any custom Host:
            header as that will produce *two* in the same request! */
         hd_name_eq(name, namelen, STRCONST("Host:")))
        ;
      else if(data->state.httpreq == HTTPREQ_POST_FORM &&
              /* this header (extended by formdata.c) is sent later */
              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
        ;
      else if(data->state.httpreq == HTTPREQ_POST_MIME &&
              /* this header is sent later */
              hd_name_eq(name, namelen, STRCONST("Content-Type:")))
        ;
      else if(data->req.authneg &&
              /* while doing auth neg, do not allow the custom length since
                 we will force length zero then */
              hd_name_eq(name, namelen, STRCONST("Content-Length:")))
        ;
      else if(data->state.aptr.te &&
              /* when asking for Transfer-Encoding, do not pass on a custom
                 Connection: */
              hd_name_eq(name, namelen, STRCONST("Connection:")))
        ;
      else if((conn->httpversion >= 20) &&
              hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
        /* HTTP/2 does not support chunked requests */
        ;
      else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) ||
               hd_name_eq(name, namelen, STRCONST("Cookie:"))) &&
              /* be careful of sending this potentially sensitive header to
                 other hosts */
              !Curl_auth_allowed_to_host(data))
        ;
1499
1500
1501
1502
1503
1504
1505
1506
1507

1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537

        if(*ptr || semicolonp) {
          /* only send this if the contents was non-blank or done special */
          CURLcode result = CURLE_OK;
          char *compare = semicolonp ? semicolonp : headers->data;

          if(data->state.aptr.host &&
             /* a Host: header was sent already, don't pass on any custom Host:
                header as that will produce *two* in the same request! */

             checkprefix("Host:", compare))
            ;
          else if(data->state.httpreq == HTTPREQ_POST_FORM &&
                  /* this header (extended by formdata.c) is sent later */
                  checkprefix("Content-Type:", compare))
            ;
          else if(data->state.httpreq == HTTPREQ_POST_MIME &&
                  /* this header is sent later */
                  checkprefix("Content-Type:", compare))
            ;
          else if(data->req.authneg &&
                  /* while doing auth neg, don't allow the custom length since
                     we will force length zero then */
                  checkprefix("Content-Length:", compare))
            ;
          else if(data->state.aptr.te &&
                  /* when asking for Transfer-Encoding, don't pass on a custom
                     Connection: */
                  checkprefix("Connection:", compare))
            ;
          else if((conn->httpversion >= 20) &&
                  checkprefix("Transfer-Encoding:", compare))
            /* HTTP/2 doesn't support chunked requests */
            ;
          else if((checkprefix("Authorization:", compare) ||
                   checkprefix("Cookie:", compare)) &&
                  /* be careful of sending this potentially sensitive header to
                     other hosts */
                  !Curl_auth_allowed_to_host(data))
            ;







|
|
>











|




|





|







1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523

        if(*ptr || semicolonp) {
          /* only send this if the contents was non-blank or done special */
          CURLcode result = CURLE_OK;
          char *compare = semicolonp ? semicolonp : headers->data;

          if(data->state.aptr.host &&
             /* a Host: header was sent already, do not pass on any custom
                Host: header as that will produce *two* in the same
                request! */
             checkprefix("Host:", compare))
            ;
          else if(data->state.httpreq == HTTPREQ_POST_FORM &&
                  /* this header (extended by formdata.c) is sent later */
                  checkprefix("Content-Type:", compare))
            ;
          else if(data->state.httpreq == HTTPREQ_POST_MIME &&
                  /* this header is sent later */
                  checkprefix("Content-Type:", compare))
            ;
          else if(data->req.authneg &&
                  /* while doing auth neg, do not allow the custom length since
                     we will force length zero then */
                  checkprefix("Content-Length:", compare))
            ;
          else if(data->state.aptr.te &&
                  /* when asking for Transfer-Encoding, do not pass on a custom
                     Connection: */
                  checkprefix("Connection:", compare))
            ;
          else if((conn->httpversion >= 20) &&
                  checkprefix("Transfer-Encoding:", compare))
            /* HTTP/2 does not support chunked requests */
            ;
          else if((checkprefix("Authorization:", compare) ||
                   checkprefix("Cookie:", compare)) &&
                  /* be careful of sending this potentially sensitive header to
                     other hosts */
                  !Curl_auth_allowed_to_host(data))
            ;
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
  }
  Curl_safefree(aptr->host);

  ptr = Curl_checkheaders(data, STRCONST("Host"));
  if(ptr && (!data->state.this_is_a_follow ||
             strcasecompare(data->state.first_host, conn->host.name))) {
#if !defined(CURL_DISABLE_COOKIES)
    /* If we have a given custom Host: header, we extract the host name in
       order to possibly use it for cookie reasons later on. We only allow the
       custom Host: header if this is NOT a redirect, as setting Host: in the
       redirected request is being out on thin ice. Except if the host name
       is the same as the first one! */
    char *cookiehost = Curl_copy_header_value(ptr);
    if(!cookiehost)
      return CURLE_OUT_OF_MEMORY;
    if(!*cookiehost)
      /* ignore empty data */
      free(cookiehost);







|


|







1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
  }
  Curl_safefree(aptr->host);

  ptr = Curl_checkheaders(data, STRCONST("Host"));
  if(ptr && (!data->state.this_is_a_follow ||
             strcasecompare(data->state.first_host, conn->host.name))) {
#if !defined(CURL_DISABLE_COOKIES)
    /* If we have a given custom Host: header, we extract the hostname in
       order to possibly use it for cookie reasons later on. We only allow the
       custom Host: header if this is NOT a redirect, as setting Host: in the
       redirected request is being out on thin ice. Except if the hostname
       is the same as the first one! */
    char *cookiehost = Curl_copy_header_value(ptr);
    if(!cookiehost)
      return CURLE_OUT_OF_MEMORY;
    if(!*cookiehost)
      /* ignore empty data */
      free(cookiehost);
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
    if(!strcasecompare("Host:", ptr)) {
      aptr->host = aprintf("Host:%s\r\n", &ptr[5]);
      if(!aptr->host)
        return CURLE_OUT_OF_MEMORY;
    }
  }
  else {
    /* When building Host: headers, we must put the host name within
       [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
    const char *host = conn->host.name;

    if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) &&
        (conn->remote_port == PORT_HTTPS)) ||
       ((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) &&
        (conn->remote_port == PORT_HTTP)) )
      /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
         the port number in the host string */
      aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"",
                           host, conn->bits.ipv6_ip?"]":"");
    else
      aptr->host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"",
                           host, conn->bits.ipv6_ip?"]":"",
                           conn->remote_port);

    if(!aptr->host)
      /* without Host: we can't make a nice request */
      return CURLE_OUT_OF_MEMORY;
  }
  return CURLE_OK;
}

/*
 * Append the request-target to the HTTP request







|
|






|









|







1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
    if(!strcasecompare("Host:", ptr)) {
      aptr->host = aprintf("Host:%s\r\n", &ptr[5]);
      if(!aptr->host)
        return CURLE_OUT_OF_MEMORY;
    }
  }
  else {
    /* When building Host: headers, we must put the hostname within
       [brackets] if the hostname is a plain IPv6-address. RFC2732-style. */
    const char *host = conn->host.name;

    if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) &&
        (conn->remote_port == PORT_HTTPS)) ||
       ((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) &&
        (conn->remote_port == PORT_HTTP)) )
      /* if(HTTPS on port 443) OR (HTTP on port 80) then do not include
         the port number in the host string */
      aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"",
                           host, conn->bits.ipv6_ip?"]":"");
    else
      aptr->host = aprintf("Host: %s%s%s:%d\r\n", conn->bits.ipv6_ip?"[":"",
                           host, conn->bits.ipv6_ip?"]":"",
                           conn->remote_port);

    if(!aptr->host)
      /* without Host: we cannot make a nice request */
      return CURLE_OUT_OF_MEMORY;
  }
  return CURLE_OK;
}

/*
 * Append the request-target to the HTTP request
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816

#ifndef CURL_DISABLE_PROXY
  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
    /* Using a proxy but does not tunnel through it */

    /* The path sent to the proxy is in fact the entire URL. But if the remote
       host is a IDN-name, we must make sure that the request we produce only
       uses the encoded host name! */

    /* and no fragment part */
    CURLUcode uc;
    char *url;
    CURLU *h = curl_url_dup(data->state.uh);
    if(!h)
      return CURLE_OUT_OF_MEMORY;







|







1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802

#ifndef CURL_DISABLE_PROXY
  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
    /* Using a proxy but does not tunnel through it */

    /* The path sent to the proxy is in fact the entire URL. But if the remote
       host is a IDN-name, we must make sure that the request we produce only
       uses the encoded hostname! */

    /* and no fragment part */
    CURLUcode uc;
    char *url;
    CURLU *h = curl_url_dup(data->state.uh);
    if(!h)
      return CURLE_OUT_OF_MEMORY;
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
    uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
    if(uc) {
      curl_url_cleanup(h);
      return CURLE_OUT_OF_MEMORY;
    }

    if(strcasecompare("http", data->state.up.scheme)) {
      /* when getting HTTP, we don't want the userinfo the URL */
      uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
      if(uc) {
        curl_url_cleanup(h);
        return CURLE_OUT_OF_MEMORY;
      }
      uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
      if(uc) {
        curl_url_cleanup(h);
        return CURLE_OUT_OF_MEMORY;
      }
    }
    /* Extract the URL to use in the request. */
    uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
    if(uc) {
      curl_url_cleanup(h);
      return CURLE_OUT_OF_MEMORY;
    }

    curl_url_cleanup(h);

    /* target or url */
    result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
      data->set.str[STRING_TARGET]:url);
    free(url);
    if(result)
      return (result);

    if(strcasecompare("ftp", data->state.up.scheme)) {







|




















|







1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
    uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
    if(uc) {
      curl_url_cleanup(h);
      return CURLE_OUT_OF_MEMORY;
    }

    if(strcasecompare("http", data->state.up.scheme)) {
      /* when getting HTTP, we do not want the userinfo the URL */
      uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
      if(uc) {
        curl_url_cleanup(h);
        return CURLE_OUT_OF_MEMORY;
      }
      uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
      if(uc) {
        curl_url_cleanup(h);
        return CURLE_OUT_OF_MEMORY;
      }
    }
    /* Extract the URL to use in the request. */
    uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
    if(uc) {
      curl_url_cleanup(h);
      return CURLE_OUT_OF_MEMORY;
    }

    curl_url_cleanup(h);

    /* target or URL */
    result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
      data->set.str[STRING_TARGET]:url);
    free(url);
    if(result)
      return (result);

    if(strcasecompare("ftp", data->state.up.scheme)) {
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
     * file size before we continue this venture in the dark lands of HTTP.
     * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
     *********************************************************************/

    if(data->state.resume_from < 0) {
      /*
       * This is meant to get the size of the present remote-file by itself.
       * We don't support this now. Bail out!
       */
      data->state.resume_from = 0;
    }

    if(data->state.resume_from && !data->req.authneg) {
      /* only act on the first request */
      CURLcode result;







|







2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
     * file size before we continue this venture in the dark lands of HTTP.
     * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
     *********************************************************************/

    if(data->state.resume_from < 0) {
      /*
       * This is meant to get the size of the present remote-file by itself.
       * We do not support this now. Bail out!
       */
      data->state.resume_from = 0;
    }

    if(data->state.resume_from && !data->req.authneg) {
      /* only act on the first request */
      CURLcode result;
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
  char *ptr;

  *announced_exp100 = FALSE;
  /* Avoid Expect: 100-continue if Upgrade: is used */
  if(data->req.upgr101 != UPGR101_INIT)
    return CURLE_OK;

  /* For really small puts we don't use Expect: headers at all, and for
     the somewhat bigger ones we allow the app to disable it. Just make
     sure that the expect100header is always set to the preferred value
     here. */
  ptr = Curl_checkheaders(data, STRCONST("Expect"));
  if(ptr) {
    *announced_exp100 =
      Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));







|







2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
  char *ptr;

  *announced_exp100 = FALSE;
  /* Avoid Expect: 100-continue if Upgrade: is used */
  if(data->req.upgr101 != UPGR101_INIT)
    return CURLE_OK;

  /* For really small puts we do not use Expect: headers at all, and for
     the somewhat bigger ones we allow the app to disable it. Just make
     sure that the expect100header is always set to the preferred value
     here. */
  ptr = Curl_checkheaders(data, STRCONST("Expect"));
  if(ptr) {
    *announced_exp100 =
      Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
  case HTTPREQ_PUT:
  case HTTPREQ_POST:
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
  case HTTPREQ_POST_FORM:
  case HTTPREQ_POST_MIME:
#endif
    /* We only set Content-Length and allow a custom Content-Length if
       we don't upload data chunked, as RFC2616 forbids us to set both
       kinds of headers (Transfer-Encoding: chunked and Content-Length).
       We do not override a custom "Content-Length" header, but during
       authentication negotiation that header is suppressed.
     */
    if(req_clen >= 0 && !data->req.upload_chunky &&
       (data->req.authneg ||
        !Curl_checkheaders(data, STRCONST("Content-Length")))) {
      /* we allow replacing this header if not during auth negotiation,
         although it isn't very wise to actually set your own */
      result = Curl_dyn_addf(r,
                             "Content-Length: %" CURL_FORMAT_CURL_OFF_T
                             "\r\n", req_clen);
    }
    if(result)
      goto out;








|








|







2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
  case HTTPREQ_PUT:
  case HTTPREQ_POST:
#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
  case HTTPREQ_POST_FORM:
  case HTTPREQ_POST_MIME:
#endif
    /* We only set Content-Length and allow a custom Content-Length if
       we do not upload data chunked, as RFC2616 forbids us to set both
       kinds of headers (Transfer-Encoding: chunked and Content-Length).
       We do not override a custom "Content-Length" header, but during
       authentication negotiation that header is suppressed.
     */
    if(req_clen >= 0 && !data->req.upload_chunky &&
       (data->req.authneg ||
        !Curl_checkheaders(data, STRCONST("Content-Length")))) {
      /* we allow replacing this header if not during auth negotiation,
         although it is not very wise to actually set your own */
      result = Curl_dyn_addf(r,
                             "Content-Length: %" CURL_FORMAT_CURL_OFF_T
                             "\r\n", req_clen);
    }
    if(result)
      goto out;

2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
    if(announced_exp100)
      result = http_exp100_add_reader(data);
  }

out:
  if(!result) {
    /* setup variables for the upcoming transfer */
    Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
  }
  return result;
}

#if !defined(CURL_DISABLE_COOKIES)

CURLcode Curl_http_cookies(struct Curl_easy *data,







|







2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
    if(announced_exp100)
      result = http_exp100_add_reader(data);
  }

out:
  if(!result) {
    /* setup variables for the upcoming transfer */
    Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
  }
  return result;
}

#if !defined(CURL_DISABLE_COOKIES)

CURLcode Curl_http_cookies(struct Curl_easy *data,
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
#endif

CURLcode Curl_http_range(struct Curl_easy *data,
                         Curl_HttpReq httpreq)
{
  if(data->state.use_range) {
    /*
     * A range is selected. We use different headers whether we're downloading
     * or uploading and we always let customized headers override our internal
     * ones if any such are specified.
     */
    if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
       !Curl_checkheaders(data, STRCONST("Range"))) {
      /* if a line like this was already allocated, free the previous one */
      free(data->state.aptr.rangeline);
      data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
                                           data->state.range);
    }
    else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
            !Curl_checkheaders(data, STRCONST("Content-Range"))) {
      curl_off_t req_clen = Curl_creader_total_length(data);
      /* if a line like this was already allocated, free the previous one */
      free(data->state.aptr.rangeline);

      if(data->set.set_resume_from < 0) {
        /* Upload resume was asked for, but we don't know the size of the
           remote part so we tell the server (and act accordingly) that we
           upload the whole file (again) */
        data->state.aptr.rangeline =
          aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
                  "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
                  req_clen - 1, req_clen);








|

















|







2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
#endif

CURLcode Curl_http_range(struct Curl_easy *data,
                         Curl_HttpReq httpreq)
{
  if(data->state.use_range) {
    /*
     * A range is selected. We use different headers whether we are downloading
     * or uploading and we always let customized headers override our internal
     * ones if any such are specified.
     */
    if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
       !Curl_checkheaders(data, STRCONST("Range"))) {
      /* if a line like this was already allocated, free the previous one */
      free(data->state.aptr.rangeline);
      data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
                                           data->state.range);
    }
    else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
            !Curl_checkheaders(data, STRCONST("Content-Range"))) {
      curl_off_t req_clen = Curl_creader_total_length(data);
      /* if a line like this was already allocated, free the previous one */
      free(data->state.aptr.rangeline);

      if(data->set.set_resume_from < 0) {
        /* Upload resume was asked for, but we do not know the size of the
           remote part so we tell the server (and act accordingly) that we
           upload the whole file (again) */
        data->state.aptr.rangeline =
          aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
                  "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
                  req_clen - 1, req_clen);

2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
{
  struct connectdata *conn = data->conn;
  struct SingleRequest *k = &data->req;

  if(data->req.newurl) {
    if(conn->bits.close) {
      /* Abort after the headers if "follow Location" is set
         and we're set to close anyway. */
      k->keepon &= ~KEEP_RECV;
      k->done = TRUE;
      return CURLE_OK;
    }
    /* We have a new url to load, but since we want to be able to reuse this
       connection properly, we read the full response in "ignore more" */
    k->ignorebody = TRUE;
    infof(data, "Ignoring the response-body");
  }
  if(data->state.resume_from && !k->content_range &&
     (data->state.httpreq == HTTPREQ_GET) &&
     !k->ignorebody) {

    if(k->size == data->state.resume_from) {
      /* The resume point is at the end of file, consider this fine even if it
         doesn't allow resume from here. */
      infof(data, "The entire document is already downloaded");
      streamclose(conn, "already downloaded");
      /* Abort download */
      k->keepon &= ~KEEP_RECV;
      k->done = TRUE;
      return CURLE_OK;
    }

    /* we wanted to resume a download, although the server doesn't seem to
     * support this and we did this with a GET (if it wasn't a GET we did a
     * POST or PUT resume) */
    failf(data, "HTTP server doesn't seem to support "
          "byte ranges. Cannot resume.");
    return CURLE_RANGE_ERROR;
  }

  if(data->set.timecondition && !data->state.range) {
    /* A time condition has been set AND no ranges have been requested. This
       seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
       action for an HTTP/1.1 client */

    if(!Curl_meets_timecondition(data, k->timeofdoc)) {
      k->done = TRUE;
      /* We're simulating an HTTP 304 from server so we return
         what should have been returned from the server */
      data->info.httpcode = 304;
      infof(data, "Simulate an HTTP 304 response");
      /* we abort the transfer before it is completed == we ruin the
         reuse ability. Close the connection */
      streamclose(conn, "Simulated 304 handling");
      return CURLE_OK;







|




|










|








|
|

|











|







2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
{
  struct connectdata *conn = data->conn;
  struct SingleRequest *k = &data->req;

  if(data->req.newurl) {
    if(conn->bits.close) {
      /* Abort after the headers if "follow Location" is set
         and we are set to close anyway. */
      k->keepon &= ~KEEP_RECV;
      k->done = TRUE;
      return CURLE_OK;
    }
    /* We have a new URL to load, but since we want to be able to reuse this
       connection properly, we read the full response in "ignore more" */
    k->ignorebody = TRUE;
    infof(data, "Ignoring the response-body");
  }
  if(data->state.resume_from && !k->content_range &&
     (data->state.httpreq == HTTPREQ_GET) &&
     !k->ignorebody) {

    if(k->size == data->state.resume_from) {
      /* The resume point is at the end of file, consider this fine even if it
         does not allow resume from here. */
      infof(data, "The entire document is already downloaded");
      streamclose(conn, "already downloaded");
      /* Abort download */
      k->keepon &= ~KEEP_RECV;
      k->done = TRUE;
      return CURLE_OK;
    }

    /* we wanted to resume a download, although the server does not seem to
     * support this and we did this with a GET (if it was not a GET we did a
     * POST or PUT resume) */
    failf(data, "HTTP server does not seem to support "
          "byte ranges. Cannot resume.");
    return CURLE_RANGE_ERROR;
  }

  if(data->set.timecondition && !data->state.range) {
    /* A time condition has been set AND no ranges have been requested. This
       seems to be what chapter 13.3.4 of RFC 2616 defines to be the correct
       action for an HTTP/1.1 client */

    if(!Curl_meets_timecondition(data, k->timeofdoc)) {
      k->done = TRUE;
      /* We are simulating an HTTP 304 from server so we return
         what should have been returned from the server */
      data->info.httpcode = 304;
      infof(data, "Simulate an HTTP 304 response");
      /* we abort the transfer before it is completed == we ruin the
         reuse ability. Close the connection */
      streamclose(conn, "Simulated 304 handling");
      return CURLE_OK;
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
CURLcode Curl_transferencode(struct Curl_easy *data)
{
  if(!Curl_checkheaders(data, STRCONST("TE")) &&
     data->set.http_transfer_encoding) {
    /* When we are to insert a TE: header in the request, we must also insert
       TE in a Connection: header, so we need to merge the custom provided
       Connection: header and prevent the original to get sent. Note that if
       the user has inserted his/her own TE: header we don't do this magic
       but then assume that the user will handle it all! */
    char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
#define TE_HEADER "TE: gzip\r\n"

    Curl_safefree(data->state.aptr.te);

    if(cptr) {







|







2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
CURLcode Curl_transferencode(struct Curl_easy *data)
{
  if(!Curl_checkheaders(data, STRCONST("TE")) &&
     data->set.http_transfer_encoding) {
    /* When we are to insert a TE: header in the request, we must also insert
       TE in a Connection: header, so we need to merge the custom provided
       Connection: header and prevent the original to get sent. Note that if
       the user has inserted his/her own TE: header we do not do this magic
       but then assume that the user will handle it all! */
    char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
#define TE_HEADER "TE: gzip\r\n"

    Curl_safefree(data->state.aptr.te);

    if(cptr) {
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
    Curl_dyn_free(&req);
    goto fail;
  }

  if(!(conn->handler->flags&PROTOPT_SSL) &&
     conn->httpversion < 20 &&
     (data->state.httpwant == CURL_HTTP_VERSION_2)) {
    /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
       over SSL */
    result = Curl_http2_request_upgrade(&req, data);
    if(result) {
      Curl_dyn_free(&req);
      return result;
    }
  }







|







2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
    Curl_dyn_free(&req);
    goto fail;
  }

  if(!(conn->handler->flags&PROTOPT_SSL) &&
     conn->httpversion < 20 &&
     (data->state.httpwant == CURL_HTTP_VERSION_2)) {
    /* append HTTP2 upgrade magic stuff to the HTTP request if it is not done
       over SSL */
    result = Curl_http2_request_upgrade(&req, data);
    if(result) {
      Curl_dyn_free(&req);
      return result;
    }
  }
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859

  switch(hd[0]) {
  case 'a':
  case 'A':
#ifndef CURL_DISABLE_ALTSVC
    v = (data->asi &&
         ((data->conn->handler->flags & PROTOPT_SSL) ||
#ifdef CURLDEBUG
          /* allow debug builds to circumvent the HTTPS restriction */
          getenv("CURL_ALTSVC_HTTP")
#else
          0
#endif
        ))? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
    if(v) {







|







2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845

  switch(hd[0]) {
  case 'a':
  case 'A':
#ifndef CURL_DISABLE_ALTSVC
    v = (data->asi &&
         ((data->conn->handler->flags & PROTOPT_SSL) ||
#ifdef DEBUGBUILD
          /* allow debug builds to circumvent the HTTPS restriction */
          getenv("CURL_ALTSVC_HTTP")
#else
          0
#endif
        ))? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
    if(v) {
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
    v = (!k->http_bodyless && data->set.str[STRING_ENCODING])?
        HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
    if(v) {
      /*
       * Process Content-Encoding. Look for the values: identity,
       * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
       * x-compress are the same as gzip and compress. (Sec 3.5 RFC
       * 2616). zlib cannot handle compress.  However, errors are
       * handled further down when the response body is processed
       */
      return Curl_build_unencoding_stack(data, v, FALSE);
    }
    /* check for Content-Type: header lines to get the MIME-type */
    v = HD_VAL(hd, hdlen, "Content-Type:");
    if(v) {







|







2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
    v = (!k->http_bodyless && data->set.str[STRING_ENCODING])?
        HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
    if(v) {
      /*
       * Process Content-Encoding. Look for the values: identity,
       * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
       * x-compress are the same as gzip and compress. (Sec 3.5 RFC
       * 2616). zlib cannot handle compress. However, errors are
       * handled further down when the response body is processed
       */
      return Curl_build_unencoding_stack(data, v, FALSE);
    }
    /* check for Content-Type: header lines to get the MIME-type */
    v = HD_VAL(hd, hdlen, "Content-Type:");
    if(v) {
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
      return CURLE_OK;
    }
    if((conn->httpversion == 10) &&
       HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
      /*
       * An HTTP/1.0 reply with the 'Connection: keep-alive' line
       * tells us the connection will be kept alive for our
       * pleasure.  Default action for 1.0 is to close.
       *
       * [RFC2068, section 19.7.1] */
      connkeep(conn, "Connection keep-alive");
      infof(data, "HTTP/1.0 connection set to keep alive");
      return CURLE_OK;
    }
    v = !k->http_bodyless? HD_VAL(hd, hdlen, "Content-Range:") : NULL;







|







2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
      return CURLE_OK;
    }
    if((conn->httpversion == 10) &&
       HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
      /*
       * An HTTP/1.0 reply with the 'Connection: keep-alive' line
       * tells us the connection will be kept alive for our
       * pleasure. Default action for 1.0 is to close.
       *
       * [RFC2068, section 19.7.1] */
      connkeep(conn, "Connection keep-alive");
      infof(data, "HTTP/1.0 connection set to keep alive");
      return CURLE_OK;
    }
    v = !k->http_bodyless? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
         HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
        /*
         * When an HTTP/1.0 reply comes when using a proxy, the
         * 'Proxy-Connection: keep-alive' line tells us the
         * connection will be kept alive for our pleasure.
         * Default action for 1.0 is to close.
         */
        connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
        infof(data, "HTTP/1.0 proxy connection set to keep alive");
      }
      else if((conn->httpversion == 11) && conn->bits.httpproxy &&
              HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
        /*
         * We get an HTTP/1.1 response from a proxy and it says it'll
         * close down after this transfer.
         */
        connclose(conn, "Proxy-Connection: asked to close after done");
        infof(data, "HTTP/1.1 proxy connection set close");
      }
      return CURLE_OK;
    }







|





|







3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
         HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
        /*
         * When an HTTP/1.0 reply comes when using a proxy, the
         * 'Proxy-Connection: keep-alive' line tells us the
         * connection will be kept alive for our pleasure.
         * Default action for 1.0 is to close.
         */
        connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
        infof(data, "HTTP/1.0 proxy connection set to keep alive");
      }
      else if((conn->httpversion == 11) && conn->bits.httpproxy &&
              HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
        /*
         * We get an HTTP/1.1 response from a proxy and it says it will
         * close down after this transfer.
         */
        connclose(conn, "Proxy-Connection: asked to close after done");
        infof(data, "HTTP/1.1 proxy connection set close");
      }
      return CURLE_OK;
    }
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
  case 's':
  case 'S':
#if !defined(CURL_DISABLE_COOKIES)
    v = (data->cookies && data->state.cookie_engine)?
        HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
    if(v) {
      /* If there is a custom-set Host: name, use it here, or else use
       * real peer host name. */
      const char *host = data->state.aptr.cookiehost?
        data->state.aptr.cookiehost:conn->host.name;
      const bool secure_context =
        conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
        strcasecompare("localhost", host) ||
        !strcmp(host, "127.0.0.1") ||
        !strcmp(host, "::1") ? TRUE : FALSE;

      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
                      CURL_LOCK_ACCESS_SINGLE);
      Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
                      data->state.up.path, secure_context);
      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
      return CURLE_OK;
    }
#endif
#ifndef CURL_DISABLE_HSTS
    /* If enabled, the header is incoming and this is over HTTPS */
    v = (data->hsts &&
         ((conn->handler->flags & PROTOPT_SSL) ||
#ifdef CURLDEBUG
           /* allow debug builds to circumvent the HTTPS restriction */
           getenv("CURL_HSTS_HTTP")
#else
           0
#endif
            )
        )? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;







|




















|







3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
  case 's':
  case 'S':
#if !defined(CURL_DISABLE_COOKIES)
    v = (data->cookies && data->state.cookie_engine)?
        HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
    if(v) {
      /* If there is a custom-set Host: name, use it here, or else use
       * real peer hostname. */
      const char *host = data->state.aptr.cookiehost?
        data->state.aptr.cookiehost:conn->host.name;
      const bool secure_context =
        conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
        strcasecompare("localhost", host) ||
        !strcmp(host, "127.0.0.1") ||
        !strcmp(host, "::1") ? TRUE : FALSE;

      Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
                      CURL_LOCK_ACCESS_SINGLE);
      Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
                      data->state.up.path, secure_context);
      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
      return CURLE_OK;
    }
#endif
#ifndef CURL_DISABLE_HSTS
    /* If enabled, the header is incoming and this is over HTTPS */
    v = (data->hsts &&
         ((conn->handler->flags & PROTOPT_SSL) ||
#ifdef DEBUGBUILD
           /* allow debug builds to circumvent the HTTPS restriction */
           getenv("CURL_HSTS_HTTP")
#else
           0
#endif
            )
        )? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
    if(v) {
      /* One or more encodings. We check for chunked and/or a compression
         algorithm. */
      result = Curl_build_unencoding_stack(data, v, TRUE);
      if(result)
        return result;
      if(!k->chunk && data->set.http_transfer_encoding) {
        /* if this isn't chunked, only close can signal the end of this
         * transfer as Content-Length is said not to be trusted for
         * transfer-encoding! */
        connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
        k->ignore_cl = TRUE;
      }
      return CURLE_OK;
    }







|







3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
    if(v) {
      /* One or more encodings. We check for chunked and/or a compression
         algorithm. */
      result = Curl_build_unencoding_stack(data, v, TRUE);
      if(result)
        return result;
      if(!k->chunk && data->set.http_transfer_encoding) {
        /* if this is not chunked, only close can signal the end of this
         * transfer as Content-Length is said not to be trusted for
         * transfer-encoding! */
        connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
        k->ignore_cl = TRUE;
      }
      return CURLE_OK;
    }
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
  conn->httpversion = (unsigned char)k->httpversion;

  if(!data->state.httpversion || data->state.httpversion > k->httpversion)
    /* store the lowest server version we encounter */
    data->state.httpversion = (unsigned char)k->httpversion;

  /*
   * This code executes as part of processing the header.  As a
   * result, it's not totally clear how to interpret the
   * response code yet as that depends on what other headers may
   * be present.  401 and 407 may be errors, but may be OK
   * depending on how authentication is working.  Other codes
   * are definitely errors, so give up here.
   */
  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
     k->httpcode == 416) {
    /* "Requested Range Not Satisfiable", just proceed and
       pretend this is no error */
    k->ignorebody = TRUE; /* Avoid appending error msg to good data. */







|
|

|
|







3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
  conn->httpversion = (unsigned char)k->httpversion;

  if(!data->state.httpversion || data->state.httpversion > k->httpversion)
    /* store the lowest server version we encounter */
    data->state.httpversion = (unsigned char)k->httpversion;

  /*
   * This code executes as part of processing the header. As a
   * result, it is not totally clear how to interpret the
   * response code yet as that depends on what other headers may
   * be present. 401 and 407 may be errors, but may be OK
   * depending on how authentication is working. Other codes
   * are definitely errors, so give up here.
   */
  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
     k->httpcode == 416) {
    /* "Requested Range Not Satisfiable", just proceed and
       pretend this is no error */
    k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
  default:
    break;
  }
  return CURLE_OK;
}

/* Content-Length must be ignored if any Transfer-Encoding is present in the
   response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4.  This is
   figured out here after all headers have been received but before the final
   call to the user's header callback, so that a valid content length can be
   retrieved by the user in the final call. */
CURLcode Curl_http_size(struct Curl_easy *data)
{
  struct SingleRequest *k = &data->req;
  if(data->req.ignore_cl || k->chunk) {







|







3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
  default:
    break;
  }
  return CURLE_OK;
}

/* Content-Length must be ignored if any Transfer-Encoding is present in the
   response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
   figured out here after all headers have been received but before the final
   call to the user's header callback, so that a valid content length can be
   retrieved by the user in the final call. */
CURLcode Curl_http_size(struct Curl_easy *data)
{
  struct SingleRequest *k = &data->req;
  if(data->req.ignore_cl || k->chunk) {
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
    failf(data, "Nul byte in header");
    return CURLE_WEIRD_SERVER_REPLY;
  }
  if(k->headerline < 2)
    /* the first "header" is the status-line and it has no colon */
    return CURLE_OK;
  if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
    /* line folding, can't happen on line 2 */
    ;
  else {
    ptr = memchr(hd, ':', hdlen);
    if(!ptr) {
      /* this is bad, bail out */
      failf(data, "Header without colon");
      return CURLE_WEIRD_SERVER_REPLY;







|







3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
    failf(data, "Nul byte in header");
    return CURLE_WEIRD_SERVER_REPLY;
  }
  if(k->headerline < 2)
    /* the first "header" is the status-line and it has no colon */
    return CURLE_OK;
  if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
    /* line folding, cannot happen on line 2 */
    ;
  else {
    ptr = memchr(hd, ':', hdlen);
    if(!ptr) {
      /* this is bad, bail out */
      failf(data, "Header without colon");
      return CURLE_WEIRD_SERVER_REPLY;
3359
3360
3361
3362
3363
3364
3365


3366
























3367

3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385










3386
3387
3388
3389

3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407

3408
3409
3410
3411

3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
  if(bad) {
    failf(data, "Too large response headers: %zu > %u", bad, max);
    return CURLE_RECV_ERROR;
  }
  return CURLE_OK;
}




























static CURLcode http_on_response(struct Curl_easy *data,

                                 const char *buf, size_t blen,
                                 size_t *pconsumed)
{
  struct connectdata *conn = data->conn;
  CURLcode result = CURLE_OK;
  struct SingleRequest *k = &data->req;

  (void)buf; /* not used without HTTP2 enabled */
  *pconsumed = 0;

  if(k->upgr101 == UPGR101_RECEIVED) {
    /* supposedly upgraded to http2 now */
    if(conn->httpversion != 20)
      infof(data, "Lying server, not serving HTTP/2");
  }
  if(conn->httpversion < 20) {
    conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
  }











  if(k->httpcode < 100) {
    failf(data, "Unsupported response code in HTTP response");
    return CURLE_UNSUPPORTED_PROTOCOL;

  }
  else if(k->httpcode < 200) {
    /* "A user agent MAY ignore unexpected 1xx status responses."
     * By default, we expect to get more responses after this one. */
    k->header = TRUE;
    k->headerline = 0; /* restart the header line counter */

    switch(k->httpcode) {
    case 100:
      /*
       * We have made an HTTP PUT or POST and this is 1.1-lingo
       * that tells us that the server is OK with this and ready
       * to receive the data.
       */
      Curl_http_exp100_got100(data);
      break;
    case 101:
      /* Switching Protocols only allowed from HTTP/1.1 */

      if(conn->httpversion != 11) {
        /* invalid for other HTTP versions */
        failf(data, "unexpected 101 response code");
        return CURLE_WEIRD_SERVER_REPLY;

      }
      if(k->upgr101 == UPGR101_H2) {
        /* Switching to HTTP/2, where we will get more responses */
        infof(data, "Received 101, Switching to HTTP/2");
        k->upgr101 = UPGR101_RECEIVED;
        /* We expect more response from HTTP/2 later */
        k->header = TRUE;
        k->headerline = 0; /* restart the header line counter */
        /* Any remaining `buf` bytes are already HTTP/2 and passed to
         * be processed. */
        result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
        if(result)
          return result;
        *pconsumed += blen;
      }
#ifdef USE_WEBSOCKETS
      else if(k->upgr101 == UPGR101_WS) {
        /* verify the response. Any passed `buf` bytes are already in
         * WebSockets format and taken in by the protocol handler. */
        result = Curl_ws_accept(data, buf, blen);
        if(result)
          return result;
        *pconsumed += blen; /* ws accept handled the data */
        k->header = FALSE; /* we will not get more responses */
        if(data->set.connect_only)
          k->keepon &= ~KEEP_RECV; /* read no more content */
      }
#endif
      else {
        /* We silently accept this as the final response.
         * TODO: this looks, uhm, wrong. What are we switching to if we
         * did not ask for an Upgrade? Maybe the application provided an
         * `Upgrade: xxx` header? */
        k->header = FALSE;
      }
      break;
    default:
      /* The server may send us other 1xx responses, like informative
       * 103. This have no influence on request processing and we expect
       * to receive a final response eventually. */
      break;
    }
    return result;
  }

  /* k->httpcode >= 200, final response */
  k->header = FALSE;

  if(k->upgr101 == UPGR101_H2) {
    /* A requested upgrade was denied, poke the multi handle to possibly







>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>


















>
>
>
>
>
>
>
>
>
>



|
>


















>



|
>












|








|




















|







3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
  if(bad) {
    failf(data, "Too large response headers: %zu > %u", bad, max);
    return CURLE_RECV_ERROR;
  }
  return CURLE_OK;
}

static CURLcode http_write_header(struct Curl_easy *data,
                                  const char *hd, size_t hdlen)
{
  CURLcode result;
  int writetype;

  /* now, only output this if the header AND body are requested:
   */
  Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);

  writetype = CLIENTWRITE_HEADER |
    ((data->req.httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);

  result = Curl_client_write(data, writetype, hd, hdlen);
  if(result)
    return result;

  result = Curl_bump_headersize(data, hdlen, FALSE);
  if(result)
    return result;

  data->req.deductheadercount = (100 <= data->req.httpcode &&
                                 199 >= data->req.httpcode)?
                                data->req.headerbytecount:0;
  return result;
}

static CURLcode http_on_response(struct Curl_easy *data,
                                 const char *last_hd, size_t last_hd_len,
                                 const char *buf, size_t blen,
                                 size_t *pconsumed)
{
  struct connectdata *conn = data->conn;
  CURLcode result = CURLE_OK;
  struct SingleRequest *k = &data->req;

  (void)buf; /* not used without HTTP2 enabled */
  *pconsumed = 0;

  if(k->upgr101 == UPGR101_RECEIVED) {
    /* supposedly upgraded to http2 now */
    if(conn->httpversion != 20)
      infof(data, "Lying server, not serving HTTP/2");
  }
  if(conn->httpversion < 20) {
    conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
  }

  if(k->httpcode < 200 && last_hd) {
    /* Intermediate responses might trigger processing of more
     * responses, write the last header to the client before
     * proceeding. */
    result = http_write_header(data, last_hd, last_hd_len);
    last_hd = NULL; /* handled it */
    if(result)
      goto out;
  }

  if(k->httpcode < 100) {
    failf(data, "Unsupported response code in HTTP response");
    result = CURLE_UNSUPPORTED_PROTOCOL;
    goto out;
  }
  else if(k->httpcode < 200) {
    /* "A user agent MAY ignore unexpected 1xx status responses."
     * By default, we expect to get more responses after this one. */
    k->header = TRUE;
    k->headerline = 0; /* restart the header line counter */

    switch(k->httpcode) {
    case 100:
      /*
       * We have made an HTTP PUT or POST and this is 1.1-lingo
       * that tells us that the server is OK with this and ready
       * to receive the data.
       */
      Curl_http_exp100_got100(data);
      break;
    case 101:
      /* Switching Protocols only allowed from HTTP/1.1 */

      if(conn->httpversion != 11) {
        /* invalid for other HTTP versions */
        failf(data, "unexpected 101 response code");
        result = CURLE_WEIRD_SERVER_REPLY;
        goto out;
      }
      if(k->upgr101 == UPGR101_H2) {
        /* Switching to HTTP/2, where we will get more responses */
        infof(data, "Received 101, Switching to HTTP/2");
        k->upgr101 = UPGR101_RECEIVED;
        /* We expect more response from HTTP/2 later */
        k->header = TRUE;
        k->headerline = 0; /* restart the header line counter */
        /* Any remaining `buf` bytes are already HTTP/2 and passed to
         * be processed. */
        result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
        if(result)
          goto out;
        *pconsumed += blen;
      }
#ifdef USE_WEBSOCKETS
      else if(k->upgr101 == UPGR101_WS) {
        /* verify the response. Any passed `buf` bytes are already in
         * WebSockets format and taken in by the protocol handler. */
        result = Curl_ws_accept(data, buf, blen);
        if(result)
          goto out;
        *pconsumed += blen; /* ws accept handled the data */
        k->header = FALSE; /* we will not get more responses */
        if(data->set.connect_only)
          k->keepon &= ~KEEP_RECV; /* read no more content */
      }
#endif
      else {
        /* We silently accept this as the final response.
         * TODO: this looks, uhm, wrong. What are we switching to if we
         * did not ask for an Upgrade? Maybe the application provided an
         * `Upgrade: xxx` header? */
        k->header = FALSE;
      }
      break;
    default:
      /* The server may send us other 1xx responses, like informative
       * 103. This have no influence on request processing and we expect
       * to receive a final response eventually. */
      break;
    }
    goto out;
  }

  /* k->httpcode >= 200, final response */
  k->header = FALSE;

  if(k->upgr101 == UPGR101_H2) {
    /* A requested upgrade was denied, poke the multi handle to possibly
3508
3509
3510
3511
3512
3513
3514
3515

3516
3517
3518
3519
3520
3521
3522
3523

3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
  }
#endif

#ifdef USE_WEBSOCKETS
  /* All >=200 HTTP status codes are errors when wanting websockets */
  if(data->req.upgr101 == UPGR101_WS) {
    failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
    return CURLE_HTTP_RETURNED_ERROR;

  }
#endif

  /* Check if this response means the transfer errored. */
  if(http_should_fail(data, data->req.httpcode)) {
    failf(data, "The requested URL returned error: %d",
          k->httpcode);
    return CURLE_HTTP_RETURNED_ERROR;

  }

  /* Curl_http_auth_act() checks what authentication methods
   * that are available and decides which one (if any) to
   * use. It will set 'newurl' if an auth method was picked. */
  result = Curl_http_auth_act(data);
  if(result)
    return result;

  if(k->httpcode >= 300) {
    if((!data->req.authneg) && !conn->bits.close &&
       !Curl_creader_will_rewind(data)) {
      /*
       * General treatment of errors when about to send data. Including :
       * "417 Expectation Failed", while waiting for 100-continue.







|
>







|
>







|







3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
  }
#endif

#ifdef USE_WEBSOCKETS
  /* All >=200 HTTP status codes are errors when wanting websockets */
  if(data->req.upgr101 == UPGR101_WS) {
    failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
    result = CURLE_HTTP_RETURNED_ERROR;
    goto out;
  }
#endif

  /* Check if this response means the transfer errored. */
  if(http_should_fail(data, data->req.httpcode)) {
    failf(data, "The requested URL returned error: %d",
          k->httpcode);
    result = CURLE_HTTP_RETURNED_ERROR;
    goto out;
  }

  /* Curl_http_auth_act() checks what authentication methods
   * that are available and decides which one (if any) to
   * use. It will set 'newurl' if an auth method was picked. */
  result = Curl_http_auth_act(data);
  if(result)
    goto out;

  if(k->httpcode >= 300) {
    if((!data->req.authneg) && !conn->bits.close &&
       !Curl_creader_will_rewind(data)) {
      /*
       * General treatment of errors when about to send data. Including :
       * "417 Expectation Failed", while waiting for 100-continue.
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
      switch(data->state.httpreq) {
      case HTTPREQ_PUT:
      case HTTPREQ_POST:
      case HTTPREQ_POST_FORM:
      case HTTPREQ_POST_MIME:
        /* We got an error response. If this happened before the whole
         * request body has been sent we stop sending and mark the
         * connection for closure after we've read the entire response.
         */
        if(!Curl_req_done_sending(data)) {
          if((k->httpcode == 417) && Curl_http_exp100_is_selected(data)) {
            /* 417 Expectation Failed - try again without the Expect
               header */
            if(!k->writebytecount && http_exp100_is_waiting(data)) {
              infof(data, "Got HTTP failure 417 while waiting for a 100");
            }
            else {
              infof(data, "Got HTTP failure 417 while sending data");
              streamclose(conn,
                          "Stop sending data before everything sent");
              result = http_perhapsrewind(data, conn);
              if(result)
                return result;
            }
            data->state.disableexpect = TRUE;
            DEBUGASSERT(!data->req.newurl);
            data->req.newurl = strdup(data->state.url);
            Curl_req_abort_sending(data);
          }
          else if(data->set.http_keep_sending_on_error) {
            infof(data, "HTTP error before end of send, keep sending");
            http_exp100_send_anyway(data);
          }
          else {
            infof(data, "HTTP error before end of send, stop sending");
            streamclose(conn, "Stop sending data before everything sent");
            result = Curl_req_abort_sending(data);
            if(result)
              return result;
          }
        }
        break;

      default: /* default label present to avoid compiler warnings */
        break;
      }







|














|















|







3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
      switch(data->state.httpreq) {
      case HTTPREQ_PUT:
      case HTTPREQ_POST:
      case HTTPREQ_POST_FORM:
      case HTTPREQ_POST_MIME:
        /* We got an error response. If this happened before the whole
         * request body has been sent we stop sending and mark the
         * connection for closure after we have read the entire response.
         */
        if(!Curl_req_done_sending(data)) {
          if((k->httpcode == 417) && Curl_http_exp100_is_selected(data)) {
            /* 417 Expectation Failed - try again without the Expect
               header */
            if(!k->writebytecount && http_exp100_is_waiting(data)) {
              infof(data, "Got HTTP failure 417 while waiting for a 100");
            }
            else {
              infof(data, "Got HTTP failure 417 while sending data");
              streamclose(conn,
                          "Stop sending data before everything sent");
              result = http_perhapsrewind(data, conn);
              if(result)
                goto out;
            }
            data->state.disableexpect = TRUE;
            DEBUGASSERT(!data->req.newurl);
            data->req.newurl = strdup(data->state.url);
            Curl_req_abort_sending(data);
          }
          else if(data->set.http_keep_sending_on_error) {
            infof(data, "HTTP error before end of send, keep sending");
            http_exp100_send_anyway(data);
          }
          else {
            infof(data, "HTTP error before end of send, stop sending");
            streamclose(conn, "Stop sending data before everything sent");
            result = Curl_req_abort_sending(data);
            if(result)
              goto out;
          }
        }
        break;

      default: /* default label present to avoid compiler warnings */
        break;
      }
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627









3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641

3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670

3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
  }

  /* This is the last response that we will got for the current request.
   * Check on the body size and determine if the response is complete.
   */
  result = Curl_http_size(data);
  if(result)
    return result;

  /* If we requested a "no body", this is a good time to get
   * out and return home.
   */
  if(data->req.no_body)
    k->download_done = TRUE;

  /* If max download size is *zero* (nothing) we already have
     nothing and can safely return ok now!  But for HTTP/2, we'd
     like to call http2_handle_stream_close to properly close a
     stream.  In order to do this, we keep reading until we
     close the stream. */
  if(0 == k->maxdownload
     && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
     && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
    k->download_done = TRUE;

  /* final response without error, prepare to receive the body */
  return Curl_http_firstwrite(data);









}

static CURLcode http_rw_hd(struct Curl_easy *data,
                           const char *hd, size_t hdlen,
                           const char *buf_remain, size_t blen,
                           size_t *pconsumed)
{
  CURLcode result = CURLE_OK;
  struct SingleRequest *k = &data->req;
  int writetype;

  *pconsumed = 0;
  if((0x0a == *hd) || (0x0d == *hd)) {
    /* Empty header line means end of headers! */

    size_t consumed;

    /* now, only output this if the header AND body are requested:
     */
    Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);

    writetype = CLIENTWRITE_HEADER |
      ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);

    result = Curl_client_write(data, writetype, hd, hdlen);
    if(result)
      return result;

    result = Curl_bump_headersize(data, hdlen, FALSE);
    if(result)
      return result;

    data->req.deductheadercount =
      (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;

    /* analyze the response to find out what to do. */
    /* Caveat: we clear anything in the header brigade, because a
     * response might switch HTTP version which may call use recursively.
     * Not nice, but that is currently the way of things. */
    Curl_dyn_reset(&data->state.headerb);
    result = http_on_response(data, buf_remain, blen, &consumed);
    if(result)
      return result;
    *pconsumed += consumed;

    return CURLE_OK;
  }

  /*
   * Checks for special headers coming up.
   */

  writetype = CLIENTWRITE_HEADER;
  if(!k->headerline++) {
    /* This is the first header, it MUST be the error code line
       or else we consider this to be the body right away! */
    bool fine_statusline = FALSE;

    k->httpversion = 0; /* Don't know yet */
    if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
      /*
       * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
       *
       * The response code is always a three-digit number in HTTP as the spec
       * says. We allow any three-digit number here, but we cannot make
       * guarantees on future behaviors since it isn't within the protocol.
       */
      const char *p = hd;

      while(*p && ISBLANK(*p))
        p++;
      if(!strncmp(p, "HTTP/", 5)) {
        p += 5;







|








|

|







|
>
>
>
>
>
>
>
>
>














>


<
<
<
|
<
<
|
<


<
<
<
<
<
<
<






|
|
|

>
|












|






|







3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681



3682


3683

3684
3685







3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
  }

  /* This is the last response that we will got for the current request.
   * Check on the body size and determine if the response is complete.
   */
  result = Curl_http_size(data);
  if(result)
    goto out;

  /* If we requested a "no body", this is a good time to get
   * out and return home.
   */
  if(data->req.no_body)
    k->download_done = TRUE;

  /* If max download size is *zero* (nothing) we already have
     nothing and can safely return ok now!  But for HTTP/2, we would
     like to call http2_handle_stream_close to properly close a
     stream. In order to do this, we keep reading until we
     close the stream. */
  if(0 == k->maxdownload
     && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
     && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
    k->download_done = TRUE;

  /* final response without error, prepare to receive the body */
  result = Curl_http_firstwrite(data);

out:
  if(last_hd) {
    /* if not written yet, write it now */
    CURLcode r2 = http_write_header(data, last_hd, last_hd_len);
    if(!result)
      result = r2;
  }
  return result;
}

static CURLcode http_rw_hd(struct Curl_easy *data,
                           const char *hd, size_t hdlen,
                           const char *buf_remain, size_t blen,
                           size_t *pconsumed)
{
  CURLcode result = CURLE_OK;
  struct SingleRequest *k = &data->req;
  int writetype;

  *pconsumed = 0;
  if((0x0a == *hd) || (0x0d == *hd)) {
    /* Empty header line means end of headers! */
    struct dynbuf last_header;
    size_t consumed;




    Curl_dyn_init(&last_header, hdlen + 1);


    result = Curl_dyn_addn(&last_header, hd, hdlen);

    if(result)
      return result;








    /* analyze the response to find out what to do. */
    /* Caveat: we clear anything in the header brigade, because a
     * response might switch HTTP version which may call use recursively.
     * Not nice, but that is currently the way of things. */
    Curl_dyn_reset(&data->state.headerb);
    result = http_on_response(data, Curl_dyn_ptr(&last_header),
                              Curl_dyn_len(&last_header),
                              buf_remain, blen, &consumed);
    *pconsumed += consumed;
    Curl_dyn_free(&last_header);
    return result;
  }

  /*
   * Checks for special headers coming up.
   */

  writetype = CLIENTWRITE_HEADER;
  if(!k->headerline++) {
    /* This is the first header, it MUST be the error code line
       or else we consider this to be the body right away! */
    bool fine_statusline = FALSE;

    k->httpversion = 0; /* Do not know yet */
    if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
      /*
       * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
       *
       * The response code is always a three-digit number in HTTP as the spec
       * says. We allow any three-digit number here, but we cannot make
       * guarantees on future behaviors since it is not within the protocol.
       */
      const char *p = hd;

      while(*p && ISBLANK(*p))
        p++;
      if(!strncmp(p, "HTTP/", 5)) {
        p += 5;
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
      DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired"));
      data->req.keepon &= ~KEEP_SEND;
      data->req.keepon |= KEEP_SEND_TIMED;
      *nread = 0;
      *eos = FALSE;
      return CURLE_OK;
    }
    /* we've waited long enough, continue anyway */
    http_exp100_continue(data, reader);
    infof(data, "Done waiting for 100-continue");
    FALLTHROUGH();
  default:
    DEBUGF(infof(data, "cr_exp100_read, pass through"));
    return Curl_creader_read(data, reader->next, buf, blen, nread, eos);
  }







|







4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
      DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired"));
      data->req.keepon &= ~KEEP_SEND;
      data->req.keepon |= KEEP_SEND_TIMED;
      *nread = 0;
      *eos = FALSE;
      return CURLE_OK;
    }
    /* we have waited long enough, continue anyway */
    http_exp100_continue(data, reader);
    infof(data, "Done waiting for 100-continue");
    FALLTHROUGH();
  default:
    DEBUGF(infof(data, "cr_exp100_read, pass through"));
    return Curl_creader_read(data, reader->next, buf, blen, nread, eos);
  }
4456
4457
4458
4459
4460
4461
4462

4463
4464
4465
4466
4467
4468
4469
  cr_exp100_read,
  Curl_creader_def_close,
  Curl_creader_def_needs_rewind,
  Curl_creader_def_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,

  cr_exp100_done,
  sizeof(struct cr_exp100_ctx)
};

static CURLcode http_exp100_add_reader(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;







>







4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
  cr_exp100_read,
  Curl_creader_def_close,
  Curl_creader_def_needs_rewind,
  Curl_creader_def_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,
  Curl_creader_def_is_paused,
  cr_exp100_done,
  sizeof(struct cr_exp100_ctx)
};

static CURLcode http_exp100_add_reader(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;
Changes to jni/curl/lib/http.h.
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

char *Curl_copy_header_value(const char *header);

char *Curl_checkProxyheaders(struct Curl_easy *data,
                             const struct connectdata *conn,
                             const char *thisheader,
                             const size_t thislen);
struct HTTP; /* see below */

CURLcode Curl_add_timecondition(struct Curl_easy *data,
#ifndef USE_HYPER
                                struct dynbuf *req
#else
                                void *headers
#endif







<







69
70
71
72
73
74
75

76
77
78
79
80
81
82

char *Curl_copy_header_value(const char *header);

char *Curl_checkProxyheaders(struct Curl_easy *data,
                             const struct connectdata *conn,
                             const char *thisheader,
                             const size_t thislen);


CURLcode Curl_add_timecondition(struct Curl_easy *data,
#ifndef USE_HYPER
                                struct dynbuf *req
#else
                                void *headers
#endif
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
                              const char *auth);
CURLcode Curl_http_auth_act(struct Curl_easy *data);

/* If only the PICKNONE bit is set, there has been a round-trip and we
   selected to use no auth at all. Ie, we actively select no auth, as opposed
   to not having one selected. The other CURLAUTH_* defines are present in the
   public curl/curl.h header. */
#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */

/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
   data get included in the initial data chunk sent to the server. If the
   data is larger than this, it will automatically get split up in multiple
   system calls.

   This value used to be fairly big (100K), but we must take into account that







|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
                              const char *auth);
CURLcode Curl_http_auth_act(struct Curl_easy *data);

/* If only the PICKNONE bit is set, there has been a round-trip and we
   selected to use no auth at all. Ie, we actively select no auth, as opposed
   to not having one selected. The other CURLAUTH_* defines are present in the
   public curl/curl.h header. */
#define CURLAUTH_PICKNONE (1<<30) /* do not use auth */

/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
   data get included in the initial data chunk sent to the server. If the
   data is larger than this, it will automatically get split up in multiple
   system calls.

   This value used to be fairly big (100K), but we must take into account that
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
void Curl_http_exp100_got100(struct Curl_easy *data);

#endif /* CURL_DISABLE_HTTP */

/****************************************************************************
 * HTTP unique setup
 ***************************************************************************/
struct HTTP {
  /* TODO: no longer used, we should remove it from SingleRequest */
  char unused;
};

CURLcode Curl_http_size(struct Curl_easy *data);

CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
                                  const char *buf, size_t blen,
                                  size_t *pconsumed);








<
<
<
<







182
183
184
185
186
187
188




189
190
191
192
193
194
195
void Curl_http_exp100_got100(struct Curl_easy *data);

#endif /* CURL_DISABLE_HTTP */

/****************************************************************************
 * HTTP unique setup
 ***************************************************************************/





CURLcode Curl_http_size(struct Curl_easy *data);

CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
                                  const char *buf, size_t blen,
                                  size_t *pconsumed);

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  char *authority;
  char *path;
  struct dynhds headers;
  struct dynhds trailers;
};

/**
 * Create a HTTP request struct.
 */
CURLcode Curl_http_req_make(struct httpreq **preq,
                            const char *method, size_t m_len,
                            const char *scheme, size_t s_len,
                            const char *authority, size_t a_len,
                            const char *path, size_t p_len);








|







231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  char *authority;
  char *path;
  struct dynhds headers;
  struct dynhds trailers;
};

/**
 * Create an HTTP request struct.
 */
CURLcode Curl_http_req_make(struct httpreq **preq,
                            const char *method, size_t m_len,
                            const char *scheme, size_t s_len,
                            const char *authority, size_t a_len,
                            const char *path, size_t p_len);

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  char *description;
  struct dynhds headers;
  struct dynhds trailers;
  struct http_resp *prev;
};

/**
 * Create a HTTP response struct.
 */
CURLcode Curl_http_resp_make(struct http_resp **presp,
                             int status,
                             const char *description);

void Curl_http_resp_free(struct http_resp *resp);

#endif /* HEADER_CURL_HTTP_H */







|








281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
  char *description;
  struct dynhds headers;
  struct dynhds trailers;
  struct http_resp *prev;
};

/**
 * Create an HTTP response struct.
 */
CURLcode Curl_http_resp_make(struct http_resp **presp,
                             int status,
                             const char *description);

void Curl_http_resp_free(struct http_resp *resp);

#endif /* HEADER_CURL_HTTP_H */
Changes to jni/curl/lib/http1.c.
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    /* URL parser wants 0-termination */
    if(target_len >= sizeof(tmp))
      goto out;
    memcpy(tmp, target, target_len);
    tmp[target_len] = '\0';
    /* See if treating TARGET as an absolute URL makes sense */
    if(Curl_is_absolute_url(tmp, NULL, 0, FALSE)) {
      int url_options;

      url = curl_url();
      if(!url) {
        result = CURLE_OUT_OF_MEMORY;
        goto out;
      }
      url_options = (CURLU_NON_SUPPORT_SCHEME|







|







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    /* URL parser wants 0-termination */
    if(target_len >= sizeof(tmp))
      goto out;
    memcpy(tmp, target, target_len);
    tmp[target_len] = '\0';
    /* See if treating TARGET as an absolute URL makes sense */
    if(Curl_is_absolute_url(tmp, NULL, 0, FALSE)) {
      unsigned int url_options;

      url = curl_url();
      if(!url) {
        result = CURLE_OUT_OF_MEMORY;
        goto out;
      }
      url_options = (CURLU_NON_SUPPORT_SCHEME|
Changes to jni/curl/lib/http2.c.
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

137
138
139

140
141
142
143
144
145
146
#define H2_STREAM_RECV_CHUNKS   (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)
/* keep smaller stream upload buffer (default h2 window size) to have
 * our progress bars and "upload done" reporting closer to reality */
#define H2_STREAM_SEND_CHUNKS   ((64 * 1024) / H2_CHUNK_SIZE)
/* spare chunks we keep for a full window */
#define H2_STREAM_POOL_SPARES   (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)

/* We need to accommodate the max number of streams with their window
 * sizes on the overall connection. Streams might become PAUSED which
 * will block their received QUOTA in the connection window. And if we
 * run out of space, the server is blocked from sending us any data.
 * See #10988 for an issue with this. */
#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE)

#define H2_SETTINGS_IV_LEN  3
#define H2_BINSETTINGS_LEN 80

static int populate_settings(nghttp2_settings_entry *iv,
                             struct Curl_easy *data)
{
  iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
  iv[0].value = Curl_multi_max_concurrent_streams(data->multi);

  iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
  iv[1].value = H2_STREAM_WINDOW_SIZE;

  iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
  iv[2].value = data->multi->push_cb != NULL;

  return 3;
}

static ssize_t populate_binsettings(uint8_t *binsettings,
                                    struct Curl_easy *data)
{
  nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
  int ivlen;

  ivlen = populate_settings(iv, data);
  /* this returns number of bytes it wrote or a negative number on error. */
  return nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
                                       iv, ivlen);
}

struct cf_h2_ctx {
  nghttp2_session *h2;
  /* The easy handle used in the current filter call, cleared at return */
  struct cf_call_data call_data;

  struct bufq inbufq;           /* network input */
  struct bufq outbufq;          /* network output */
  struct bufc_pool stream_bufcp; /* spares for stream buffers */
  struct dynbuf scratch;        /* scratch buffer for temp use */

  struct Curl_hash streams; /* hash of `data->id` to `h2_stream_ctx` */
  size_t drain_total; /* sum of all stream's UrlState drain */
  uint32_t max_concurrent_streams;
  int32_t goaway_error;

  int32_t last_stream_id;
  BIT(conn_closed);
  BIT(goaway);

  BIT(enable_push);
  BIT(nw_out_blocked);
};

/* How to access `call_data` from a cf_h2 filter */
#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf)  \







|
|
|
<
|





|
|

















|




















|
>
|

|
>







79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#define H2_STREAM_RECV_CHUNKS   (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)
/* keep smaller stream upload buffer (default h2 window size) to have
 * our progress bars and "upload done" reporting closer to reality */
#define H2_STREAM_SEND_CHUNKS   ((64 * 1024) / H2_CHUNK_SIZE)
/* spare chunks we keep for a full window */
#define H2_STREAM_POOL_SPARES   (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)

/* We need to accommodate the max number of streams with their window sizes on
 * the overall connection. Streams might become PAUSED which will block their
 * received QUOTA in the connection window. If we run out of space, the server

 * is blocked from sending us any data. See #10988 for an issue with this. */
#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE)

#define H2_SETTINGS_IV_LEN  3
#define H2_BINSETTINGS_LEN 80

static size_t populate_settings(nghttp2_settings_entry *iv,
                                struct Curl_easy *data)
{
  iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
  iv[0].value = Curl_multi_max_concurrent_streams(data->multi);

  iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
  iv[1].value = H2_STREAM_WINDOW_SIZE;

  iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
  iv[2].value = data->multi->push_cb != NULL;

  return 3;
}

static ssize_t populate_binsettings(uint8_t *binsettings,
                                    struct Curl_easy *data)
{
  nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
  size_t ivlen;

  ivlen = populate_settings(iv, data);
  /* this returns number of bytes it wrote or a negative number on error. */
  return nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
                                       iv, ivlen);
}

struct cf_h2_ctx {
  nghttp2_session *h2;
  /* The easy handle used in the current filter call, cleared at return */
  struct cf_call_data call_data;

  struct bufq inbufq;           /* network input */
  struct bufq outbufq;          /* network output */
  struct bufc_pool stream_bufcp; /* spares for stream buffers */
  struct dynbuf scratch;        /* scratch buffer for temp use */

  struct Curl_hash streams; /* hash of `data->id` to `h2_stream_ctx` */
  size_t drain_total; /* sum of all stream's UrlState drain */
  uint32_t max_concurrent_streams;
  uint32_t goaway_error;        /* goaway error code from server */
  int32_t remote_max_sid;       /* max id processed by server */
  int32_t local_max_sid;        /* max id processed by us */
  BIT(conn_closed);
  BIT(rcvd_goaway);
  BIT(sent_goaway);
  BIT(enable_push);
  BIT(nw_out_blocked);
};

/* How to access `call_data` from a cf_h2 filter */
#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf)  \
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
                                 struct h2_stream_ctx **pstream)
{
  struct cf_h2_ctx *ctx = cf->ctx;
  struct h2_stream_ctx *stream;

  (void)cf;
  DEBUGASSERT(data);
  if(!data->req.p.http) {
    failf(data, "initialization failure, transfer not http initialized");
    return CURLE_FAILED_INIT;
  }
  stream = H2_STREAM_CTX(ctx, data);
  if(stream) {
    *pstream = stream;
    return CURLE_OK;
  }

  stream = h2_stream_ctx_create(ctx);







<
<
<
<







286
287
288
289
290
291
292




293
294
295
296
297
298
299
                                 struct h2_stream_ctx **pstream)
{
  struct cf_h2_ctx *ctx = cf->ctx;
  struct h2_stream_ctx *stream;

  (void)cf;
  DEBUGASSERT(data);




  stream = H2_STREAM_CTX(ctx, data);
  if(stream) {
    *pstream = stream;
    return CURLE_OK;
  }

  stream = h2_stream_ctx_create(ctx);
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

  DEBUGASSERT(!ctx->h2);
  Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
  Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
  Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
  Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
  Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free);
  ctx->last_stream_id = 2147483647;

  rc = nghttp2_session_callbacks_new(&cbs);
  if(rc) {
    failf(data, "Couldn't initialize nghttp2 callbacks");
    goto out;
  }








|







430
431
432
433
434
435
436
437
438
439
440
441
442
443
444

  DEBUGASSERT(!ctx->h2);
  Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
  Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
  Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
  Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
  Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free);
  ctx->remote_max_sid = 2147483647;

  rc = nghttp2_session_callbacks_new(&cbs);
  if(rc) {
    failf(data, "Couldn't initialize nghttp2 callbacks");
    goto out;
  }

482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517

    result = http2_data_setup(cf, data, &stream);
    if(result)
      goto out;
    DEBUGASSERT(stream);
    stream->id = 1;
    /* queue SETTINGS frame (again) */
    rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen,
                                  data->state.httpreq == HTTPREQ_HEAD,
                                  NULL);
    if(rc) {
      failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
            nghttp2_strerror(rc), rc);
      result = CURLE_HTTP2;
      goto out;
    }

    rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id,
                                              data);
    if(rc) {
      infof(data, "http/2: failed to set user_data for stream %u",
            stream->id);
      DEBUGASSERT(0);
    }
    CURL_TRC_CF(data, cf, "created session via Upgrade");
  }
  else {
    nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
    int ivlen;

    ivlen = populate_settings(iv, data);
    rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE,
                                 iv, ivlen);
    if(rc) {
      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
            nghttp2_strerror(rc), rc);







|




















|







479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514

    result = http2_data_setup(cf, data, &stream);
    if(result)
      goto out;
    DEBUGASSERT(stream);
    stream->id = 1;
    /* queue SETTINGS frame (again) */
    rc = nghttp2_session_upgrade2(ctx->h2, binsettings, (size_t)binlen,
                                  data->state.httpreq == HTTPREQ_HEAD,
                                  NULL);
    if(rc) {
      failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
            nghttp2_strerror(rc), rc);
      result = CURLE_HTTP2;
      goto out;
    }

    rc = nghttp2_session_set_stream_user_data(ctx->h2, stream->id,
                                              data);
    if(rc) {
      infof(data, "http/2: failed to set user_data for stream %u",
            stream->id);
      DEBUGASSERT(0);
    }
    CURL_TRC_CF(data, cf, "created session via Upgrade");
  }
  else {
    nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
    size_t ivlen;

    ivlen = populate_settings(iv, data);
    rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE,
                                 iv, ivlen);
    if(rc) {
      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
            nghttp2_strerror(rc), rc);
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  bool alive = TRUE;

  *input_pending = FALSE;
  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    return FALSE;

  if(*input_pending) {
    /* This happens before we've sent off a request and the connection is
       not in use by any other transfer, there shouldn't be any data here,
       only "protocol frames" */
    CURLcode result;
    ssize_t nread = -1;

    *input_pending = FALSE;
    nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
    if(nread != -1) {







|
|







605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  bool alive = TRUE;

  *input_pending = FALSE;
  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    return FALSE;

  if(*input_pending) {
    /* This happens before we have sent off a request and the connection is
       not in use by any other transfer, there should not be any data here,
       only "protocol frames" */
    CURLcode result;
    ssize_t nread = -1;

    *input_pending = FALSE;
    nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
    if(nread != -1) {
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
}

static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf,
                                      struct Curl_easy *data)
{
  struct Curl_easy *second = curl_easy_duphandle(data);
  if(second) {
    /* setup the request struct */
    struct HTTP *http = calloc(1, sizeof(struct HTTP));
    if(!http) {
      (void)Curl_close(&second);
    }
    else {
      struct h2_stream_ctx *second_stream;

      second->req.p.http = http;
      http2_data_setup(cf, second, &second_stream);
      second->state.priority.weight = data->state.priority.weight;
    }
  }
  return second;
}

static int set_transfer_url(struct Curl_easy *data,
                            struct curl_pushheaders *hp)
{







<
<
<
<
<
<
|
<
<
|
|
<







787
788
789
790
791
792
793






794


795
796

797
798
799
800
801
802
803
}

static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf,
                                      struct Curl_easy *data)
{
  struct Curl_easy *second = curl_easy_duphandle(data);
  if(second) {






    struct h2_stream_ctx *second_stream;


    http2_data_setup(cf, second, &second_stream);
    second->state.priority.weight = data->state.priority.weight;

  }
  return second;
}

static int set_transfer_url(struct Curl_easy *data,
                            struct curl_pushheaders *hp)
{
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
  data->state.url = url;
  return 0;
}

static void discard_newhandle(struct Curl_cfilter *cf,
                              struct Curl_easy *newhandle)
{
  if(newhandle->req.p.http) {
    http2_data_done(cf, newhandle);
  }
  (void)Curl_close(&newhandle);
}

static int push_promise(struct Curl_cfilter *cf,
                        struct Curl_easy *data,
                        const nghttp2_push_promise *frame)
{







<
|
<







851
852
853
854
855
856
857

858

859
860
861
862
863
864
865
  data->state.url = url;
  return 0;
}

static void discard_newhandle(struct Curl_cfilter *cf,
                              struct Curl_easy *newhandle)
{

  http2_data_done(cf, newhandle);

  (void)Curl_close(&newhandle);
}

static int push_promise(struct Curl_cfilter *cf,
                        struct Curl_easy *data,
                        const nghttp2_push_promise *frame)
{
963
964
965
966
967
968
969




970
971
972
973
974
975
976
    if(rv) {
      infof(data, "failed to set user_data for stream %u",
            newstream->id);
      DEBUGASSERT(0);
      rv = CURL_PUSH_DENY;
      goto fail;
    }




  }
  else {
    CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ignore it");
    rv = CURL_PUSH_DENY;
  }
fail:
  return rv;







>
>
>
>







949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
    if(rv) {
      infof(data, "failed to set user_data for stream %u",
            newstream->id);
      DEBUGASSERT(0);
      rv = CURL_PUSH_DENY;
      goto fail;
    }

    /* success, remember max stream id processed */
    if(newstream->id > ctx->local_max_sid)
      ctx->local_max_sid = newstream->id;
  }
  else {
    CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ignore it");
    rv = CURL_PUSH_DENY;
  }
fail:
  return rv;
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  /* If the transfer write is errored, we do not want any more data */
  if(stream->xfer_result) {
    struct cf_h2_ctx *ctx = cf->ctx;
    CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of data, "
                "RST-ing stream",
                stream->id, stream->xfer_result, blen);
    nghttp2_submit_rst_stream(ctx->h2, 0, stream->id,
                              NGHTTP2_ERR_CALLBACK_FAILURE);
  }
}

static CURLcode on_stream_frame(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                const nghttp2_frame *frame)
{







|







993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  /* If the transfer write is errored, we do not want any more data */
  if(stream->xfer_result) {
    struct cf_h2_ctx *ctx = cf->ctx;
    CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of data, "
                "RST-ing stream",
                stream->id, stream->xfer_result, blen);
    nghttp2_submit_rst_stream(ctx->h2, 0, stream->id,
                              (uint32_t)NGHTTP2_ERR_CALLBACK_FAILURE);
  }
}

static CURLcode on_stream_frame(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                const nghttp2_frame *frame)
{
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
    }
    if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
      drain_stream(cf, data, stream);
    }
    break;
  case NGHTTP2_HEADERS:
    if(stream->bodystarted) {
      /* Only valid HEADERS after body started is trailer HEADERS.  We
         buffer them in on_header callback. */
      break;
    }

    /* nghttp2 guarantees that :status is received, and we store it to
       stream->status_code. Fuzzing has proven this can still be reached
       without status code having been set. */







|







1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
    }
    if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
      drain_stream(cf, data, stream);
    }
    break;
  case NGHTTP2_HEADERS:
    if(stream->bodystarted) {
      /* Only valid HEADERS after body started is trailer HEADERS. We
         buffer them in on_header callback. */
      break;
    }

    /* nghttp2 guarantees that :status is received, and we store it to
       stream->status_code. Fuzzing has proven this can still be reached
       without status code having been set. */
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
          if(stream)
            drain_stream(cf, data, stream);
        }
      }
      break;
    }
    case NGHTTP2_GOAWAY:
      ctx->goaway = TRUE;
      ctx->goaway_error = frame->goaway.error_code;
      ctx->last_stream_id = frame->goaway.last_stream_id;
      if(data) {
        infof(data, "received GOAWAY, error=%d, last_stream=%u",
                    ctx->goaway_error, ctx->last_stream_id);
        Curl_multi_connchanged(data->multi);
      }
      break;
    default:
      break;
    }
    return 0;







|

|

|
|







1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
          if(stream)
            drain_stream(cf, data, stream);
        }
      }
      break;
    }
    case NGHTTP2_GOAWAY:
      ctx->rcvd_goaway = TRUE;
      ctx->goaway_error = frame->goaway.error_code;
      ctx->remote_max_sid = frame->goaway.last_stream_id;
      if(data) {
        infof(data, "received GOAWAY, error=%u, last_stream=%u",
                    ctx->goaway_error, ctx->remote_max_sid);
        Curl_multi_connchanged(data->multi);
      }
      break;
    default:
      break;
    }
    return 0;
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
  binlen = populate_binsettings(binsettings, data);
  if(binlen <= 0) {
    failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
    Curl_dyn_free(req);
    return CURLE_FAILED_INIT;
  }

  result = Curl_base64url_encode((const char *)binsettings, binlen,
                                 &base64, &blen);
  if(result) {
    Curl_dyn_free(req);
    return result;
  }

  result = Curl_dyn_addf(req,







|







1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
  binlen = populate_binsettings(binsettings, data);
  if(binlen <= 0) {
    failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
    Curl_dyn_free(req);
    return CURLE_FAILED_INIT;
  }

  result = Curl_base64url_encode((const char *)binsettings, (size_t)binlen,
                                 &base64, &blen);
  if(result) {
    Curl_dyn_free(req);
    return result;
  }

  result = Curl_dyn_addf(req,
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
                                         CURLcode *err)
{
  ssize_t rv = 0;

  if(stream->error == NGHTTP2_REFUSED_STREAM) {
    CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
                "connection", stream->id);
    connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */
    data->state.refused_stream = TRUE;
    *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
    return -1;
  }
  else if(stream->error != NGHTTP2_NO_ERROR) {
    if(stream->resp_hds_complete && data->req.no_body) {
      CURL_TRC_CF(data, cf, "[%d] error after response headers, but we did "







|







1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
                                         CURLcode *err)
{
  ssize_t rv = 0;

  if(stream->error == NGHTTP2_REFUSED_STREAM) {
    CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
                "connection", stream->id);
    connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
    data->state.refused_stream = TRUE;
    *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
    return -1;
  }
  else if(stream->error != NGHTTP2_NO_ERROR) {
    if(stream->resp_hds_complete && data->req.no_body) {
      CURL_TRC_CF(data, cf, "[%d] error after response headers, but we did "
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
  nghttp2_priority_spec_init(pri_spec, depstream_id,
                             sweight_wanted(data),
                             data->set.priority.exclusive);
  data->state.priority = *prio;
}

/*
 * Check if there's been an update in the priority /
 * dependency settings and if so it submits a PRIORITY frame with the updated
 * info.
 * Flush any out data pending in the network buffer.
 */
static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
                                  struct Curl_easy *data)
{







|







1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
  nghttp2_priority_spec_init(pri_spec, depstream_id,
                             sweight_wanted(data),
                             data->set.priority.exclusive);
  data->state.priority = *prio;
}

/*
 * Check if there is been an update in the priority /
 * dependency settings and if so it submits a PRIORITY frame with the updated
 * info.
 * Flush any out data pending in the network buffer.
 */
static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
                                  struct Curl_easy *data)
{
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
  }
  else if(stream->closed) {
    CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
    nread = http2_handle_stream_close(cf, data, stream, err);
  }
  else if(stream->reset ||
          (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
          (ctx->goaway && ctx->last_stream_id < stream->id)) {
    CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2;
    nread = -1;
  }

  if(nread < 0 && *err != CURLE_AGAIN)
    CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d",







|







1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
  }
  else if(stream->closed) {
    CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
    nread = http2_handle_stream_close(cf, data, stream, err);
  }
  else if(stream->reset ||
          (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
          (ctx->rcvd_goaway && ctx->remote_max_sid < stream->id)) {
    CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
    *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2;
    nread = -1;
  }

  if(nread < 0 && *err != CURLE_AGAIN)
    CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d",
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
      drain_stream(cf, data, stream);
    }
  }

out:
  result = h2_progress_egress(cf, data);
  if(result == CURLE_AGAIN) {
    /* pending data to send, need to be called again. Ideally, we'd
     * monitor the socket for POLLOUT, but we might not be in SENDING
     * transfer state any longer and are unable to make this happen.
     */
    drain_stream(cf, data, stream);
  }
  else if(result) {
    *err = result;







|







2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
      drain_stream(cf, data, stream);
    }
  }

out:
  result = h2_progress_egress(cf, data);
  if(result == CURLE_AGAIN) {
    /* pending data to send, need to be called again. Ideally, we would
     * monitor the socket for POLLOUT, but we might not be in SENDING
     * transfer state any longer and are unable to make this happen.
     */
    drain_stream(cf, data, stream);
  }
  else if(result) {
    *err = result;
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
    blocked = 1;
  }

  if(stream && blocked && nwritten > 0) {
    /* Unable to send all data, due to connection blocked or H2 window
     * exhaustion. Data is left in our stream buffer, or nghttp2's internal
     * frame buffer or our network out buffer. */
    size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2,
                                                                stream->id);
    /* At the start of a stream, we are called with request headers
     * and, possibly, parts of the body. Later, only body data.
     * If we cannot send pure body data, we EAGAIN. If there had been
     * header, we return that *they* have been written and remember the
     * block on the data length only. */
    stream->upload_blocked_len = ((size_t)nwritten) - hdslen;
    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu "







|
|







2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
    blocked = 1;
  }

  if(stream && blocked && nwritten > 0) {
    /* Unable to send all data, due to connection blocked or H2 window
     * exhaustion. Data is left in our stream buffer, or nghttp2's internal
     * frame buffer or our network out buffer. */
    size_t rwin = (size_t)nghttp2_session_get_stream_remote_window_size(
                    ctx->h2, stream->id);
    /* At the start of a stream, we are called with request headers
     * and, possibly, parts of the body. Later, only body data.
     * If we cannot send pure body data, we EAGAIN. If there had been
     * header, we return that *they* have been written and remember the
     * block on the data length only. */
    stream->upload_blocked_len = ((size_t)nwritten) - hdslen;
    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu "
2354
2355
2356
2357
2358
2359
2360

2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384








2385
2386
2387
2388
2389
2390
2391
}

static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 struct easy_pollset *ps)
{
  struct cf_h2_ctx *ctx = cf->ctx;

  curl_socket_t sock;
  bool want_recv, want_send;

  if(!ctx->h2)
    return;

  sock = Curl_conn_cf_get_socket(cf, data);
  Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
  if(want_recv || want_send) {
    struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
    struct cf_call_data save;
    bool c_exhaust, s_exhaust;

    CF_DATA_SAVE(save, cf, data);
    c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2);
    s_exhaust = want_send && stream && stream->id >= 0 &&
                !nghttp2_session_get_stream_remote_window_size(ctx->h2,
                                                               stream->id);
    want_recv = (want_recv || c_exhaust || s_exhaust);
    want_send = (!s_exhaust && want_send) ||
                (!c_exhaust && nghttp2_session_want_write(ctx->h2));

    Curl_pollset_set(data, ps, sock, want_recv, want_send);
    CF_DATA_RESTORE(cf, save);








  }
}

static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              bool blocking, bool *done)
{







>










<













>
>
>
>
>
>
>
>







2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361

2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
}

static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 struct easy_pollset *ps)
{
  struct cf_h2_ctx *ctx = cf->ctx;
  struct cf_call_data save;
  curl_socket_t sock;
  bool want_recv, want_send;

  if(!ctx->h2)
    return;

  sock = Curl_conn_cf_get_socket(cf, data);
  Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
  if(want_recv || want_send) {
    struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);

    bool c_exhaust, s_exhaust;

    CF_DATA_SAVE(save, cf, data);
    c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2);
    s_exhaust = want_send && stream && stream->id >= 0 &&
                !nghttp2_session_get_stream_remote_window_size(ctx->h2,
                                                               stream->id);
    want_recv = (want_recv || c_exhaust || s_exhaust);
    want_send = (!s_exhaust && want_send) ||
                (!c_exhaust && nghttp2_session_want_write(ctx->h2));

    Curl_pollset_set(data, ps, sock, want_recv, want_send);
    CF_DATA_RESTORE(cf, save);
  }
  else if(ctx->sent_goaway && !cf->shutdown) {
    /* shutdown in progress */
    CF_DATA_SAVE(save, cf, data);
    want_send = nghttp2_session_want_write(ctx->h2);
    want_recv = nghttp2_session_want_read(ctx->h2);
    Curl_pollset_set(data, ps, sock, want_recv, want_send);
    CF_DATA_RESTORE(cf, save);
  }
}

static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              bool blocking, bool *done)
{
2442
2443
2444
2445
2446
2447
2448

2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463












































2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487

  if(ctx) {
    struct cf_call_data save;

    CF_DATA_SAVE(save, cf, data);
    cf_h2_ctx_clear(ctx);
    CF_DATA_RESTORE(cf, save);

  }
  if(cf->next)
    cf->next->cft->do_close(cf->next, data);
}

static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_h2_ctx *ctx = cf->ctx;

  (void)data;
  if(ctx) {
    cf_h2_ctx_free(ctx);
    cf->ctx = NULL;
  }
}













































static CURLcode http2_data_pause(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 bool pause)
{
#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
  struct cf_h2_ctx *ctx = cf->ctx;
  struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);

  DEBUGASSERT(data);
  if(ctx && ctx->h2 && stream) {
    uint32_t window = pause? 0 : stream->local_window_size;

    int rv = nghttp2_session_set_local_window_size(ctx->h2,
                                                   NGHTTP2_FLAG_NONE,
                                                   stream->id,
                                                   window);
    if(rv) {
      failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return CURLE_HTTP2;
    }

    if(!pause)







>















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













|
|
|
|







2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530

  if(ctx) {
    struct cf_call_data save;

    CF_DATA_SAVE(save, cf, data);
    cf_h2_ctx_clear(ctx);
    CF_DATA_RESTORE(cf, save);
    cf->connected = FALSE;
  }
  if(cf->next)
    cf->next->cft->do_close(cf->next, data);
}

static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_h2_ctx *ctx = cf->ctx;

  (void)data;
  if(ctx) {
    cf_h2_ctx_free(ctx);
    cf->ctx = NULL;
  }
}

static CURLcode cf_h2_shutdown(struct Curl_cfilter *cf,
                               struct Curl_easy *data, bool *done)
{
  struct cf_h2_ctx *ctx = cf->ctx;
  struct cf_call_data save;
  CURLcode result;
  int rv;

  if(!cf->connected || !ctx->h2 || cf->shutdown || ctx->conn_closed) {
    *done = TRUE;
    return CURLE_OK;
  }

  CF_DATA_SAVE(save, cf, data);

  if(!ctx->sent_goaway) {
    rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
                               ctx->local_max_sid, 0,
                               (const uint8_t *)"shutown", sizeof("shutown"));
    if(rv) {
      failf(data, "nghttp2_submit_goaway() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      result = CURLE_SEND_ERROR;
      goto out;
    }
    ctx->sent_goaway = TRUE;
  }
  /* GOAWAY submitted, process egress and ingress until nghttp2 is done. */
  result = CURLE_OK;
  if(nghttp2_session_want_write(ctx->h2))
    result = h2_progress_egress(cf, data);
  if(!result && nghttp2_session_want_read(ctx->h2))
    result = h2_progress_ingress(cf, data, 0);

  *done = (ctx->conn_closed ||
           (!result && !nghttp2_session_want_write(ctx->h2) &&
            !nghttp2_session_want_read(ctx->h2)));

out:
  CF_DATA_RESTORE(cf, save);
  cf->shutdown = (result || *done);
  return result;
}

static CURLcode http2_data_pause(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 bool pause)
{
#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
  struct cf_h2_ctx *ctx = cf->ctx;
  struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);

  DEBUGASSERT(data);
  if(ctx && ctx->h2 && stream) {
    uint32_t window = pause? 0 : stream->local_window_size;

    int rv = (int)nghttp2_session_set_local_window_size(ctx->h2,
                                                        NGHTTP2_FLAG_NONE,
                                                        stream->id,
                                                        (int32_t)window);
    if(rv) {
      failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
            nghttp2_strerror(rv), rv);
      return CURLE_HTTP2;
    }

    if(!pause)
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
    }
    DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
                 window, stream->id));

#ifdef DEBUGBUILD
    {
      /* read out the stream local window again */
      uint32_t window2 =
        nghttp2_session_get_stream_local_window_size(ctx->h2,
                                                     stream->id);
      DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
                   window2, stream->id));
    }
#endif
  }







|







2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
    }
    DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
                 window, stream->id));

#ifdef DEBUGBUILD
    {
      /* read out the stream local window again */
      uint32_t window2 = (uint32_t)
        nghttp2_session_get_stream_local_window_size(ctx->h2,
                                                     stream->id);
      DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
                   window2, stream->id));
    }
#endif
  }
2628
2629
2630
2631
2632
2633
2634

2635
2636
2637
2638
2639
2640
2641
struct Curl_cftype Curl_cft_nghttp2 = {
  "HTTP/2",
  CF_TYPE_MULTIPLEX,
  CURL_LOG_LVL_NONE,
  cf_h2_destroy,
  cf_h2_connect,
  cf_h2_close,

  Curl_cf_def_get_host,
  cf_h2_adjust_pollset,
  cf_h2_data_pending,
  cf_h2_send,
  cf_h2_recv,
  cf_h2_cntrl,
  cf_h2_is_alive,







>







2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
struct Curl_cftype Curl_cft_nghttp2 = {
  "HTTP/2",
  CF_TYPE_MULTIPLEX,
  CURL_LOG_LVL_NONE,
  cf_h2_destroy,
  cf_h2_connect,
  cf_h2_close,
  cf_h2_shutdown,
  Curl_cf_def_get_host,
  cf_h2_adjust_pollset,
  cf_h2_data_pending,
  cf_h2_send,
  cf_h2_recv,
  cf_h2_cntrl,
  cf_h2_is_alive,
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
                           int sockindex)
{
  (void)sockindex;
  if(!Curl_conn_is_http2(data, conn, sockindex) &&
     data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
#ifndef CURL_DISABLE_PROXY
    if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
      /* We don't support HTTP/2 proxies yet. Also it's debatable
         whether or not this setting should apply to HTTP/2 proxies. */
      infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
      return FALSE;
    }
#endif
    return TRUE;
  }







|







2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
                           int sockindex)
{
  (void)sockindex;
  if(!Curl_conn_is_http2(data, conn, sockindex) &&
     data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
#ifndef CURL_DISABLE_PROXY
    if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
      /* We do not support HTTP/2 proxies yet. Also it is debatable
         whether or not this setting should apply to HTTP/2 proxies. */
      infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
      return FALSE;
    }
#endif
    return TRUE;
  }
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
  DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex));
  DEBUGF(infof(data, "switching to HTTP/2"));

  result = http2_cfilter_add(&cf, data, conn, sockindex, FALSE);
  if(result)
    return result;

  conn->httpversion = 20; /* we know we're on HTTP/2 now */
  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
  Curl_multi_connchanged(data->multi);

  if(cf->next) {
    bool done;
    return Curl_conn_cf_connect(cf, data, FALSE, &done);







|







2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
  DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex));
  DEBUGF(infof(data, "switching to HTTP/2"));

  result = http2_cfilter_add(&cf, data, conn, sockindex, FALSE);
  if(result)
    return result;

  conn->httpversion = 20; /* we know we are on HTTP/2 now */
  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
  Curl_multi_connchanged(data->multi);

  if(cf->next) {
    bool done;
    return Curl_conn_cf_connect(cf, data, FALSE, &done);
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
  DEBUGASSERT(!Curl_cf_is_http2(cf, data));

  result = http2_cfilter_insert_after(cf, data, FALSE);
  if(result)
    return result;

  cf_h2 = cf->next;
  cf->conn->httpversion = 20; /* we know we're on HTTP/2 now */
  cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
  cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
  Curl_multi_connchanged(data->multi);

  if(cf_h2->next) {
    bool done;
    return Curl_conn_cf_connect(cf_h2, data, FALSE, &done);







|







2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
  DEBUGASSERT(!Curl_cf_is_http2(cf, data));

  result = http2_cfilter_insert_after(cf, data, FALSE);
  if(result)
    return result;

  cf_h2 = cf->next;
  cf->conn->httpversion = 20; /* we know we are on HTTP/2 now */
  cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
  cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
  Curl_multi_connchanged(data->multi);

  if(cf_h2->next) {
    bool done;
    return Curl_conn_cf_connect(cf_h2, data, FALSE, &done);
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
            copied, nread);
      return CURLE_HTTP2;
    }
    infof(data, "Copied HTTP/2 data in stream buffer to connection buffer"
          " after upgrade: len=%zu", nread);
  }

  conn->httpversion = 20; /* we know we're on HTTP/2 now */
  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
  Curl_multi_connchanged(data->multi);

  if(cf->next) {
    bool done;
    return Curl_conn_cf_connect(cf, data, FALSE, &done);







|







2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
            copied, nread);
      return CURLE_HTTP2;
    }
    infof(data, "Copied HTTP/2 data in stream buffer to connection buffer"
          " after upgrade: len=%zu", nread);
  }

  conn->httpversion = 20; /* we know we are on HTTP/2 now */
  conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
  conn->bundle->multiuse = BUNDLE_MULTIPLEX;
  Curl_multi_connchanged(data->multi);

  if(cf->next) {
    bool done;
    return Curl_conn_cf_connect(cf, data, FALSE, &done);
Changes to jni/curl/lib/http_aws_sigv4.c.
418
419
420
421
422
423
424






































































425
426
427
428
429
430
431
    return -1;
  if(bb->len == 0)
    return 1;
  return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len);
}

#define MAX_QUERYPAIRS 64







































































static CURLcode canon_query(struct Curl_easy *data,
                            const char *query, struct dynbuf *dq)
{
  CURLcode result = CURLE_OK;
  int entry = 0;
  int i;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
    return -1;
  if(bb->len == 0)
    return 1;
  return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len);
}

#define MAX_QUERYPAIRS 64

/**
 * found_equals have a double meaning,
 * detect if an equal have been found when called from canon_query,
 * and mark that this function is called to compute the path,
 * if found_equals is NULL.
 */
static CURLcode canon_string(const char *q, size_t len,
                             struct dynbuf *dq, bool *found_equals)
{
  CURLcode result = CURLE_OK;

  for(; len && !result; q++, len--) {
    if(ISALNUM(*q))
      result = Curl_dyn_addn(dq, q, 1);
    else {
      switch(*q) {
      case '-':
      case '.':
      case '_':
      case '~':
        /* allowed as-is */
        result = Curl_dyn_addn(dq, q, 1);
        break;
      case '%':
        /* uppercase the following if hexadecimal */
        if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) {
          char tmp[3]="%";
          tmp[1] = Curl_raw_toupper(q[1]);
          tmp[2] = Curl_raw_toupper(q[2]);
          result = Curl_dyn_addn(dq, tmp, 3);
          q += 2;
          len -= 2;
        }
        else
          /* '%' without a following two-digit hex, encode it */
          result = Curl_dyn_addn(dq, "%25", 3);
        break;
      default: {
        const char hex[] = "0123456789ABCDEF";
        char out[3]={'%'};

        if(!found_equals) {
          /* if found_equals is NULL assuming, been in path */
          if(*q == '/') {
            /* allowed as if */
            result = Curl_dyn_addn(dq, q, 1);
            break;
          }
        }
        else {
          /* allowed as-is */
          if(*q == '=') {
            result = Curl_dyn_addn(dq, q, 1);
            *found_equals = true;
            break;
          }
        }
        /* URL encode */
        out[1] = hex[((unsigned char)*q)>>4];
        out[2] = hex[*q & 0xf];
        result = Curl_dyn_addn(dq, out, 3);
        break;
      }
      }
    }
  }
  return result;
}


static CURLcode canon_query(struct Curl_easy *data,
                            const char *query, struct dynbuf *dq)
{
  CURLcode result = CURLE_OK;
  int entry = 0;
  int i;
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
    return CURLE_URL_MALFORMAT;
  }

  qsort(&array[0], entry, sizeof(struct pair), compare_func);

  ap = &array[0];
  for(i = 0; !result && (i < entry); i++, ap++) {
    size_t len;
    const char *q = ap->p;
    bool found_equals = false;
    if(!ap->len)
      continue;
    for(len = ap->len; len && !result; q++, len--) {
      if(ISALNUM(*q))
        result = Curl_dyn_addn(dq, q, 1);
      else {
        switch(*q) {
        case '-':
        case '.':
        case '_':
        case '~':
          /* allowed as-is */
          result = Curl_dyn_addn(dq, q, 1);
          break;
        case '=':
          /* allowed as-is */
          result = Curl_dyn_addn(dq, q, 1);
          found_equals = true;
          break;
        case '%':
          /* uppercase the following if hexadecimal */
          if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) {
            char tmp[3]="%";
            tmp[1] = Curl_raw_toupper(q[1]);
            tmp[2] = Curl_raw_toupper(q[2]);
            result = Curl_dyn_addn(dq, tmp, 3);
            q += 2;
            len -= 2;
          }
          else
            /* '%' without a following two-digit hex, encode it */
            result = Curl_dyn_addn(dq, "%25", 3);
          break;
        default: {
          /* URL encode */
          const char hex[] = "0123456789ABCDEF";
          char out[3]={'%'};
          out[1] = hex[((unsigned char)*q)>>4];
          out[2] = hex[*q & 0xf];
          result = Curl_dyn_addn(dq, out, 3);
          break;
        }
        }
      }
    }
    if(!result && !found_equals) {
      /* queries without value still need an equals */
      result = Curl_dyn_addn(dq, "=", 1);
    }
    if(!result && i < entry - 1) {
      /* insert ampersands between query pairs */
      result = Curl_dyn_addn(dq, "&", 1);







<




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







526
527
528
529
530
531
532

533
534
535
536















537



























538
539
540
541
542
543
544
    return CURLE_URL_MALFORMAT;
  }

  qsort(&array[0], entry, sizeof(struct pair), compare_func);

  ap = &array[0];
  for(i = 0; !result && (i < entry); i++, ap++) {

    const char *q = ap->p;
    bool found_equals = false;
    if(!ap->len)
      continue;















    result = canon_string(q, ap->len, dq, &found_equals);



























    if(!result && !found_equals) {
      /* queries without value still need an equals */
      result = Curl_dyn_addn(dq, "=", 1);
    }
    if(!result && i < entry - 1) {
      /* insert ampersands between query pairs */
      result = Curl_dyn_addn(dq, "&", 1);
536
537
538
539
540
541
542

543
544
545
546
547
548
549
  time_t clock;
  struct tm tm;
  char timestamp[TIMESTAMP_SIZE];
  char date[9];
  struct dynbuf canonical_headers;
  struct dynbuf signed_headers;
  struct dynbuf canonical_query;

  char *date_header = NULL;
  Curl_HttpReq httpreq;
  const char *method = NULL;
  char *payload_hash = NULL;
  size_t payload_hash_len = 0;
  unsigned char sha_hash[SHA256_DIGEST_LENGTH];
  char sha_hex[SHA256_HEX_LENGTH];







>







563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
  time_t clock;
  struct tm tm;
  char timestamp[TIMESTAMP_SIZE];
  char date[9];
  struct dynbuf canonical_headers;
  struct dynbuf signed_headers;
  struct dynbuf canonical_query;
  struct dynbuf canonical_path;
  char *date_header = NULL;
  Curl_HttpReq httpreq;
  const char *method = NULL;
  char *payload_hash = NULL;
  size_t payload_hash_len = 0;
  unsigned char sha_hash[SHA256_DIGEST_LENGTH];
  char sha_hex[SHA256_HEX_LENGTH];
566
567
568
569
570
571
572

573
574
575
576
577
578
579
    return CURLE_OK;
  }

  /* we init those buffers here, so goto fail will free initialized dynbuf */
  Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
  Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
  Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);


  /*
   * Parameters parsing
   * Google and Outscale use the same OSC or GOOG,
   * but Amazon uses AWS and AMZ for header arguments.
   * AWS is the default because most of non-amazon providers
   * are still using aws:amz as a prefix.







>







594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
    return CURLE_OK;
  }

  /* we init those buffers here, so goto fail will free initialized dynbuf */
  Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
  Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
  Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
  Curl_dyn_init(&canonical_path, CURL_MAX_HTTP_HEADER);

  /*
   * Parameters parsing
   * Google and Outscale use the same OSC or GOOG,
   * but Amazon uses AWS and AMZ for header arguments.
   * AWS is the default because most of non-amazon providers
   * are still using aws:amz as a prefix.
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  */
  (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]"
               ":%" MAX_SIGV4_LEN_TXT "[^:]"
               ":%" MAX_SIGV4_LEN_TXT "[^:]"
               ":%" MAX_SIGV4_LEN_TXT "s",
               provider0, provider1, region, service);
  if(!provider0[0]) {
    failf(data, "first aws-sigv4 provider can't be empty");
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    goto fail;
  }
  else if(!provider1[0])
    strcpy(provider1, provider0);

  if(!service[0]) {







|







616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
  */
  (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]"
               ":%" MAX_SIGV4_LEN_TXT "[^:]"
               ":%" MAX_SIGV4_LEN_TXT "[^:]"
               ":%" MAX_SIGV4_LEN_TXT "s",
               provider0, provider1, region, service);
  if(!provider0[0]) {
    failf(data, "first aws-sigv4 provider cannot be empty");
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    goto fail;
  }
  else if(!provider1[0])
    strcpy(provider1, provider0);

  if(!service[0]) {
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678

#ifdef DEBUGBUILD
  {
    char *force_timestamp = getenv("CURL_FORCETIME");
    if(force_timestamp)
      clock = 0;
    else
      time(&clock);
  }
#else
  time(&clock);
#endif
  result = Curl_gmtime(clock, &tm);
  if(result) {
    goto fail;
  }
  if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
    result = CURLE_OUT_OF_MEMORY;







|


|







690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707

#ifdef DEBUGBUILD
  {
    char *force_timestamp = getenv("CURL_FORCETIME");
    if(force_timestamp)
      clock = 0;
    else
      clock = time(NULL);
  }
#else
  clock = time(NULL);
#endif
  result = Curl_gmtime(clock, &tm);
  if(result) {
    goto fail;
  }
  if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
    result = CURLE_OUT_OF_MEMORY;
694
695
696
697
698
699
700





701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718

  memcpy(date, timestamp, sizeof(date));
  date[sizeof(date) - 1] = 0;

  result = canon_query(data, data->state.up.query, &canonical_query);
  if(result)
    goto fail;





  result = CURLE_OUT_OF_MEMORY;

  canonical_request =
    curl_maprintf("%s\n" /* HTTPRequestMethod */
                  "%s\n" /* CanonicalURI */
                  "%s\n" /* CanonicalQueryString */
                  "%s\n" /* CanonicalHeaders */
                  "%s\n" /* SignedHeaders */
                  "%.*s",  /* HashedRequestPayload in hex */
                  method,
                  data->state.up.path,
                  Curl_dyn_ptr(&canonical_query) ?
                  Curl_dyn_ptr(&canonical_query) : "",
                  Curl_dyn_ptr(&canonical_headers),
                  Curl_dyn_ptr(&signed_headers),
                  (int)payload_hash_len, payload_hash);
  if(!canonical_request)
    goto fail;







>
>
>
>
>










|







723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752

  memcpy(date, timestamp, sizeof(date));
  date[sizeof(date) - 1] = 0;

  result = canon_query(data, data->state.up.query, &canonical_query);
  if(result)
    goto fail;

  result = canon_string(data->state.up.path, strlen(data->state.up.path),
                        &canonical_path, NULL);
  if(result)
    goto fail;
  result = CURLE_OUT_OF_MEMORY;

  canonical_request =
    curl_maprintf("%s\n" /* HTTPRequestMethod */
                  "%s\n" /* CanonicalURI */
                  "%s\n" /* CanonicalQueryString */
                  "%s\n" /* CanonicalHeaders */
                  "%s\n" /* SignedHeaders */
                  "%.*s",  /* HashedRequestPayload in hex */
                  method,
                  Curl_dyn_ptr(&canonical_path),
                  Curl_dyn_ptr(&canonical_query) ?
                  Curl_dyn_ptr(&canonical_query) : "",
                  Curl_dyn_ptr(&canonical_headers),
                  Curl_dyn_ptr(&signed_headers),
                  (int)payload_hash_len, payload_hash);
  if(!canonical_request)
    goto fail;
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786

  /* provider 0 uppercase */
  auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
                               "Credential=%s/%s, "
                               "SignedHeaders=%s, "
                               "Signature=%s\r\n"
                               /*
                                * date_header is added here, only if it wasn't
                                * user-specified (using CURLOPT_HTTPHEADER).
                                * date_header includes \r\n
                                */
                               "%s"
                               "%s", /* optional sha256 header includes \r\n */
                               provider0,
                               user,







|







806
807
808
809
810
811
812
813
814
815
816
817
818
819
820

  /* provider 0 uppercase */
  auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
                               "Credential=%s/%s, "
                               "SignedHeaders=%s, "
                               "Signature=%s\r\n"
                               /*
                                * date_header is added here, only if it was not
                                * user-specified (using CURLOPT_HTTPHEADER).
                                * date_header includes \r\n
                                */
                               "%s"
                               "%s", /* optional sha256 header includes \r\n */
                               provider0,
                               user,
796
797
798
799
800
801
802

803
804
805
806
807
808
809
810
811
812
813
814
  Curl_safefree(data->state.aptr.userpwd);
  data->state.aptr.userpwd = auth_headers;
  data->state.authhost.done = TRUE;
  result = CURLE_OK;

fail:
  Curl_dyn_free(&canonical_query);

  Curl_dyn_free(&canonical_headers);
  Curl_dyn_free(&signed_headers);
  free(canonical_request);
  free(request_type);
  free(credential_scope);
  free(str_to_sign);
  free(secret);
  free(date_header);
  return result;
}

#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */







>












830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
  Curl_safefree(data->state.aptr.userpwd);
  data->state.aptr.userpwd = auth_headers;
  data->state.authhost.done = TRUE;
  result = CURLE_OK;

fail:
  Curl_dyn_free(&canonical_query);
  Curl_dyn_free(&canonical_path);
  Curl_dyn_free(&canonical_headers);
  Curl_dyn_free(&signed_headers);
  free(canonical_request);
  free(request_type);
  free(credential_scope);
  free(str_to_sign);
  free(secret);
  free(date_header);
  return result;
}

#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */
Changes to jni/curl/lib/http_chunks.c.
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
        ch->state = CHUNK_LF; /* now wait for the CRLF */
      }
      break;

    case CHUNK_LF:
      /* waiting for the LF after a chunk size */
      if(*buf == 0x0a) {
        /* we're now expecting data to come, unless size was zero! */
        if(0 == ch->datasize) {
          ch->state = CHUNK_TRAILER; /* now check for trailers */
        }
        else {
          ch->state = CHUNK_DATA;
          CURL_TRC_WRITE(data, "http_chunked, chunk start of %"
                         CURL_FORMAT_CURL_OFF_T " bytes", ch->datasize);







|







178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
        ch->state = CHUNK_LF; /* now wait for the CRLF */
      }
      break;

    case CHUNK_LF:
      /* waiting for the LF after a chunk size */
      if(*buf == 0x0a) {
        /* we are now expecting data to come, unless size was zero! */
        if(0 == ch->datasize) {
          ch->state = CHUNK_TRAILER; /* now check for trailers */
        }
        else {
          ch->state = CHUNK_DATA;
          CURL_TRC_WRITE(data, "http_chunked, chunk start of %"
                         CURL_FORMAT_CURL_OFF_T " bytes", ch->datasize);
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
          Curl_dyn_reset(&ch->trailer);
          ch->state = CHUNK_TRAILER_CR;
          if(*buf == 0x0a)
            /* already on the LF */
            break;
        }
        else {
          /* no trailer, we're on the final CRLF pair */
          ch->state = CHUNK_TRAILER_POSTCR;
          break; /* don't advance the pointer */
        }
      }
      else {
        result = Curl_dyn_addn(&ch->trailer, buf, 1);
        if(result) {
          ch->state = CHUNK_FAILED;
          ch->last_code = CHUNKE_OUT_OF_MEMORY;







|

|







285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
          Curl_dyn_reset(&ch->trailer);
          ch->state = CHUNK_TRAILER_CR;
          if(*buf == 0x0a)
            /* already on the LF */
            break;
        }
        else {
          /* no trailer, we are on the final CRLF pair */
          ch->state = CHUNK_TRAILER_POSTCR;
          break; /* do not advance the pointer */
        }
      }
      else {
        result = Curl_dyn_addn(&ch->trailer, buf, 1);
        if(result) {
          ch->state = CHUNK_FAILED;
          ch->last_code = CHUNKE_OUT_OF_MEMORY;
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
      break;

    case CHUNK_STOP:
      if(*buf == 0x0a) {
        blen--;
        (*pconsumed)++;
        /* Record the length of any data left in the end of the buffer
           even if there's no more chunks to read */
        ch->datasize = blen;
        ch->state = CHUNK_DONE;
        CURL_TRC_WRITE(data, "http_chunk, response complete");
        return CURLE_OK;
      }
      else {
        ch->state = CHUNK_FAILED;







|







340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
      break;

    case CHUNK_STOP:
      if(*buf == 0x0a) {
        blen--;
        (*pconsumed)++;
        /* Record the length of any data left in the end of the buffer
           even if there is no more chunks to read */
        ch->datasize = blen;
        ch->state = CHUNK_DONE;
        CURL_TRC_WRITE(data, "http_chunk, response complete");
        return CURLE_OK;
      }
      else {
        ch->state = CHUNK_FAILED;
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  NULL,
  cw_chunked_init,
  cw_chunked_write,
  cw_chunked_close,
  sizeof(struct chunked_writer)
};

/* max length of a HTTP chunk that we want to generate */
#define CURL_CHUNKED_MINLEN   (1024)
#define CURL_CHUNKED_MAXLEN   (64 * 1024)

struct chunked_reader {
  struct Curl_creader super;
  struct bufq chunkbuf;
  BIT(read_eos);  /* we read an EOS from the next reader */







|







466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
  NULL,
  cw_chunked_init,
  cw_chunked_write,
  cw_chunked_close,
  sizeof(struct chunked_writer)
};

/* max length of an HTTP chunk that we want to generate */
#define CURL_CHUNKED_MINLEN   (1024)
#define CURL_CHUNKED_MAXLEN   (64 * 1024)

struct chunked_reader {
  struct Curl_creader super;
  struct bufq chunkbuf;
  BIT(read_eos);  /* we read an EOS from the next reader */
655
656
657
658
659
660
661

662
663
664
665
666
667
668
  cr_chunked_read,
  cr_chunked_close,
  Curl_creader_def_needs_rewind,
  cr_chunked_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,

  Curl_creader_def_done,
  sizeof(struct chunked_reader)
};

CURLcode Curl_httpchunk_add_reader(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;







>







655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  cr_chunked_read,
  cr_chunked_close,
  Curl_creader_def_needs_rewind,
  cr_chunked_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,
  Curl_creader_def_is_paused,
  Curl_creader_def_done,
  sizeof(struct chunked_reader)
};

CURLcode Curl_httpchunk_add_reader(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;
Changes to jni/curl/lib/http_chunks.h.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "dynbuf.h"

struct connectdata;

/*
 * The longest possible hexadecimal number we support in a chunked transfer.
 * Neither RFC2616 nor the later HTTP specs define a maximum chunk size.
 * For 64 bit curl_off_t we support 16 digits. For 32 bit, 8 digits.
 */
#define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2)

typedef enum {
  /* await and buffer all hexadecimal digits until we get one that isn't a
     hexadecimal digit. When done, we go CHUNK_LF */
  CHUNK_HEX,

  /* wait for LF, ignore all else */
  CHUNK_LF,

  /* We eat the amount of data specified. When done, we move on to the
     POST_CR state. */
  CHUNK_DATA,

  /* POSTLF should get a CR and then a LF and nothing else, then move back to
     HEX as the CRLF combination marks the end of a chunk. A missing CR is no
     big deal. */
  CHUNK_POSTLF,

  /* Used to mark that we're out of the game.  NOTE: that there's a 'datasize'
     field in the struct that will tell how many bytes that were not passed to
     the client in the end of the last buffer! */
  CHUNK_STOP,

  /* At this point optional trailer headers can be found, unless the next line
     is CRLF */
  CHUNK_TRAILER,

  /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR.







|




|















|
|
|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "dynbuf.h"

struct connectdata;

/*
 * The longest possible hexadecimal number we support in a chunked transfer.
 * Neither RFC2616 nor the later HTTP specs define a maximum chunk size.
 * For 64-bit curl_off_t we support 16 digits. For 32-bit, 8 digits.
 */
#define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2)

typedef enum {
  /* await and buffer all hexadecimal digits until we get one that is not a
     hexadecimal digit. When done, we go CHUNK_LF */
  CHUNK_HEX,

  /* wait for LF, ignore all else */
  CHUNK_LF,

  /* We eat the amount of data specified. When done, we move on to the
     POST_CR state. */
  CHUNK_DATA,

  /* POSTLF should get a CR and then a LF and nothing else, then move back to
     HEX as the CRLF combination marks the end of a chunk. A missing CR is no
     big deal. */
  CHUNK_POSTLF,

  /* Used to mark that we are out of the game. NOTE: that there is a
     'datasize' field in the struct that will tell how many bytes that were
     not passed to the client in the end of the last buffer! */
  CHUNK_STOP,

  /* At this point optional trailer headers can be found, unless the next line
     is CRLF */
  CHUNK_TRAILER,

  /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR.
Changes to jni/curl/lib/http_negotiate.c.
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  neg_ctx->havenegdata = len != 0;
  if(!len) {
    if(state == GSS_AUTHSUCC) {
      infof(data, "Negotiate auth restarted");
      Curl_http_auth_cleanup_negotiate(conn);
    }
    else if(state != GSS_AUTHNONE) {
      /* The server rejected our authentication and hasn't supplied any more
      negotiation mechanisms */
      Curl_http_auth_cleanup_negotiate(conn);
      return CURLE_LOGIN_DENIED;
    }
  }

  /* Supports SSL channel binding for Windows ISS extended protection */







|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  neg_ctx->havenegdata = len != 0;
  if(!len) {
    if(state == GSS_AUTHSUCC) {
      infof(data, "Negotiate auth restarted");
      Curl_http_auth_cleanup_negotiate(conn);
    }
    else if(state != GSS_AUTHNONE) {
      /* The server rejected our authentication and has not supplied any more
      negotiation mechanisms */
      Curl_http_auth_cleanup_negotiate(conn);
      return CURLE_LOGIN_DENIED;
    }
  }

  /* Supports SSL channel binding for Windows ISS extended protection */
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    }
  #endif
  #endif
  }

  if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) {
    /* connection is already authenticated,
     * don't send a header in future requests */
    authp->done = TRUE;
  }

  neg_ctx->havenegdata = FALSE;

  return CURLE_OK;
}







|







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    }
  #endif
  #endif
  }

  if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) {
    /* connection is already authenticated,
     * do not send a header in future requests */
    authp->done = TRUE;
  }

  neg_ctx->havenegdata = FALSE;

  return CURLE_OK;
}
Changes to jni/curl/lib/http_ntlm.c.
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
  ntlm->sslContext = conn->sslContext;
#endif
#endif

  Curl_bufref_init(&ntlmmsg);

  /* connection is already authenticated, don't send a header in future
   * requests so go directly to NTLMSTATE_LAST */
  if(*state == NTLMSTATE_TYPE3)
    *state = NTLMSTATE_LAST;

  switch(*state) {
  case NTLMSTATE_TYPE1:
  default: /* for the weird cases we (re)start here */







|







196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
  ntlm->sslContext = conn->sslContext;
#endif
#endif

  Curl_bufref_init(&ntlmmsg);

  /* connection is already authenticated, do not send a header in future
   * requests so go directly to NTLMSTATE_LAST */
  if(*state == NTLMSTATE_TYPE3)
    *state = NTLMSTATE_LAST;

  switch(*state) {
  case NTLMSTATE_TYPE1:
  default: /* for the weird cases we (re)start here */
Changes to jni/curl/lib/http_proxy.c.
294
295
296
297
298
299
300

301
302
303
304
305
306
307
struct Curl_cftype Curl_cft_http_proxy = {
  "HTTP-PROXY",
  CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
  0,
  http_proxy_cf_destroy,
  http_proxy_cf_connect,
  http_proxy_cf_close,

  Curl_cf_http_proxy_get_host,
  Curl_cf_def_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,







>







294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
struct Curl_cftype Curl_cft_http_proxy = {
  "HTTP-PROXY",
  CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
  0,
  http_proxy_cf_destroy,
  http_proxy_cf_connect,
  http_proxy_cf_close,
  Curl_cf_def_shutdown,
  Curl_cf_http_proxy_get_host,
  Curl_cf_def_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
Changes to jni/curl/lib/idn.c.
50
51
52
53
54
55
56


57
58


59
60

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80


81
82
83
84


85
86

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106


107
108
109
110
111
112
113
#include "curl_memory.h"
#include "memdebug.h"

/* for macOS and iOS targets */
#if defined(USE_APPLE_IDN)
#include <unicode/uidna.h>



static CURLcode mac_idn_to_ascii(const char *in, char **out)
{


  UErrorCode err = U_ZERO_ERROR;
  UIDNA* idna = uidna_openUTS46(UIDNA_CHECK_BIDI, &err);

  if(U_FAILURE(err)) {
    return CURLE_OUT_OF_MEMORY;
  }
  else {
    UIDNAInfo info = UIDNA_INFO_INITIALIZER;
    char buffer[256] = {0};
    (void)uidna_nameToASCII_UTF8(idna, in, -1, buffer,
      sizeof(buffer), &info, &err);
    uidna_close(idna);
    if(U_FAILURE(err)) {
      return CURLE_URL_MALFORMAT;
    }
    else {
      *out = strdup(buffer);
      if(*out)
        return CURLE_OK;
      else
        return CURLE_OUT_OF_MEMORY;
    }
  }


}

static CURLcode mac_ascii_to_idn(const char *in, char **out)
{


  UErrorCode err = U_ZERO_ERROR;
  UIDNA* idna = uidna_openUTS46(UIDNA_CHECK_BIDI, &err);

  if(U_FAILURE(err)) {
    return CURLE_OUT_OF_MEMORY;
  }
  else {
    UIDNAInfo info = UIDNA_INFO_INITIALIZER;
    char buffer[256] = {0};
    (void)uidna_nameToUnicodeUTF8(idna, in, -1, buffer,
      sizeof(buffer), &info, &err);
    uidna_close(idna);
    if(U_FAILURE(err)) {
      return CURLE_URL_MALFORMAT;
    }
    else {
      *out = strdup(buffer);
      if(*out)
        return CURLE_OK;
      else
        return CURLE_OUT_OF_MEMORY;
    }
  }


}
#endif

#ifdef USE_WIN32_IDN
/* using Windows kernel32 and normaliz libraries. */

#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600







>
>


>
>
|
|
>
|
<
<
<
|
|
|
|
|
|
<
<
<
|
|
|
|
|
|
|
>
>




>
>
|
|
>
|
<
<
<
|
|
|
|
|
|
<
<
<
|
|
|
|
|
|
|
>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66



67
68
69
70
71
72



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91



92
93
94
95
96
97



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "curl_memory.h"
#include "memdebug.h"

/* for macOS and iOS targets */
#if defined(USE_APPLE_IDN)
#include <unicode/uidna.h>

#define MAX_HOST_LENGTH 512

static CURLcode mac_idn_to_ascii(const char *in, char **out)
{
  size_t inlen = strlen(in);
  if(inlen < MAX_HOST_LENGTH) {
    UErrorCode err = U_ZERO_ERROR;
    UIDNA* idna = uidna_openUTS46(
      UIDNA_CHECK_BIDI|UIDNA_NONTRANSITIONAL_TO_ASCII, &err);
    if(!U_FAILURE(err)) {



      UIDNAInfo info = UIDNA_INFO_INITIALIZER;
      char buffer[MAX_HOST_LENGTH] = {0};
      (void)uidna_nameToASCII_UTF8(idna, in, -1, buffer,
                                   sizeof(buffer) - 1, &info, &err);
      uidna_close(idna);
      if(!U_FAILURE(err)) {



        *out = strdup(buffer);
        if(*out)
          return CURLE_OK;
        else
          return CURLE_OUT_OF_MEMORY;
      }
    }
  }
  return CURLE_URL_MALFORMAT;
}

static CURLcode mac_ascii_to_idn(const char *in, char **out)
{
  size_t inlen = strlen(in);
  if(inlen < MAX_HOST_LENGTH) {
    UErrorCode err = U_ZERO_ERROR;
    UIDNA* idna = uidna_openUTS46(
      UIDNA_CHECK_BIDI|UIDNA_NONTRANSITIONAL_TO_UNICODE, &err);
    if(!U_FAILURE(err)) {



      UIDNAInfo info = UIDNA_INFO_INITIALIZER;
      char buffer[MAX_HOST_LENGTH] = {0};
      (void)uidna_nameToUnicodeUTF8(idna, in, -1, buffer,
                                    sizeof(buffer) - 1, &info, &err);
      uidna_close(idna);
      if(!U_FAILURE(err)) {



        *out = strdup(buffer);
        if(*out)
          return CURLE_OK;
        else
          return CURLE_OUT_OF_MEMORY;
      }
    }
  }
  return CURLE_URL_MALFORMAT;
}
#endif

#ifdef USE_WIN32_IDN
/* using Windows kernel32 and normaliz libraries. */

#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
}

#ifdef USE_IDN
/*
 * Curl_idn_decode() returns an allocated IDN decoded string if it was
 * possible. NULL on error.
 *
 * CURLE_URL_MALFORMAT - the host name could not be converted
 * CURLE_OUT_OF_MEMORY - memory problem
 *
 */
static CURLcode idn_decode(const char *input, char **output)
{
  char *decoded = NULL;
  CURLcode result = CURLE_OK;







|







203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
}

#ifdef USE_IDN
/*
 * Curl_idn_decode() returns an allocated IDN decoded string if it was
 * possible. NULL on error.
 *
 * CURLE_URL_MALFORMAT - the hostname could not be converted
 * CURLE_OUT_OF_MEMORY - memory problem
 *
 */
static CURLcode idn_decode(const char *input, char **output)
{
  char *decoded = NULL;
  CURLcode result = CURLE_OK;
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#endif /* USE_IDN */

/*
 * Perform any necessary IDN conversion of hostname
 */
CURLcode Curl_idnconvert_hostname(struct hostname *host)
{
  /* set the name we use to display the host name */
  host->dispname = host->name;

#ifdef USE_IDN
  /* Check name for non-ASCII and convert hostname if we can */
  if(!Curl_is_ASCII_name(host->name)) {
    char *decoded;
    CURLcode result = Curl_idn_decode(host->name, &decoded);







|







315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#endif /* USE_IDN */

/*
 * Perform any necessary IDN conversion of hostname
 */
CURLcode Curl_idnconvert_hostname(struct hostname *host)
{
  /* set the name we use to display the hostname */
  host->dispname = host->name;

#ifdef USE_IDN
  /* Check name for non-ASCII and convert hostname if we can */
  if(!Curl_is_ASCII_name(host->name)) {
    char *decoded;
    CURLcode result = Curl_idn_decode(host->name, &decoded);
Changes to jni/curl/lib/imap.c.
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
                                   struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  char *user;
  char *passwd;

  /* Check we have a username and password to authenticate with and end the
     connect phase if we don't */
  if(!data->state.aptr.user) {
    imap_state(data, IMAP_STOP);

    return result;
  }

  /* Make sure the username and password are in the correct atom format */







|







508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
                                   struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  char *user;
  char *passwd;

  /* Check we have a username and password to authenticate with and end the
     connect phase if we do not */
  if(!data->state.aptr.user) {
    imap_state(data, IMAP_STOP);

    return result;
  }

  /* Make sure the username and password are in the correct atom format */
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
                                            struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  struct imap_conn *imapc = &conn->proto.imapc;
  saslprogress progress;

  /* Check if already authenticated OR if there is enough data to authenticate
     with and end the connect phase if we don't */
  if(imapc->preauth ||
     !Curl_sasl_can_authenticate(&imapc->sasl, data)) {
    imap_state(data, IMAP_STOP);
    return result;
  }

  /* Calculate the SASL login details */







|







608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
                                            struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  struct imap_conn *imapc = &conn->proto.imapc;
  saslprogress progress;

  /* Check if already authenticated OR if there is enough data to authenticate
     with and end the connect phase if we do not */
  if(imapc->preauth ||
     !Curl_sasl_can_authenticate(&imapc->sasl, data)) {
    imap_state(data, IMAP_STOP);
    return result;
  }

  /* Calculate the SASL login details */
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
    return CURLE_URL_MALFORMAT;
  }

#ifndef CURL_DISABLE_MIME
  /* Prepare the mime data if some. */
  if(data->set.mimepost.kind != MIMEKIND_NONE) {
    /* Use the whole structure as data. */
    data->set.mimepost.flags &= ~MIME_BODY_ONLY;

    /* Add external headers and mime version. */
    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
    result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
                                       NULL, MIMESTRATEGY_MAIL);

    if(!result)







|







772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
    return CURLE_URL_MALFORMAT;
  }

#ifndef CURL_DISABLE_MIME
  /* Prepare the mime data if some. */
  if(data->set.mimepost.kind != MIMEKIND_NONE) {
    /* Use the whole structure as data. */
    data->set.mimepost.flags &= ~(unsigned int)MIME_BODY_ONLY;

    /* Add external headers and mime version. */
    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
    result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
                                       NULL, MIMESTRATEGY_MAIL);

    if(!result)
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
      pp->nfinal = 0; /* done */

      if(chunk > (size_t)size)
        /* The conversion from curl_off_t to size_t is always fine here */
        chunk = (size_t)size;

      if(!chunk) {
        /* no size, we're done with the data */
        imap_state(data, IMAP_STOP);
        return CURLE_OK;
      }
      result = Curl_client_write(data, CLIENTWRITE_BODY,
                                 Curl_dyn_ptr(&pp->recvbuf), chunk);
      if(result)
        return result;







|







1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
      pp->nfinal = 0; /* done */

      if(chunk > (size_t)size)
        /* The conversion from curl_off_t to size_t is always fine here */
        chunk = (size_t)size;

      if(!chunk) {
        /* no size, we are done with the data */
        imap_state(data, IMAP_STOP);
        return CURLE_OK;
      }
      result = Curl_client_write(data, CLIENTWRITE_BODY,
                                 Curl_dyn_ptr(&pp->recvbuf), chunk);
      if(result)
        return result;
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
        /* Free the cache */
        Curl_dyn_reset(&pp->recvbuf);
      }
    }

    if(data->req.bytecount == size)
      /* The entire data is already transferred! */
      Curl_xfer_setup(data, -1, -1, FALSE, -1);
    else {
      /* IMAP download */
      data->req.maxdownload = size;
      /* force a recv/send check of this connection, as the data might've been
       read off the socket already */
      data->state.select_bits = CURL_CSELECT_IN;
      Curl_xfer_setup(data, FIRSTSOCKET, size, FALSE, -1);
    }
  }
  else {
    /* We don't know how to parse this line */
    failf(data, "Failed to parse FETCH response.");
    result = CURLE_WEIRD_SERVER_REPLY;
  }

  /* End of DO phase */
  imap_state(data, IMAP_STOP);








|






|



|







1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
        /* Free the cache */
        Curl_dyn_reset(&pp->recvbuf);
      }
    }

    if(data->req.bytecount == size)
      /* The entire data is already transferred! */
      Curl_xfer_setup_nop(data);
    else {
      /* IMAP download */
      data->req.maxdownload = size;
      /* force a recv/send check of this connection, as the data might've been
       read off the socket already */
      data->state.select_bits = CURL_CSELECT_IN;
      Curl_xfer_setup1(data, CURL_XFER_RECV, size, FALSE);
    }
  }
  else {
    /* We do not know how to parse this line */
    failf(data, "Failed to parse FETCH response.");
    result = CURLE_WEIRD_SERVER_REPLY;
  }

  /* End of DO phase */
  imap_state(data, IMAP_STOP);

1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
    result = CURLE_UPLOAD_FAILED;
  }
  else {
    /* Set the progress upload size */
    Curl_pgrsSetUploadSize(data, data->state.infilesize);

    /* IMAP upload */
    Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);

    /* End of DO phase */
    imap_state(data, IMAP_STOP);
  }

  return result;
}







|







1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
    result = CURLE_UPLOAD_FAILED;
  }
  else {
    /* Set the progress upload size */
    Curl_pgrsSetUploadSize(data, data->state.infilesize);

    /* IMAP upload */
    Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);

    /* End of DO phase */
    imap_state(data, IMAP_STOP);
  }

  return result;
}
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
{
  struct IMAP *imap = data->req.p.imap;

  (void)connected;

  if(imap->transfer != PPTRANSFER_BODY)
    /* no data to transfer */
    Curl_xfer_setup(data, -1, -1, FALSE, -1);

  return CURLE_OK;
}

/* Called from multi.c while DOing */
static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done)
{







|







1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
{
  struct IMAP *imap = data->req.p.imap;

  (void)connected;

  if(imap->transfer != PPTRANSFER_BODY)
    /* no data to transfer */
    Curl_xfer_setup_nop(data);

  return CURLE_OK;
}

/* Called from multi.c while DOing */
static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done)
{
Changes to jni/curl/lib/inet_ntop.c.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 * Format an IPv4 address, more or less like inet_ntop().
 *
 * Returns `dst' (as a const)
 * Note:
 *  - uses no statics
 *  - takes a unsigned char* not an in_addr as input
 */
static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
{
  char tmp[sizeof("255.255.255.255")];
  size_t len;

  DEBUGASSERT(size >= 16);

  tmp[0] = '\0';







|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 * Format an IPv4 address, more or less like inet_ntop().
 *
 * Returns `dst' (as a const)
 * Note:
 *  - uses no statics
 *  - takes a unsigned char* not an in_addr as input
 */
static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
{
  char tmp[sizeof("255.255.255.255")];
  size_t len;

  DEBUGASSERT(size >= 16);

  tmp[0] = '\0';
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  strcpy(dst, tmp);
  return dst;
}

/*
 * Convert IPv6 binary address into presentation (printable) format.
 */
static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
{
  /*
   * Note that int32_t and int16_t need only be "at least" large enough
   * to contain a value of the specified size.  On some systems, like
   * Crays, there is no such thing as an integer variable with 16 bits.
   * Keep this in mind if you think this function should have been coded
   * to use pointer overlays.  All the world's not a VAX.
   */
  char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
  char *tp;
  struct {
    int base;
    int len;
  } best, cur;







|



|


|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  strcpy(dst, tmp);
  return dst;
}

/*
 * Convert IPv6 binary address into presentation (printable) format.
 */
static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
{
  /*
   * Note that int32_t and int16_t need only be "at least" large enough
   * to contain a value of the specified size. On some systems, like
   * Crays, there is no such thing as an integer variable with 16 bits.
   * Keep this in mind if you think this function should have been coded
   * to use pointer overlays. All the world's not a VAX.
   */
  char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
  char *tp;
  struct {
    int base;
    int len;
  } best, cur;
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

  /* Was it a trailing run of 0x00's?
   */
  if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
    *tp++ = ':';
  *tp++ = '\0';

  /* Check for overflow, copy, and we're done.
   */
  if((size_t)(tp - tmp) > size) {
    errno = ENOSPC;
    return (NULL);
  }
  strcpy(dst, tmp);
  return dst;
}

/*
 * Convert a network format address to presentation format.
 *
 * Returns pointer to presentation format address (`buf').
 * Returns NULL on error and errno set with the specific
 * error, EAFNOSUPPORT or ENOSPC.
 *
 * On Windows we store the error in the thread errno, not
 * in the winsock error code. This is to avoid losing the
 * actual last winsock error. So when this function returns
 * NULL, check errno not SOCKERRNO.
 */
char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
{
  switch(af) {
  case AF_INET:
    return inet_ntop4((const unsigned char *)src, buf, size);
  case AF_INET6:







|
















|
|
<
|







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

190
191
192
193
194
195
196
197

  /* Was it a trailing run of 0x00's?
   */
  if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
    *tp++ = ':';
  *tp++ = '\0';

  /* Check for overflow, copy, and we are done.
   */
  if((size_t)(tp - tmp) > size) {
    errno = ENOSPC;
    return (NULL);
  }
  strcpy(dst, tmp);
  return dst;
}

/*
 * Convert a network format address to presentation format.
 *
 * Returns pointer to presentation format address (`buf').
 * Returns NULL on error and errno set with the specific
 * error, EAFNOSUPPORT or ENOSPC.
 *
 * On Windows we store the error in the thread errno, not in the winsock error
 * code. This is to avoid losing the actual last winsock error. When this

 * function returns NULL, check errno not SOCKERRNO.
 */
char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
{
  switch(af) {
  case AF_INET:
    return inet_ntop4((const unsigned char *)src, buf, size);
  case AF_INET6:
Changes to jni/curl/lib/inet_ntop.h.
28
29
30
31
32
33
34

35



36

37
38
39

char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);

#ifdef HAVE_INET_NTOP
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif

#define Curl_inet_ntop(af,addr,buf,size) \



        inet_ntop(af, addr, buf, (curl_socklen_t)size)

#endif

#endif /* HEADER_CURL_INET_NTOP_H */







>

>
>
>
|
>



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);

#ifdef HAVE_INET_NTOP
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef _WIN32
#define Curl_inet_ntop(af,addr,buf,size) \
        inet_ntop(af, addr, buf, size)
#else
#define Curl_inet_ntop(af,addr,buf,size) \
        inet_ntop(af, addr, buf, (curl_socklen_t)(size))
#endif
#endif

#endif /* HEADER_CURL_INET_NTOP_H */
Changes to jni/curl/lib/inet_pton.c.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 * everywhere.
 */
#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif

/*
 * WARNING: Don't even consider trying to compile this on a system where
 * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
 */

static int      inet_pton4(const char *src, unsigned char *dst);
static int      inet_pton6(const char *src, unsigned char *dst);

/* int
 * inet_pton(af, src, dst)
 *      convert from presentation format (which usually means ASCII printable)
 *      to network format (which is usually some kind of binary format).
 * return:
 *      1 if the address was valid for the specified address family
 *      0 if the address wasn't valid (`dst' is untouched in this case)
 *      -1 if some other error occurred (`dst' is untouched in this case, too)
 * notice:
 *      On Windows we store the error in the thread errno, not
 *      in the winsock error code. This is to avoid losing the
 *      actual last winsock error. So when this function returns
 *      -1, check errno not SOCKERRNO.
 * author:
 *      Paul Vixie, 1996.
 */
int
Curl_inet_pton(int af, const char *src, void *dst)
{







|
|











|




|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 * everywhere.
 */
#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif

/*
 * WARNING: Do not even consider trying to compile this on a system where
 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
 */

static int      inet_pton4(const char *src, unsigned char *dst);
static int      inet_pton6(const char *src, unsigned char *dst);

/* int
 * inet_pton(af, src, dst)
 *      convert from presentation format (which usually means ASCII printable)
 *      to network format (which is usually some kind of binary format).
 * return:
 *      1 if the address was valid for the specified address family
 *      0 if the address was not valid (`dst' is untouched in this case)
 *      -1 if some other error occurred (`dst' is untouched in this case, too)
 * notice:
 *      On Windows we store the error in the thread errno, not
 *      in the winsock error code. This is to avoid losing the
 *      actual last winsock error. When this function returns
 *      -1, check errno not SOCKERRNO.
 * author:
 *      Paul Vixie, 1996.
 */
int
Curl_inet_pton(int af, const char *src, void *dst)
{
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

/* int
 * inet_pton4(src, dst)
 *      like inet_aton() but without all the hexadecimal and shorthand.
 * return:
 *      1 if `src' is a valid dotted quad, else 0.
 * notice:
 *      does not touch `dst' unless it's returning 1.
 * author:
 *      Paul Vixie, 1996.
 */
static int
inet_pton4(const char *src, unsigned char *dst)
{
  static const char digits[] = "0123456789";







|







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

/* int
 * inet_pton4(src, dst)
 *      like inet_aton() but without all the hexadecimal and shorthand.
 * return:
 *      1 if `src' is a valid dotted quad, else 0.
 * notice:
 *      does not touch `dst' unless it is returning 1.
 * author:
 *      Paul Vixie, 1996.
 */
static int
inet_pton4(const char *src, unsigned char *dst)
{
  static const char digits[] = "0123456789";
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

/* int
 * inet_pton6(src, dst)
 *      convert presentation level address to network order binary form.
 * return:
 *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
 * notice:
 *      (1) does not touch `dst' unless it's returning 1.
 *      (2) :: in a full address is silently ignored.
 * credit:
 *      inspired by Mark Andrews.
 * author:
 *      Paul Vixie, 1996.
 */
static int







|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

/* int
 * inet_pton6(src, dst)
 *      convert presentation level address to network order binary form.
 * return:
 *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
 * notice:
 *      (1) does not touch `dst' unless it is returning 1.
 *      (2) :: in a full address is silently ignored.
 * credit:
 *      inspired by Mark Andrews.
 * author:
 *      Paul Vixie, 1996.
 */
static int
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
      return (0);
    *tp++ = (unsigned char) ((val >> 8) & 0xff);
    *tp++ = (unsigned char) (val & 0xff);
  }
  if(colonp) {
    /*
     * Since some memmove()'s erroneously fail to handle
     * overlapping regions, we'll do the shift by hand.
     */
    const ssize_t n = tp - colonp;
    ssize_t i;

    if(tp == endp)
      return (0);
    for(i = 1; i <= n; i++) {







|







217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
      return (0);
    *tp++ = (unsigned char) ((val >> 8) & 0xff);
    *tp++ = (unsigned char) (val & 0xff);
  }
  if(colonp) {
    /*
     * Since some memmove()'s erroneously fail to handle
     * overlapping regions, we will do the shift by hand.
     */
    const ssize_t n = tp - colonp;
    ssize_t i;

    if(tp == endp)
      return (0);
    for(i = 1; i <= n; i++) {
Changes to jni/curl/lib/krb5.c.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.  */







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.  */
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  int state;
  int len;

  /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
   * libraries modify the input buffer in gss_wrap()
   */
  dec.value = (void *)from;
  dec.length = length;
  maj = gss_wrap(&min, *context,
                 level == PROT_PRIVATE,
                 GSS_C_QOP_DEFAULT,
                 &dec, &state, &enc);

  if(maj != GSS_S_COMPLETE)
    return -1;

  /* malloc a new buffer, in case gss_release_buffer doesn't work as
     expected */
  *to = malloc(enc.length);
  if(!*to)
    return -1;
  memcpy(*to, enc.value, enc.length);
  len = curlx_uztosi(enc.length);
  gss_release_buffer(&min, &enc);







|








|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  int state;
  int len;

  /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
   * libraries modify the input buffer in gss_wrap()
   */
  dec.value = (void *)from;
  dec.length = (size_t)length;
  maj = gss_wrap(&min, *context,
                 level == PROT_PRIVATE,
                 GSS_C_QOP_DEFAULT,
                 &dec, &state, &enc);

  if(maj != GSS_S_COMPLETE)
    return -1;

  /* malloc a new buffer, in case gss_release_buffer does not work as
     expected */
  *to = malloc(enc.length);
  if(!*to)
    return -1;
  memcpy(*to, enc.value, enc.length);
  len = curlx_uztosi(enc.length);
  gss_release_buffer(&min, &enc);
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  chan.acceptor_address.length = l - 4;
  chan.acceptor_address.value = &remote_addr->sin_addr.s_addr;
  chan.application_data.length = 0;
  chan.application_data.value = NULL;

  /* this loop will execute twice (once for service, once for host) */
  for(;;) {
    /* this really shouldn't be repeated here, but can't help it */
    if(service == srv_host) {
      result = ftpsend(data, conn, "AUTH GSSAPI");
      if(result)
        return -2;

      if(Curl_GetFTPResponse(data, &nread, NULL))
        return -1;







|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  chan.acceptor_address.length = l - 4;
  chan.acceptor_address.value = &remote_addr->sin_addr.s_addr;
  chan.application_data.length = 0;
  chan.application_data.value = NULL;

  /* this loop will execute twice (once for service, once for host) */
  for(;;) {
    /* this really should not be repeated here, but cannot help it */
    if(service == srv_host) {
      result = ftpsend(data, conn, "AUTH GSSAPI");
      if(result)
        return -2;

      if(Curl_GetFTPResponse(data, &nread, NULL))
        return -1;
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
          break;
        }
        else {
          struct pingpong *pp = &conn->proto.ftpc.pp;
          size_t len = Curl_dyn_len(&pp->recvbuf);
          p = Curl_dyn_ptr(&pp->recvbuf);
          if((len < 4) || (p[0] != '2' && p[0] != '3')) {
            infof(data, "Server didn't accept auth data");
            ret = AUTH_ERROR;
            break;
          }
        }

        _gssresp.value = NULL; /* make sure it is initialized */
        p += 4; /* over '789 ' */







|







325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
          break;
        }
        else {
          struct pingpong *pp = &conn->proto.ftpc.pp;
          size_t len = Curl_dyn_len(&pp->recvbuf);
          p = Curl_dyn_ptr(&pp->recvbuf);
          if((len < 4) || (p[0] != '2' && p[0] != '3')) {
            infof(data, "Server did not accept auth data");
            ret = AUTH_ERROR;
            break;
          }
        }

        _gssresp.value = NULL; /* make sure it is initialized */
        p += 4; /* over '789 ' */
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
  int nread;

  result = socket_read(data, sockindex, &len, sizeof(len));
  if(result)
    return result;

  if(len) {
    len = ntohl(len);
    if(len > CURL_MAX_INPUT_LENGTH)
      return CURLE_TOO_LARGE;

    Curl_dyn_reset(&buf->buf);
  }
  else
    return CURLE_RECV_ERROR;

  do {
    char buffer[1024];
    nread = CURLMIN(len, (int)sizeof(buffer));
    result = socket_read(data, sockindex, buffer, nread);
    if(result)
      return result;
    result = Curl_dyn_addn(&buf->buf, buffer, nread);
    if(result)
      return result;
    len -= nread;
  } while(len);







|











|







520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
  int nread;

  result = socket_read(data, sockindex, &len, sizeof(len));
  if(result)
    return result;

  if(len) {
    len = (int)ntohl((uint32_t)len);
    if(len > CURL_MAX_INPUT_LENGTH)
      return CURLE_TOO_LARGE;

    Curl_dyn_reset(&buf->buf);
  }
  else
    return CURLE_RECV_ERROR;

  do {
    char buffer[1024];
    nread = CURLMIN(len, (int)sizeof(buffer));
    result = socket_read(data, sockindex, buffer, (size_t)nread);
    if(result)
      return result;
    result = Curl_dyn_addn(&buf->buf, buffer, nread);
    if(result)
      return result;
    len -= nread;
  } while(len);
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640

  if(iscmd) {
    if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
      prot_level = PROT_PRIVATE;
    else
      prot_level = conn->command_prot;
  }
  bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
                             (void **)&buffer);
  if(!buffer || bytes <= 0)
    return; /* error */

  if(iscmd) {
    error = Curl_base64_encode(buffer, curlx_sitouz(bytes),
                               &cmd_buffer, &cmd_size);







|







626
627
628
629
630
631
632
633
634
635
636
637
638
639
640

  if(iscmd) {
    if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
      prot_level = PROT_PRIVATE;
    else
      prot_level = conn->command_prot;
  }
  bytes = conn->mech->encode(conn->app_data, from, length, (int)prot_level,
                             (void **)&buffer);
  if(!buffer || bytes <= 0)
    return; /* error */

  if(iscmd) {
    error = Curl_base64_encode(buffer, curlx_sitouz(bytes),
                               &cmd_buffer, &cmd_size);
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
      socket_write(data, fd, "\r\n", 2);
      infof(data, "Send: %s%s", prot_level == PROT_PRIVATE?enc:mic,
            cmd_buffer);
      free(cmd_buffer);
    }
  }
  else {
    htonl_bytes = htonl(bytes);
    socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes));
    socket_write(data, fd, buffer, curlx_sitouz(bytes));
  }
  free(buffer);
}

static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,







|







654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
      socket_write(data, fd, "\r\n", 2);
      infof(data, "Send: %s%s", prot_level == PROT_PRIVATE?enc:mic,
            cmd_buffer);
      free(cmd_buffer);
    }
  }
  else {
    htonl_bytes = (int)htonl((OM_uint32)bytes);
    socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes));
    socket_write(data, fd, buffer, curlx_sitouz(bytes));
  }
  free(buffer);
}

static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
  if(decoded_sz > (size_t)INT_MAX) {
    free(buf);
    return -1;
  }
  decoded_len = curlx_uztosi(decoded_sz);

  decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
                                   level, conn);
  if(decoded_len <= 0) {
    free(buf);
    return -1;
  }

  {
    buf[decoded_len] = '\n';







|







720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
  if(decoded_sz > (size_t)INT_MAX) {
    free(buf);
    return -1;
  }
  decoded_len = curlx_uztosi(decoded_sz);

  decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
                                   (int)level, conn);
  if(decoded_len <= 0) {
    free(buf);
    return -1;
  }

  {
    buf[decoded_len] = '\n';
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
    conn->buffer_size = buffer_size;

    line = Curl_dyn_ptr(&pp->recvbuf);
    pbsz = strstr(line, "PBSZ=");
    if(pbsz) {
      /* stick to default value if the check fails */
      if(ISDIGIT(pbsz[5]))
        buffer_size = atoi(&pbsz[5]);
      if(buffer_size < conn->buffer_size)
        conn->buffer_size = buffer_size;
    }
  }

  /* Now try to negotiate the protection level. */
  code = ftp_send_command(data, "PROT %c", level_to_char(level));







|







785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
    conn->buffer_size = buffer_size;

    line = Curl_dyn_ptr(&pp->recvbuf);
    pbsz = strstr(line, "PBSZ=");
    if(pbsz) {
      /* stick to default value if the check fails */
      if(ISDIGIT(pbsz[5]))
        buffer_size = (unsigned int)atoi(&pbsz[5]);
      if(buffer_size < conn->buffer_size)
        conn->buffer_size = buffer_size;
    }
  }

  /* Now try to negotiate the protection level. */
  code = ftp_send_command(data, "PROT %c", level_to_char(level));
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
  }

  /* Authenticate */
  ret = mech->auth(conn->app_data, data, conn);

  if(ret != AUTH_CONTINUE) {
    if(ret != AUTH_OK) {
      /* Mechanism has dumped the error to stderr, don't error here. */
      return CURLE_USE_SSL_FAILED;
    }
    DEBUGASSERT(ret == AUTH_OK);

    conn->mech = mech;
    conn->sec_complete = 1;
    conn->recv[FIRSTSOCKET] = sec_recv;







|







874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
  }

  /* Authenticate */
  ret = mech->auth(conn->app_data, data, conn);

  if(ret != AUTH_CONTINUE) {
    if(ret != AUTH_OK) {
      /* Mechanism has dumped the error to stderr, do not error here. */
      return CURLE_USE_SSL_FAILED;
    }
    DEBUGASSERT(ret == AUTH_OK);

    conn->mech = mech;
    conn->sec_complete = 1;
    conn->recv[FIRSTSOCKET] = sec_recv;
Changes to jni/curl/lib/ldap.c.
248
249
250
251
252
253
254
255

256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

299
300

301
302
303
304
305
306
307
  else
#endif
  {
    /* required anyway if one of upper preprocessor definitions enabled */
  }

  if(method && user && passwd) {
    rc = Curl_create_sspi_identity(user, passwd, &cred);

    if(!rc) {
      rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method);
      Curl_sspi_free_identity(&cred);
    }
  }
  else {
    /* proceed with current user credentials */
    method = LDAP_AUTH_NEGOTIATE;
    rc = ldap_bind_s(server, NULL, NULL, method);
  }
  return rc;
}
#endif /* #if defined(USE_WINDOWS_SSPI) */

static int ldap_win_bind(struct Curl_easy *data, LDAP *server,
                         const char *user, const char *passwd)
{
  int rc = LDAP_INVALID_CREDENTIALS;

  PTCHAR inuser = NULL;
  PTCHAR inpass = NULL;

  if(user && passwd && (data->set.httpauth & CURLAUTH_BASIC)) {
    inuser = curlx_convert_UTF8_to_tchar((char *) user);
    inpass = curlx_convert_UTF8_to_tchar((char *) passwd);

    rc = ldap_simple_bind_s(server, inuser, inpass);

    curlx_unicodefree(inuser);
    curlx_unicodefree(inpass);
  }
#if defined(USE_WINDOWS_SSPI)
  else {
    rc = ldap_win_bind_auth(server, user, passwd, data->set.httpauth);
  }
#endif

  return rc;
}
#endif /* #if defined(USE_WIN32_LDAP) */

#if defined(USE_WIN32_LDAP)
#define FREE_ON_WINLDAP(x) curlx_unicodefree(x)

#else
#define FREE_ON_WINLDAP(x)

#endif


static CURLcode ldap_do(struct Curl_easy *data, bool *done)
{
  CURLcode result = CURLE_OK;
  int rc = 0;







|
>

|






|

















|






|









>


>







248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  else
#endif
  {
    /* required anyway if one of upper preprocessor definitions enabled */
  }

  if(method && user && passwd) {
    CURLcode res = Curl_create_sspi_identity(user, passwd, &cred);
    rc = (int)res;
    if(!rc) {
      rc = (int)ldap_bind_s(server, NULL, (TCHAR *)&cred, method);
      Curl_sspi_free_identity(&cred);
    }
  }
  else {
    /* proceed with current user credentials */
    method = LDAP_AUTH_NEGOTIATE;
    rc = (int)ldap_bind_s(server, NULL, NULL, method);
  }
  return rc;
}
#endif /* #if defined(USE_WINDOWS_SSPI) */

static int ldap_win_bind(struct Curl_easy *data, LDAP *server,
                         const char *user, const char *passwd)
{
  int rc = LDAP_INVALID_CREDENTIALS;

  PTCHAR inuser = NULL;
  PTCHAR inpass = NULL;

  if(user && passwd && (data->set.httpauth & CURLAUTH_BASIC)) {
    inuser = curlx_convert_UTF8_to_tchar((char *) user);
    inpass = curlx_convert_UTF8_to_tchar((char *) passwd);

    rc = (int)ldap_simple_bind_s(server, inuser, inpass);

    curlx_unicodefree(inuser);
    curlx_unicodefree(inpass);
  }
#if defined(USE_WINDOWS_SSPI)
  else {
    rc = (int)ldap_win_bind_auth(server, user, passwd, data->set.httpauth);
  }
#endif

  return rc;
}
#endif /* #if defined(USE_WIN32_LDAP) */

#if defined(USE_WIN32_LDAP)
#define FREE_ON_WINLDAP(x) curlx_unicodefree(x)
#define curl_ldap_num_t ULONG
#else
#define FREE_ON_WINLDAP(x)
#define curl_ldap_num_t int
#endif


static CURLcode ldap_do(struct Curl_easy *data, bool *done)
{
  CURLcode result = CURLE_OK;
  int rc = 0;
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347

#ifdef HAVE_LDAP_URL_PARSE
  rc = ldap_url_parse(data->state.url, &ludp);
#else
  rc = _ldap_url_parse(data, conn, &ludp);
#endif
  if(rc) {
    failf(data, "Bad LDAP URL: %s", ldap_err2string(rc));
    result = CURLE_URL_MALFORMAT;
    goto quit;
  }

  /* Get the URL scheme (either ldap or ldaps) */
  if(conn->given->flags & PROTOPT_SSL)
    ldap_ssl = 1;







|







336
337
338
339
340
341
342
343
344
345
346
347
348
349
350

#ifdef HAVE_LDAP_URL_PARSE
  rc = ldap_url_parse(data->state.url, &ludp);
#else
  rc = _ldap_url_parse(data, conn, &ludp);
#endif
  if(rc) {
    failf(data, "Bad LDAP URL: %s", ldap_err2string((curl_ldap_num_t)rc));
    result = CURLE_URL_MALFORMAT;
    goto quit;
  }

  /* Get the URL scheme (either ldap or ldaps) */
  if(conn->given->flags & PROTOPT_SSL)
    ldap_ssl = 1;
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
#endif
  ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);

  if(ldap_ssl) {
#ifdef HAVE_LDAP_SSL
#ifdef USE_WIN32_LDAP
    /* Win32 LDAP SDK doesn't support insecure mode without CA! */
    server = ldap_sslinit(host, conn->primary.remote_port, 1);
    ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
#else
    int ldap_option;
    char *ldap_ca = conn->ssl_config.CAfile;
#if defined(CURL_HAS_NOVELL_LDAPSDK)
    rc = ldapssl_client_init(NULL, NULL);
    if(rc != LDAP_SUCCESS) {







|
|







371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
#endif
  ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);

  if(ldap_ssl) {
#ifdef HAVE_LDAP_SSL
#ifdef USE_WIN32_LDAP
    /* Win32 LDAP SDK does not support insecure mode without CA! */
    server = ldap_sslinit(host, (curl_ldap_num_t)conn->primary.remote_port, 1);
    ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
#else
    int ldap_option;
    char *ldap_ca = conn->ssl_config.CAfile;
#if defined(CURL_HAS_NOVELL_LDAPSDK)
    rc = ldapssl_client_init(NULL, NULL);
    if(rc != LDAP_SUCCESS) {
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  }
  else if(data->set.use_ssl > CURLUSESSL_TRY) {
    failf(data, "LDAP local: explicit TLS not supported");
    result = CURLE_NOT_BUILT_IN;
    goto quit;
  }
  else {
    server = ldap_init(host, conn->primary.remote_port);
    if(!server) {
      failf(data, "LDAP local: Cannot connect to %s:%u",
            conn->host.dispname, conn->primary.remote_port);
      result = CURLE_COULDNT_CONNECT;
      goto quit;
    }
  }







|







502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
  }
  else if(data->set.use_ssl > CURLUSESSL_TRY) {
    failf(data, "LDAP local: explicit TLS not supported");
    result = CURLE_NOT_BUILT_IN;
    goto quit;
  }
  else {
    server = ldap_init(host, (curl_ldap_num_t)conn->primary.remote_port);
    if(!server) {
      failf(data, "LDAP local: Cannot connect to %s:%u",
            conn->host.dispname, conn->primary.remote_port);
      result = CURLE_COULDNT_CONNECT;
      goto quit;
    }
  }
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542

543
544
545
546
547
548
549
550
551
552
553
#else
    rc = ldap_simple_bind_s(server, user, passwd);
#endif
  }
  if(rc) {
#ifdef USE_WIN32_LDAP
    failf(data, "LDAP local: bind via ldap_win_bind %s",
          ldap_err2string(rc));
#else
    failf(data, "LDAP local: bind via ldap_simple_bind_s %s",
          ldap_err2string(rc));
#endif
    result = CURLE_LDAP_CANNOT_BIND;
    goto quit;
  }

  Curl_pgrsSetDownloadCounter(data, 0);
  rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,

                     ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);

  if(rc && rc != LDAP_SIZELIMIT_EXCEEDED) {
    failf(data, "LDAP remote: %s", ldap_err2string(rc));
    result = CURLE_LDAP_SEARCH_FAILED;
    goto quit;
  }

  num = 0;
  for(entryIterator = ldap_first_entry(server, ldapmsg);
      entryIterator;







|









|
>
|


|







528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
#else
    rc = ldap_simple_bind_s(server, user, passwd);
#endif
  }
  if(rc) {
#ifdef USE_WIN32_LDAP
    failf(data, "LDAP local: bind via ldap_win_bind %s",
          ldap_err2string((ULONG)rc));
#else
    failf(data, "LDAP local: bind via ldap_simple_bind_s %s",
          ldap_err2string(rc));
#endif
    result = CURLE_LDAP_CANNOT_BIND;
    goto quit;
  }

  Curl_pgrsSetDownloadCounter(data, 0);
  rc = (int)ldap_search_s(server, ludp->lud_dn,
                          (curl_ldap_num_t)ludp->lud_scope,
                          ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);

  if(rc && rc != LDAP_SIZELIMIT_EXCEEDED) {
    failf(data, "LDAP remote: %s", ldap_err2string((curl_ldap_num_t)rc));
    result = CURLE_LDAP_SEARCH_FAILED;
    goto quit;
  }

  num = 0;
  for(entryIterator = ldap_first_entry(server, ldapmsg);
      entryIterator;
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
  if(ldap_ssl)
    ldapssl_client_deinit();
#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */

  FREE_ON_WINLDAP(host);

  /* no data to transfer */
  Curl_xfer_setup(data, -1, -1, FALSE, -1);
  connclose(conn, "LDAP connection always disable reuse");

  return result;
}

#ifdef DEBUG_LDAP
static void _ldap_trace(const char *fmt, ...)







|







754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
  if(ldap_ssl)
    ldapssl_client_deinit();
#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */

  FREE_ON_WINLDAP(host);

  /* no data to transfer */
  Curl_xfer_setup_nop(data);
  connclose(conn, "LDAP connection always disable reuse");

  return result;
}

#ifdef DEBUG_LDAP
static void _ldap_trace(const char *fmt, ...)
Changes to jni/curl/lib/libcurl.rc.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#define RC_VERSION  LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0

VS_VERSION_INFO VERSIONINFO
  FILEVERSION     RC_VERSION
  PRODUCTVERSION  RC_VERSION
  FILEFLAGSMASK   VS_FFI_FILEFLAGSMASK
#if defined(DEBUGBUILD) || defined(_DEBUG)
  FILEFLAGS VS_FF_DEBUG
#else
  FILEFLAGS 0L
#endif
  FILEOS      VOS__WINDOWS32
  FILETYPE    VFT_DLL
  FILESUBTYPE 0L







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#define RC_VERSION  LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0

VS_VERSION_INFO VERSIONINFO
  FILEVERSION     RC_VERSION
  PRODUCTVERSION  RC_VERSION
  FILEFLAGSMASK   VS_FFI_FILEFLAGSMASK
#if defined(DEBUGBUILD) || defined(UNITTESTS) || defined(CURLDEBUG) || defined(_DEBUG)
  FILEFLAGS VS_FF_DEBUG
#else
  FILEFLAGS 0L
#endif
  FILEOS      VOS__WINDOWS32
  FILETYPE    VFT_DLL
  FILESUBTYPE 0L
Changes to jni/curl/lib/macos.c.
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

CURLcode Curl_macos_init(void)
{
  {
    /*
     * The automagic conversion from IPv4 literals to IPv6 literals only
     * works if the SCDynamicStoreCopyProxies system function gets called
     * first. As Curl currently doesn't support system-wide HTTP proxies, we
     * therefore don't use any value this function might return.
     *
     * This function is only available on macOS and is not needed for
     * IPv4-only builds, hence the conditions for defining
     * CURL_MACOS_CALL_COPYPROXIES in curl_setup.h.
     */
    CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
    if(dict)







|
|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

CURLcode Curl_macos_init(void)
{
  {
    /*
     * The automagic conversion from IPv4 literals to IPv6 literals only
     * works if the SCDynamicStoreCopyProxies system function gets called
     * first. As Curl currently does not support system-wide HTTP proxies, we
     * therefore do not use any value this function might return.
     *
     * This function is only available on macOS and is not needed for
     * IPv4-only builds, hence the conditions for defining
     * CURL_MACOS_CALL_COPYPROXIES in curl_setup.h.
     */
    CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
    if(dict)
Changes to jni/curl/lib/md4.c.
33
34
35
36
37
38
39



40
41
42
43
44
45
46
#include "warnless.h"

#ifdef USE_OPENSSL
#include <openssl/opensslv.h>
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(USE_AMISSL)
/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */
#define OPENSSL_NO_MD4



#endif
#endif /* USE_OPENSSL */

#ifdef USE_WOLFSSL
#include <wolfssl/options.h>
#define VOID_MD4_INIT
#ifdef NO_MD4







>
>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include "warnless.h"

#ifdef USE_OPENSSL
#include <openssl/opensslv.h>
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(USE_AMISSL)
/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */
#define OPENSSL_NO_MD4
#else
/* Cover also OPENSSL_NO_MD4 configured in openssl */
#include <openssl/opensslconf.h>
#endif
#endif /* USE_OPENSSL */

#ifdef USE_WOLFSSL
#include <wolfssl/options.h>
#define VOID_MD4_INIT
#ifdef NO_MD4
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261

    Curl_safefree(ctx->data);
    ctx->size = 0;
  }
}

#else
/* When no other crypto library is available, or the crypto library doesn't
 * support MD4, we use this code segment this implementation of it
 *
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD4 Message-Digest Algorithm (RFC 1320).
 *
 * Homepage:
 https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.  In case
 * this attempt to disclaim copyright and place the software in the public
 * domain is deemed null and void, then the software is Copyright (c) 2001
 * Alexander Peslyak and it is hereby released to the general public under the
 * following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * (This is a heavily cut-down "BSD license".)
 *
 * This differs from Colin Plumb's older public domain implementation in that
 * no exactly 32-bit integer data type is required (any 32-bit or wider
 * unsigned integer data type will do), there's no compile-time endianness
 * configuration, and the function prototypes match OpenSSL's.  No code from
 * Colin Plumb's implementation has been reused; this comment merely compares
 * the properties of the two independent implementations.
 *
 * The primary goals of this implementation are portability and ease of use.
 * It is meant to be fast, but not as fast as possible.  Some known
 * optimizations are not included to reduce source code size and avoid
 * compile-time configuration.
 */

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD4_u32plus;








|











|
|








|





|
|




|







216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264

    Curl_safefree(ctx->data);
    ctx->size = 0;
  }
}

#else
/* When no other crypto library is available, or the crypto library does not
 * support MD4, we use this code segment this implementation of it
 *
 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
 * MD4 Message-Digest Algorithm (RFC 1320).
 *
 * Homepage:
 https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
 *
 * This software was written by Alexander Peslyak in 2001. No copyright is
 * claimed, and the software is hereby placed in the public domain. In case
 * this attempt to disclaim copyright and place the software in the public
 * domain is deemed null and void, then the software is Copyright (c) 2001
 * Alexander Peslyak and it is hereby released to the general public under the
 * following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There is ABSOLUTELY NO WARRANTY, express or implied.
 *
 * (This is a heavily cut-down "BSD license".)
 *
 * This differs from Colin Plumb's older public domain implementation in that
 * no exactly 32-bit integer data type is required (any 32-bit or wider
 * unsigned integer data type will do), there is no compile-time endianness
 * configuration, and the function prototypes match OpenSSL's. No code from
 * Colin Plumb's implementation has been reused; this comment merely compares
 * the properties of the two independent implementations.
 *
 * The primary goals of this implementation are portability and ease of use.
 * It is meant to be fast, but not as fast as possible. Some known
 * optimizations are not included to reduce source code size and avoid
 * compile-time configuration.
 */

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD4_u32plus;

273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318

319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398

/*
 * The basic MD4 functions.
 *
 * F and G are optimized compared to their RFC 1320 definitions, with the
 * optimization for F borrowed from Colin Plumb's MD5 implementation.
 */
#define F(x, y, z)                      ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z)                      (((x) & ((y) | (z))) | ((y) & (z)))
#define H(x, y, z)                      ((x) ^ (y) ^ (z))

/*
 * The MD4 transformation for all three rounds.
 */
#define STEP(f, a, b, c, d, x, s) \
        (a) += f((b), (c), (d)) + (x); \
        (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));

/*
 * SET reads 4 input bytes in little-endian byte order and stores them
 * in a properly aligned word in host byte order.
 *
 * The check for little-endian architectures that tolerate unaligned
 * memory accesses is just an optimization.  Nothing will break if it
 * doesn't work.
 */
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) \
        (*(MD4_u32plus *)(void *)&ptr[(n) * 4])
#define GET(n) \
        SET(n)
#else
#define SET(n) \
        (ctx->block[(n)] = \
        (MD4_u32plus)ptr[(n) * 4] | \
        ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \
        ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \
        ((MD4_u32plus)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
        (ctx->block[(n)])
#endif

/*
 * This processes one or more 64-byte data blocks, but does NOT update
 * the bit counters.  There are no alignment requirements.
 */

static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
{
  const unsigned char *ptr;
  MD4_u32plus a, b, c, d;

  ptr = (const unsigned char *)data;

  a = ctx->a;
  b = ctx->b;
  c = ctx->c;
  d = ctx->d;

  do {
    MD4_u32plus saved_a, saved_b, saved_c, saved_d;

    saved_a = a;
    saved_b = b;
    saved_c = c;
    saved_d = d;

/* Round 1 */
    STEP(F, a, b, c, d, SET(0), 3)
    STEP(F, d, a, b, c, SET(1), 7)
    STEP(F, c, d, a, b, SET(2), 11)
    STEP(F, b, c, d, a, SET(3), 19)
    STEP(F, a, b, c, d, SET(4), 3)
    STEP(F, d, a, b, c, SET(5), 7)
    STEP(F, c, d, a, b, SET(6), 11)
    STEP(F, b, c, d, a, SET(7), 19)
    STEP(F, a, b, c, d, SET(8), 3)
    STEP(F, d, a, b, c, SET(9), 7)
    STEP(F, c, d, a, b, SET(10), 11)
    STEP(F, b, c, d, a, SET(11), 19)
    STEP(F, a, b, c, d, SET(12), 3)
    STEP(F, d, a, b, c, SET(13), 7)
    STEP(F, c, d, a, b, SET(14), 11)
    STEP(F, b, c, d, a, SET(15), 19)

/* Round 2 */
    STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3)
    STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5)
    STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9)
    STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13)
    STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3)
    STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5)
    STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9)
    STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13)
    STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3)
    STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5)
    STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9)
    STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13)
    STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3)
    STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5)
    STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9)
    STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13)

/* Round 3 */
    STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3)
    STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9)
    STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11)
    STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15)
    STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3)
    STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9)
    STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11)
    STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15)
    STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3)
    STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9)
    STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11)
    STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15)
    STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3)
    STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9)
    STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11)
    STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15)

    a += saved_a;
    b += saved_b;
    c += saved_c;
    d += saved_d;

    ptr += 64;







|
|
|




|








|
|


|

|
|

|





|





|

>
|




















|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402

/*
 * The basic MD4 functions.
 *
 * F and G are optimized compared to their RFC 1320 definitions, with the
 * optimization for F borrowed from Colin Plumb's MD5 implementation.
 */
#define MD4_F(x, y, z)                  ((z) ^ ((x) & ((y) ^ (z))))
#define MD4_G(x, y, z)                  (((x) & ((y) | (z))) | ((y) & (z)))
#define MD4_H(x, y, z)                  ((x) ^ (y) ^ (z))

/*
 * The MD4 transformation for all three rounds.
 */
#define MD4_STEP(f, a, b, c, d, x, s) \
        (a) += f((b), (c), (d)) + (x); \
        (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));

/*
 * SET reads 4 input bytes in little-endian byte order and stores them
 * in a properly aligned word in host byte order.
 *
 * The check for little-endian architectures that tolerate unaligned
 * memory accesses is just an optimization. Nothing will break if it
 * does not work.
 */
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define MD4_SET(n) \
        (*(MD4_u32plus *)(void *)&ptr[(n) * 4])
#define MD4_GET(n) \
        MD4_SET(n)
#else
#define MD4_SET(n) \
        (ctx->block[(n)] = \
        (MD4_u32plus)ptr[(n) * 4] | \
        ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \
        ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \
        ((MD4_u32plus)ptr[(n) * 4 + 3] << 24))
#define MD4_GET(n) \
        (ctx->block[(n)])
#endif

/*
 * This processes one or more 64-byte data blocks, but does NOT update
 * the bit counters. There are no alignment requirements.
 */
static const void *my_md4_body(MD4_CTX *ctx,
                               const void *data, unsigned long size)
{
  const unsigned char *ptr;
  MD4_u32plus a, b, c, d;

  ptr = (const unsigned char *)data;

  a = ctx->a;
  b = ctx->b;
  c = ctx->c;
  d = ctx->d;

  do {
    MD4_u32plus saved_a, saved_b, saved_c, saved_d;

    saved_a = a;
    saved_b = b;
    saved_c = c;
    saved_d = d;

/* Round 1 */
    MD4_STEP(MD4_F, a, b, c, d, MD4_SET(0), 3)
    MD4_STEP(MD4_F, d, a, b, c, MD4_SET(1), 7)
    MD4_STEP(MD4_F, c, d, a, b, MD4_SET(2), 11)
    MD4_STEP(MD4_F, b, c, d, a, MD4_SET(3), 19)
    MD4_STEP(MD4_F, a, b, c, d, MD4_SET(4), 3)
    MD4_STEP(MD4_F, d, a, b, c, MD4_SET(5), 7)
    MD4_STEP(MD4_F, c, d, a, b, MD4_SET(6), 11)
    MD4_STEP(MD4_F, b, c, d, a, MD4_SET(7), 19)
    MD4_STEP(MD4_F, a, b, c, d, MD4_SET(8), 3)
    MD4_STEP(MD4_F, d, a, b, c, MD4_SET(9), 7)
    MD4_STEP(MD4_F, c, d, a, b, MD4_SET(10), 11)
    MD4_STEP(MD4_F, b, c, d, a, MD4_SET(11), 19)
    MD4_STEP(MD4_F, a, b, c, d, MD4_SET(12), 3)
    MD4_STEP(MD4_F, d, a, b, c, MD4_SET(13), 7)
    MD4_STEP(MD4_F, c, d, a, b, MD4_SET(14), 11)
    MD4_STEP(MD4_F, b, c, d, a, MD4_SET(15), 19)

/* Round 2 */
    MD4_STEP(MD4_G, a, b, c, d, MD4_GET(0) + 0x5a827999, 3)
    MD4_STEP(MD4_G, d, a, b, c, MD4_GET(4) + 0x5a827999, 5)
    MD4_STEP(MD4_G, c, d, a, b, MD4_GET(8) + 0x5a827999, 9)
    MD4_STEP(MD4_G, b, c, d, a, MD4_GET(12) + 0x5a827999, 13)
    MD4_STEP(MD4_G, a, b, c, d, MD4_GET(1) + 0x5a827999, 3)
    MD4_STEP(MD4_G, d, a, b, c, MD4_GET(5) + 0x5a827999, 5)
    MD4_STEP(MD4_G, c, d, a, b, MD4_GET(9) + 0x5a827999, 9)
    MD4_STEP(MD4_G, b, c, d, a, MD4_GET(13) + 0x5a827999, 13)
    MD4_STEP(MD4_G, a, b, c, d, MD4_GET(2) + 0x5a827999, 3)
    MD4_STEP(MD4_G, d, a, b, c, MD4_GET(6) + 0x5a827999, 5)
    MD4_STEP(MD4_G, c, d, a, b, MD4_GET(10) + 0x5a827999, 9)
    MD4_STEP(MD4_G, b, c, d, a, MD4_GET(14) + 0x5a827999, 13)
    MD4_STEP(MD4_G, a, b, c, d, MD4_GET(3) + 0x5a827999, 3)
    MD4_STEP(MD4_G, d, a, b, c, MD4_GET(7) + 0x5a827999, 5)
    MD4_STEP(MD4_G, c, d, a, b, MD4_GET(11) + 0x5a827999, 9)
    MD4_STEP(MD4_G, b, c, d, a, MD4_GET(15) + 0x5a827999, 13)

/* Round 3 */
    MD4_STEP(MD4_H, a, b, c, d, MD4_GET(0) + 0x6ed9eba1, 3)
    MD4_STEP(MD4_H, d, a, b, c, MD4_GET(8) + 0x6ed9eba1, 9)
    MD4_STEP(MD4_H, c, d, a, b, MD4_GET(4) + 0x6ed9eba1, 11)
    MD4_STEP(MD4_H, b, c, d, a, MD4_GET(12) + 0x6ed9eba1, 15)
    MD4_STEP(MD4_H, a, b, c, d, MD4_GET(2) + 0x6ed9eba1, 3)
    MD4_STEP(MD4_H, d, a, b, c, MD4_GET(10) + 0x6ed9eba1, 9)
    MD4_STEP(MD4_H, c, d, a, b, MD4_GET(6) + 0x6ed9eba1, 11)
    MD4_STEP(MD4_H, b, c, d, a, MD4_GET(14) + 0x6ed9eba1, 15)
    MD4_STEP(MD4_H, a, b, c, d, MD4_GET(1) + 0x6ed9eba1, 3)
    MD4_STEP(MD4_H, d, a, b, c, MD4_GET(9) + 0x6ed9eba1, 9)
    MD4_STEP(MD4_H, c, d, a, b, MD4_GET(5) + 0x6ed9eba1, 11)
    MD4_STEP(MD4_H, b, c, d, a, MD4_GET(13) + 0x6ed9eba1, 15)
    MD4_STEP(MD4_H, a, b, c, d, MD4_GET(3) + 0x6ed9eba1, 3)
    MD4_STEP(MD4_H, d, a, b, c, MD4_GET(11) + 0x6ed9eba1, 9)
    MD4_STEP(MD4_H, c, d, a, b, MD4_GET(7) + 0x6ed9eba1, 11)
    MD4_STEP(MD4_H, b, c, d, a, MD4_GET(15) + 0x6ed9eba1, 15)

    a += saved_a;
    b += saved_b;
    c += saved_c;
    d += saved_d;

    ptr += 64;
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
      memcpy(&ctx->buffer[used], data, size);
      return;
    }

    memcpy(&ctx->buffer[used], data, available);
    data = (const unsigned char *)data + available;
    size -= available;
    body(ctx, ctx->buffer, 64);
  }

  if(size >= 64) {
    data = body(ctx, data, size & ~(unsigned long)0x3f);
    size &= 0x3f;
  }

  memcpy(ctx->buffer, data, size);
}

static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
{
  unsigned long used, available;

  used = ctx->lo & 0x3f;

  ctx->buffer[used++] = 0x80;

  available = 64 - used;

  if(available < 8) {
    memset(&ctx->buffer[used], 0, available);
    body(ctx, ctx->buffer, 64);
    used = 0;
    available = 64;
  }

  memset(&ctx->buffer[used], 0, available - 8);

  ctx->lo <<= 3;
  ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
  ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
  ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
  ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff);
  ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
  ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
  ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
  ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);

  body(ctx, ctx->buffer, 64);

  result[0] = curlx_ultouc((ctx->a)&0xff);
  result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
  result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
  result[3] = curlx_ultouc(ctx->a >> 24);
  result[4] = curlx_ultouc((ctx->b)&0xff);
  result[5] = curlx_ultouc((ctx->b >> 8)&0xff);







|



|


















|
















|







442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
      memcpy(&ctx->buffer[used], data, size);
      return;
    }

    memcpy(&ctx->buffer[used], data, available);
    data = (const unsigned char *)data + available;
    size -= available;
    my_md4_body(ctx, ctx->buffer, 64);
  }

  if(size >= 64) {
    data = my_md4_body(ctx, data, size & ~(unsigned long)0x3f);
    size &= 0x3f;
  }

  memcpy(ctx->buffer, data, size);
}

static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
{
  unsigned long used, available;

  used = ctx->lo & 0x3f;

  ctx->buffer[used++] = 0x80;

  available = 64 - used;

  if(available < 8) {
    memset(&ctx->buffer[used], 0, available);
    my_md4_body(ctx, ctx->buffer, 64);
    used = 0;
    available = 64;
  }

  memset(&ctx->buffer[used], 0, available - 8);

  ctx->lo <<= 3;
  ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
  ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
  ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
  ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff);
  ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
  ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
  ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
  ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);

  my_md4_body(ctx, ctx->buffer, 64);

  result[0] = curlx_ultouc((ctx->a)&0xff);
  result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
  result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
  result[3] = curlx_ultouc(ctx->a >> 24);
  result[4] = curlx_ultouc((ctx->b)&0xff);
  result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
Changes to jni/curl/lib/md5.c.
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#endif
}

#elif defined(AN_APPLE_OS)

/* For Apple operating systems: CommonCrypto has the functions we need.
   These functions are available on Tiger and later, as well as iOS 2.0
   and later. If you're building for an older cat, well, sorry.

   Declaring the functions as static like this seems to be a bit more
   reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
#  define my_md5_ctx CC_MD5_CTX

static CURLcode my_md5_init(my_md5_ctx *ctx)
{







|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#endif
}

#elif defined(AN_APPLE_OS)

/* For Apple operating systems: CommonCrypto has the functions we need.
   These functions are available on Tiger and later, as well as iOS 2.0
   and later. If you are building for an older cat, well, sorry.

   Declaring the functions as static like this seems to be a bit more
   reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
#  define my_md5_ctx CC_MD5_CTX

static CURLcode my_md5_init(my_md5_ctx *ctx)
{
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
 *
 * Homepage:
 https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
 *
 * This software was written by Alexander Peslyak in 2001.  No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 *
 * (This is a heavily cut-down "BSD license".)
 *
 * This differs from Colin Plumb's older public domain implementation in that
 * no exactly 32-bit integer data type is required (any 32-bit or wider
 * unsigned integer data type will do), there's no compile-time endianness
 * configuration, and the function prototypes match OpenSSL's.  No code from
 * Colin Plumb's implementation has been reused; this comment merely compares
 * the properties of the two independent implementations.
 *
 * The primary goals of this implementation are portability and ease of use.
 * It is meant to be fast, but not as fast as possible.  Some known
 * optimizations are not included to reduce source code size and avoid
 * compile-time configuration.
 */

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;








|









|





|
|




|







250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
 *
 * Homepage:
 https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
 *
 * Author:
 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
 *
 * This software was written by Alexander Peslyak in 2001. No copyright is
 * claimed, and the software is hereby placed in the public domain.
 * In case this attempt to disclaim copyright and place the software in the
 * public domain is deemed null and void, then the software is
 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
 * general public under the following terms:
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There is ABSOLUTELY NO WARRANTY, express or implied.
 *
 * (This is a heavily cut-down "BSD license".)
 *
 * This differs from Colin Plumb's older public domain implementation in that
 * no exactly 32-bit integer data type is required (any 32-bit or wider
 * unsigned integer data type will do), there is no compile-time endianness
 * configuration, and the function prototypes match OpenSSL's. No code from
 * Colin Plumb's implementation has been reused; this comment merely compares
 * the properties of the two independent implementations.
 *
 * The primary goals of this implementation are portability and ease of use.
 * It is meant to be fast, but not as fast as possible. Some known
 * optimizations are not included to reduce source code size and avoid
 * compile-time configuration.
 */

/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348

349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
/*
 * The basic MD5 functions.
 *
 * F and G are optimized compared to their RFC 1321 definitions for
 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
 * implementation.
 */
#define F(x, y, z)                      ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z)                      ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z)                      (((x) ^ (y)) ^ (z))
#define H2(x, y, z)                     ((x) ^ ((y) ^ (z)))
#define I(x, y, z)                      ((y) ^ ((x) | ~(z)))

/*
 * The MD5 transformation for all four rounds.
 */
#define STEP(f, a, b, c, d, x, t, s) \
        (a) += f((b), (c), (d)) + (x) + (t); \
        (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
        (a) += (b);

/*
 * SET reads 4 input bytes in little-endian byte order and stores them
 * in a properly aligned word in host byte order.
 *
 * The check for little-endian architectures that tolerate unaligned
 * memory accesses is just an optimization.  Nothing will break if it
 * doesn't work.
 */
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) \
        (*(MD5_u32plus *)(void *)&ptr[(n) * 4])
#define GET(n) \
        SET(n)
#else
#define SET(n) \
        (ctx->block[(n)] = \
        (MD5_u32plus)ptr[(n) * 4] | \
        ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
        ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
        ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
        (ctx->block[(n)])
#endif

/*
 * This processes one or more 64-byte data blocks, but does NOT update
 * the bit counters.  There are no alignment requirements.
 */

static const void *body(my_md5_ctx *ctx, const void *data, unsigned long size)
{
  const unsigned char *ptr;
  MD5_u32plus a, b, c, d;

  ptr = (const unsigned char *)data;

  a = ctx->a;
  b = ctx->b;
  c = ctx->c;
  d = ctx->d;

  do {
    MD5_u32plus saved_a, saved_b, saved_c, saved_d;

    saved_a = a;
    saved_b = b;
    saved_c = c;
    saved_d = d;

/* Round 1 */
    STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
    STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
    STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
    STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
    STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
    STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
    STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
    STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
    STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
    STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
    STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
    STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
    STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
    STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
    STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
    STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)

/* Round 2 */
    STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
    STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
    STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
    STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
    STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
    STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
    STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
    STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
    STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
    STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
    STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
    STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
    STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
    STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
    STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
    STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)

/* Round 3 */
    STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
    STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
    STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
    STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
    STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
    STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
    STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
    STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
    STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
    STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
    STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
    STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
    STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
    STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
    STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
    STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)

/* Round 4 */
    STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
    STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
    STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
    STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
    STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
    STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
    STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
    STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
    STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
    STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
    STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
    STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
    STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
    STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
    STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
    STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)

    a += saved_a;
    b += saved_b;
    c += saved_c;
    d += saved_d;

    ptr += 64;







|
|
|
|
|




|









|
|


|

|
|

|





|





|

>
|




















|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
/*
 * The basic MD5 functions.
 *
 * F and G are optimized compared to their RFC 1321 definitions for
 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
 * implementation.
 */
#define MD5_F(x, y, z)                  ((z) ^ ((x) & ((y) ^ (z))))
#define MD5_G(x, y, z)                  ((y) ^ ((z) & ((x) ^ (y))))
#define MD5_H(x, y, z)                  (((x) ^ (y)) ^ (z))
#define MD5_H2(x, y, z)                 ((x) ^ ((y) ^ (z)))
#define MD5_I(x, y, z)                  ((y) ^ ((x) | ~(z)))

/*
 * The MD5 transformation for all four rounds.
 */
#define MD5_STEP(f, a, b, c, d, x, t, s) \
        (a) += f((b), (c), (d)) + (x) + (t); \
        (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
        (a) += (b);

/*
 * SET reads 4 input bytes in little-endian byte order and stores them
 * in a properly aligned word in host byte order.
 *
 * The check for little-endian architectures that tolerate unaligned
 * memory accesses is just an optimization. Nothing will break if it
 * does not work.
 */
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define MD5_SET(n) \
        (*(MD5_u32plus *)(void *)&ptr[(n) * 4])
#define MD5_GET(n) \
        MD5_SET(n)
#else
#define MD5_SET(n) \
        (ctx->block[(n)] = \
        (MD5_u32plus)ptr[(n) * 4] | \
        ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
        ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
        ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
#define MD5_GET(n) \
        (ctx->block[(n)])
#endif

/*
 * This processes one or more 64-byte data blocks, but does NOT update
 * the bit counters. There are no alignment requirements.
 */
static const void *my_md5_body(my_md5_ctx *ctx,
                               const void *data, unsigned long size)
{
  const unsigned char *ptr;
  MD5_u32plus a, b, c, d;

  ptr = (const unsigned char *)data;

  a = ctx->a;
  b = ctx->b;
  c = ctx->c;
  d = ctx->d;

  do {
    MD5_u32plus saved_a, saved_b, saved_c, saved_d;

    saved_a = a;
    saved_b = b;
    saved_c = c;
    saved_d = d;

/* Round 1 */
    MD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7)
    MD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12)
    MD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17)
    MD5_STEP(MD5_F, b, c, d, a, MD5_SET(3), 0xc1bdceee, 22)
    MD5_STEP(MD5_F, a, b, c, d, MD5_SET(4), 0xf57c0faf, 7)
    MD5_STEP(MD5_F, d, a, b, c, MD5_SET(5), 0x4787c62a, 12)
    MD5_STEP(MD5_F, c, d, a, b, MD5_SET(6), 0xa8304613, 17)
    MD5_STEP(MD5_F, b, c, d, a, MD5_SET(7), 0xfd469501, 22)
    MD5_STEP(MD5_F, a, b, c, d, MD5_SET(8), 0x698098d8, 7)
    MD5_STEP(MD5_F, d, a, b, c, MD5_SET(9), 0x8b44f7af, 12)
    MD5_STEP(MD5_F, c, d, a, b, MD5_SET(10), 0xffff5bb1, 17)
    MD5_STEP(MD5_F, b, c, d, a, MD5_SET(11), 0x895cd7be, 22)
    MD5_STEP(MD5_F, a, b, c, d, MD5_SET(12), 0x6b901122, 7)
    MD5_STEP(MD5_F, d, a, b, c, MD5_SET(13), 0xfd987193, 12)
    MD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17)
    MD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22)

/* Round 2 */
    MD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5)
    MD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9)
    MD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14)
    MD5_STEP(MD5_G, b, c, d, a, MD5_GET(0), 0xe9b6c7aa, 20)
    MD5_STEP(MD5_G, a, b, c, d, MD5_GET(5), 0xd62f105d, 5)
    MD5_STEP(MD5_G, d, a, b, c, MD5_GET(10), 0x02441453, 9)
    MD5_STEP(MD5_G, c, d, a, b, MD5_GET(15), 0xd8a1e681, 14)
    MD5_STEP(MD5_G, b, c, d, a, MD5_GET(4), 0xe7d3fbc8, 20)
    MD5_STEP(MD5_G, a, b, c, d, MD5_GET(9), 0x21e1cde6, 5)
    MD5_STEP(MD5_G, d, a, b, c, MD5_GET(14), 0xc33707d6, 9)
    MD5_STEP(MD5_G, c, d, a, b, MD5_GET(3), 0xf4d50d87, 14)
    MD5_STEP(MD5_G, b, c, d, a, MD5_GET(8), 0x455a14ed, 20)
    MD5_STEP(MD5_G, a, b, c, d, MD5_GET(13), 0xa9e3e905, 5)
    MD5_STEP(MD5_G, d, a, b, c, MD5_GET(2), 0xfcefa3f8, 9)
    MD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14)
    MD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20)

/* Round 3 */
    MD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4)
    MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11)
    MD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16)
    MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(14), 0xfde5380c, 23)
    MD5_STEP(MD5_H, a, b, c, d, MD5_GET(1), 0xa4beea44, 4)
    MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(4), 0x4bdecfa9, 11)
    MD5_STEP(MD5_H, c, d, a, b, MD5_GET(7), 0xf6bb4b60, 16)
    MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(10), 0xbebfbc70, 23)
    MD5_STEP(MD5_H, a, b, c, d, MD5_GET(13), 0x289b7ec6, 4)
    MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(0), 0xeaa127fa, 11)
    MD5_STEP(MD5_H, c, d, a, b, MD5_GET(3), 0xd4ef3085, 16)
    MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(6), 0x04881d05, 23)
    MD5_STEP(MD5_H, a, b, c, d, MD5_GET(9), 0xd9d4d039, 4)
    MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(12), 0xe6db99e5, 11)
    MD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16)
    MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23)

/* Round 4 */
    MD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6)
    MD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10)
    MD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15)
    MD5_STEP(MD5_I, b, c, d, a, MD5_GET(5), 0xfc93a039, 21)
    MD5_STEP(MD5_I, a, b, c, d, MD5_GET(12), 0x655b59c3, 6)
    MD5_STEP(MD5_I, d, a, b, c, MD5_GET(3), 0x8f0ccc92, 10)
    MD5_STEP(MD5_I, c, d, a, b, MD5_GET(10), 0xffeff47d, 15)
    MD5_STEP(MD5_I, b, c, d, a, MD5_GET(1), 0x85845dd1, 21)
    MD5_STEP(MD5_I, a, b, c, d, MD5_GET(8), 0x6fa87e4f, 6)
    MD5_STEP(MD5_I, d, a, b, c, MD5_GET(15), 0xfe2ce6e0, 10)
    MD5_STEP(MD5_I, c, d, a, b, MD5_GET(6), 0xa3014314, 15)
    MD5_STEP(MD5_I, b, c, d, a, MD5_GET(13), 0x4e0811a1, 21)
    MD5_STEP(MD5_I, a, b, c, d, MD5_GET(4), 0xf7537e82, 6)
    MD5_STEP(MD5_I, d, a, b, c, MD5_GET(11), 0xbd3af235, 10)
    MD5_STEP(MD5_I, c, d, a, b, MD5_GET(2), 0x2ad7d2bb, 15)
    MD5_STEP(MD5_I, b, c, d, a, MD5_GET(9), 0xeb86d391, 21)

    a += saved_a;
    b += saved_b;
    c += saved_c;
    d += saved_d;

    ptr += 64;
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
      memcpy(&ctx->buffer[used], data, size);
      return;
    }

    memcpy(&ctx->buffer[used], data, available);
    data = (const unsigned char *)data + available;
    size -= available;
    body(ctx, ctx->buffer, 64);
  }

  if(size >= 64) {
    data = body(ctx, data, size & ~(unsigned long)0x3f);
    size &= 0x3f;
  }

  memcpy(ctx->buffer, data, size);
}

static void my_md5_final(unsigned char *result, my_md5_ctx *ctx)
{
  unsigned long used, available;

  used = ctx->lo & 0x3f;

  ctx->buffer[used++] = 0x80;

  available = 64 - used;

  if(available < 8) {
    memset(&ctx->buffer[used], 0, available);
    body(ctx, ctx->buffer, 64);
    used = 0;
    available = 64;
  }

  memset(&ctx->buffer[used], 0, available - 8);

  ctx->lo <<= 3;
  ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
  ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
  ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
  ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24);
  ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
  ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
  ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
  ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);

  body(ctx, ctx->buffer, 64);

  result[0] = curlx_ultouc((ctx->a)&0xff);
  result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
  result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
  result[3] = curlx_ultouc(ctx->a >> 24);
  result[4] = curlx_ultouc((ctx->b)&0xff);
  result[5] = curlx_ultouc((ctx->b >> 8)&0xff);







|



|


















|
















|







489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
      memcpy(&ctx->buffer[used], data, size);
      return;
    }

    memcpy(&ctx->buffer[used], data, available);
    data = (const unsigned char *)data + available;
    size -= available;
    my_md5_body(ctx, ctx->buffer, 64);
  }

  if(size >= 64) {
    data = my_md5_body(ctx, data, size & ~(unsigned long)0x3f);
    size &= 0x3f;
  }

  memcpy(ctx->buffer, data, size);
}

static void my_md5_final(unsigned char *result, my_md5_ctx *ctx)
{
  unsigned long used, available;

  used = ctx->lo & 0x3f;

  ctx->buffer[used++] = 0x80;

  available = 64 - used;

  if(available < 8) {
    memset(&ctx->buffer[used], 0, available);
    my_md5_body(ctx, ctx->buffer, 64);
    used = 0;
    available = 64;
  }

  memset(&ctx->buffer[used], 0, available - 8);

  ctx->lo <<= 3;
  ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
  ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
  ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
  ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24);
  ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
  ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
  ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
  ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);

  my_md5_body(ctx, ctx->buffer, 64);

  result[0] = curlx_ultouc((ctx->a)&0xff);
  result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
  result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
  result[3] = curlx_ultouc(ctx->a >> 24);
  result[4] = curlx_ultouc((ctx->b)&0xff);
  result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
Changes to jni/curl/lib/memdebug.c.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

#ifdef CURLDEBUG

#include <curl/curl.h>

#include "urldata.h"

#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

struct memdebug {
  size_t size;
  union {
    curl_off_t o;
    double d;
    void *p;
  } mem[1];
  /* I'm hoping this is the thing with the strictest alignment
   * requirements.  That also means we waste some space :-( */
};

/*
 * Note that these debug functions are very simple and they are meant to
 * remain so. For advanced analysis, record a log file and write perl scripts
 * to analyze them!
 *
 * Don't use these with multithreaded test programs!
 */

FILE *curl_dbg_logfile = NULL;
static bool registered_cleanup = FALSE; /* atexit registered cleanup */
static bool memlimit = FALSE; /* enable memory limit */
static long memsize = 0;  /* set number of mallocs allowed */








|













|
|







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

#ifdef CURLDEBUG

#include <curl/curl.h>

#include "urldata.h"

#define MEMDEBUG_NODEFINES /* do not redefine the standard functions */

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

struct memdebug {
  size_t size;
  union {
    curl_off_t o;
    double d;
    void *p;
  } mem[1];
  /* I am hoping this is the thing with the strictest alignment
   * requirements. That also means we waste some space :-( */
};

/*
 * Note that these debug functions are very simple and they are meant to
 * remain so. For advanced analysis, record a log file and write perl scripts
 * to analyze them!
 *
 * Do not use these with multithreaded test programs!
 */

FILE *curl_dbg_logfile = NULL;
static bool registered_cleanup = FALSE; /* atexit registered cleanup */
static bool memlimit = FALSE; /* enable memory limit */
static long memsize = 0;  /* set number of mallocs allowed */

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
     curl_dbg_logfile != stderr &&
     curl_dbg_logfile != stdout) {
    fclose(curl_dbg_logfile);
  }
  curl_dbg_logfile = NULL;
}

/* this sets the log file name */
void curl_dbg_memdebug(const char *logname)
{
  if(!curl_dbg_logfile) {
    if(logname && *logname)
      curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT);
    else
      curl_dbg_logfile = stderr;
#ifdef MEMDEBUG_LOG_SYNC
    /* Flush the log file after every line so the log isn't lost in a crash */
    if(curl_dbg_logfile)
      setbuf(curl_dbg_logfile, (char *)NULL);
#endif
  }
  if(!registered_cleanup)
    registered_cleanup = !atexit(curl_dbg_cleanup);
}

/* This function sets the number of malloc() calls that should return
   successfully! */
void curl_dbg_memlimit(long limit)
{
  if(!memlimit) {
    memlimit = TRUE;
    memsize = limit;
  }
}

/* returns TRUE if this isn't allowed! */
static bool countcheck(const char *func, int line, const char *source)
{
  /* if source is NULL, then the call is made internally and this check
     should not be made */
  if(memlimit && source) {
    if(!memsize) {
      /* log to file */







|








|


















|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
     curl_dbg_logfile != stderr &&
     curl_dbg_logfile != stdout) {
    fclose(curl_dbg_logfile);
  }
  curl_dbg_logfile = NULL;
}

/* this sets the log filename */
void curl_dbg_memdebug(const char *logname)
{
  if(!curl_dbg_logfile) {
    if(logname && *logname)
      curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT);
    else
      curl_dbg_logfile = stderr;
#ifdef MEMDEBUG_LOG_SYNC
    /* Flush the log file after every line so the log is not lost in a crash */
    if(curl_dbg_logfile)
      setbuf(curl_dbg_logfile, (char *)NULL);
#endif
  }
  if(!registered_cleanup)
    registered_cleanup = !atexit(curl_dbg_cleanup);
}

/* This function sets the number of malloc() calls that should return
   successfully! */
void curl_dbg_memlimit(long limit)
{
  if(!memlimit) {
    memlimit = TRUE;
    memsize = limit;
  }
}

/* returns TRUE if this is not allowed! */
static bool countcheck(const char *func, int line, const char *source)
{
  /* if source is NULL, then the call is made internally and this check
     should not be made */
  if(memlimit && source) {
    if(!memsize) {
      /* log to file */
Changes to jni/curl/lib/memdebug.h.
133
134
135
136
137
138
139
140
141
142
143
144
145
146

147
148
149
150
151
152
153
#    undef _tcsdup
#    define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
#  endif
#endif

#undef socket
#define socket(domain,type,protocol)\
 curl_dbg_socket(domain, type, protocol, __LINE__, __FILE__)
#undef accept /* for those with accept as a macro */
#define accept(sock,addr,len)\
 curl_dbg_accept(sock, addr, len, __LINE__, __FILE__)
#ifdef HAVE_SOCKETPAIR
#define socketpair(domain,type,protocol,socket_vector)\
 curl_dbg_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__)

#endif

#ifdef HAVE_GETADDRINFO
#if defined(getaddrinfo) && defined(__osf__)
/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
   our macro as for other platforms. Instead, we redefine the new name they
   define getaddrinfo to become! */







|





|
>







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#    undef _tcsdup
#    define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
#  endif
#endif

#undef socket
#define socket(domain,type,protocol)\
 curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__)
#undef accept /* for those with accept as a macro */
#define accept(sock,addr,len)\
 curl_dbg_accept(sock, addr, len, __LINE__, __FILE__)
#ifdef HAVE_SOCKETPAIR
#define socketpair(domain,type,protocol,socket_vector)\
 curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \
                     __LINE__, __FILE__)
#endif

#ifdef HAVE_GETADDRINFO
#if defined(getaddrinfo) && defined(__osf__)
/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
   our macro as for other platforms. Instead, we redefine the new name they
   define getaddrinfo to become! */
Changes to jni/curl/lib/mime.c.
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  part->freefunc = NULL;
  part->arg = (void *) part;          /* Defaults to part itself. */
  part->data = NULL;
  part->fp = NULL;
  part->datasize = (curl_off_t) 0;    /* No size yet. */
  cleanup_encoder_state(&part->encstate);
  part->kind = MIMEKIND_NONE;
  part->flags &= ~MIME_FAST_READ;
  part->lastreadstatus = 1; /* Successful read status. */
  part->state.state = MIMESTATE_BEGIN;
}

static void mime_subparts_free(void *ptr)
{
  curl_mime *mime = (curl_mime *) ptr;

  if(mime && mime->parent) {
    mime->parent->freefunc = NULL;  /* Be sure we won't be called again. */
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
  }
  curl_mime_free(mime);
}

/* Do not free subparts: unbind them. This is used for the top level only. */
static void mime_subparts_unbind(void *ptr)
{
  curl_mime *mime = (curl_mime *) ptr;

  if(mime && mime->parent) {
    mime->parent->freefunc = NULL;  /* Be sure we won't be called again. */
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
    mime->parent = NULL;
  }
}


void Curl_mime_cleanpart(curl_mimepart *part)







|









|











|







1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  part->freefunc = NULL;
  part->arg = (void *) part;          /* Defaults to part itself. */
  part->data = NULL;
  part->fp = NULL;
  part->datasize = (curl_off_t) 0;    /* No size yet. */
  cleanup_encoder_state(&part->encstate);
  part->kind = MIMEKIND_NONE;
  part->flags &= ~(unsigned int)MIME_FAST_READ;
  part->lastreadstatus = 1; /* Successful read status. */
  part->state.state = MIMESTATE_BEGIN;
}

static void mime_subparts_free(void *ptr)
{
  curl_mime *mime = (curl_mime *) ptr;

  if(mime && mime->parent) {
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
  }
  curl_mime_free(mime);
}

/* Do not free subparts: unbind them. This is used for the top level only. */
static void mime_subparts_unbind(void *ptr)
{
  curl_mime *mime = (curl_mime *) ptr;

  if(mime && mime->parent) {
    mime->parent->freefunc = NULL;  /* Be sure we will not be called again. */
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
    mime->parent = NULL;
  }
}


void Curl_mime_cleanpart(curl_mimepart *part)
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196

/* Recursively delete a mime handle and its parts. */
void curl_mime_free(curl_mime *mime)
{
  curl_mimepart *part;

  if(mime) {
    mime_subparts_unbind(mime);  /* Be sure it's not referenced anymore. */
    while(mime->firstpart) {
      part = mime->firstpart;
      mime->firstpart = part->nextpart;
      Curl_mime_cleanpart(part);
      free(part);
    }
    free(mime);







|







1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196

/* Recursively delete a mime handle and its parts. */
void curl_mime_free(curl_mime *mime)
{
  curl_mimepart *part;

  if(mime) {
    mime_subparts_unbind(mime);  /* Be sure it is not referenced anymore. */
    while(mime->firstpart) {
      part = mime->firstpart;
      mime->firstpart = part->nextpart;
      Curl_mime_cleanpart(part);
      free(part);
    }
    free(mime);
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
    if(!part->name)
      return CURLE_OUT_OF_MEMORY;
  }

  return CURLE_OK;
}

/* Set mime part remote file name. */
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
{
  if(!part)
    return CURLE_BAD_FUNCTION_ARGUMENT;

  Curl_safefree(part->filename);








|







1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
    if(!part->name)
      return CURLE_OUT_OF_MEMORY;
  }

  return CURLE_OK;
}

/* Set mime part remote filename. */
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
{
  if(!part)
    return CURLE_BAD_FUNCTION_ARGUMENT;

  Curl_safefree(part->filename);

1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
{
  if(!part)
    return CURLE_BAD_FUNCTION_ARGUMENT;

  if(part->flags & MIME_USERHEADERS_OWNER) {
    if(part->userheaders != headers)  /* Allow setting twice the same list. */
      curl_slist_free_all(part->userheaders);
    part->flags &= ~MIME_USERHEADERS_OWNER;
  }
  part->userheaders = headers;
  if(headers && take_ownership)
    part->flags |= MIME_USERHEADERS_OWNER;
  return CURLE_OK;
}








|







1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
{
  if(!part)
    return CURLE_BAD_FUNCTION_ARGUMENT;

  if(part->flags & MIME_USERHEADERS_OWNER) {
    if(part->userheaders != headers)  /* Allow setting twice the same list. */
      curl_slist_free_all(part->userheaders);
    part->flags &= ~(unsigned int)MIME_USERHEADERS_OWNER;
  }
  part->userheaders = headers;
  if(headers && take_ownership)
    part->flags |= MIME_USERHEADERS_OWNER;
  return CURLE_OK;
}

1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564

    /* Should not be the part's root. */
    root = part->parent;
    if(root) {
      while(root->parent && root->parent->parent)
        root = root->parent->parent;
      if(subparts == root) {
        /* Can't add as a subpart of itself. */
        return CURLE_BAD_FUNCTION_ARGUMENT;
      }
    }

    subparts->parent = part;
    /* Subparts are processed internally: no read callback. */
    part->seekfunc = mime_subparts_seek;







|







1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564

    /* Should not be the part's root. */
    root = part->parent;
    if(root) {
      while(root->parent && root->parent->parent)
        root = root->parent->parent;
      if(subparts == root) {
        /* cannot add as a subpart of itself. */
        return CURLE_BAD_FUNCTION_ARGUMENT;
      }
    }

    subparts->parent = part;
    /* Subparts are processed internally: no read callback. */
    part->seekfunc = mime_subparts_seek;
1658
1659
1660
1661
1662
1663
1664
1665

1666
1667
1668
1669
1670
1671
1672

  if(part->encoder)
    size = part->encoder->sizefunc(part);

  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
    /* Compute total part size. */
    size += slist_size(part->curlheaders, 2, NULL, 0);
    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));

    size += 2;    /* CRLF after headers. */
  }
  return size;
}

/* Add a header. */
/* VARARGS2 */







|
>







1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673

  if(part->encoder)
    size = part->encoder->sizefunc(part);

  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
    /* Compute total part size. */
    size += slist_size(part->curlheaders, 2, NULL, 0);
    size += slist_size(part->userheaders, 2,
                       STRCONST("Content-Type"));
    size += 2;    /* CRLF after headers. */
  }
  return size;
}

/* Add a header. */
/* VARARGS2 */
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
  const char *cte = NULL;
  CURLcode ret = CURLE_OK;

  /* Get rid of previously prepared headers. */
  curl_slist_free_all(part->curlheaders);
  part->curlheaders = NULL;

  /* Be sure we won't access old headers later. */
  if(part->state.state == MIMESTATE_CURLHEADERS)
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);

  /* Check if content type is specified. */
  customct = part->mimetype;
  if(!customct)
    customct = search_header(part->userheaders, STRCONST("Content-Type"));







|







1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
  const char *cte = NULL;
  CURLcode ret = CURLE_OK;

  /* Get rid of previously prepared headers. */
  curl_slist_free_all(part->curlheaders);
  part->curlheaders = NULL;

  /* Be sure we will not access old headers later. */
  if(part->state.state == MIMESTATE_CURLHEADERS)
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);

  /* Check if content type is specified. */
  customct = part->mimetype;
  if(!customct)
    customct = search_header(part->userheaders, STRCONST("Content-Type"));
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
      ctx->total_len -= offset;

      if(ctx->total_len <= 0) {
        failf(data, "Mime post already completely uploaded");
        return CURLE_PARTIAL_FILE;
      }
    }
    /* we've passed, proceed as normal */
  }
  return CURLE_OK;
}

static CURLcode cr_mime_rewind(struct Curl_easy *data,
                               struct Curl_creader *reader)
{







|







2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
      ctx->total_len -= offset;

      if(ctx->total_len <= 0) {
        failf(data, "Mime post already completely uploaded");
        return CURLE_PARTIAL_FILE;
      }
    }
    /* we have passed, proceed as normal */
  }
  return CURLE_OK;
}

static CURLcode cr_mime_rewind(struct Curl_easy *data,
                               struct Curl_creader *reader)
{
2090
2091
2092
2093
2094
2095
2096








2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107

2108
2109
2110
2111
2112
2113
2114
                                struct Curl_creader *reader)
{
  struct cr_mime_ctx *ctx = reader->ctx;
  (void)data;
  mime_unpause(ctx->part);
  return CURLE_OK;
}









static const struct Curl_crtype cr_mime = {
  "cr-mime",
  cr_mime_init,
  cr_mime_read,
  Curl_creader_def_close,
  cr_mime_needs_rewind,
  cr_mime_total_length,
  cr_mime_resume_from,
  cr_mime_rewind,
  cr_mime_unpause,

  Curl_creader_def_done,
  sizeof(struct cr_mime_ctx)
};

CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
{
  struct Curl_creader *r;







>
>
>
>
>
>
>
>











>







2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
                                struct Curl_creader *reader)
{
  struct cr_mime_ctx *ctx = reader->ctx;
  (void)data;
  mime_unpause(ctx->part);
  return CURLE_OK;
}

static bool cr_mime_is_paused(struct Curl_easy *data,
                              struct Curl_creader *reader)
{
  struct cr_mime_ctx *ctx = reader->ctx;
  (void)data;
  return (ctx->part && ctx->part->lastreadstatus == CURL_READFUNC_PAUSE);
}

static const struct Curl_crtype cr_mime = {
  "cr-mime",
  cr_mime_init,
  cr_mime_read,
  Curl_creader_def_close,
  cr_mime_needs_rewind,
  cr_mime_total_length,
  cr_mime_resume_from,
  cr_mime_rewind,
  cr_mime_unpause,
  cr_mime_is_paused,
  Curl_creader_def_done,
  sizeof(struct cr_mime_ctx)
};

CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
{
  struct Curl_creader *r;
Changes to jni/curl/lib/mime.h.
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

/* A mime part. */
struct curl_mimepart {
  curl_mime *parent;               /* Parent mime structure. */
  curl_mimepart *nextpart;         /* Forward linked list. */
  enum mimekind kind;              /* The part kind. */
  unsigned int flags;              /* Flags. */
  char *data;                      /* Memory data or file name. */
  curl_read_callback readfunc;     /* Read function. */
  curl_seek_callback seekfunc;     /* Seek function. */
  curl_free_callback freefunc;     /* Argument free function. */
  void *arg;                       /* Argument to callback functions. */
  FILE *fp;                        /* File pointer. */
  struct curl_slist *curlheaders;  /* Part headers. */
  struct curl_slist *userheaders;  /* Part headers. */
  char *mimetype;                  /* Part mime type. */
  char *filename;                  /* Remote file name. */
  char *name;                      /* Data name. */
  curl_off_t datasize;             /* Expected data size. */
  struct mime_state state;         /* Current readback state. */
  const struct mime_encoder *encoder; /* Content data encoder. */
  struct mime_encoder_state encstate; /* Data encoder state. */
  size_t lastreadstatus;           /* Last read callback returned status. */
};







|








|







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

/* A mime part. */
struct curl_mimepart {
  curl_mime *parent;               /* Parent mime structure. */
  curl_mimepart *nextpart;         /* Forward linked list. */
  enum mimekind kind;              /* The part kind. */
  unsigned int flags;              /* Flags. */
  char *data;                      /* Memory data or filename. */
  curl_read_callback readfunc;     /* Read function. */
  curl_seek_callback seekfunc;     /* Seek function. */
  curl_free_callback freefunc;     /* Argument free function. */
  void *arg;                       /* Argument to callback functions. */
  FILE *fp;                        /* File pointer. */
  struct curl_slist *curlheaders;  /* Part headers. */
  struct curl_slist *userheaders;  /* Part headers. */
  char *mimetype;                  /* Part mime type. */
  char *filename;                  /* Remote filename. */
  char *name;                      /* Data name. */
  curl_off_t datasize;             /* Expected data size. */
  struct mime_state state;         /* Current readback state. */
  const struct mime_encoder *encoder; /* Content data encoder. */
  struct mime_encoder_state encstate; /* Data encoder state. */
  size_t lastreadstatus;           /* Last read callback returned status. */
};
Changes to jni/curl/lib/mprintf.c.
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873

    case FORMAT_STRING: {
      const char *str;
      size_t len;

      str = (char *)iptr->val.str;
      if(!str) {
        /* Write null string if there's space.  */
        if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
          str = nilstr;
          len = sizeof(nilstr) - 1;
          /* Disable quotes around (nil) */
          flags &= ~(unsigned int)FLAGS_ALT;
        }
        else {







|







859
860
861
862
863
864
865
866
867
868
869
870
871
872
873

    case FORMAT_STRING: {
      const char *str;
      size_t len;

      str = (char *)iptr->val.str;
      if(!str) {
        /* Write null string if there is space.  */
        if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
          str = nilstr;
          len = sizeof(nilstr) - 1;
          /* Disable quotes around (nil) */
          flags &= ~(unsigned int)FLAGS_ALT;
        }
        else {
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
}

/* fputc() look-alike */
static int addbyter(unsigned char outc, void *f)
{
  struct nsprintf *infop = f;
  if(infop->length < infop->max) {
    /* only do this if we haven't reached max length yet */
    *infop->buffer++ = (char)outc; /* store */
    infop->length++; /* we are now one byte larger */
    return 0;     /* fputc() returns like this on success */
  }
  return 1;
}








|







1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
}

/* fputc() look-alike */
static int addbyter(unsigned char outc, void *f)
{
  struct nsprintf *infop = f;
  if(infop->length < infop->max) {
    /* only do this if we have not reached max length yet */
    *infop->buffer++ = (char)outc; /* store */
    infop->length++; /* we are now one byte larger */
    return 0;     /* fputc() returns like this on success */
  }
  return 1;
}

1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  info.length = 0;
  info.max = maxlength;

  retcode = formatf(&info, addbyter, format, ap_save);
  if(info.max) {
    /* we terminate this with a zero byte */
    if(info.max == info.length) {
      /* we're at maximum, scrap the last letter */
      info.buffer[-1] = 0;
      DEBUGASSERT(retcode);
      retcode--; /* don't count the nul byte */
    }
    else
      info.buffer[0] = 0;
  }
  return retcode;
}








|


|







1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
  info.length = 0;
  info.max = maxlength;

  retcode = formatf(&info, addbyter, format, ap_save);
  if(info.max) {
    /* we terminate this with a zero byte */
    if(info.max == info.length) {
      /* we are at maximum, scrap the last letter */
      info.buffer[-1] = 0;
      DEBUGASSERT(retcode);
      retcode--; /* do not count the nul byte */
    }
    else
      info.buffer[0] = 0;
  }
  return retcode;
}

Changes to jni/curl/lib/mqtt.c.
150
151
152
153
154
155
156
157
158
159
160

161
162
163
164
165
166
167
168
169
170
171
172
  (void)data;
  sock[0] = conn->sock[FIRSTSOCKET];
  return GETSOCK_READSOCK(FIRSTSOCKET);
}

static int mqtt_encode_len(char *buf, size_t len)
{
  unsigned char encoded;
  int i;

  for(i = 0; (len > 0) && (i<4); i++) {

    encoded = len % 0x80;
    len /= 0x80;
    if(len)
      encoded |= 0x80;
    buf[i] = encoded;
  }

  return i;
}

/* add the passwd to the CONNECT packet */
static int add_passwd(const char *passwd, const size_t plen,







<



>




|







150
151
152
153
154
155
156

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  (void)data;
  sock[0] = conn->sock[FIRSTSOCKET];
  return GETSOCK_READSOCK(FIRSTSOCKET);
}

static int mqtt_encode_len(char *buf, size_t len)
{

  int i;

  for(i = 0; (len > 0) && (i<4); i++) {
    unsigned char encoded;
    encoded = len % 0x80;
    len /= 0x80;
    if(len)
      encoded |= 0x80;
    buf[i] = (char)encoded;
  }

  return i;
}

/* add the passwd to the CONNECT packet */
static int add_passwd(const char *passwd, const size_t plen,
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  }
  infof(data, "Using client id '%s'", client_id);

  /* position where starts the user payload */
  start_user = pos + 3 + MQTT_CLIENTID_LEN;
  /* position where starts the password payload */
  start_pwd = start_user + ulen;
  /* if user name was provided, add it to the packet */
  if(ulen) {
    start_pwd += 2;

    rc = add_user(username, ulen,
                  (unsigned char *)packet, start_user, remain_pos);
    if(rc) {
      failf(data, "Username is too large: [%zu]", ulen);







|







308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  }
  infof(data, "Using client id '%s'", client_id);

  /* position where starts the user payload */
  start_user = pos + 3 + MQTT_CLIENTID_LEN;
  /* position where starts the password payload */
  start_pwd = start_user + ulen;
  /* if username was provided, add it to the packet */
  if(ulen) {
    start_pwd += 2;

    rc = add_user(username, ulen,
                  (unsigned char *)packet, start_user, remain_pos);
    if(rc) {
      failf(data, "Username is too large: [%zu]", ulen);
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616

  if(lenbytes)
    *lenbytes = i;

  return len;
}

#ifdef CURLDEBUG
static const char *statenames[]={
  "MQTT_FIRST",
  "MQTT_REMAINING_LENGTH",
  "MQTT_CONNACK",
  "MQTT_SUBACK",
  "MQTT_SUBACK_COMING",
  "MQTT_PUBWAIT",
  "MQTT_PUB_REMAIN",

  "NOT A STATE"
};
#endif

/* The only way to change state */
static void mqstate(struct Curl_easy *data,
                    enum mqttstate state,
                    enum mqttstate nextstate) /* used if state == FIRST */
{
  struct connectdata *conn = data->conn;
  struct mqtt_conn *mqtt = &conn->proto.mqtt;
#ifdef CURLDEBUG
  infof(data, "%s (from %s) (next is %s)",
        statenames[state],
        statenames[mqtt->state],
        (state == MQTT_FIRST)? statenames[nextstate] : "");
#endif
  mqtt->state = state;
  if(state == MQTT_FIRST)







|




















|







581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616

  if(lenbytes)
    *lenbytes = i;

  return len;
}

#ifdef DEBUGBUILD
static const char *statenames[]={
  "MQTT_FIRST",
  "MQTT_REMAINING_LENGTH",
  "MQTT_CONNACK",
  "MQTT_SUBACK",
  "MQTT_SUBACK_COMING",
  "MQTT_PUBWAIT",
  "MQTT_PUB_REMAIN",

  "NOT A STATE"
};
#endif

/* The only way to change state */
static void mqstate(struct Curl_easy *data,
                    enum mqttstate state,
                    enum mqttstate nextstate) /* used if state == FIRST */
{
  struct connectdata *conn = data->conn;
  struct mqtt_conn *mqtt = &conn->proto.mqtt;
#ifdef DEBUGBUILD
  infof(data, "%s (from %s) (next is %s)",
        statenames[state],
        statenames[mqtt->state],
        (state == MQTT_FIRST)? statenames[nextstate] : "");
#endif
  mqtt->state = state;
  if(state == MQTT_FIRST)
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct mqtt_conn *mqtt = &conn->proto.mqtt;
  struct MQTT *mq = data->req.p.mqtt;
  ssize_t nread;
  unsigned char byte;

  *done = FALSE;

  if(mq->nsend) {
    /* send the remainder of an outgoing packet */
    char *ptr = mq->sendleftovers;
    result = mqtt_send(data, mq->sendleftovers, mq->nsend);







|







739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct mqtt_conn *mqtt = &conn->proto.mqtt;
  struct MQTT *mq = data->req.p.mqtt;
  ssize_t nread;
  unsigned char recvbyte;

  *done = FALSE;

  if(mq->nsend) {
    /* send the remainder of an outgoing packet */
    char *ptr = mq->sendleftovers;
    result = mqtt_send(data, mq->sendleftovers, mq->nsend);
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
    Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
    /* remember the first byte */
    mq->npacket = 0;
    mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
    FALLTHROUGH();
  case MQTT_REMAINING_LENGTH:
    do {
      result = Curl_xfer_recv(data, (char *)&byte, 1, &nread);
      if(result || !nread)
        break;
      Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
      mq->pkt_hd[mq->npacket++] = byte;
    } while((byte & 0x80) && (mq->npacket < 4));
    if(!result && nread && (byte & 0x80))
      /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
         127 * 128^3 bytes. server tried to send more */
      result = CURLE_WEIRD_SERVER_REPLY;
    if(result)
      break;
    mq->remaining_length = mqtt_decode_len(mq->pkt_hd, mq->npacket, NULL);
    mq->npacket = 0;







|


|
|
|
|







772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
    Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
    /* remember the first byte */
    mq->npacket = 0;
    mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
    FALLTHROUGH();
  case MQTT_REMAINING_LENGTH:
    do {
      result = Curl_xfer_recv(data, (char *)&recvbyte, 1, &nread);
      if(result || !nread)
        break;
      Curl_debug(data, CURLINFO_HEADER_IN, (char *)&recvbyte, 1);
      mq->pkt_hd[mq->npacket++] = recvbyte;
    } while((recvbyte & 0x80) && (mq->npacket < 4));
    if(!result && nread && (recvbyte & 0x80))
      /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
         127 * 128^3 bytes. server tried to send more */
      result = CURLE_WEIRD_SERVER_REPLY;
    if(result)
      break;
    mq->remaining_length = mqtt_decode_len(mq->pkt_hd, mq->npacket, NULL);
    mq->npacket = 0;
Changes to jni/curl/lib/multi.c.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

/*
  CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
  to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes.  Still, every
  CURL handle takes 45-50 K memory, therefore this 3K are not significant.
*/
#ifndef CURL_SOCKET_HASH_TABLE_SIZE
#define CURL_SOCKET_HASH_TABLE_SIZE 911
#endif

#ifndef CURL_CONNECTION_HASH_SIZE







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

/*
  CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
  to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
  CURL handle takes 45-50 K memory, therefore this 3K are not significant.
*/
#ifndef CURL_SOCKET_HASH_TABLE_SIZE
#define CURL_SOCKET_HASH_TABLE_SIZE 911
#endif

#ifndef CURL_CONNECTION_HASH_SIZE
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  Curl_pgrsTime(data, TIMER_PRETRANSFER);
}

static void init_completed(struct Curl_easy *data)
{
  /* this is a completed transfer */

  /* Important: reset the conn pointer so that we don't point to memory
     that could be freed anytime */
  Curl_detach_connection(data);
  Curl_expire_clear(data); /* stop all timers */
}

/* always use this function to change state, to make debugging easier */
static void mstate(struct Curl_easy *data, CURLMstate state







|







131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  Curl_pgrsTime(data, TIMER_PRETRANSFER);
}

static void init_completed(struct Curl_easy *data)
{
  /* this is a completed transfer */

  /* Important: reset the conn pointer so that we do not point to memory
     that could be freed anytime */
  Curl_detach_connection(data);
  Curl_expire_clear(data); /* stop all timers */
}

/* always use this function to change state, to make debugging easier */
static void mstate(struct Curl_easy *data, CURLMstate state
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  };

#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void) lineno;
#endif

  if(oldstate == state)
    /* don't bother when the new state is the same as the old state */
    return;

  data->mstate = state;

#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
  if(data->mstate >= MSTATE_PENDING &&
     data->mstate < MSTATE_COMPLETED) {
    infof(data,
          "STATE: %s => %s handle %p; line %d",
          multi_statename[oldstate], multi_statename[data->mstate],
          (void *)data, lineno);
  }
#endif

  if(state == MSTATE_COMPLETED) {
    /* changing to COMPLETED means there's one less easy handle 'alive' */
    DEBUGASSERT(data->multi->num_alive > 0);
    data->multi->num_alive--;
    if(!data->multi->num_alive) {
      /* free the transfer buffer when we have no more active transfers */
      multi_xfer_bufs_free(data->multi);
    }
  }







|















|







171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  };

#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void) lineno;
#endif

  if(oldstate == state)
    /* do not bother when the new state is the same as the old state */
    return;

  data->mstate = state;

#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
  if(data->mstate >= MSTATE_PENDING &&
     data->mstate < MSTATE_COMPLETED) {
    infof(data,
          "STATE: %s => %s handle %p; line %d",
          multi_statename[oldstate], multi_statename[data->mstate],
          (void *)data, lineno);
  }
#endif

  if(state == MSTATE_COMPLETED) {
    /* changing to COMPLETED means there is one less easy handle 'alive' */
    DEBUGASSERT(data->multi->num_alive > 0);
    data->multi->num_alive--;
    if(!data->multi->num_alive) {
      /* free the transfer buffer when we have no more active transfers */
      multi_xfer_bufs_free(data->multi);
    }
  }
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371











372
373
374
375
376
377
378
}

static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
{
  curl_socket_t fd = *((curl_socket_t *) key);
  (void) key_length;

  return (fd % slots_num);
}

/*
 * sh_init() creates a new socket hash and returns the handle for it.
 *
 * Quote from README.multi_socket:
 *
 * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
 * is somewhat of a bottle neck. Its current implementation may be a bit too
 * limiting. It simply has a fixed-size array, and on each entry in the array
 * it has a linked list with entries. So the hash only checks which list to
 * scan through. The code I had used so for used a list with merely 7 slots
 * (as that is what the DNS hash uses) but with 7000 connections that would
 * make an average of 1000 nodes in each list to run through. I upped that to
 * 97 slots (I believe a prime is suitable) and noticed a significant speed
 * increase.  I need to reconsider the hash implementation or use a rather
 * large default value like this. At 9000 connections I was still below 10us
 * per call."
 *
 */
static void sh_init(struct Curl_hash *hash, size_t hashsize)
{
  Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
                 sh_freeentry);
}












/*
 * multi_addmsg()
 *
 * Called when a transfer is completed. Adds the given msg pointer to
 * the list kept in the multi handle.
 */







|










|
|
|
|
|
|









>
>
>
>
>
>
>
>
>
>
>







339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
}

static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
{
  curl_socket_t fd = *((curl_socket_t *) key);
  (void) key_length;

  return (fd % (curl_socket_t)slots_num);
}

/*
 * sh_init() creates a new socket hash and returns the handle for it.
 *
 * Quote from README.multi_socket:
 *
 * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
 * is somewhat of a bottle neck. Its current implementation may be a bit too
 * limiting. It simply has a fixed-size array, and on each entry in the array
 * it has a linked list with entries. The hash only checks which list to scan
 * through. The code I had used so for used a list with merely 7 slots (as
 * that is what the DNS hash uses) but with 7000 connections that would make
 * an average of 1000 nodes in each list to run through. I upped that to 97
 * slots (I believe a prime is suitable) and noticed a significant speed
 * increase. I need to reconsider the hash implementation or use a rather
 * large default value like this. At 9000 connections I was still below 10us
 * per call."
 *
 */
static void sh_init(struct Curl_hash *hash, size_t hashsize)
{
  Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
                 sh_freeentry);
}

/* multi->proto_hash destructor. Should never be called as elements
 * MUST be added with their own destructor */
static void ph_freeentry(void *p)
{
  (void)p;
  /* Will always be FALSE. Cannot use a 0 assert here since compilers
   * are not in agreement if they then want a NORETURN attribute or
   * not. *sigh* */
  DEBUGASSERT(p == NULL);
}

/*
 * multi_addmsg()
 *
 * Called when a transfer is completed. Adds the given msg pointer to
 * the list kept in the multi handle.
 */
392
393
394
395
396
397
398



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433

434
435
436
437
438
439
440

  multi->magic = CURL_MULTI_HANDLE;

  Curl_init_dnscache(&multi->hostcache, dnssize);

  sh_init(&multi->sockhash, hashsize);




  if(Curl_conncache_init(&multi->conn_cache, chashsize))
    goto error;

  Curl_llist_init(&multi->msglist, NULL);
  Curl_llist_init(&multi->pending, NULL);
  Curl_llist_init(&multi->msgsent, NULL);

  multi->multiplexing = TRUE;
  multi->max_concurrent_streams = 100;

#ifdef USE_WINSOCK
  multi->wsa_event = WSACreateEvent();
  if(multi->wsa_event == WSA_INVALID_EVENT)
    goto error;
#else
#ifdef ENABLE_WAKEUP
  if(wakeup_create(multi->wakeup_pair) < 0) {
    multi->wakeup_pair[0] = CURL_SOCKET_BAD;
    multi->wakeup_pair[1] = CURL_SOCKET_BAD;
  }
  else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 ||
          curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) {
    wakeup_close(multi->wakeup_pair[0]);
    wakeup_close(multi->wakeup_pair[1]);
    multi->wakeup_pair[0] = CURL_SOCKET_BAD;
    multi->wakeup_pair[1] = CURL_SOCKET_BAD;
  }
#endif
#endif

  return multi;

error:

  sockhash_destroy(&multi->sockhash);

  Curl_hash_destroy(&multi->hostcache);
  Curl_conncache_destroy(&multi->conn_cache);
  free(multi);
  return NULL;
}

struct Curl_multi *curl_multi_init(void)







>
>
>
|















|
<
<
<
<
<
<
<











>







403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429







430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448

  multi->magic = CURL_MULTI_HANDLE;

  Curl_init_dnscache(&multi->hostcache, dnssize);

  sh_init(&multi->sockhash, hashsize);

  Curl_hash_init(&multi->proto_hash, 23,
                 Curl_hash_str, Curl_str_key_compare, ph_freeentry);

  if(Curl_conncache_init(&multi->conn_cache, multi, chashsize))
    goto error;

  Curl_llist_init(&multi->msglist, NULL);
  Curl_llist_init(&multi->pending, NULL);
  Curl_llist_init(&multi->msgsent, NULL);

  multi->multiplexing = TRUE;
  multi->max_concurrent_streams = 100;

#ifdef USE_WINSOCK
  multi->wsa_event = WSACreateEvent();
  if(multi->wsa_event == WSA_INVALID_EVENT)
    goto error;
#else
#ifdef ENABLE_WAKEUP
  if(wakeup_create(multi->wakeup_pair, TRUE) < 0) {







    multi->wakeup_pair[0] = CURL_SOCKET_BAD;
    multi->wakeup_pair[1] = CURL_SOCKET_BAD;
  }
#endif
#endif

  return multi;

error:

  sockhash_destroy(&multi->sockhash);
  Curl_hash_destroy(&multi->proto_hash);
  Curl_hash_destroy(&multi->hostcache);
  Curl_conncache_destroy(&multi->conn_cache);
  free(multi);
  return NULL;
}

struct Curl_multi *curl_multi_init(void)
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
    data->multi_easy = NULL;
  }

  /* Initialize timeout list for this handle */
  Curl_llist_init(&data->state.timeoutlist, NULL);

  /*
   * No failure allowed in this function beyond this point. And no
   * modification of easy nor multi handle allowed before this except for
   * potential multi's connection cache growing which won't be undone in this
   * function no matter what.
   */
  if(data->set.errorbuffer)
    data->set.errorbuffer[0] = 0;

  data->state.os_errno = 0;

  /* make the Curl_easy refer back to this multi handle - before Curl_expire()







|
|
|
|







548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
    data->multi_easy = NULL;
  }

  /* Initialize timeout list for this handle */
  Curl_llist_init(&data->state.timeoutlist, NULL);

  /*
   * No failure allowed in this function beyond this point. No modification of
   * easy nor multi handle allowed before this except for potential multi's
   * connection cache growing which will not be undone in this function no
   * matter what.
   */
  if(data->set.errorbuffer)
    data->set.errorbuffer[0] = 0;

  data->state.os_errno = 0;

  /* make the Curl_easy refer back to this multi handle - before Curl_expire()
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
  Curl_safefree(data->req.newurl);
  Curl_safefree(data->req.location);

  switch(status) {
  case CURLE_ABORTED_BY_CALLBACK:
  case CURLE_READ_ERROR:
  case CURLE_WRITE_ERROR:
    /* When we're aborted due to a callback return code it basically have to
       be counted as premature as there is trouble ahead if we don't. We have
       many callbacks and protocols work differently, we could potentially do
       this more fine-grained in the future. */
    premature = TRUE;
    FALLTHROUGH();
  default:
    break;
  }







|
|







688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  Curl_safefree(data->req.newurl);
  Curl_safefree(data->req.location);

  switch(status) {
  case CURLE_ABORTED_BY_CALLBACK:
  case CURLE_READ_ERROR:
  case CURLE_WRITE_ERROR:
    /* When we are aborted due to a callback return code it basically have to
       be counted as premature as there is trouble ahead if we do not. We have
       many callbacks and protocols work differently, we could potentially do
       this more fine-grained in the future. */
    premature = TRUE;
    FALLTHROUGH();
  default:
    break;
  }
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
     place in a NTLM/NEGOTIATE authentication handshake

     if conn->bits.close is TRUE, it means that the connection should be
     closed in spite of all our efforts to be nice, due to protocol
     restrictions in our or the server's end

     if premature is TRUE, it means this connection was said to be DONE before
     the entire request operation is complete and thus we can't know in what
     state it is for reusing, so we're forced to close it. In a perfect world
     we can add code that keep track of if we really must close it here or not,
     but currently we have no such detail knowledge.
  */

  data->state.recent_conn_id = conn->connection_id;
  if((data->set.reuse_forbid
#if defined(USE_NTLM)







|
|







753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
     place in a NTLM/NEGOTIATE authentication handshake

     if conn->bits.close is TRUE, it means that the connection should be
     closed in spite of all our efforts to be nice, due to protocol
     restrictions in our or the server's end

     if premature is TRUE, it means this connection was said to be DONE before
     the entire request operation is complete and thus we cannot know in what
     state it is for reusing, so we are forced to close it. In a perfect world
     we can add code that keep track of if we really must close it here or not,
     but currently we have no such detail knowledge.
  */

  data->state.recent_conn_id = conn->connection_id;
  if((data->set.reuse_forbid
#if defined(USE_NTLM)
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
       alive connections when this is removed */
    multi->num_alive--;
  }

  if(data->conn &&
     data->mstate > MSTATE_DO &&
     data->mstate < MSTATE_COMPLETED) {
    /* Set connection owner so that the DONE function closes it.  We can
       safely do this here since connection is killed. */
    streamclose(data->conn, "Removed with partial response");
  }

  if(data->conn) {
    /* multi_done() clears the association between the easy handle and the
       connection.

       Note that this ignores the return code simply because there's
       nothing really useful to do with it anyway! */
    (void)multi_done(data, data->result, premature);
  }

  /* The timer must be shut down before data->multi is set to NULL, else the
     timenode will remain in the splay tree after curl_easy_cleanup is
     called. Do it after multi_done() in case that sets another time! */







|








|







867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
       alive connections when this is removed */
    multi->num_alive--;
  }

  if(data->conn &&
     data->mstate > MSTATE_DO &&
     data->mstate < MSTATE_COMPLETED) {
    /* Set connection owner so that the DONE function closes it. We can
       safely do this here since connection is killed. */
    streamclose(data->conn, "Removed with partial response");
  }

  if(data->conn) {
    /* multi_done() clears the association between the easy handle and the
       connection.

       Note that this ignores the return code simply because there is
       nothing really useful to do with it anyway! */
    (void)multi_done(data, data->result, premature);
  }

  /* The timer must be shut down before data->multi is set to NULL, else the
     timenode will remain in the splay tree after curl_easy_cleanup is
     called. Do it after multi_done() in case that sets another time! */
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928

  Curl_wildcard_dtor(&data->wildcard);

  /* change state without using multistate(), only to make singlesocket() do
     what we want */
  data->mstate = MSTATE_COMPLETED;

  /* This ignores the return code even in case of problems because there's
     nothing more to do about that, here */
  (void)singlesocket(multi, easy); /* to let the application know what sockets
                                      that vanish with this handle */

  /* Remove the association between the connection and the handle */
  Curl_detach_connection(data);

  if(data->set.connect_only && !data->multi_easy) {
    /* This removes a handle that was part the multi interface that used
       CONNECT_ONLY, that connection is now left alive but since this handle
       has bits.close set nothing can use that transfer anymore and it is
       forbidden from reuse. And this easy handle cannot find the connection
       anymore once removed from the multi handle

       Better close the connection here, at once.
    */
    struct connectdata *c;
    curl_socket_t s;
    s = Curl_getconnectinfo(data, &c);







|











|







910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936

  Curl_wildcard_dtor(&data->wildcard);

  /* change state without using multistate(), only to make singlesocket() do
     what we want */
  data->mstate = MSTATE_COMPLETED;

  /* This ignores the return code even in case of problems because there is
     nothing more to do about that, here */
  (void)singlesocket(multi, easy); /* to let the application know what sockets
                                      that vanish with this handle */

  /* Remove the association between the connection and the handle */
  Curl_detach_connection(data);

  if(data->set.connect_only && !data->multi_easy) {
    /* This removes a handle that was part the multi interface that used
       CONNECT_ONLY, that connection is now left alive but since this handle
       has bits.close set nothing can use that transfer anymore and it is
       forbidden from reuse. This easy handle cannot find the connection
       anymore once removed from the multi handle

       Better close the connection here, at once.
    */
    struct connectdata *c;
    curl_socket_t s;
    s = Curl_getconnectinfo(data, &c);
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
#ifdef USE_LIBPSL
  /* Remove the PSL association. */
  if(data->psl == &multi->psl)
    data->psl = NULL;
#endif

  /* as this was using a shared connection cache we clear the pointer to that
     since we're not part of that multi handle anymore */
  data->state.conn_cache = NULL;

  data->multi = NULL; /* clear the association to this multi handle */

  /* make sure there's no pending message in the queue sent from this easy
     handle */
  for(e = multi->msglist.head; e; e = e->next) {
    struct Curl_message *msg = e->ptr;

    if(msg->extmsg.easy_handle == easy) {
      Curl_llist_remove(&multi->msglist, e, NULL);
      /* there can only be one from this specific handle */







|




|







949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
#ifdef USE_LIBPSL
  /* Remove the PSL association. */
  if(data->psl == &multi->psl)
    data->psl = NULL;
#endif

  /* as this was using a shared connection cache we clear the pointer to that
     since we are not part of that multi handle anymore */
  data->state.conn_cache = NULL;

  data->multi = NULL; /* clear the association to this multi handle */

  /* make sure there is no pending message in the queue sent from this easy
     handle */
  for(e = multi->msglist.head; e; e = e->next) {
    struct Curl_message *msg = e->ptr;

    if(msg->extmsg.easy_handle == easy) {
      Curl_llist_remove(&multi->msglist, e, NULL);
      /* there can only be one from this specific handle */
998
999
1000
1001
1002
1003
1004
1005
1006

1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021


1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032




1033
1034

1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045


1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058


1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079

/*
 * Curl_attach_connection() attaches this transfer to this connection.
 *
 * This is the only function that should assign data->conn
 */
void Curl_attach_connection(struct Curl_easy *data,
                             struct connectdata *conn)
{

  DEBUGASSERT(!data->conn);
  DEBUGASSERT(conn);
  data->conn = conn;
  Curl_llist_append(&conn->easyq, data, &data->conn_queue);
  if(conn->handler && conn->handler->attach)
    conn->handler->attach(data, conn);
  Curl_conn_ev_data_attach(conn, data);
}

static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
  struct connectdata *conn = data->conn;
  (void)socks;
  /* Not using `conn->sockfd` as `Curl_xfer_setup()` initializes
   * that *after* the connect. */


  if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) {
    /* Default is to wait to something from the server */
    socks[0] = conn->sock[FIRSTSOCKET];
    return GETSOCK_READSOCK(0);
  }
  return GETSOCK_BLANK;
}

static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
  struct connectdata *conn = data->conn;




  if(conn && conn->handler->proto_getsock)
    return conn->handler->proto_getsock(data, conn, socks);

  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
    /* Default is to wait to something from the server */
    socks[0] = conn->sockfd;
    return GETSOCK_READSOCK(0);
  }
  return GETSOCK_BLANK;
}

static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
  struct connectdata *conn = data->conn;


  if(conn && conn->handler->domore_getsock)
    return conn->handler->domore_getsock(data, conn, socks);
  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
    /* Default is that we want to send something to the server */
    socks[0] = conn->sockfd;
    return GETSOCK_WRITESOCK(0);
  }
  return GETSOCK_BLANK;
}

static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
  struct connectdata *conn = data->conn;


  if(conn && conn->handler->doing_getsock)
    return conn->handler->doing_getsock(data, conn, socks);
  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
    /* Default is that we want to send something to the server */
    socks[0] = conn->sockfd;
    return GETSOCK_WRITESOCK(0);
  }
  return GETSOCK_BLANK;
}

static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
{
  struct connectdata *conn = data->conn;

  if(!conn)
    return GETSOCK_BLANK;
  else if(conn->handler->perform_getsock)
    return conn->handler->perform_getsock(data, conn, sock);
  else {
    /* Default is to obey the data->req.keepon flags for send/recv */
    int bitmap = GETSOCK_BLANK;







|

>












|
|
|
>
>
|

|








>
>
>
>
|

>
|

|








>
>
|

|










>
>
|

|










<







1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091

1092
1093
1094
1095
1096
1097
1098

/*
 * Curl_attach_connection() attaches this transfer to this connection.
 *
 * This is the only function that should assign data->conn
 */
void Curl_attach_connection(struct Curl_easy *data,
                            struct connectdata *conn)
{
  DEBUGASSERT(data);
  DEBUGASSERT(!data->conn);
  DEBUGASSERT(conn);
  data->conn = conn;
  Curl_llist_append(&conn->easyq, data, &data->conn_queue);
  if(conn->handler && conn->handler->attach)
    conn->handler->attach(data, conn);
  Curl_conn_ev_data_attach(conn, data);
}

static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
  struct connectdata *conn = data->conn;
  curl_socket_t sockfd;

  if(!conn)
    return GETSOCK_BLANK;
  sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
  if(sockfd != CURL_SOCKET_BAD) {
    /* Default is to wait to something from the server */
    socks[0] = sockfd;
    return GETSOCK_READSOCK(0);
  }
  return GETSOCK_BLANK;
}

static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
  struct connectdata *conn = data->conn;
  curl_socket_t sockfd;

  if(!conn)
    return GETSOCK_BLANK;
  if(conn->handler->proto_getsock)
    return conn->handler->proto_getsock(data, conn, socks);
  sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
  if(sockfd != CURL_SOCKET_BAD) {
    /* Default is to wait to something from the server */
    socks[0] = sockfd;
    return GETSOCK_READSOCK(0);
  }
  return GETSOCK_BLANK;
}

static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
  struct connectdata *conn = data->conn;
  if(!conn)
    return GETSOCK_BLANK;
  if(conn->handler->domore_getsock)
    return conn->handler->domore_getsock(data, conn, socks);
  else if(conn->sockfd != CURL_SOCKET_BAD) {
    /* Default is that we want to send something to the server */
    socks[0] = conn->sockfd;
    return GETSOCK_WRITESOCK(0);
  }
  return GETSOCK_BLANK;
}

static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
  struct connectdata *conn = data->conn;
  if(!conn)
    return GETSOCK_BLANK;
  if(conn->handler->doing_getsock)
    return conn->handler->doing_getsock(data, conn, socks);
  else if(conn->sockfd != CURL_SOCKET_BAD) {
    /* Default is that we want to send something to the server */
    socks[0] = conn->sockfd;
    return GETSOCK_WRITESOCK(0);
  }
  return GETSOCK_BLANK;
}

static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
{
  struct connectdata *conn = data->conn;

  if(!conn)
    return GETSOCK_BLANK;
  else if(conn->handler->perform_getsock)
    return conn->handler->perform_getsock(data, conn, sock);
  else {
    /* Default is to obey the data->req.keepon flags for send/recv */
    int bitmap = GETSOCK_BLANK;
1102
1103
1104
1105
1106
1107
1108

1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121

1122
1123
1124
1125
1126


1127
1128
1129
1130
1131
1132
1133
}

/* Initializes `poll_set` with the current socket poll actions needed
 * for transfer `data`. */
static void multi_getsock(struct Curl_easy *data,
                          struct easy_pollset *ps)
{

  /* The no connection case can happen when this is called from
     curl_multi_remove_handle() => singlesocket() => multi_getsock().
  */
  Curl_pollset_reset(data, ps);
  if(!data->conn)
    return;

  switch(data->mstate) {
  case MSTATE_INIT:
  case MSTATE_PENDING:
  case MSTATE_SETUP:
  case MSTATE_CONNECT:
    /* nothing to poll for yet */

    break;

  case MSTATE_RESOLVING:
    Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
    /* connection filters are not involved in this phase */


    break;

  case MSTATE_CONNECTING:
  case MSTATE_TUNNELING:
    Curl_pollset_add_socks(data, ps, connecting_getsock);
    Curl_conn_adjust_pollset(data, ps);
    break;







>













>




|
>
>







1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
}

/* Initializes `poll_set` with the current socket poll actions needed
 * for transfer `data`. */
static void multi_getsock(struct Curl_easy *data,
                          struct easy_pollset *ps)
{
  bool expect_sockets = TRUE;
  /* The no connection case can happen when this is called from
     curl_multi_remove_handle() => singlesocket() => multi_getsock().
  */
  Curl_pollset_reset(data, ps);
  if(!data->conn)
    return;

  switch(data->mstate) {
  case MSTATE_INIT:
  case MSTATE_PENDING:
  case MSTATE_SETUP:
  case MSTATE_CONNECT:
    /* nothing to poll for yet */
    expect_sockets = FALSE;
    break;

  case MSTATE_RESOLVING:
    Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
    /* connection filters are not involved in this phase. It's ok if we get no
     * sockets to wait for. Resolving can wake up from other sources. */
    expect_sockets = FALSE;
    break;

  case MSTATE_CONNECTING:
  case MSTATE_TUNNELING:
    Curl_pollset_add_socks(data, ps, connecting_getsock);
    Curl_conn_adjust_pollset(data, ps);
    break;
1153
1154
1155
1156
1157
1158
1159

1160
1161
1162
1163
1164
1165

1166
1167
1168
1169
1170

1171
1172







1173
1174
1175
1176
1177
1178
1179
  case MSTATE_PERFORMING:
    Curl_pollset_add_socks(data, ps, perform_getsock);
    Curl_conn_adjust_pollset(data, ps);
    break;

  case MSTATE_RATELIMITING:
    /* we need to let time pass, ignore socket(s) */

    break;

  case MSTATE_DONE:
  case MSTATE_COMPLETED:
  case MSTATE_MSGSENT:
    /* nothing more to poll for */

    break;

  default:
    failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
    DEBUGASSERT(0);

    break;
  }







}

CURLMcode curl_multi_fdset(struct Curl_multi *multi,
                           fd_set *read_fd_set, fd_set *write_fd_set,
                           fd_set *exc_fd_set, int *max_fd)
{
  /* Scan through all the easy handles to get the file descriptors set.







>






>





>


>
>
>
>
>
>
>







1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
  case MSTATE_PERFORMING:
    Curl_pollset_add_socks(data, ps, perform_getsock);
    Curl_conn_adjust_pollset(data, ps);
    break;

  case MSTATE_RATELIMITING:
    /* we need to let time pass, ignore socket(s) */
    expect_sockets = FALSE;
    break;

  case MSTATE_DONE:
  case MSTATE_COMPLETED:
  case MSTATE_MSGSENT:
    /* nothing more to poll for */
    expect_sockets = FALSE;
    break;

  default:
    failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
    DEBUGASSERT(0);
    expect_sockets = FALSE;
    break;
  }

  if(expect_sockets && !ps->num &&
     !(data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) &&
     Curl_conn_is_ip_connected(data, FIRSTSOCKET)) {
    infof(data, "WARNING: no socket in pollset, transfer may stall!");
    DEBUGASSERT(0);
  }
}

CURLMcode curl_multi_fdset(struct Curl_multi *multi,
                           fd_set *read_fd_set, fd_set *write_fd_set,
                           fd_set *exc_fd_set, int *max_fd)
{
  /* Scan through all the easy handles to get the file descriptors set.
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207

  memset(&ps, 0, sizeof(ps));
  for(data = multi->easyp; data; data = data->next) {
    multi_getsock(data, &ps);

    for(i = 0; i < ps.num; i++) {
      if(!FDSET_SOCK(ps.sockets[i]))
        /* pretend it doesn't exist */
        continue;
      if(ps.actions[i] & CURL_POLL_IN)
        FD_SET(ps.sockets[i], read_fd_set);
      if(ps.actions[i] & CURL_POLL_OUT)
        FD_SET(ps.sockets[i], write_fd_set);
      if((int)ps.sockets[i] > this_max_fd)
        this_max_fd = (int)ps.sockets[i];







|







1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240

  memset(&ps, 0, sizeof(ps));
  for(data = multi->easyp; data; data = data->next) {
    multi_getsock(data, &ps);

    for(i = 0; i < ps.num; i++) {
      if(!FDSET_SOCK(ps.sockets[i]))
        /* pretend it does not exist */
        continue;
      if(ps.actions[i] & CURL_POLL_IN)
        FD_SET(ps.sockets[i], read_fd_set);
      if(ps.actions[i] & CURL_POLL_OUT)
        FD_SET(ps.sockets[i], write_fd_set);
      if((int)ps.sockets[i] > this_max_fd)
        this_max_fd = (int)ps.sockets[i];
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237

1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269

1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393

1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406

1407
1408
1409
1410
1411
1412
1413
1414
1415
1416













1417


1418
1419
1420
1421
1422
1423
1424
1425
1426

1427
1428
1429
1430

1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447

1448
1449
1450
1451
1452
1453
1454

1455
1456
1457
1458
1459
1460
1461
1462
1463








1464
1465
1466
1467
1468
1469
1470
1471
1472

1473
1474
1475
1476
1477
1478
1479


1480
1481
1482
1483
1484
1485
1486

1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530

CURLMcode curl_multi_waitfds(struct Curl_multi *multi,
                             struct curl_waitfd *ufds,
                             unsigned int size,
                             unsigned int *fd_count)
{
  struct Curl_easy *data;
  unsigned int nfds = 0;
  struct easy_pollset ps;
  unsigned int i;
  CURLMcode result = CURLM_OK;
  struct curl_waitfd *ufd;
  unsigned int j;

  if(!ufds)
    return CURLM_BAD_FUNCTION_ARGUMENT;

  if(!GOOD_MULTI_HANDLE(multi))
    return CURLM_BAD_HANDLE;

  if(multi->in_callback)
    return CURLM_RECURSIVE_API_CALL;


  memset(&ps, 0, sizeof(ps));
  for(data = multi->easyp; data; data = data->next) {
    multi_getsock(data, &ps);

    for(i = 0; i < ps.num; i++) {
      if(nfds < size) {
        curl_socket_t fd = ps.sockets[i];
        int fd_idx = -1;

        /* Simple linear search to skip an already added descriptor */
        for(j = 0; j < nfds; j++) {
          if(ufds[j].fd == fd) {
            fd_idx = (int)j;
            break;
          }
        }

        if(fd_idx < 0) {
          ufd = &ufds[nfds++];
          ufd->fd = ps.sockets[i];
          ufd->events = 0;
        }
        else
          ufd = &ufds[fd_idx];

        if(ps.actions[i] & CURL_POLL_IN)
          ufd->events |= CURL_WAIT_POLLIN;
        if(ps.actions[i] & CURL_POLL_OUT)
          ufd->events |= CURL_WAIT_POLLOUT;
      }
      else
        return CURLM_OUT_OF_MEMORY;

    }
  }

  if(fd_count)
    *fd_count = nfds;
  return result;
}

#ifdef USE_WINSOCK
/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets can't
 * be reset this way because an empty datagram would be sent. #9203
 *
 * "On Windows the internal state of FD_WRITE as returned from
 * WSAEnumNetworkEvents is only reset after successful send()."
 */
static void reset_socket_fdwrite(curl_socket_t s)
{
  int t;
  int l = (int)sizeof(t);
  if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM)
    send(s, NULL, 0, 0);
}
#endif

static CURLMcode ufds_increase(struct pollfd **pfds, unsigned int *pfds_len,
                               unsigned int inc, bool *is_malloced)
{
  struct pollfd *new_fds, *old_fds = *pfds;
  unsigned int new_len = *pfds_len + inc;

  new_fds = calloc(new_len, sizeof(struct pollfd));
  if(!new_fds) {
    if(*is_malloced)
      free(old_fds);
    *pfds = NULL;
    *pfds_len = 0;
    return CURLM_OUT_OF_MEMORY;
  }
  memcpy(new_fds, old_fds, (*pfds_len) * sizeof(struct pollfd));
  if(*is_malloced)
    free(old_fds);
  *pfds = new_fds;
  *pfds_len = new_len;
  *is_malloced = TRUE;
  return CURLM_OK;
}

#define NUM_POLLS_ON_STACK 10

static CURLMcode multi_wait(struct Curl_multi *multi,
                            struct curl_waitfd extra_fds[],
                            unsigned int extra_nfds,
                            int timeout_ms,
                            int *ret,
                            bool extrawait, /* when no socket, wait */
                            bool use_wakeup)
{
  struct Curl_easy *data;
  struct easy_pollset ps;
  size_t i;
  long timeout_internal;
  int retcode = 0;
  struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
  struct pollfd *ufds = &a_few_on_stack[0];
  unsigned int ufds_len = NUM_POLLS_ON_STACK;
  unsigned int nfds = 0, curl_nfds = 0; /* how many ufds are in use */
  bool ufds_malloc = FALSE;
#ifdef USE_WINSOCK
  WSANETWORKEVENTS wsa_events;
  DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
#endif
#ifndef ENABLE_WAKEUP
  (void)use_wakeup;
#endif

  if(!GOOD_MULTI_HANDLE(multi))
    return CURLM_BAD_HANDLE;

  if(multi->in_callback)
    return CURLM_RECURSIVE_API_CALL;

  if(timeout_ms < 0)
    return CURLM_BAD_FUNCTION_ARGUMENT;

  /* If the internally desired timeout is actually shorter than requested from
     the outside, then use the shorter time! But only if the internal timer
     is actually larger than -1! */
  (void)multi_timeout(multi, &timeout_internal);
  if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
    timeout_ms = (int)timeout_internal;

  memset(ufds, 0, ufds_len * sizeof(struct pollfd));
  memset(&ps, 0, sizeof(ps));

  /* Add the curl handles to our pollfds first */
  for(data = multi->easyp; data; data = data->next) {
    multi_getsock(data, &ps);

    for(i = 0; i < ps.num; i++) {
      short events = 0;
#ifdef USE_WINSOCK
      long mask = 0;
#endif
      if(ps.actions[i] & CURL_POLL_IN) {
#ifdef USE_WINSOCK
        mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
#endif
        events |= POLLIN;
      }
      if(ps.actions[i] & CURL_POLL_OUT) {
#ifdef USE_WINSOCK
        mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
        reset_socket_fdwrite(ps.sockets[i]);
#endif
        events |= POLLOUT;
      }
      if(events) {
        if(nfds && ps.sockets[i] == ufds[nfds-1].fd) {
          ufds[nfds-1].events |= events;
        }
        else {
          if(nfds >= ufds_len) {
            if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
              return CURLM_OUT_OF_MEMORY;

          }
          DEBUGASSERT(nfds < ufds_len);
          ufds[nfds].fd = ps.sockets[i];
          ufds[nfds].events = events;
          ++nfds;
        }
      }
#ifdef USE_WINSOCK
      if(mask) {
        if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) {
          if(ufds_malloc)
            free(ufds);
          return CURLM_INTERNAL_ERROR;

        }
      }
#endif
    }
  }

  curl_nfds = nfds; /* what curl internally used in ufds */

  /* Add external file descriptions from poll-like struct curl_waitfd */
  for(i = 0; i < extra_nfds; i++) {













#ifdef USE_WINSOCK


    long mask = 0;
    if(extra_fds[i].events & CURL_WAIT_POLLIN)
      mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
    if(extra_fds[i].events & CURL_WAIT_POLLPRI)
      mask |= FD_OOB;
    if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
      mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
      reset_socket_fdwrite(extra_fds[i].fd);
    }

    if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
      if(ufds_malloc)
        free(ufds);
      return CURLM_INTERNAL_ERROR;

    }
#endif
    if(nfds >= ufds_len) {
      if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
        return CURLM_OUT_OF_MEMORY;
    }
    DEBUGASSERT(nfds < ufds_len);
    ufds[nfds].fd = extra_fds[i].fd;
    ufds[nfds].events = 0;
    if(extra_fds[i].events & CURL_WAIT_POLLIN)
      ufds[nfds].events |= POLLIN;
    if(extra_fds[i].events & CURL_WAIT_POLLPRI)
      ufds[nfds].events |= POLLPRI;
    if(extra_fds[i].events & CURL_WAIT_POLLOUT)
      ufds[nfds].events |= POLLOUT;
    ++nfds;
  }


#ifdef ENABLE_WAKEUP
#ifndef USE_WINSOCK
  if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
    if(nfds >= ufds_len) {
      if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
        return CURLM_OUT_OF_MEMORY;

    }
    DEBUGASSERT(nfds < ufds_len);
    ufds[nfds].fd = multi->wakeup_pair[0];
    ufds[nfds].events = POLLIN;
    ++nfds;
  }
#endif
#endif









#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
  if(nfds || use_wakeup) {
#else
  if(nfds) {
#endif
    int pollrc;
#ifdef USE_WINSOCK
    if(nfds)
      pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */

    else
      pollrc = 0;
#else
    pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */
#endif
    if(pollrc < 0)
      return CURLM_UNRECOVERABLE_POLL;



    if(pollrc > 0) {
      retcode = pollrc;
#ifdef USE_WINSOCK
    }
    else { /* now wait... if not ready during the pre-check (pollrc == 0) */
      WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);

    }
    /* With WinSock, we have to run the following section unconditionally
       to call WSAEventSelect(fd, event, 0) on all the sockets */
    {
#endif
      /* copy revents results from the poll to the curl_multi_wait poll
         struct, the bit values of the actual underlying poll() implementation
         may not be the same as the ones in the public libcurl API! */
      for(i = 0; i < extra_nfds; i++) {
        unsigned r = ufds[curl_nfds + i].revents;
        unsigned short mask = 0;
#ifdef USE_WINSOCK
        curl_socket_t s = extra_fds[i].fd;
        wsa_events.lNetworkEvents = 0;
        if(WSAEnumNetworkEvents(s, NULL, &wsa_events) == 0) {
          if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))
            mask |= CURL_WAIT_POLLIN;
          if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE))
            mask |= CURL_WAIT_POLLOUT;
          if(wsa_events.lNetworkEvents & FD_OOB)
            mask |= CURL_WAIT_POLLPRI;
          if(ret && !pollrc && wsa_events.lNetworkEvents)
            retcode++;
        }
        WSAEventSelect(s, multi->wsa_event, 0);
        if(!pollrc) {
          extra_fds[i].revents = mask;
          continue;
        }
#endif
        if(r & POLLIN)
          mask |= CURL_WAIT_POLLIN;
        if(r & POLLOUT)
          mask |= CURL_WAIT_POLLOUT;
        if(r & POLLPRI)
          mask |= CURL_WAIT_POLLPRI;
        extra_fds[i].revents = mask;
      }

#ifdef USE_WINSOCK
      /* Count up all our own sockets that had activity,
         and remove them from the event. */
      if(curl_nfds) {








|

<

<
<










>



|
<
<
<
|
|
<
<
<
<
<
|
|

<
<
<
<
<
<
<
|
<
<
<
<
<
<
|
>
|
|
|

|




|














<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















|
<
|
|

















<
<
<
<
<
<
|
<





|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
>
|
<
<
<
<
|
|
<
<
|
<
<
|
>
|
|
<
<
<
<
|
<


>
>
>
>
>
>
>
>
>
>
>
>
>

>
>

|

|

|

|

>
|
<
<
|
>
|
<
<
<
<

<
<
<
<
<
<
<
<
<
<

>




|
<
|
>

<
<
<
<




>
>
>
>
>
>
>
>

|

|



<
|
>



|

|
|
>
>






|
>









|
















|









|







1248
1249
1250
1251
1252
1253
1254
1255
1256

1257


1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272



1273
1274





1275
1276
1277







1278






1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304























1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321

1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340






1341

1342
1343
1344
1345
1346
1347

























1348
1349
1350




1351
1352


1353


1354
1355
1356
1357




1358

1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387


1388
1389
1390




1391










1392
1393
1394
1395
1396
1397
1398

1399
1400
1401




1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420

1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483

CURLMcode curl_multi_waitfds(struct Curl_multi *multi,
                             struct curl_waitfd *ufds,
                             unsigned int size,
                             unsigned int *fd_count)
{
  struct Curl_easy *data;
  struct curl_waitfds cwfds;
  struct easy_pollset ps;

  CURLMcode result = CURLM_OK;



  if(!ufds)
    return CURLM_BAD_FUNCTION_ARGUMENT;

  if(!GOOD_MULTI_HANDLE(multi))
    return CURLM_BAD_HANDLE;

  if(multi->in_callback)
    return CURLM_RECURSIVE_API_CALL;

  Curl_waitfds_init(&cwfds, ufds, size);
  memset(&ps, 0, sizeof(ps));
  for(data = multi->easyp; data; data = data->next) {
    multi_getsock(data, &ps);
    if(Curl_waitfds_add_ps(&cwfds, &ps)) {



      result = CURLM_OUT_OF_MEMORY;
      goto out;





    }
  }








  if(Curl_conncache_add_waitfds(&multi->conn_cache, &cwfds)) {






    result = CURLM_OUT_OF_MEMORY;
    goto out;
  }

out:
  if(fd_count)
    *fd_count = cwfds.n;
  return result;
}

#ifdef USE_WINSOCK
/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets cannot
 * be reset this way because an empty datagram would be sent. #9203
 *
 * "On Windows the internal state of FD_WRITE as returned from
 * WSAEnumNetworkEvents is only reset after successful send()."
 */
static void reset_socket_fdwrite(curl_socket_t s)
{
  int t;
  int l = (int)sizeof(t);
  if(!getsockopt(s, SOL_SOCKET, SO_TYPE, (char *)&t, &l) && t == SOCK_STREAM)
    send(s, NULL, 0, 0);
}
#endif
























#define NUM_POLLS_ON_STACK 10

static CURLMcode multi_wait(struct Curl_multi *multi,
                            struct curl_waitfd extra_fds[],
                            unsigned int extra_nfds,
                            int timeout_ms,
                            int *ret,
                            bool extrawait, /* when no socket, wait */
                            bool use_wakeup)
{
  struct Curl_easy *data;
  struct easy_pollset ps;
  size_t i;
  long timeout_internal;
  int retcode = 0;
  struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
  struct curl_pollfds cpfds;

  unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */
  CURLMcode result = CURLM_OK;
#ifdef USE_WINSOCK
  WSANETWORKEVENTS wsa_events;
  DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
#endif
#ifndef ENABLE_WAKEUP
  (void)use_wakeup;
#endif

  if(!GOOD_MULTI_HANDLE(multi))
    return CURLM_BAD_HANDLE;

  if(multi->in_callback)
    return CURLM_RECURSIVE_API_CALL;

  if(timeout_ms < 0)
    return CURLM_BAD_FUNCTION_ARGUMENT;







  Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);

  memset(&ps, 0, sizeof(ps));

  /* Add the curl handles to our pollfds first */
  for(data = multi->easyp; data; data = data->next) {
    multi_getsock(data, &ps);
    if(Curl_pollfds_add_ps(&cpfds, &ps)) {

























      result = CURLM_OUT_OF_MEMORY;
      goto out;
    }




  }



  if(Curl_conncache_add_pollfds(&multi->conn_cache, &cpfds)) {


    result = CURLM_OUT_OF_MEMORY;
    goto out;
  }





  curl_nfds = cpfds.n; /* what curl internally uses in cpfds */

  /* Add external file descriptions from poll-like struct curl_waitfd */
  for(i = 0; i < extra_nfds; i++) {
    unsigned short events = 0;
    if(extra_fds[i].events & CURL_WAIT_POLLIN)
      events |= POLLIN;
    if(extra_fds[i].events & CURL_WAIT_POLLPRI)
      events |= POLLPRI;
    if(extra_fds[i].events & CURL_WAIT_POLLOUT)
      events |= POLLOUT;
    if(Curl_pollfds_add_sock(&cpfds, extra_fds[i].fd, events)) {
      result = CURLM_OUT_OF_MEMORY;
      goto out;
    }
  }

#ifdef USE_WINSOCK
  /* Set the WSA events based on the collected pollds */
  for(i = 0; i < cpfds.n; i++) {
    long mask = 0;
    if(cpfds.pfds[i].events & POLLIN)
      mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
    if(cpfds.pfds[i].events & POLLPRI)
      mask |= FD_OOB;
    if(cpfds.pfds[i].events & POLLOUT) {
      mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
      reset_socket_fdwrite(cpfds.pfds[i].fd);
    }
    if(mask) {
      if(WSAEventSelect(cpfds.pfds[i].fd, multi->wsa_event, mask) != 0) {


        result = CURLM_OUT_OF_MEMORY;
        goto out;
      }




    }










  }
#endif

#ifdef ENABLE_WAKEUP
#ifndef USE_WINSOCK
  if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
    if(Curl_pollfds_add_sock(&cpfds, multi->wakeup_pair[0], POLLIN)) {

      result = CURLM_OUT_OF_MEMORY;
      goto out;
    }




  }
#endif
#endif

  /* We check the internal timeout *AFTER* we collected all sockets to
   * poll. Collecting the sockets may install new timers by protocols
   * and connection filters.
   * Use the shorter one of the internal and the caller requested timeout. */
  (void)multi_timeout(multi, &timeout_internal);
  if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
    timeout_ms = (int)timeout_internal;

#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
  if(cpfds.n || use_wakeup) {
#else
  if(cpfds.n) {
#endif
    int pollrc;
#ifdef USE_WINSOCK

    if(cpfds.n)         /* just pre-check with WinSock */
      pollrc = Curl_poll(cpfds.pfds, cpfds.n, 0);
    else
      pollrc = 0;
#else
    pollrc = Curl_poll(cpfds.pfds, cpfds.n, timeout_ms); /* wait... */
#endif
    if(pollrc < 0) {
      result = CURLM_UNRECOVERABLE_POLL;
      goto out;
    }

    if(pollrc > 0) {
      retcode = pollrc;
#ifdef USE_WINSOCK
    }
    else { /* now wait... if not ready during the pre-check (pollrc == 0) */
      WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, (DWORD)timeout_ms,
                               FALSE);
    }
    /* With WinSock, we have to run the following section unconditionally
       to call WSAEventSelect(fd, event, 0) on all the sockets */
    {
#endif
      /* copy revents results from the poll to the curl_multi_wait poll
         struct, the bit values of the actual underlying poll() implementation
         may not be the same as the ones in the public libcurl API! */
      for(i = 0; i < extra_nfds; i++) {
        unsigned r = (unsigned)cpfds.pfds[curl_nfds + i].revents;
        unsigned short mask = 0;
#ifdef USE_WINSOCK
        curl_socket_t s = extra_fds[i].fd;
        wsa_events.lNetworkEvents = 0;
        if(WSAEnumNetworkEvents(s, NULL, &wsa_events) == 0) {
          if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))
            mask |= CURL_WAIT_POLLIN;
          if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE))
            mask |= CURL_WAIT_POLLOUT;
          if(wsa_events.lNetworkEvents & FD_OOB)
            mask |= CURL_WAIT_POLLPRI;
          if(ret && !pollrc && wsa_events.lNetworkEvents)
            retcode++;
        }
        WSAEventSelect(s, multi->wsa_event, 0);
        if(!pollrc) {
          extra_fds[i].revents = (short)mask;
          continue;
        }
#endif
        if(r & POLLIN)
          mask |= CURL_WAIT_POLLIN;
        if(r & POLLOUT)
          mask |= CURL_WAIT_POLLOUT;
        if(r & POLLPRI)
          mask |= CURL_WAIT_POLLPRI;
        extra_fds[i].revents = (short)mask;
      }

#ifdef USE_WINSOCK
      /* Count up all our own sockets that had activity,
         and remove them from the event. */
      if(curl_nfds) {

1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
        }
      }

      WSAResetEvent(multi->wsa_event);
#else
#ifdef ENABLE_WAKEUP
      if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
        if(ufds[curl_nfds + extra_nfds].revents & POLLIN) {
          char buf[64];
          ssize_t nread;
          while(1) {
            /* the reading socket is non-blocking, try to read
               data from it until it receives an error (except EINTR).
               In normal cases it will get EAGAIN or EWOULDBLOCK
               when there is no more data, breaking the loop. */







|







1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
        }
      }

      WSAResetEvent(multi->wsa_event);
#else
#ifdef ENABLE_WAKEUP
      if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
        if(cpfds.pfds[curl_nfds + extra_nfds].revents & POLLIN) {
          char buf[64];
          ssize_t nread;
          while(1) {
            /* the reading socket is non-blocking, try to read
               data from it until it receives an error (except EINTR).
               In normal cases it will get EAGAIN or EWOULDBLOCK
               when there is no more data, breaking the loop. */
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596


1597
1598
1599
1600
1601
1602
1603
1604
        }
      }
#endif
#endif
    }
  }

  if(ufds_malloc)
    free(ufds);
  if(ret)
    *ret = retcode;
#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
  if(extrawait && !nfds && !use_wakeup) {
#else
  if(extrawait && !nfds) {
#endif
    long sleep_ms = 0;

    /* Avoid busy-looping when there's nothing particular to wait for */
    if(!curl_multi_timeout(multi, &sleep_ms) && sleep_ms) {
      if(sleep_ms > timeout_ms)
        sleep_ms = timeout_ms;
      /* when there are no easy handles in the multi, this holds a -1
         timeout */
      else if(sleep_ms < 0)
        sleep_ms = timeout_ms;
      Curl_wait_ms(sleep_ms);
    }
  }



  return CURLM_OK;
}

CURLMcode curl_multi_wait(struct Curl_multi *multi,
                          struct curl_waitfd extra_fds[],
                          unsigned int extra_nfds,
                          int timeout_ms,
                          int *ret)







<
<



|

|



|











>
>
|







1520
1521
1522
1523
1524
1525
1526


1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
        }
      }
#endif
#endif
    }
  }



  if(ret)
    *ret = retcode;
#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
  if(extrawait && !cpfds.n && !use_wakeup) {
#else
  if(extrawait && !cpfds.n) {
#endif
    long sleep_ms = 0;

    /* Avoid busy-looping when there is nothing particular to wait for */
    if(!curl_multi_timeout(multi, &sleep_ms) && sleep_ms) {
      if(sleep_ms > timeout_ms)
        sleep_ms = timeout_ms;
      /* when there are no easy handles in the multi, this holds a -1
         timeout */
      else if(sleep_ms < 0)
        sleep_ms = timeout_ms;
      Curl_wait_ms(sleep_ms);
    }
  }

out:
  Curl_pollfds_cleanup(&cpfds);
  return result;
}

CURLMcode curl_multi_wait(struct Curl_multi *multi,
                          struct curl_waitfd extra_fds[],
                          unsigned int extra_nfds,
                          int timeout_ms,
                          int *ret)
1618
1619
1620
1621
1622
1623
1624









1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638

1639

1640

1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
}

CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
{
  /* this function is usually called from another thread,
     it has to be careful only to access parts of the
     Curl_multi struct that are constant */










  /* GOOD_MULTI_HANDLE can be safely called */
  if(!GOOD_MULTI_HANDLE(multi))
    return CURLM_BAD_HANDLE;

#ifdef ENABLE_WAKEUP
#ifdef USE_WINSOCK
  if(WSASetEvent(multi->wsa_event))
    return CURLM_OK;
#else
  /* the wakeup_pair variable is only written during init and cleanup,
     making it safe to access from another thread after the init part
     and before cleanup */
  if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {

    char buf[1];

    buf[0] = 1;

    while(1) {
      /* swrite() is not thread-safe in general, because concurrent calls
         can have their messages interleaved, but in this case the content
         of the messages does not matter, which makes it ok to call.

         The write socket is set to non-blocking, this way this function
         cannot block, making it safe to call even from the same thread
         that will call curl_multi_wait(). If swrite() returns that it
         would block, it's considered successful because it means that
         previous calls to this function will wake up the poll(). */
      if(wakeup_write(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
        int err = SOCKERRNO;
        int return_success;
#ifdef USE_WINSOCK
        return_success = WSAEWOULDBLOCK == err;
#else







>
>
>
>
>
>
>
>
>














>
|
>

>








|







1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
}

CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
{
  /* this function is usually called from another thread,
     it has to be careful only to access parts of the
     Curl_multi struct that are constant */

#if defined(ENABLE_WAKEUP) && !defined(USE_WINSOCK)
#ifdef USE_EVENTFD
  const void *buf;
  const uint64_t val = 1;
#else
  char buf[1];
#endif
#endif

  /* GOOD_MULTI_HANDLE can be safely called */
  if(!GOOD_MULTI_HANDLE(multi))
    return CURLM_BAD_HANDLE;

#ifdef ENABLE_WAKEUP
#ifdef USE_WINSOCK
  if(WSASetEvent(multi->wsa_event))
    return CURLM_OK;
#else
  /* the wakeup_pair variable is only written during init and cleanup,
     making it safe to access from another thread after the init part
     and before cleanup */
  if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
#ifdef USE_EVENTFD
    buf = &val;
#else
    buf[0] = 1;
#endif
    while(1) {
      /* swrite() is not thread-safe in general, because concurrent calls
         can have their messages interleaved, but in this case the content
         of the messages does not matter, which makes it ok to call.

         The write socket is set to non-blocking, this way this function
         cannot block, making it safe to call even from the same thread
         that will call curl_multi_wait(). If swrite() returns that it
         would block, it is considered successful because it means that
         previous calls to this function will wake up the poll(). */
      if(wakeup_write(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
        int err = SOCKERRNO;
        int return_success;
#ifdef USE_WINSOCK
        return_success = WSAEWOULDBLOCK == err;
#else
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
  if(multi->in_callback)
    return CURLM_RECURSIVE_API_CALL;

  rc = curl_multi_add_handle(multi, data);
  if(!rc) {
    struct SingleRequest *k = &data->req;

    /* pass in NULL for 'conn' here since we don't want to init the
       connection, only this transfer */
    Curl_init_do(data, NULL);

    /* take this handle to the perform state right away */
    multistate(data, MSTATE_PERFORMING);
    Curl_attach_connection(data, conn);
    k->keepon |= KEEP_RECV; /* setup to receive! */







|







1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
  if(multi->in_callback)
    return CURLM_RECURSIVE_API_CALL;

  rc = curl_multi_add_handle(multi, data);
  if(!rc) {
    struct SingleRequest *k = &data->req;

    /* pass in NULL for 'conn' here since we do not want to init the
       connection, only this transfer */
    Curl_init_do(data, NULL);

    /* take this handle to the perform state right away */
    multistate(data, MSTATE_PERFORMING);
    Curl_attach_connection(data, conn);
    k->keepon |= KEEP_RECV; /* setup to receive! */
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752

/*
 * multi_do_more() is called during the DO_MORE multi state. It is basically a
 * second stage DO state which (wrongly) was introduced to support FTP's
 * second connection.
 *
 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
 * DOING state there's more work to do!
 */

static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;








|







1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717

/*
 * multi_do_more() is called during the DO_MORE multi state. It is basically a
 * second stage DO state which (wrongly) was introduced to support FTP's
 * second connection.
 *
 * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
 * DOING state there is more work to do!
 */

static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;

1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905














1906
1907
1908
1909
1910
1911
1912

  *protocol_done = FALSE;

  if(Curl_conn_is_connected(conn, FIRSTSOCKET)
     && conn->bits.protoconnstart) {
    /* We already are connected, get back. This may happen when the connect
       worked fine in the first call, like when we connect to a local server
       or proxy. Note that we don't know if the protocol is actually done.

       Unless this protocol doesn't have any protocol-connect callback, as
       then we know we're done. */
    if(!conn->handler->connecting)
      *protocol_done = TRUE;

    return CURLE_OK;
  }

  if(!conn->bits.protoconnstart) {
    if(conn->handler->connect_it) {
      /* is there a protocol-specific connect() procedure? */

      /* Call the protocol-specific connect function */
      result = conn->handler->connect_it(data, protocol_done);
    }
    else
      *protocol_done = TRUE;

    /* it has started, possibly even completed but that knowledge isn't stored
       in this bit! */
    if(!result)
      conn->bits.protoconnstart = TRUE;
  }

  return result; /* pass back status */
}

static void set_in_callback(struct Curl_multi *multi, bool value)
{
  multi->in_callback = value;
}















static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                 struct curltime *nowp,
                                 struct Curl_easy *data)
{
  struct Curl_message *msg = NULL;
  bool connected;







|

|
|
















|












>
>
>
>
>
>
>
>
>
>
>
>
>
>







1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891

  *protocol_done = FALSE;

  if(Curl_conn_is_connected(conn, FIRSTSOCKET)
     && conn->bits.protoconnstart) {
    /* We already are connected, get back. This may happen when the connect
       worked fine in the first call, like when we connect to a local server
       or proxy. Note that we do not know if the protocol is actually done.

       Unless this protocol does not have any protocol-connect callback, as
       then we know we are done. */
    if(!conn->handler->connecting)
      *protocol_done = TRUE;

    return CURLE_OK;
  }

  if(!conn->bits.protoconnstart) {
    if(conn->handler->connect_it) {
      /* is there a protocol-specific connect() procedure? */

      /* Call the protocol-specific connect function */
      result = conn->handler->connect_it(data, protocol_done);
    }
    else
      *protocol_done = TRUE;

    /* it has started, possibly even completed but that knowledge is not stored
       in this bit! */
    if(!result)
      conn->bits.protoconnstart = TRUE;
  }

  return result; /* pass back status */
}

static void set_in_callback(struct Curl_multi *multi, bool value)
{
  multi->in_callback = value;
}

/*
 * posttransfer() is called immediately after a transfer ends
 */
static void multi_posttransfer(struct Curl_easy *data)
{
#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
  /* restore the signal handler for SIGPIPE before we get back */
  if(!data->set.no_signal)
    signal(SIGPIPE, data->state.prev_signal);
#else
  (void)data; /* unused parameter */
#endif
}

static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                 struct curltime *nowp,
                                 struct Curl_easy *data)
{
  struct Curl_message *msg = NULL;
  bool connected;
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
  if(!GOOD_EASY_HANDLE(data))
    return CURLM_BAD_EASY_HANDLE;

  if(multi->dead) {
    /* a multi-level callback returned error before, meaning every individual
     transfer now has failed */
    result = CURLE_ABORTED_BY_CALLBACK;
    Curl_posttransfer(data);
    multi_done(data, result, FALSE);
    multistate(data, MSTATE_COMPLETED);
  }

  multi_warn_debug(multi, data);

  do {







|







1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
  if(!GOOD_EASY_HANDLE(data))
    return CURLM_BAD_EASY_HANDLE;

  if(multi->dead) {
    /* a multi-level callback returned error before, meaning every individual
     transfer now has failed */
    result = CURLE_ABORTED_BY_CALLBACK;
    multi_posttransfer(data);
    multi_done(data, result, FALSE);
    multistate(data, MSTATE_COMPLETED);
  }

  multi_warn_debug(multi, data);

  do {
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
      }
      else
        process_pending_handles(data->multi);

      if(!result) {
        *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
        if(async)
          /* We're now waiting for an asynchronous name lookup */
          multistate(data, MSTATE_RESOLVING);
        else {
          /* after the connect has been sent off, go WAITCONNECT unless the
             protocol connect is already done and we can go directly to
             WAITDO or DO! */
          rc = CURLM_CALL_MULTI_PERFORM;








|







1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
      }
      else
        process_pending_handles(data->multi);

      if(!result) {
        *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
        if(async)
          /* We are now waiting for an asynchronous name lookup */
          multistate(data, MSTATE_RESOLVING);
        else {
          /* after the connect has been sent off, go WAITCONNECT unless the
             protocol connect is already done and we can go directly to
             WAITDO or DO! */
          rc = CURLM_CALL_MULTI_PERFORM;

2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072

      if(!dns)
        result = Curl_resolv_check(data, &dns);

      /* Update sockets here, because the socket(s) may have been
         closed and the application thus needs to be told, even if it
         is likely that the same socket(s) will again be used further
         down.  If the name has not yet been resolved, it is likely
         that new sockets have been opened in an attempt to contact
         another resolver. */
      rc = singlesocket(multi, data);
      if(rc)
        return rc;

      if(dns) {







|







2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051

      if(!dns)
        result = Curl_resolv_check(data, &dns);

      /* Update sockets here, because the socket(s) may have been
         closed and the application thus needs to be told, even if it
         is likely that the same socket(s) will again be used further
         down. If the name has not yet been resolved, it is likely
         that new sockets have been opened in an attempt to contact
         another resolver. */
      rc = singlesocket(multi, data);
      if(rc)
        return rc;

      if(dns) {
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
      result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
      if(connected && !result) {
        rc = CURLM_CALL_MULTI_PERFORM;
        multistate(data, MSTATE_PROTOCONNECT);
      }
      else if(result) {
        /* failure detected */
        Curl_posttransfer(data);
        multi_done(data, result, TRUE);
        stream_error = TRUE;
        break;
      }
      break;

    case MSTATE_PROTOCONNECT:







|







2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
      result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
      if(connected && !result) {
        rc = CURLM_CALL_MULTI_PERFORM;
        multistate(data, MSTATE_PROTOCONNECT);
      }
      else if(result) {
        /* failure detected */
        multi_posttransfer(data);
        multi_done(data, result, TRUE);
        stream_error = TRUE;
        break;
      }
      break;

    case MSTATE_PROTOCONNECT:
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201

2202
2203
2204
2205
2206
2207
2208
2209
2210
      else if(!result) {
        /* protocol connect has completed, go WAITDO or DO */
        multistate(data, MSTATE_DO);
        rc = CURLM_CALL_MULTI_PERFORM;
      }
      else {
        /* failure detected */
        Curl_posttransfer(data);
        multi_done(data, result, TRUE);
        stream_error = TRUE;
      }
      break;

    case MSTATE_PROTOCONNECTING:
      /* protocol-specific connect phase */
      result = protocol_connecting(data, &protocol_connected);
      if(!result && protocol_connected) {
        /* after the connect has completed, go WAITDO or DO */
        multistate(data, MSTATE_DO);
        rc = CURLM_CALL_MULTI_PERFORM;
      }
      else if(result) {
        /* failure detected */
        Curl_posttransfer(data);
        multi_done(data, result, TRUE);
        stream_error = TRUE;
      }
      break;

    case MSTATE_DO:
      if(data->set.fprereq) {
        int prereq_rc;

        /* call the prerequest callback function */
        Curl_set_in_callback(data, true);
        prereq_rc = data->set.fprereq(data->set.prereq_userp,
                                      data->info.primary.remote_ip,
                                      data->info.primary.local_ip,
                                      data->info.primary.remote_port,
                                      data->info.primary.local_port);
        Curl_set_in_callback(data, false);
        if(prereq_rc != CURL_PREREQFUNC_OK) {
          failf(data, "operation aborted by pre-request callback");
          /* failure in pre-request callback - don't do any other processing */

          result = CURLE_ABORTED_BY_CALLBACK;
          Curl_posttransfer(data);
          multi_done(data, result, FALSE);
          stream_error = TRUE;
          break;
        }
      }

      if(data->set.connect_only == 1) {







|















|



















|
>

|







2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
      else if(!result) {
        /* protocol connect has completed, go WAITDO or DO */
        multistate(data, MSTATE_DO);
        rc = CURLM_CALL_MULTI_PERFORM;
      }
      else {
        /* failure detected */
        multi_posttransfer(data);
        multi_done(data, result, TRUE);
        stream_error = TRUE;
      }
      break;

    case MSTATE_PROTOCONNECTING:
      /* protocol-specific connect phase */
      result = protocol_connecting(data, &protocol_connected);
      if(!result && protocol_connected) {
        /* after the connect has completed, go WAITDO or DO */
        multistate(data, MSTATE_DO);
        rc = CURLM_CALL_MULTI_PERFORM;
      }
      else if(result) {
        /* failure detected */
        multi_posttransfer(data);
        multi_done(data, result, TRUE);
        stream_error = TRUE;
      }
      break;

    case MSTATE_DO:
      if(data->set.fprereq) {
        int prereq_rc;

        /* call the prerequest callback function */
        Curl_set_in_callback(data, true);
        prereq_rc = data->set.fprereq(data->set.prereq_userp,
                                      data->info.primary.remote_ip,
                                      data->info.primary.local_ip,
                                      data->info.primary.remote_port,
                                      data->info.primary.local_port);
        Curl_set_in_callback(data, false);
        if(prereq_rc != CURL_PREREQFUNC_OK) {
          failf(data, "operation aborted by pre-request callback");
          /* failure in pre-request callback - do not do any other
             processing */
          result = CURLE_ABORTED_BY_CALLBACK;
          multi_posttransfer(data);
          multi_done(data, result, FALSE);
          stream_error = TRUE;
          break;
        }
      }

      if(data->set.connect_only == 1) {
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
            /* some steps needed for wildcard matching */
            if(data->state.wildcardmatch) {
              struct WildcardData *wc = data->wildcard;
              if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
                /* skip some states if it is important */
                multi_done(data, CURLE_OK, FALSE);

                /* if there's no connection left, skip the DONE state */
                multistate(data, data->conn ?
                           MSTATE_DONE : MSTATE_COMPLETED);
                rc = CURLM_CALL_MULTI_PERFORM;
                break;
              }
            }
#endif
            /* DO was not completed in one function call, we must continue
               DOING... */
            multistate(data, MSTATE_DOING);
            rc = CURLM_CALL_MULTI_PERFORM;
          }

          /* after DO, go DO_DONE... or DO_MORE */
          else if(data->conn->bits.do_more) {
            /* we're supposed to do more, but we need to sit down, relax
               and wait a little while first */
            multistate(data, MSTATE_DOING_MORE);
            rc = CURLM_CALL_MULTI_PERFORM;
          }
          else {
            /* we're done with the DO, now DID */
            multistate(data, MSTATE_DID);
            rc = CURLM_CALL_MULTI_PERFORM;
          }
        }
        else if((CURLE_SEND_ERROR == result) &&
                data->conn->bits.reuse) {
          /*
           * In this situation, a connection that we were trying to use
           * may have unexpectedly died.  If possible, send the connection
           * back to the CONNECT phase so we can try again.
           */
          char *newurl = NULL;
          followtype follow = FOLLOW_NONE;
          CURLcode drc;

          drc = Curl_retry_request(data, &newurl);
          if(drc) {
            /* a failure here pretty much implies an out of memory */
            result = drc;
            stream_error = TRUE;
          }

          Curl_posttransfer(data);
          drc = multi_done(data, result, FALSE);

          /* When set to retry the connection, we must go back to the CONNECT
           * state */
          if(newurl) {
            if(!drc || (drc == CURLE_SEND_ERROR)) {
              follow = FOLLOW_RETRY;
              drc = Curl_follow(data, newurl, follow);
              if(!drc) {
                multistate(data, MSTATE_SETUP);
                rc = CURLM_CALL_MULTI_PERFORM;
                result = CURLE_OK;
              }
              else {
                /* Follow failed */
                result = drc;
              }
            }
            else {
              /* done didn't return OK or SEND_ERROR */
              result = drc;
            }
          }
          else {
            /* Have error handler disconnect conn if we can't retry */
            stream_error = TRUE;
          }
          free(newurl);
        }
        else {
          /* failure detected */
          Curl_posttransfer(data);
          if(data->conn)
            multi_done(data, result, FALSE);
          stream_error = TRUE;
        }
      }
      break;








|















|





|








|













|



















|




|






|







2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
            /* some steps needed for wildcard matching */
            if(data->state.wildcardmatch) {
              struct WildcardData *wc = data->wildcard;
              if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
                /* skip some states if it is important */
                multi_done(data, CURLE_OK, FALSE);

                /* if there is no connection left, skip the DONE state */
                multistate(data, data->conn ?
                           MSTATE_DONE : MSTATE_COMPLETED);
                rc = CURLM_CALL_MULTI_PERFORM;
                break;
              }
            }
#endif
            /* DO was not completed in one function call, we must continue
               DOING... */
            multistate(data, MSTATE_DOING);
            rc = CURLM_CALL_MULTI_PERFORM;
          }

          /* after DO, go DO_DONE... or DO_MORE */
          else if(data->conn->bits.do_more) {
            /* we are supposed to do more, but we need to sit down, relax
               and wait a little while first */
            multistate(data, MSTATE_DOING_MORE);
            rc = CURLM_CALL_MULTI_PERFORM;
          }
          else {
            /* we are done with the DO, now DID */
            multistate(data, MSTATE_DID);
            rc = CURLM_CALL_MULTI_PERFORM;
          }
        }
        else if((CURLE_SEND_ERROR == result) &&
                data->conn->bits.reuse) {
          /*
           * In this situation, a connection that we were trying to use
           * may have unexpectedly died. If possible, send the connection
           * back to the CONNECT phase so we can try again.
           */
          char *newurl = NULL;
          followtype follow = FOLLOW_NONE;
          CURLcode drc;

          drc = Curl_retry_request(data, &newurl);
          if(drc) {
            /* a failure here pretty much implies an out of memory */
            result = drc;
            stream_error = TRUE;
          }

          multi_posttransfer(data);
          drc = multi_done(data, result, FALSE);

          /* When set to retry the connection, we must go back to the CONNECT
           * state */
          if(newurl) {
            if(!drc || (drc == CURLE_SEND_ERROR)) {
              follow = FOLLOW_RETRY;
              drc = Curl_follow(data, newurl, follow);
              if(!drc) {
                multistate(data, MSTATE_SETUP);
                rc = CURLM_CALL_MULTI_PERFORM;
                result = CURLE_OK;
              }
              else {
                /* Follow failed */
                result = drc;
              }
            }
            else {
              /* done did not return OK or SEND_ERROR */
              result = drc;
            }
          }
          else {
            /* Have error handler disconnect conn if we cannot retry */
            stream_error = TRUE;
          }
          free(newurl);
        }
        else {
          /* failure detected */
          multi_posttransfer(data);
          if(data->conn)
            multi_done(data, result, FALSE);
          stream_error = TRUE;
        }
      }
      break;

2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
          multistate(data, data->conn->bits.do_more?
                     MSTATE_DOING_MORE : MSTATE_DID);
          rc = CURLM_CALL_MULTI_PERFORM;
        } /* dophase_done */
      }
      else {
        /* failure detected */
        Curl_posttransfer(data);
        multi_done(data, result, FALSE);
        stream_error = TRUE;
      }
      break;

    case MSTATE_DOING_MORE:
      /*







|







2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
          multistate(data, data->conn->bits.do_more?
                     MSTATE_DOING_MORE : MSTATE_DID);
          rc = CURLM_CALL_MULTI_PERFORM;
        } /* dophase_done */
      }
      else {
        /* failure detected */
        multi_posttransfer(data);
        multi_done(data, result, FALSE);
        stream_error = TRUE;
      }
      break;

    case MSTATE_DOING_MORE:
      /*
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
          rc = CURLM_CALL_MULTI_PERFORM;
        }
        /* else
           stay in DO_MORE */
      }
      else {
        /* failure detected */
        Curl_posttransfer(data);
        multi_done(data, result, FALSE);
        stream_error = TRUE;
      }
      break;

    case MSTATE_DID:
      DEBUGASSERT(data->conn);
      if(data->conn->bits.multiplex)
        /* Check if we can move pending requests to send pipe */
        process_pending_handles(multi); /*  multiplexed */

      /* Only perform the transfer if there's a good socket to work with.
         Having both BAD is a signal to skip immediately to DONE */
      if((data->conn->sockfd != CURL_SOCKET_BAD) ||
         (data->conn->writesockfd != CURL_SOCKET_BAD))
        multistate(data, MSTATE_PERFORMING);
      else {
#ifndef CURL_DISABLE_FTP
        if(data->state.wildcardmatch &&







|











|







2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
          rc = CURLM_CALL_MULTI_PERFORM;
        }
        /* else
           stay in DO_MORE */
      }
      else {
        /* failure detected */
        multi_posttransfer(data);
        multi_done(data, result, FALSE);
        stream_error = TRUE;
      }
      break;

    case MSTATE_DID:
      DEBUGASSERT(data->conn);
      if(data->conn->bits.multiplex)
        /* Check if we can move pending requests to send pipe */
        process_pending_handles(multi); /*  multiplexed */

      /* Only perform the transfer if there is a good socket to work with.
         Having both BAD is a signal to skip immediately to DONE */
      if((data->conn->sockfd != CURL_SOCKET_BAD) ||
         (data->conn->writesockfd != CURL_SOCKET_BAD))
        multistate(data, MSTATE_PERFORMING);
      else {
#ifndef CURL_DISABLE_FTP
        if(data->state.wildcardmatch &&
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
        result = Curl_speedcheck(data, *nowp);

      if(result) {
        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
           result != CURLE_HTTP2_STREAM)
          streamclose(data->conn, "Transfer returned error");

        Curl_posttransfer(data);
        multi_done(data, result, TRUE);
      }
      else {
        send_timeout_ms = 0;
        if(data->set.max_send_speed)
          send_timeout_ms =
            Curl_pgrsLimitWaitTime(data->progress.uploaded,







|







2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
        result = Curl_speedcheck(data, *nowp);

      if(result) {
        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
           result != CURLE_HTTP2_STREAM)
          streamclose(data->conn, "Transfer returned error");

        multi_posttransfer(data);
        multi_done(data, result, TRUE);
      }
      else {
        send_timeout_ms = 0;
        if(data->set.max_send_speed)
          send_timeout_ms =
            Curl_pgrsLimitWaitTime(data->progress.uploaded,
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
        else
          result = ret;
      }

      if(result) {
        /*
         * The transfer phase returned error, we mark the connection to get
         * closed to prevent being reused. This is because we can't possibly
         * know if the connection is in a good shape or not now.  Unless it is
         * a protocol which uses two "channels" like FTP, as then the error
         * happened in the data connection.
         */

        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
           result != CURLE_HTTP2_STREAM)
          streamclose(data->conn, "Transfer returned error");

        Curl_posttransfer(data);
        multi_done(data, result, TRUE);
      }
      else if(data->req.done && !Curl_cwriter_is_paused(data)) {

        /* call this even if the readwrite function returned error */
        Curl_posttransfer(data);

        /* When we follow redirects or is set to retry the connection, we must
           to go back to the CONNECT state */
        if(data->req.newurl || retry) {
          followtype follow = FOLLOW_NONE;
          if(!retry) {
            /* if the URL is a follow-location and not just a retried request







|
|








|





|







2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
        else
          result = ret;
      }

      if(result) {
        /*
         * The transfer phase returned error, we mark the connection to get
         * closed to prevent being reused. This is because we cannot possibly
         * know if the connection is in a good shape or not now. Unless it is
         * a protocol which uses two "channels" like FTP, as then the error
         * happened in the data connection.
         */

        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
           result != CURLE_HTTP2_STREAM)
          streamclose(data->conn, "Transfer returned error");

        multi_posttransfer(data);
        multi_done(data, result, TRUE);
      }
      else if(data->req.done && !Curl_cwriter_is_paused(data)) {

        /* call this even if the readwrite function returned error */
        multi_posttransfer(data);

        /* When we follow redirects or is set to retry the connection, we must
           to go back to the CONNECT state */
        if(data->req.newurl || retry) {
          followtype follow = FOLLOW_NONE;
          if(!retry) {
            /* if the URL is a follow-location and not just a retried request
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
            multistate(data, MSTATE_SETUP);
            rc = CURLM_CALL_MULTI_PERFORM;
          }
        }
        else {
          /* after the transfer is done, go DONE */

          /* but first check to see if we got a location info even though we're
             not following redirects */
          if(data->req.location) {
            free(newurl);
            newurl = data->req.location;
            data->req.location = NULL;
            result = Curl_follow(data, newurl, FOLLOW_FAKE);
            if(result) {
              stream_error = TRUE;
              result = multi_done(data, result, TRUE);
            }
          }

          if(!result) {
            multistate(data, MSTATE_DONE);
            rc = CURLM_CALL_MULTI_PERFORM;
          }
        }
      }
      else if(data->state.select_bits) {
        /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer
           won't get stuck on this transfer at the expense of other concurrent
           transfers */
        Curl_expire(data, 0, EXPIRE_RUN_NOW);
      }
      free(newurl);
      break;
    }

    case MSTATE_DONE:







|
|

















|

|
|







2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
            multistate(data, MSTATE_SETUP);
            rc = CURLM_CALL_MULTI_PERFORM;
          }
        }
        else {
          /* after the transfer is done, go DONE */

          /* but first check to see if we got a location info even though we
             are not following redirects */
          if(data->req.location) {
            free(newurl);
            newurl = data->req.location;
            data->req.location = NULL;
            result = Curl_follow(data, newurl, FOLLOW_FAKE);
            if(result) {
              stream_error = TRUE;
              result = multi_done(data, result, TRUE);
            }
          }

          if(!result) {
            multistate(data, MSTATE_DONE);
            rc = CURLM_CALL_MULTI_PERFORM;
          }
        }
      }
      else if(data->state.select_bits && !Curl_xfer_is_blocked(data)) {
        /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer
           will not get stuck on this transfer at the expense of other
           concurrent transfers */
        Curl_expire(data, 0, EXPIRE_RUN_NOW);
      }
      free(newurl);
      break;
    }

    case MSTATE_DONE:
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
          /* if a wildcard is set and we are not ending -> lets start again
             with MSTATE_INIT */
          multistate(data, MSTATE_INIT);
          break;
        }
      }
#endif
      /* after we have DONE what we're supposed to do, go COMPLETED, and
         it doesn't matter what the multi_done() returned! */
      multistate(data, MSTATE_COMPLETED);
      break;

    case MSTATE_COMPLETED:
      break;

    case MSTATE_PENDING:







|
|







2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
          /* if a wildcard is set and we are not ending -> lets start again
             with MSTATE_INIT */
          multistate(data, MSTATE_INIT);
          break;
        }
      }
#endif
      /* after we have DONE what we are supposed to do, go COMPLETED, and
         it does not matter what the multi_done() returned! */
      multistate(data, MSTATE_COMPLETED);
      break;

    case MSTATE_COMPLETED:
      break;

    case MSTATE_PENDING:
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679

2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
    }

statemachine_end:

    if(data->mstate < MSTATE_COMPLETED) {
      if(result) {
        /*
         * If an error was returned, and we aren't in completed state now,
         * then we go to completed and consider this transfer aborted.
         */

        /* NOTE: no attempt to disconnect connections must be made
           in the case blocks above - cleanup happens only here */

        /* Check if we can move pending requests to send pipe */
        process_pending_handles(multi); /* connection */

        if(data->conn) {
          if(stream_error) {
            /* Don't attempt to send data over a connection that timed out */
            bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
            struct connectdata *conn = data->conn;

            /* This is where we make sure that the conn pointer is reset.
               We don't have to do this in every case block above where a
               failure is detected */
            Curl_detach_connection(data);

            /* remove connection from cache */
            Curl_conncache_remove_conn(data, conn, TRUE);

            /* disconnect properly */
            Curl_disconnect(data, conn, dead_connection);
          }
        }
        else if(data->mstate == MSTATE_CONNECT) {
          /* Curl_connect() failed */
          (void)Curl_posttransfer(data);

        }

        multistate(data, MSTATE_COMPLETED);
        rc = CURLM_CALL_MULTI_PERFORM;
      }
      /* if there's still a connection to use, call the progress function */
      else if(data->conn && Curl_pgrsUpdate(data)) {
        /* aborted due to progress callback return code must close the
           connection */
        result = CURLE_ABORTED_BY_CALLBACK;
        streamclose(data->conn, "Aborted by callback");

        /* if not yet in DONE state, go there, otherwise COMPLETED */







|











|




|












|
>





|







2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
    }

statemachine_end:

    if(data->mstate < MSTATE_COMPLETED) {
      if(result) {
        /*
         * If an error was returned, and we are not in completed state now,
         * then we go to completed and consider this transfer aborted.
         */

        /* NOTE: no attempt to disconnect connections must be made
           in the case blocks above - cleanup happens only here */

        /* Check if we can move pending requests to send pipe */
        process_pending_handles(multi); /* connection */

        if(data->conn) {
          if(stream_error) {
            /* Do not attempt to send data over a connection that timed out */
            bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
            struct connectdata *conn = data->conn;

            /* This is where we make sure that the conn pointer is reset.
               We do not have to do this in every case block above where a
               failure is detected */
            Curl_detach_connection(data);

            /* remove connection from cache */
            Curl_conncache_remove_conn(data, conn, TRUE);

            /* disconnect properly */
            Curl_disconnect(data, conn, dead_connection);
          }
        }
        else if(data->mstate == MSTATE_CONNECT) {
          /* Curl_connect() failed */
          multi_posttransfer(data);
          Curl_pgrsUpdate_nometer(data);
        }

        multistate(data, MSTATE_COMPLETED);
        rc = CURLM_CALL_MULTI_PERFORM;
      }
      /* if there is still a connection to use, call the progress function */
      else if(data->conn && Curl_pgrsUpdate(data)) {
        /* aborted due to progress callback return code must close the
           connection */
        result = CURLE_ABORTED_BY_CALLBACK;
        streamclose(data->conn, "Aborted by callback");

        /* if not yet in DONE state, go there, otherwise COMPLETED */
2748
2749
2750
2751
2752
2753
2754

2755
2756
2757
2758
2759
2760
2761
2762

2763
2764
2765
2766


2767
2768
2769
2770
2771
2772
2773
    sigpipe_ignore(data, &pipe_st);
    /* Do the loop and only alter the signal ignore state if the next handle
       has a different NO_SIGNAL state than the previous */
    do {
      /* the current node might be unlinked in multi_runsingle(), get the next
         pointer now */
      struct Curl_easy *datanext = data->next;

      if(data->set.no_signal != nosig) {
        sigpipe_restore(&pipe_st);
        sigpipe_ignore(data, &pipe_st);
        nosig = data->set.no_signal;
      }
      result = multi_runsingle(multi, &now, data);
      if(result)
        returncode = result;

      data = datanext; /* operate on next handle */
    } while(data);
    sigpipe_restore(&pipe_st);
  }



  /*
   * Simply remove all expired timers from the splay since handles are dealt
   * with unconditionally by this function and curl_multi_timeout() requires
   * that already passed/handled expire times are removed from the splay.
   *
   * It is important that the 'now' value is set at the entry of this function







>








>




>
>







2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
    sigpipe_ignore(data, &pipe_st);
    /* Do the loop and only alter the signal ignore state if the next handle
       has a different NO_SIGNAL state than the previous */
    do {
      /* the current node might be unlinked in multi_runsingle(), get the next
         pointer now */
      struct Curl_easy *datanext = data->next;

      if(data->set.no_signal != nosig) {
        sigpipe_restore(&pipe_st);
        sigpipe_ignore(data, &pipe_st);
        nosig = data->set.no_signal;
      }
      result = multi_runsingle(multi, &now, data);
      if(result)
        returncode = result;

      data = datanext; /* operate on next handle */
    } while(data);
    sigpipe_restore(&pipe_st);
  }

  Curl_conncache_multi_perform(multi);

  /*
   * Simply remove all expired timers from the splay since handles are dealt
   * with unconditionally by this function and curl_multi_timeout() requires
   * that already passed/handled expire times are removed from the splay.
   *
   * It is important that the 'now' value is set at the entry of this function
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
          move_pending_to_connect(multi, data);
        }
      }
      (void)add_next_timeout(now, multi, t->payload);
    }
  } while(t);

  *running_handles = multi->num_alive;

  if(CURLM_OK >= returncode)
    returncode = Curl_update_timer(multi);

  return returncode;
}








|







2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
          move_pending_to_connect(multi, data);
        }
      }
      (void)add_next_timeout(now, multi, t->payload);
    }
  } while(t);

  *running_handles = (int)multi->num_alive;

  if(CURLM_OK >= returncode)
    returncode = Curl_update_timer(multi);

  return returncode;
}

2825
2826
2827
2828
2829
2830
2831



2832
2833
2834
2835
2836
2837
2838
    multi->magic = 0; /* not good anymore */

    unlink_all_msgsent_handles(multi);
    process_pending_handles(multi);
    /* First remove all remaining easy handles */
    data = multi->easyp;
    while(data) {



      nextdata = data->next;
      if(!data->state.done && data->conn)
        /* if DONE was never called for this handle */
        (void)multi_done(data, CURLE_OK, TRUE);
      if(data->dns.hostcachetype == HCACHE_MULTI) {
        /* clear out the usage of the shared DNS cache */
        Curl_hostcache_clean(data, data->dns.hostcache);







>
>
>







2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
    multi->magic = 0; /* not good anymore */

    unlink_all_msgsent_handles(multi);
    process_pending_handles(multi);
    /* First remove all remaining easy handles */
    data = multi->easyp;
    while(data) {
      if(!GOOD_EASY_HANDLE(data))
        return CURLM_BAD_HANDLE;

      nextdata = data->next;
      if(!data->state.done && data->conn)
        /* if DONE was never called for this handle */
        (void)multi_done(data, CURLE_OK, TRUE);
      if(data->dns.hostcachetype == HCACHE_MULTI) {
        /* clear out the usage of the shared DNS cache */
        Curl_hostcache_clean(data, data->dns.hostcache);
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858

2859
2860
2861
2862
2863
2864
2865
2866
2867

2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
        data->psl = NULL;
#endif

      data = nextdata;
    }

    /* Close all the connections in the connection cache */
    Curl_conncache_close_all_connections(&multi->conn_cache);

    sockhash_destroy(&multi->sockhash);

    Curl_conncache_destroy(&multi->conn_cache);
    Curl_hash_destroy(&multi->hostcache);
    Curl_psl_destroy(&multi->psl);

#ifdef USE_WINSOCK
    WSACloseEvent(multi->wsa_event);
#else
#ifdef ENABLE_WAKEUP
    wakeup_close(multi->wakeup_pair[0]);

    wakeup_close(multi->wakeup_pair[1]);
#endif
#endif

#ifdef USE_SSL
    Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
#endif

    multi_xfer_bufs_free(multi);
    free(multi);

    return CURLM_OK;
  }







|


>









>



<
<
<







2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860



2861
2862
2863
2864
2865
2866
2867
        data->psl = NULL;
#endif

      data = nextdata;
    }

    /* Close all the connections in the connection cache */
    Curl_conncache_multi_close_all(multi);

    sockhash_destroy(&multi->sockhash);
    Curl_hash_destroy(&multi->proto_hash);
    Curl_conncache_destroy(&multi->conn_cache);
    Curl_hash_destroy(&multi->hostcache);
    Curl_psl_destroy(&multi->psl);

#ifdef USE_WINSOCK
    WSACloseEvent(multi->wsa_event);
#else
#ifdef ENABLE_WAKEUP
    wakeup_close(multi->wakeup_pair[0]);
#ifndef USE_EVENTFD
    wakeup_close(multi->wakeup_pair[1]);
#endif
#endif



#endif

    multi_xfer_bufs_free(multi);
    free(multi);

    return CURLM_OK;
  }
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
















2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981


2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
 * and if we have a different state in any of those sockets from last time we
 * call the callback accordingly.
 */
static CURLMcode singlesocket(struct Curl_multi *multi,
                              struct Curl_easy *data)
{
  struct easy_pollset cur_poll;
  unsigned int i;
  struct Curl_sh_entry *entry;
  curl_socket_t s;
  int rc;

  /* Fill in the 'current' struct with the state as it is now: what sockets to
     supervise and for what actions */
  multi_getsock(data, &cur_poll);

















  /* We have 0 .. N sockets already and we get to know about the 0 .. M
     sockets we should have from now on. Detect the differences, remove no
     longer supervised ones and add new ones */

  /* walk over the sockets we got right now */
  for(i = 0; i < cur_poll.num; i++) {
    unsigned char cur_action = cur_poll.actions[i];
    unsigned char last_action = 0;
    int comboaction;

    s = cur_poll.sockets[i];

    /* get it from the hash */
    entry = sh_getentry(&multi->sockhash, s);
    if(entry) {
      /* check if new for this transfer */
      unsigned int j;
      for(j = 0; j< data->last_poll.num; j++) {
        if(s == data->last_poll.sockets[j]) {
          last_action = data->last_poll.actions[j];
          break;
        }
      }
    }
    else {
      /* this is a socket we didn't have before, add it to the hash! */
      entry = sh_addentry(&multi->sockhash, s);
      if(!entry)
        /* fatal */
        return CURLM_OUT_OF_MEMORY;
    }
    if(last_action && (last_action != cur_action)) {
      /* Socket was used already, but different action now */
      if(last_action & CURL_POLL_IN)
        entry->readers--;
      if(last_action & CURL_POLL_OUT)
        entry->writers--;
      if(cur_action & CURL_POLL_IN)
        entry->readers++;
      if(cur_action & CURL_POLL_OUT)
        entry->writers++;
    }
    else if(!last_action) {


      /* a new transfer using this socket */
      entry->users++;
      if(cur_action & CURL_POLL_IN)
        entry->readers++;
      if(cur_action & CURL_POLL_OUT)
        entry->writers++;

      /* add 'data' to the transfer hash on this socket! */
      if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
                        sizeof(struct Curl_easy *), data)) {
        Curl_hash_destroy(&entry->transfers);
        return CURLM_OUT_OF_MEMORY;
      }
    }







|
<
<
<




>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






|
|



|






|
|
|





|
















|
>
>






<







2910
2911
2912
2913
2914
2915
2916
2917



2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989

2990
2991
2992
2993
2994
2995
2996
 * and if we have a different state in any of those sockets from last time we
 * call the callback accordingly.
 */
static CURLMcode singlesocket(struct Curl_multi *multi,
                              struct Curl_easy *data)
{
  struct easy_pollset cur_poll;
  CURLMcode mresult;




  /* Fill in the 'current' struct with the state as it is now: what sockets to
     supervise and for what actions */
  multi_getsock(data, &cur_poll);
  mresult = Curl_multi_pollset_ev(multi, data, &cur_poll, &data->last_poll);

  if(!mresult) /* Remember for next time */
    memcpy(&data->last_poll, &cur_poll, sizeof(cur_poll));
  return mresult;
}

CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
                                struct Curl_easy *data,
                                struct easy_pollset *ps,
                                struct easy_pollset *last_ps)
{
  unsigned int i;
  struct Curl_sh_entry *entry;
  curl_socket_t s;
  int rc;

  /* We have 0 .. N sockets already and we get to know about the 0 .. M
     sockets we should have from now on. Detect the differences, remove no
     longer supervised ones and add new ones */

  /* walk over the sockets we got right now */
  for(i = 0; i < ps->num; i++) {
    unsigned char cur_action = ps->actions[i];
    unsigned char last_action = 0;
    int comboaction;

    s = ps->sockets[i];

    /* get it from the hash */
    entry = sh_getentry(&multi->sockhash, s);
    if(entry) {
      /* check if new for this transfer */
      unsigned int j;
      for(j = 0; j< last_ps->num; j++) {
        if(s == last_ps->sockets[j]) {
          last_action = last_ps->actions[j];
          break;
        }
      }
    }
    else {
      /* this is a socket we did not have before, add it to the hash! */
      entry = sh_addentry(&multi->sockhash, s);
      if(!entry)
        /* fatal */
        return CURLM_OUT_OF_MEMORY;
    }
    if(last_action && (last_action != cur_action)) {
      /* Socket was used already, but different action now */
      if(last_action & CURL_POLL_IN)
        entry->readers--;
      if(last_action & CURL_POLL_OUT)
        entry->writers--;
      if(cur_action & CURL_POLL_IN)
        entry->readers++;
      if(cur_action & CURL_POLL_OUT)
        entry->writers++;
    }
    else if(!last_action &&
            !Curl_hash_pick(&entry->transfers, (char *)&data, /* hash key */
                            sizeof(struct Curl_easy *))) {
      /* a new transfer using this socket */
      entry->users++;
      if(cur_action & CURL_POLL_IN)
        entry->readers++;
      if(cur_action & CURL_POLL_OUT)
        entry->writers++;

      /* add 'data' to the transfer hash on this socket! */
      if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
                        sizeof(struct Curl_easy *), data)) {
        Curl_hash_destroy(&entry->transfers);
        return CURLM_OUT_OF_MEMORY;
      }
    }
3010
3011
3012
3013
3014
3015
3016
3017

3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
      set_in_callback(multi, FALSE);
      if(rc == -1) {
        multi->dead = TRUE;
        return CURLM_ABORTED_BY_CALLBACK;
      }
    }

    entry->action = comboaction; /* store the current action state */

  }

  /* Check for last_poll.sockets that no longer appear in cur_poll.sockets.
   * Need to remove the easy handle from the multi->sockhash->transfers and
   * remove multi->sockhash entry when this was the last transfer */
  for(i = 0; i< data->last_poll.num; i++) {
    unsigned int j;
    bool stillused = FALSE;
    s = data->last_poll.sockets[i];
    for(j = 0; j < cur_poll.num; j++) {
      if(s == cur_poll.sockets[j]) {
        /* this is still supervised */
        stillused = TRUE;
        break;
      }
    }
    if(stillused)
      continue;

    entry = sh_getentry(&multi->sockhash, s);
    /* if this is NULL here, the socket has been closed and notified so
       already by Curl_multi_closed() */
    if(entry) {
      unsigned char oldactions = data->last_poll.actions[i];
      /* this socket has been removed. Decrease user count */
      entry->users--;
      if(oldactions & CURL_POLL_OUT)
        entry->writers--;
      if(oldactions & CURL_POLL_IN)
        entry->readers--;
      if(!entry->users) {







|
>


|


|


|
|
|












|







3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
      set_in_callback(multi, FALSE);
      if(rc == -1) {
        multi->dead = TRUE;
        return CURLM_ABORTED_BY_CALLBACK;
      }
    }

    /* store the current action state */
    entry->action = (unsigned int)comboaction;
  }

  /* Check for last_poll.sockets that no longer appear in ps->sockets.
   * Need to remove the easy handle from the multi->sockhash->transfers and
   * remove multi->sockhash entry when this was the last transfer */
  for(i = 0; i < last_ps->num; i++) {
    unsigned int j;
    bool stillused = FALSE;
    s = last_ps->sockets[i];
    for(j = 0; j < ps->num; j++) {
      if(s == ps->sockets[j]) {
        /* this is still supervised */
        stillused = TRUE;
        break;
      }
    }
    if(stillused)
      continue;

    entry = sh_getentry(&multi->sockhash, s);
    /* if this is NULL here, the socket has been closed and notified so
       already by Curl_multi_closed() */
    if(entry) {
      unsigned char oldactions = last_ps->actions[i];
      /* this socket has been removed. Decrease user count */
      entry->users--;
      if(oldactions & CURL_POLL_OUT)
        entry->writers--;
      if(oldactions & CURL_POLL_IN)
        entry->readers--;
      if(!entry->users) {
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
                            sizeof(struct Curl_easy *))) {
          DEBUGASSERT(NULL);
        }
      }
    }
  } /* for loop over num */

  /* Remember for next time */
  memcpy(&data->last_poll, &cur_poll, sizeof(data->last_poll));
  return CURLM_OK;
}

CURLcode Curl_updatesocket(struct Curl_easy *data)
{
  if(singlesocket(data->multi, data))
    return CURLE_ABORTED_BY_CALLBACK;
  return CURLE_OK;
}


/*
 * Curl_multi_closed()
 *
 * Used by the connect code to tell the multi_socket code that one of the
 * sockets we were using is about to be closed.  This function will then
 * remove it from the sockethash for this handle to make the multi_socket API
 * behave properly, especially for the case when libcurl will create another
 * socket again and it gets the same file descriptor number.
 */

void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
{
  if(data) {
    /* if there's still an easy handle associated with this connection */
    struct Curl_multi *multi = data->multi;
    if(multi) {
      /* this is set if this connection is part of a handle that is added to
         a multi handle, and only then this is necessary */
      struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);

      if(entry) {







<
<















|








|







3066
3067
3068
3069
3070
3071
3072


3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
                            sizeof(struct Curl_easy *))) {
          DEBUGASSERT(NULL);
        }
      }
    }
  } /* for loop over num */



  return CURLM_OK;
}

CURLcode Curl_updatesocket(struct Curl_easy *data)
{
  if(singlesocket(data->multi, data))
    return CURLE_ABORTED_BY_CALLBACK;
  return CURLE_OK;
}


/*
 * Curl_multi_closed()
 *
 * Used by the connect code to tell the multi_socket code that one of the
 * sockets we were using is about to be closed. This function will then
 * remove it from the sockethash for this handle to make the multi_socket API
 * behave properly, especially for the case when libcurl will create another
 * socket again and it gets the same file descriptor number.
 */

void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
{
  if(data) {
    /* if there is still an easy handle associated with this connection */
    struct Curl_multi *multi = data->multi;
    if(multi) {
      /* this is set if this connection is part of a handle that is added to
         a multi handle, and only then this is necessary */
      struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);

      if(entry) {
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
    tv->tv_sec = 0;
    tv->tv_usec = 0;
  }
  else {
    /* copy the first entry to 'tv' */
    memcpy(tv, &node->time, sizeof(*tv));

    /* Insert this node again into the splay.  Keep the timer in the list in
       case we need to recompute future timers. */
    multi->timetree = Curl_splayinsert(*tv, multi->timetree,
                                       &d->state.timenode);
  }
  return CURLM_OK;
}








|







3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
    tv->tv_sec = 0;
    tv->tv_usec = 0;
  }
  else {
    /* copy the first entry to 'tv' */
    memcpy(tv, &node->time, sizeof(*tv));

    /* Insert this node again into the splay. Keep the timer in the list in
       case we need to recompute future timers. */
    multi->timetree = Curl_splayinsert(*tv, multi->timetree,
                                       &d->state.timenode);
  }
  return CURLM_OK;
}

3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221




3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253

    /* or should we fall-through and do the timer-based stuff? */
    return result;
  }
  if(s != CURL_SOCKET_TIMEOUT) {
    struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);

    if(!entry)
      /* Unmatched socket, we can't act on it but we ignore this fact.  In
         real-world tests it has been proved that libevent can in fact give
         the application actions even though the socket was just previously
         asked to get removed, so thus we better survive stray socket actions
         and just move on. */
      ;




    else {
      struct Curl_hash_iterator iter;
      struct Curl_hash_element *he;

      /* the socket can be shared by many transfers, iterate */
      Curl_hash_start_iterate(&entry->transfers, &iter);
      for(he = Curl_hash_next_element(&iter); he;
          he = Curl_hash_next_element(&iter)) {
        data = (struct Curl_easy *)he->ptr;
        DEBUGASSERT(data);
        DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);

        if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
          /* set socket event bitmask if they're not locked */
          data->state.select_bits |= (unsigned char)ev_bitmask;

        Curl_expire(data, 0, EXPIRE_RUN_NOW);
      }

      /* Now we fall-through and do the timer-based stuff, since we don't want
         to force the user to have to deal with timeouts as long as at least
         one connection in fact has traffic. */

      data = NULL; /* set data to NULL again to avoid calling
                      multi_runsingle() in case there's no need to */
      now = Curl_now(); /* get a newer time since the multi_runsingle() loop
                           may have taken some time */
    }
  }
  else {
    /* Asked to run due to time-out. Clear the 'lastcall' variable to force
       Curl_update_timer() to trigger a callback to the app again even if the







|
|




<
>
>
>
>













|





|




|







3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220

3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256

    /* or should we fall-through and do the timer-based stuff? */
    return result;
  }
  if(s != CURL_SOCKET_TIMEOUT) {
    struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);

    if(!entry) {
      /* Unmatched socket, we cannot act on it but we ignore this fact. In
         real-world tests it has been proved that libevent can in fact give
         the application actions even though the socket was just previously
         asked to get removed, so thus we better survive stray socket actions
         and just move on. */

      /* The socket might come from a connection that is being shut down
       * by the multi's conncache. */
      Curl_conncache_multi_socket(multi, s, ev_bitmask);
    }
    else {
      struct Curl_hash_iterator iter;
      struct Curl_hash_element *he;

      /* the socket can be shared by many transfers, iterate */
      Curl_hash_start_iterate(&entry->transfers, &iter);
      for(he = Curl_hash_next_element(&iter); he;
          he = Curl_hash_next_element(&iter)) {
        data = (struct Curl_easy *)he->ptr;
        DEBUGASSERT(data);
        DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);

        if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
          /* set socket event bitmask if they are not locked */
          data->state.select_bits |= (unsigned char)ev_bitmask;

        Curl_expire(data, 0, EXPIRE_RUN_NOW);
      }

      /* Now we fall-through and do the timer-based stuff, since we do not want
         to force the user to have to deal with timeouts as long as at least
         one connection in fact has traffic. */

      data = NULL; /* set data to NULL again to avoid calling
                      multi_runsingle() in case there is no need to */
      now = Curl_now(); /* get a newer time since the multi_runsingle() loop
                           may have taken some time */
    }
  }
  else {
    /* Asked to run due to time-out. Clear the 'lastcall' variable to force
       Curl_update_timer() to trigger a callback to the app again even if the
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
           last */
        result = singlesocket(multi, data);
        if(result)
          break;
      }
    }

    /* Check if there's one (more) expired timer to deal with! This function
       extracts a matching node if there is one */

    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
    if(t) {
      data = t->payload; /* assign this for next loop */
      (void)add_next_timeout(now, multi, t->payload);
    }

  } while(t);
  if(first)
    sigpipe_restore(&pipe_st);

  *running_handles = multi->num_alive;
  return result;
}

#undef curl_multi_setopt
CURLMcode curl_multi_setopt(struct Curl_multi *multi,
                            CURLMoption option, ...)
{







|












|







3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
           last */
        result = singlesocket(multi, data);
        if(result)
          break;
      }
    }

    /* Check if there is one (more) expired timer to deal with! This function
       extracts a matching node if there is one */

    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
    if(t) {
      data = t->payload; /* assign this for next loop */
      (void)add_next_timeout(now, multi, t->payload);
    }

  } while(t);
  if(first)
    sigpipe_restore(&pipe_st);

  *running_handles = (int)multi->num_alive;
  return result;
}

#undef curl_multi_setopt
CURLMcode curl_multi_setopt(struct Curl_multi *multi,
                            CURLMoption option, ...)
{
3347
3348
3349
3350
3351
3352
3353



3354
3355
3356
3357
3358
3359
3360
      multi->maxconnects = (unsigned int)uarg;
    break;
  case CURLMOPT_MAX_HOST_CONNECTIONS:
    multi->max_host_connections = va_arg(param, long);
    break;
  case CURLMOPT_MAX_TOTAL_CONNECTIONS:
    multi->max_total_connections = va_arg(param, long);



    break;
    /* options formerly used for pipelining */
  case CURLMOPT_MAX_PIPELINE_LENGTH:
    break;
  case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
    break;
  case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:







>
>
>







3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
      multi->maxconnects = (unsigned int)uarg;
    break;
  case CURLMOPT_MAX_HOST_CONNECTIONS:
    multi->max_host_connections = va_arg(param, long);
    break;
  case CURLMOPT_MAX_TOTAL_CONNECTIONS:
    multi->max_total_connections = va_arg(param, long);
    /* for now, let this also decide the max number of connections
     * in shutdown handling */
    multi->max_shutdown_connections = va_arg(param, long);
    break;
    /* options formerly used for pipelining */
  case CURLMOPT_MAX_PIPELINE_LENGTH:
    break;
  case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
    break;
  case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447

    /* splay the lowest to the bottom */
    multi->timetree = Curl_splay(tv_zero, multi->timetree);

    if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
      /* some time left before expiration */
      timediff_t diff = Curl_timediff_ceil(multi->timetree->key, now);
      /* this should be safe even on 32 bit archs, as we don't use that
         overly long timeouts */
      *timeout_ms = (long)diff;
    }
    else
      /* 0 means immediately */
      *timeout_ms = 0;
  }







|







3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453

    /* splay the lowest to the bottom */
    multi->timetree = Curl_splay(tv_zero, multi->timetree);

    if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
      /* some time left before expiration */
      timediff_t diff = Curl_timediff_ceil(multi->timetree->key, now);
      /* this should be safe even on 32-bit archs, as we do not use that
         overly long timeouts */
      *timeout_ms = (long)diff;
    }
    else
      /* 0 means immediately */
      *timeout_ms = 0;
  }
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
  if(multi_timeout(multi, &timeout_ms)) {
    return CURLM_OK;
  }
  if(timeout_ms < 0) {
    static const struct curltime none = {0, 0};
    if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
      multi->timer_lastcall = none;
      /* there's no timeout now but there was one previously, tell the app to
         disable it */
      set_in_callback(multi, TRUE);
      rc = multi->timer_cb(multi, -1, multi->timer_userp);
      set_in_callback(multi, FALSE);
      if(rc == -1) {
        multi->dead = TRUE;
        return CURLM_ABORTED_BY_CALLBACK;







|







3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
  if(multi_timeout(multi, &timeout_ms)) {
    return CURLM_OK;
  }
  if(timeout_ms < 0) {
    static const struct curltime none = {0, 0};
    if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
      multi->timer_lastcall = none;
      /* there is no timeout now but there was one previously, tell the app to
         disable it */
      set_in_callback(multi, TRUE);
      rc = multi->timer_cb(multi, -1, multi->timer_userp);
      set_in_callback(multi, FALSE);
      if(rc == -1) {
        multi->dead = TRUE;
        return CURLM_ABORTED_BY_CALLBACK;
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
     remaining! */
  if(!multi)
    return;

  DEBUGASSERT(id < EXPIRE_LAST);

  set = Curl_now();
  set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bit conversion */
  set.tv_usec += (unsigned int)(milli%1000)*1000;

  if(set.tv_usec >= 1000000) {
    set.tv_sec++;
    set.tv_usec -= 1000000;
  }

  /* Remove any timer with the same id just in case. */
  multi_deltimeout(data, id);

  /* Add it to the timer list.  It must stay in the list until it has expired
     in case we need to recompute the minimum timer later. */
  multi_addtimeout(data, &set, id);

  if(nowp->tv_sec || nowp->tv_usec) {
    /* This means that the struct is added as a node in the splay tree.
       Compare if the new time is earlier, and only remove-old/add-new if it
       is. */
    timediff_t diff = Curl_timediff(set, *nowp);
    int rc;

    if(diff > 0) {
      /* The current splay tree entry is sooner than this new expiry time.
         We don't need to update our splay tree entry. */
      return;
    }

    /* Since this is an updated time, we must remove the previous entry from
       the splay tree first and then re-add the new value */
    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
                          &multi->timetree);







|
|









|












|







3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
     remaining! */
  if(!multi)
    return;

  DEBUGASSERT(id < EXPIRE_LAST);

  set = Curl_now();
  set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bits conversion */
  set.tv_usec += (int)(milli%1000)*1000;

  if(set.tv_usec >= 1000000) {
    set.tv_sec++;
    set.tv_usec -= 1000000;
  }

  /* Remove any timer with the same id just in case. */
  multi_deltimeout(data, id);

  /* Add it to the timer list. It must stay in the list until it has expired
     in case we need to recompute the minimum timer later. */
  multi_addtimeout(data, &set, id);

  if(nowp->tv_sec || nowp->tv_usec) {
    /* This means that the struct is added as a node in the splay tree.
       Compare if the new time is earlier, and only remove-old/add-new if it
       is. */
    timediff_t diff = Curl_timediff(set, *nowp);
    int rc;

    if(diff > 0) {
      /* The current splay tree entry is sooner than this new expiry time.
         We do not need to update our splay tree entry. */
      return;
    }

    /* Since this is an updated time, we must remove the previous entry from
       the splay tree first and then re-add the new value */
    rc = Curl_splayremove(multi->timetree, &data->state.timenode,
                          &multi->timetree);
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
  there->socketp = hashp;

  return CURLM_OK;
}

size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
{
  return multi ? multi->max_host_connections : 0;
}

size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
{
  return multi ? multi->max_total_connections : 0;
}

/*
 * When information about a connection has appeared, call this!
 */

void Curl_multiuse_state(struct Curl_easy *data,







|




|







3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
  there->socketp = hashp;

  return CURLM_OK;
}

size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
{
  return multi ? (size_t)multi->max_host_connections : 0;
}

size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
{
  return multi ? (size_t)multi->max_total_connections : 0;
}

/*
 * When information about a connection has appeared, call this!
 */

void Curl_multiuse_state(struct Curl_easy *data,
Changes to jni/curl/lib/multihandle.h.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#if !defined(CURL_DISABLE_SOCKETPAIR)
#define ENABLE_WAKEUP
#endif

/* value for MAXIMUM CONCURRENT STREAMS upper limit */
#define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)

/* Curl_multi SSL backend-specific data; declared differently by each SSL
   backend */
struct multi_ssl_backend_data;

/* This is the struct known as CURLM on the outside */
struct Curl_multi {
  /* First a simple identifier to easier detect if a user mix up
     this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
  unsigned int magic;

  /* We have a doubly-linked list with easy handles */







<
<
<
<







76
77
78
79
80
81
82




83
84
85
86
87
88
89
#if !defined(CURL_DISABLE_SOCKETPAIR)
#define ENABLE_WAKEUP
#endif

/* value for MAXIMUM CONCURRENT STREAMS upper limit */
#define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)





/* This is the struct known as CURLM on the outside */
struct Curl_multi {
  /* First a simple identifier to easier detect if a user mix up
     this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
  unsigned int magic;

  /* We have a doubly-linked list with easy handles */
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142







143
144
145
146
147
148
149
150
151


152
153
154
155
156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
171
172
173
174
175
  /* buffer used for transfer data, lazy initialized */
  char *xfer_buf; /* the actual buffer */
  size_t xfer_buf_len;      /* the allocated length */
  /* buffer used for upload data, lazy initialized */
  char *xfer_ulbuf; /* the actual buffer */
  size_t xfer_ulbuf_len;      /* the allocated length */

#if defined(USE_SSL)
  struct multi_ssl_backend_data *ssl_backend_data;
#endif

  /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
     the pluralis form, there can be more than one easy handle waiting on the
     same actual socket) */
  struct Curl_hash sockhash;








  /* Shared connection cache (bundles)*/
  struct conncache conn_cache;

  long max_host_connections; /* if >0, a fixed limit of the maximum number
                                of connections per host */

  long max_total_connections; /* if >0, a fixed limit of the maximum number
                                 of connections in total */



  /* timer callback and user data pointer for the *socket() API */
  curl_multi_timer_callback timer_cb;
  void *timer_userp;
  struct curltime timer_lastcall; /* the fixed time for the timeout for the
                                    previous callback */
#ifdef USE_WINSOCK
  WSAEVENT wsa_event; /* winsock event used for waits */
#else
#ifdef ENABLE_WAKEUP
  curl_socket_t wakeup_pair[2]; /* pipe()/socketpair() used for wakeup
                                   0 is used for read, 1 is used for write */

#endif
#endif
  unsigned int max_concurrent_streams;
  unsigned int maxconnects; /* if >0, a fixed limit of the maximum number of
                               entries we're allowed to grow the connection
                               cache to */
#define IPV6_UNKNOWN 0
#define IPV6_DEAD    1
#define IPV6_WORKS   2
  unsigned char ipv6_up;       /* IPV6_* defined */
  BIT(multiplexing);           /* multiplexing wanted */
  BIT(recheckstate);           /* see Curl_multi_connchanged */







<
<
<
<




>
>
>
>
>
>
>









>
>










|
|
>




|







124
125
126
127
128
129
130




131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  /* buffer used for transfer data, lazy initialized */
  char *xfer_buf; /* the actual buffer */
  size_t xfer_buf_len;      /* the allocated length */
  /* buffer used for upload data, lazy initialized */
  char *xfer_ulbuf; /* the actual buffer */
  size_t xfer_ulbuf_len;      /* the allocated length */





  /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
     the pluralis form, there can be more than one easy handle waiting on the
     same actual socket) */
  struct Curl_hash sockhash;
  /* `proto_hash` is a general key-value store for protocol implementations
   * with the lifetime of the multi handle. The number of elements kept here
   * should be in the order of supported protocols (and sub-protocols like
   * TLS), *not* in the order of connections or current transfers!
   * Elements need to be added with their own destructor to be invoked when
   * the multi handle is cleaned up (see Curl_hash_add2()).*/
  struct Curl_hash proto_hash;

  /* Shared connection cache (bundles)*/
  struct conncache conn_cache;

  long max_host_connections; /* if >0, a fixed limit of the maximum number
                                of connections per host */

  long max_total_connections; /* if >0, a fixed limit of the maximum number
                                 of connections in total */
  long max_shutdown_connections; /* if >0, a fixed limit of the maximum number
                                 of connections in shutdown handling */

  /* timer callback and user data pointer for the *socket() API */
  curl_multi_timer_callback timer_cb;
  void *timer_userp;
  struct curltime timer_lastcall; /* the fixed time for the timeout for the
                                    previous callback */
#ifdef USE_WINSOCK
  WSAEVENT wsa_event; /* winsock event used for waits */
#else
#ifdef ENABLE_WAKEUP
  curl_socket_t wakeup_pair[2]; /* eventfd()/pipe()/socketpair() used for
                                   wakeup 0 is used for read, 1 is used
                                   for write */
#endif
#endif
  unsigned int max_concurrent_streams;
  unsigned int maxconnects; /* if >0, a fixed limit of the maximum number of
                               entries we are allowed to grow the connection
                               cache to */
#define IPV6_UNKNOWN 0
#define IPV6_DEAD    1
#define IPV6_WORKS   2
  unsigned char ipv6_up;       /* IPV6_* defined */
  BIT(multiplexing);           /* multiplexing wanted */
  BIT(recheckstate);           /* see Curl_multi_connchanged */
Changes to jni/curl/lib/multiif.h.
72
73
74
75
76
77
78
79
80
81
82
83
84
85









86
87
88
89
90
91
92
void Curl_multiuse_state(struct Curl_easy *data,
                         int bundlestate); /* use BUNDLE_* defines */

/*
 * Curl_multi_closed()
 *
 * Used by the connect code to tell the multi_socket code that one of the
 * sockets we were using is about to be closed.  This function will then
 * remove it from the sockethash for this handle to make the multi_socket API
 * behave properly, especially for the case when libcurl will create another
 * socket again and it gets the same file descriptor number.
 */

void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s);










/*
 * Add a handle and move it into PERFORM state at once. For pushed streams.
 */
CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
                                 struct Curl_easy *data,
                                 struct connectdata *conn);







|






>
>
>
>
>
>
>
>
>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
void Curl_multiuse_state(struct Curl_easy *data,
                         int bundlestate); /* use BUNDLE_* defines */

/*
 * Curl_multi_closed()
 *
 * Used by the connect code to tell the multi_socket code that one of the
 * sockets we were using is about to be closed. This function will then
 * remove it from the sockethash for this handle to make the multi_socket API
 * behave properly, especially for the case when libcurl will create another
 * socket again and it gets the same file descriptor number.
 */

void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s);

/* Compare the two pollsets to notify the multi_socket API of changes
 * in socket polling, e.g calling multi->socket_cb() with the changes if
 * differences are seen.
 */
CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
                                struct Curl_easy *data,
                                struct easy_pollset *ps,
                                struct easy_pollset *last_ps);

/*
 * Add a handle and move it into PERFORM state at once. For pushed streams.
 */
CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
                                 struct Curl_easy *data,
                                 struct connectdata *conn);
Changes to jni/curl/lib/netrc.c.
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
            state_password = 0;
          }
          else if(strcasecompare("login", tok))
            state_login = 1;
          else if(strcasecompare("password", tok))
            state_password = 1;
          else if(strcasecompare("machine", tok)) {
            /* ok, there's machine here go => */
            state = HOSTFOUND;
            state_our_login = FALSE;
          }
          break;
        } /* switch (state) */
        tok = ++tok_end;
      }







|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
            state_password = 0;
          }
          else if(strcasecompare("login", tok))
            state_login = 1;
          else if(strcasecompare("password", tok))
            state_password = 1;
          else if(strcasecompare("machine", tok)) {
            /* ok, there is machine here go => */
            state = HOSTFOUND;
            state_our_login = FALSE;
          }
          break;
        } /* switch (state) */
        tok = ++tok_end;
      }
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

  return retcode;
}

/*
 * @unittest: 1304
 *
 * *loginp and *passwordp MUST be allocated if they aren't NULL when passed
 * in.
 */
int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
                    char *netrcfile)
{
  int retcode = 1;
  char *filealloc = NULL;







|







273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

  return retcode;
}

/*
 * @unittest: 1304
 *
 * *loginp and *passwordp MUST be allocated if they are not NULL when passed
 * in.
 */
int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
                    char *netrcfile)
{
  int retcode = 1;
  char *filealloc = NULL;
Changes to jni/curl/lib/netrc.h.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"
#ifndef CURL_DISABLE_NETRC

/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
int Curl_parsenetrc(const char *host, char **loginp,
                    char **passwordp, char *filename);
  /* Assume: (*passwordp)[0]=0, host[0] != 0.
   * If (*loginp)[0] = 0, search for login and password within a machine
   * section in the netrc.
   * If (*loginp)[0] != 0, search for password within machine and login.
   */







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"
#ifndef CURL_DISABLE_NETRC

/* returns -1 on failure, 0 if the host is found, 1 is the host is not found */
int Curl_parsenetrc(const char *host, char **loginp,
                    char **passwordp, char *filename);
  /* Assume: (*passwordp)[0]=0, host[0] != 0.
   * If (*loginp)[0] = 0, search for login and password within a machine
   * section in the netrc.
   * If (*loginp)[0] != 0, search for password within machine and login.
   */
Changes to jni/curl/lib/nonblock.c.
46
47
48
49
50
51
52







53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
                   int nonblock   /* TRUE or FALSE */)
{
#if defined(HAVE_FCNTL_O_NONBLOCK)
  /* most recent unix versions */
  int flags;
  flags = sfcntl(sockfd, F_GETFL, 0);







  if(nonblock)
    return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK);


  return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));

#elif defined(HAVE_IOCTL_FIONBIO)

  /* older unix versions */
  int flags = nonblock ? 1 : 0;
  return ioctl(sockfd, FIONBIO, &flags);

#elif defined(HAVE_IOCTLSOCKET_FIONBIO)

  /* Windows */
  unsigned long flags = nonblock ? 1UL : 0UL;
  return ioctlsocket(sockfd, FIONBIO, &flags);

#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)

  /* Amiga */
  long flags = nonblock ? 1L : 0L;
  return IoctlSocket(sockfd, FIONBIO, (char *)&flags);








>
>
>
>
>
>
>

|
>
>
|











|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
                   int nonblock   /* TRUE or FALSE */)
{
#if defined(HAVE_FCNTL_O_NONBLOCK)
  /* most recent unix versions */
  int flags;
  flags = sfcntl(sockfd, F_GETFL, 0);
  if(flags < 0)
    return -1;
  /* Check if the current file status flags have already satisfied
   * the request, if so, it is no need to call fcntl() to replicate it.
   */
  if(!!(flags & O_NONBLOCK) == !!nonblock)
    return 0;
  if(nonblock)
    flags |= O_NONBLOCK;
  else
    flags &= ~O_NONBLOCK;
  return sfcntl(sockfd, F_SETFL, flags);

#elif defined(HAVE_IOCTL_FIONBIO)

  /* older unix versions */
  int flags = nonblock ? 1 : 0;
  return ioctl(sockfd, FIONBIO, &flags);

#elif defined(HAVE_IOCTLSOCKET_FIONBIO)

  /* Windows */
  unsigned long flags = nonblock ? 1UL : 0UL;
  return ioctlsocket(sockfd, (long)FIONBIO, &flags);

#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)

  /* Amiga */
  long flags = nonblock ? 1L : 0L;
  return IoctlSocket(sockfd, FIONBIO, (char *)&flags);

Changes to jni/curl/lib/noproxy.c.
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91


92
93
94
95
96
97
98
99
100
101
102
103
104
}

UNITTEST bool Curl_cidr6_match(const char *ipv6,
                               const char *network,
                               unsigned int bits)
{
#ifdef USE_IPV6
  int bytes;
  int rest;
  unsigned char address[16];
  unsigned char check[16];

  if(!bits)
    bits = 128;

  bytes = bits/8;
  rest = bits & 0x07;


  if(1 != Curl_inet_pton(AF_INET6, ipv6, address))
    return FALSE;
  if(1 != Curl_inet_pton(AF_INET6, network, check))
    return FALSE;
  if((bytes > 16) || ((bytes == 16) && rest))
    return FALSE;
  if(bytes && memcmp(address, check, bytes))
    return FALSE;
  if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest))))
    return FALSE;

  return TRUE;
#else







|
|






|

>
>




<
<







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97


98
99
100
101
102
103
104
}

UNITTEST bool Curl_cidr6_match(const char *ipv6,
                               const char *network,
                               unsigned int bits)
{
#ifdef USE_IPV6
  unsigned int bytes;
  unsigned int rest;
  unsigned char address[16];
  unsigned char check[16];

  if(!bits)
    bits = 128;

  bytes = bits / 8;
  rest = bits & 0x07;
  if((bytes > 16) || ((bytes == 16) && rest))
    return FALSE;
  if(1 != Curl_inet_pton(AF_INET6, ipv6, address))
    return FALSE;
  if(1 != Curl_inet_pton(AF_INET6, network, check))
    return FALSE;


  if(bytes && memcmp(address, check, bytes))
    return FALSE;
  if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest))))
    return FALSE;

  return TRUE;
#else
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  TYPE_IPV6
};

/****************************************************************
* Checks if the host is in the noproxy list. returns TRUE if it matches and
* therefore the proxy should NOT be used.
****************************************************************/
bool Curl_check_noproxy(const char *name, const char *no_proxy,
                        bool *spacesep)
{
  char hostip[128];
  *spacesep = FALSE;
  /*
   * If we don't have a hostname at all, like for example with a FILE
   * transfer, we have nothing to interrogate the noproxy list with.
   */
  if(!name || name[0] == '\0')
    return FALSE;

  /* no_proxy=domain1.dom,host.domain2.dom
   *   (a comma-separated list of hosts which should
   *   not be proxied, or an asterisk to override
   *   all proxy variables)
   */
  if(no_proxy && no_proxy[0]) {
    const char *p = no_proxy;
    size_t namelen;
    enum nametype type = TYPE_HOST;
    if(!strcmp("*", no_proxy))
      return TRUE;

    /* NO_PROXY was specified and it wasn't just an asterisk */

    if(name[0] == '[') {
      char *endptr;
      /* IPv6 numerical address */
      endptr = strchr(name, ']');
      if(!endptr)
        return FALSE;







|
<


|

|

















|







115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  TYPE_IPV6
};

/****************************************************************
* Checks if the host is in the noproxy list. returns TRUE if it matches and
* therefore the proxy should NOT be used.
****************************************************************/
bool Curl_check_noproxy(const char *name, const char *no_proxy)

{
  char hostip[128];

  /*
   * If we do not have a hostname at all, like for example with a FILE
   * transfer, we have nothing to interrogate the noproxy list with.
   */
  if(!name || name[0] == '\0')
    return FALSE;

  /* no_proxy=domain1.dom,host.domain2.dom
   *   (a comma-separated list of hosts which should
   *   not be proxied, or an asterisk to override
   *   all proxy variables)
   */
  if(no_proxy && no_proxy[0]) {
    const char *p = no_proxy;
    size_t namelen;
    enum nametype type = TYPE_HOST;
    if(!strcmp("*", no_proxy))
      return TRUE;

    /* NO_PROXY was specified and it was not just an asterisk */

    if(name[0] == '[') {
      char *endptr;
      /* IPv6 numerical address */
      endptr = strchr(name, ']');
      if(!endptr)
        return FALSE;
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    }
    else {
      unsigned int address;
      namelen = strlen(name);
      if(1 == Curl_inet_pton(AF_INET, name, &address))
        type = TYPE_IPV4;
      else {
        /* ignore trailing dots in the host name */
        if(name[namelen - 1] == '.')
          namelen--;
      }
    }

    while(*p) {
      const char *token;







|







161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
    }
    else {
      unsigned int address;
      namelen = strlen(name);
      if(1 == Curl_inet_pton(AF_INET, name, &address))
        type = TYPE_IPV4;
      else {
        /* ignore trailing dots in the hostname */
        if(name[namelen - 1] == '.')
          namelen--;
      }
    }

    while(*p) {
      const char *token;
228
229
230
231
232
233
234


235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
          memcpy(checkip, check, tokenlen);
          checkip[tokenlen] = 0;
          check = checkip;

          slash = strchr(check, '/');
          /* if the slash is part of this token, use it */
          if(slash) {


            bits = atoi(slash + 1);
            *slash = 0; /* null terminate there */
          }
          if(type == TYPE_IPV6)
            match = Curl_cidr6_match(name, check, bits);
          else
            match = Curl_cidr4_match(name, check, bits);
          break;
        }
        }
        if(match)
          return TRUE;
      } /* if(tokenlen) */
      /* pass blanks after pattern */
      while(ISBLANK(*p))
        p++;
      /* if not a comma! */
      if(*p && (*p != ',')) {
        *spacesep = TRUE;
        continue;
      }
      /* pass any number of commas */
      while(*p == ',')
        p++;
    } /* while(*p) */
  } /* NO_PROXY was specified and it wasn't just an asterisk */

  return FALSE;
}

#endif /* CURL_DISABLE_PROXY */







>
>
|















|
|
<
|
<




|





227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253

254

255
256
257
258
259
260
261
262
263
264
          memcpy(checkip, check, tokenlen);
          checkip[tokenlen] = 0;
          check = checkip;

          slash = strchr(check, '/');
          /* if the slash is part of this token, use it */
          if(slash) {
            /* if the bits variable gets a crazy value here, that is fine as
               the value will then be rejected in the cidr function */
            bits = (unsigned int)atoi(slash + 1);
            *slash = 0; /* null terminate there */
          }
          if(type == TYPE_IPV6)
            match = Curl_cidr6_match(name, check, bits);
          else
            match = Curl_cidr4_match(name, check, bits);
          break;
        }
        }
        if(match)
          return TRUE;
      } /* if(tokenlen) */
      /* pass blanks after pattern */
      while(ISBLANK(*p))
        p++;
      /* if not a comma, this ends the loop */
      if(*p != ',')

        break;

      /* pass any number of commas */
      while(*p == ',')
        p++;
    } /* while(*p) */
  } /* NO_PROXY was specified and it was not just an asterisk */

  return FALSE;
}

#endif /* CURL_DISABLE_PROXY */
Changes to jni/curl/lib/noproxy.h.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curl_setup.h"

#ifndef CURL_DISABLE_PROXY

#ifdef DEBUGBUILD

UNITTEST bool Curl_cidr4_match(const char *ipv4,    /* 1.2.3.4 address */
                               const char *network, /* 1.2.3.4 address */
                               unsigned int bits);
UNITTEST bool Curl_cidr6_match(const char *ipv6,
                               const char *network,
                               unsigned int bits);
#endif

bool Curl_check_noproxy(const char *name, const char *no_proxy,
                        bool *spacesep);

#endif

#endif /* HEADER_CURL_NOPROXY_H */







|









|
<
<



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40


41
42
43
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curl_setup.h"

#ifndef CURL_DISABLE_PROXY

#ifdef UNITTESTS

UNITTEST bool Curl_cidr4_match(const char *ipv4,    /* 1.2.3.4 address */
                               const char *network, /* 1.2.3.4 address */
                               unsigned int bits);
UNITTEST bool Curl_cidr6_match(const char *ipv6,
                               const char *network,
                               unsigned int bits);
#endif

bool Curl_check_noproxy(const char *name, const char *no_proxy);


#endif

#endif /* HEADER_CURL_NOPROXY_H */
Changes to jni/curl/lib/openldap.c.
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
      if(!lr) {
        ldap_abandon_ext(li->ld, msgid, NULL, NULL);
        result = CURLE_OUT_OF_MEMORY;
      }
      else {
        lr->msgid = msgid;
        data->req.p.ldap = lr;
        Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
        *done = TRUE;
      }
    }
  }
  return result;
}








|







917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
      if(!lr) {
        ldap_abandon_ext(li->ld, msgid, NULL, NULL);
        result = CURLE_OUT_OF_MEMORY;
      }
      else {
        lr->msgid = msgid;
        data->req.p.ldap = lr;
        Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
        *done = TRUE;
      }
    }
  }
  return result;
}

1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
static int
ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
{
  sbiod->sbiod_pvt = NULL;
  return 0;
}

/* We don't need to do anything because libcurl does it already */
static int
ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
{
  (void)sbiod;
  return 0;
}








|







1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
static int
ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
{
  sbiod->sbiod_pvt = NULL;
  return 0;
}

/* We do not need to do anything because libcurl does it already */
static int
ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
{
  (void)sbiod;
  return 0;
}

Changes to jni/curl/lib/parsedate.c.
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
      return i;
    what++;
  }
  return -1; /* return the offset or -1, no real offset is -1 */
}

/* return the time zone offset between GMT and the input one, in number
   of seconds or -1 if the timezone wasn't found/legal */

static int checktz(const char *check, size_t len)
{
  unsigned int i;
  const struct tzinfo *what = tz;
  if(len > 4) /* longer than any valid timezone */
    return -1;

  for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
    size_t ilen = strlen(what->name);
    if((ilen == len) &&
       strncasecompare(check, what->name, len))
      return what->offset*60;
    what++;
  }
  return -1;
}

static void skip(const char **date)
{
  /* skip everything that aren't letters or digits */
  while(**date && !ISALNUM(**date))
    (*date)++;
}

enum assume {
  DATE_MDAY,
  DATE_YEAR,
  DATE_TIME
};

/*
 * time2epoch: time stamp to seconds since epoch in GMT time zone.  Similar to
 * mktime but for GMT only.
 */
static time_t time2epoch(int sec, int min, int hour,
                         int mday, int mon, int year)
{
  static const int month_days_cumulative [12] =
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };







|




















|











|







240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
      return i;
    what++;
  }
  return -1; /* return the offset or -1, no real offset is -1 */
}

/* return the time zone offset between GMT and the input one, in number
   of seconds or -1 if the timezone was not found/legal */

static int checktz(const char *check, size_t len)
{
  unsigned int i;
  const struct tzinfo *what = tz;
  if(len > 4) /* longer than any valid timezone */
    return -1;

  for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
    size_t ilen = strlen(what->name);
    if((ilen == len) &&
       strncasecompare(check, what->name, len))
      return what->offset*60;
    what++;
  }
  return -1;
}

static void skip(const char **date)
{
  /* skip everything that are not letters or digits */
  while(**date && !ISALNUM(**date))
    (*date)++;
}

enum assume {
  DATE_MDAY,
  DATE_YEAR,
  DATE_TIME
};

/*
 * time2epoch: time stamp to seconds since epoch in GMT time zone. Similar to
 * mktime but for GMT only.
 */
static time_t time2epoch(int sec, int min, int hour,
                         int mday, int mon, int year)
{
  static const int month_days_cumulative [12] =
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
        if((tzoff == -1) &&
           ((end - date) == 4) &&
           (val <= 1400) &&
           (indate< date) &&
           ((date[-1] == '+' || date[-1] == '-'))) {
          /* four digits and a value less than or equal to 1400 (to take into
             account all sorts of funny time zone diffs) and it is preceded
             with a plus or minus. This is a time zone indication.  1400 is
             picked since +1300 is frequently used and +1400 is mentioned as
             an edge number in the document "ISO C 200X Proposal: Timezone
             Functions" at http://david.tribble.com/text/c0xtimezone.html If
             anyone has a more authoritative source for the exact maximum time
             zone offsets, please speak up! */
          found = TRUE;
          tzoff = (val/100 * 60 + val%100)*60;







|







441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
        if((tzoff == -1) &&
           ((end - date) == 4) &&
           (val <= 1400) &&
           (indate< date) &&
           ((date[-1] == '+' || date[-1] == '-'))) {
          /* four digits and a value less than or equal to 1400 (to take into
             account all sorts of funny time zone diffs) and it is preceded
             with a plus or minus. This is a time zone indication. 1400 is
             picked since +1300 is frequently used and +1400 is mentioned as
             an edge number in the document "ISO C 200X Proposal: Timezone
             Functions" at http://david.tribble.com/text/c0xtimezone.html If
             anyone has a more authoritative source for the exact maximum time
             zone offsets, please speak up! */
          found = TRUE;
          tzoff = (val/100 * 60 + val%100)*60;
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
    return PARSEDATE_SOONER;
  }
#endif

#if (SIZEOF_TIME_T < 5)

#ifdef HAVE_TIME_T_UNSIGNED
  /* an unsigned 32 bit time_t can only hold dates to 2106 */
  if(yearnum > 2105) {
    *output = TIME_T_MAX;
    return PARSEDATE_LATER;
  }
#else
  /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */
  if(yearnum > 2037) {
    *output = TIME_T_MAX;
    return PARSEDATE_LATER;
  }
  if(yearnum < 1903) {
    *output = TIME_T_MIN;
    return PARSEDATE_SOONER;







|





|







517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
    return PARSEDATE_SOONER;
  }
#endif

#if (SIZEOF_TIME_T < 5)

#ifdef HAVE_TIME_T_UNSIGNED
  /* an unsigned 32-bit time_t can only hold dates to 2106 */
  if(yearnum > 2105) {
    *output = TIME_T_MAX;
    return PARSEDATE_LATER;
  }
#else
  /* a signed 32-bit time_t can only hold dates to the beginning of 2038 */
  if(yearnum > 2037) {
    *output = TIME_T_MAX;
    return PARSEDATE_LATER;
  }
  if(yearnum < 1903) {
    *output = TIME_T_MIN;
    return PARSEDATE_SOONER;
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
#endif

  if((mdaynum > 31) || (monnum > 11) ||
     (hournum > 23) || (minnum > 59) || (secnum > 60))
    return PARSEDATE_FAIL; /* clearly an illegal date */

  /* time2epoch() returns a time_t. time_t is often 32 bits, sometimes even on
     architectures that feature 64 bit 'long' but ultimately time_t is the
     correct data type to use.
  */
  t = time2epoch(secnum, minnum, hournum, mdaynum, monnum, yearnum);

  /* Add the time zone diff between local time zone and GMT. */
  if(tzoff == -1)
    tzoff = 0;







|







545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
#endif

  if((mdaynum > 31) || (monnum > 11) ||
     (hournum > 23) || (minnum > 59) || (secnum > 60))
    return PARSEDATE_FAIL; /* clearly an illegal date */

  /* time2epoch() returns a time_t. time_t is often 32 bits, sometimes even on
     architectures that feature a 64 bits 'long' but ultimately time_t is the
     correct data type to use.
  */
  t = time2epoch(secnum, minnum, hournum, mdaynum, monnum, yearnum);

  /* Add the time zone diff between local time zone and GMT. */
  if(tzoff == -1)
    tzoff = 0;
Changes to jni/curl/lib/pingpong.c.
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  else
    rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
                           CURL_SOCKET_BAD,
                           pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
                           interval_ms);

  if(block) {
    /* if we didn't wait, we don't have to spend time on this now */
    if(Curl_pgrsUpdate(data))
      result = CURLE_ABORTED_BY_CALLBACK;
    else
      result = Curl_speedcheck(data, Curl_now());

    if(result)
      return result;







|







115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  else
    rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
                           CURL_SOCKET_BAD,
                           pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
                           interval_ms);

  if(block) {
    /* if we did not wait, we do not have to spend time on this now */
    if(Curl_pgrsUpdate(data))
      result = CURLE_ABORTED_BY_CALLBACK;
    else
      result = Curl_speedcheck(data, Curl_now());

    if(result)
      return result;
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#endif

  DEBUGASSERT(pp->sendleft == 0);
  DEBUGASSERT(pp->sendsize == 0);
  DEBUGASSERT(pp->sendthis == NULL);

  if(!conn)
    /* can't send without a connection! */
    return CURLE_SEND_ERROR;

  Curl_dyn_reset(&pp->sendbuf);
  result = Curl_dyn_vaddf(&pp->sendbuf, fmt, args);
  if(result)
    return result;








|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#endif

  DEBUGASSERT(pp->sendleft == 0);
  DEBUGASSERT(pp->sendsize == 0);
  DEBUGASSERT(pp->sendthis == NULL);

  if(!conn)
    /* cannot send without a connection! */
    return CURLE_SEND_ERROR;

  Curl_dyn_reset(&pp->sendbuf);
  result = Curl_dyn_vaddf(&pp->sendbuf, fmt, args);
  if(result)
    return result;

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
  }

  do {
    char *line = Curl_dyn_ptr(&pp->recvbuf);
    char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf));
    if(nl) {
      /* a newline is CRLF in pp-talk, so the CR is ignored as
         the line isn't really terminated until the LF comes */
      size_t length = nl - line + 1;

      /* output debug output if that is requested */
#ifdef HAVE_GSSAPI
      if(!conn->sec_complete)
#endif
        Curl_debug(data, CURLINFO_HEADER_IN, line, length);







|







325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
  }

  do {
    char *line = Curl_dyn_ptr(&pp->recvbuf);
    char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf));
    if(nl) {
      /* a newline is CRLF in pp-talk, so the CR is ignored as
         the line is not really terminated until the LF comes */
      size_t length = nl - line + 1;

      /* output debug output if that is requested */
#ifdef HAVE_GSSAPI
      if(!conn->sec_complete)
#endif
        Curl_debug(data, CURLINFO_HEADER_IN, line, length);
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
    }
    else {
      /* without a newline, there is no overflow */
      pp->overflow = 0;
      break;
    }

  } while(1); /* while there's buffer left to scan */

  pp->pending_resp = FALSE;

  return result;
}

int Curl_pp_getsock(struct Curl_easy *data,







|







368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
    }
    else {
      /* without a newline, there is no overflow */
      pp->overflow = 0;
      break;
    }

  } while(1); /* while there is buffer left to scan */

  pp->pending_resp = FALSE;

  return result;
}

int Curl_pp_getsock(struct Curl_easy *data,
Changes to jni/curl/lib/pingpong.h.
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

/* forward-declaration, this is defined in urldata.h */
struct connectdata;

typedef enum {
  PPTRANSFER_BODY, /* yes do transfer a body */
  PPTRANSFER_INFO, /* do still go through to get info/headers */
  PPTRANSFER_NONE  /* don't get anything and don't get info */
} curl_pp_transfer;

/*
 * 'pingpong' is the generic struct used for protocols doing server<->client
 * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc.
 *
 * It holds response cache and non-blocking sending data.







|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

/* forward-declaration, this is defined in urldata.h */
struct connectdata;

typedef enum {
  PPTRANSFER_BODY, /* yes do transfer a body */
  PPTRANSFER_INFO, /* do still go through to get info/headers */
  PPTRANSFER_NONE  /* do not get anything and do not get info */
} curl_pp_transfer;

/*
 * 'pingpong' is the generic struct used for protocols doing server<->client
 * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc.
 *
 * It holds response cache and non-blocking sending data.
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    pp->endofresp = e;                           \
  } while(0)

/*
 * Curl_pp_statemach()
 *
 * called repeatedly until done. Set 'wait' to make it wait a while on the
 * socket if there's no traffic.
 */
CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
                           bool block, bool disconnecting);

/* initialize stuff to prepare for reading a fresh new response */
void Curl_pp_init(struct pingpong *pp);








|







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    pp->endofresp = e;                           \
  } while(0)

/*
 * Curl_pp_statemach()
 *
 * called repeatedly until done. Set 'wait' to make it wait a while on the
 * socket if there is no traffic.
 */
CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
                           bool block, bool disconnecting);

/* initialize stuff to prepare for reading a fresh new response */
void Curl_pp_init(struct pingpong *pp);

Changes to jni/curl/lib/pop3.c.
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
 */
static CURLcode pop3_perform_user(struct Curl_easy *data,
                                  struct connectdata *conn)
{
  CURLcode result = CURLE_OK;

  /* Check we have a username and password to authenticate with and end the
     connect phase if we don't */
  if(!data->state.aptr.user) {
    pop3_state(data, POP3_STOP);

    return result;
  }

  /* Send the USER command */







|







402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
 */
static CURLcode pop3_perform_user(struct Curl_easy *data,
                                  struct connectdata *conn)
{
  CURLcode result = CURLE_OK;

  /* Check we have a username and password to authenticate with and end the
     connect phase if we do not */
  if(!data->state.aptr.user) {
    pop3_state(data, POP3_STOP);

    return result;
  }

  /* Send the USER command */
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  struct pop3_conn *pop3c = &conn->proto.pop3c;
  size_t i;
  struct MD5_context *ctxt;
  unsigned char digest[MD5_DIGEST_LEN];
  char secret[2 * MD5_DIGEST_LEN + 1];

  /* Check we have a username and password to authenticate with and end the
     connect phase if we don't */
  if(!data->state.aptr.user) {
    pop3_state(data, POP3_STOP);

    return result;
  }

  /* Create the digest */







|







436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  struct pop3_conn *pop3c = &conn->proto.pop3c;
  size_t i;
  struct MD5_context *ctxt;
  unsigned char digest[MD5_DIGEST_LEN];
  char secret[2 * MD5_DIGEST_LEN + 1];

  /* Check we have a username and password to authenticate with and end the
     connect phase if we do not */
  if(!data->state.aptr.user) {
    pop3_state(data, POP3_STOP);

    return result;
  }

  /* Create the digest */
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
                                            struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  struct pop3_conn *pop3c = &conn->proto.pop3c;
  saslprogress progress = SASL_IDLE;

  /* Check we have enough data to authenticate with and end the
     connect phase if we don't */
  if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) {
    pop3_state(data, POP3_STOP);
    return result;
  }

  if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
    /* Calculate the SASL login details */







|







546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
                                            struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  struct pop3_conn *pop3c = &conn->proto.pop3c;
  saslprogress progress = SASL_IDLE;

  /* Check we have enough data to authenticate with and end the
     connect phase if we do not */
  if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) {
    pop3_state(data, POP3_STOP);
    return result;
  }

  if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
    /* Calculate the SASL login details */
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768

        line += wordlen;
        len -= wordlen;
      }
    }
  }
  else {
    /* Clear text is supported when CAPA isn't recognised */
    if(pop3code != '+')
      pop3c->authtypes |= POP3_TYPE_CLEARTEXT;

    if(!data->set.use_ssl || Curl_conn_is_ssl(conn, FIRSTSOCKET))
      result = pop3_perform_authentication(data, conn);
    else if(pop3code == '+' && pop3c->tls_supported)
      /* Switch to TLS connection now */







|







754
755
756
757
758
759
760
761
762
763
764
765
766
767
768

        line += wordlen;
        len -= wordlen;
      }
    }
  }
  else {
    /* Clear text is supported when CAPA is not recognised */
    if(pop3code != '+')
      pop3c->authtypes |= POP3_TYPE_CLEARTEXT;

    if(!data->set.use_ssl || Curl_conn_is_ssl(conn, FIRSTSOCKET))
      result = pop3_perform_authentication(data, conn);
    else if(pop3code == '+' && pop3c->tls_supported)
      /* Switch to TLS connection now */
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
  /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
     EOB string so count this is two matching bytes. This is necessary to make
     the code detect the EOB if the only data than comes now is %2e CR LF like
     when there is no body to return. */
  pop3c->eob = 2;

  /* But since this initial CR LF pair is not part of the actual body, we set
     the strip counter here so that these bytes won't be delivered. */
  pop3c->strip = 2;

  if(pop3->transfer == PPTRANSFER_BODY) {
    /* POP3 download */
    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);

    if(pp->overflow) {
      /* The recv buffer contains data that is actually body content so send
         it as such. Note that there may even be additional "headers" after
         the body */

      /* keep only the overflow */







|




|







927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
  /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
     EOB string so count this is two matching bytes. This is necessary to make
     the code detect the EOB if the only data than comes now is %2e CR LF like
     when there is no body to return. */
  pop3c->eob = 2;

  /* But since this initial CR LF pair is not part of the actual body, we set
     the strip counter here so that these bytes will not be delivered. */
  pop3c->strip = 2;

  if(pop3->transfer == PPTRANSFER_BODY) {
    /* POP3 download */
    Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);

    if(pp->overflow) {
      /* The recv buffer contains data that is actually body content so send
         it as such. Note that there may even be additional "headers" after
         the body */

      /* keep only the overflow */
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523

    switch(str[i]) {
    case 0x0d:
      if(pop3c->eob == 0) {
        pop3c->eob++;

        if(i) {
          /* Write out the body part that didn't match */
          result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
                                     i - last);

          if(result)
            return result;

          last = i;
        }
      }
      else if(pop3c->eob == 3)
        pop3c->eob++;
      else
        /* If the character match wasn't at position 0 or 3 then restart the
           pattern matching */
        pop3c->eob = 1;
      break;

    case 0x0a:
      if(pop3c->eob == 1 || pop3c->eob == 4)
        pop3c->eob++;
      else
        /* If the character match wasn't at position 1 or 4 then start the
           search again */
        pop3c->eob = 0;
      break;

    case 0x2e:
      if(pop3c->eob == 2)
        pop3c->eob++;
      else if(pop3c->eob == 3) {
        /* We have an extra dot after the CRLF which we need to strip off */
        strip_dot = TRUE;
        pop3c->eob = 0;
      }
      else
        /* If the character match wasn't at position 2 then start the search
           again */
        pop3c->eob = 0;
      break;

    default:
      pop3c->eob = 0;
      break;







|












|








|













|







1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523

    switch(str[i]) {
    case 0x0d:
      if(pop3c->eob == 0) {
        pop3c->eob++;

        if(i) {
          /* Write out the body part that did not match */
          result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
                                     i - last);

          if(result)
            return result;

          last = i;
        }
      }
      else if(pop3c->eob == 3)
        pop3c->eob++;
      else
        /* If the character match was not at position 0 or 3 then restart the
           pattern matching */
        pop3c->eob = 1;
      break;

    case 0x0a:
      if(pop3c->eob == 1 || pop3c->eob == 4)
        pop3c->eob++;
      else
        /* If the character match was not at position 1 or 4 then start the
           search again */
        pop3c->eob = 0;
      break;

    case 0x2e:
      if(pop3c->eob == 2)
        pop3c->eob++;
      else if(pop3c->eob == 3) {
        /* We have an extra dot after the CRLF which we need to strip off */
        strip_dot = TRUE;
        pop3c->eob = 0;
      }
      else
        /* If the character match was not at position 2 then start the search
           again */
        pop3c->eob = 0;
      break;

    default:
      pop3c->eob = 0;
      break;
Changes to jni/curl/lib/progress.c.
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  if(bytes < CURL_OFF_T_C(100000))
    msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);

  else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);

  else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
    /* 'XX.XM' is good as long as we're less than 100 megs */
    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
              CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
              (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );

  else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
    /* 'XXXXM' is good until we're at 10000MB or above */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);

  else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
    /* 10000 MB - 100 GB, we show it as XX.XG */
    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
              CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
              (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );

  else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
    /* up to 10000GB, display without decimal: XXXXG */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);

  else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
    /* up to 10000TB, display without decimal: XXXXT */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);

  else
    /* up to 10000PB, display without decimal: XXXXP */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);

  /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can
     hold, but our data type is signed so 8192PB will be the maximum. */

  return max5;
}
#endif

/*







|





|




















|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  if(bytes < CURL_OFF_T_C(100000))
    msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);

  else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);

  else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
    /* 'XX.XM' is good as long as we are less than 100 megs */
    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
              CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
              (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );

  else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
    /* 'XXXXM' is good until we are at 10000MB or above */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);

  else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
    /* 10000 MB - 100 GB, we show it as XX.XG */
    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
              CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
              (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );

  else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
    /* up to 10000GB, display without decimal: XXXXG */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);

  else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
    /* up to 10000TB, display without decimal: XXXXT */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);

  else
    /* up to 10000PB, display without decimal: XXXXP */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);

  /* 16384 petabytes (16 exabytes) is the maximum a 64-bit unsigned number can
     hold, but our data type is signed so 8192PB will be the maximum. */

  return max5;
}
#endif

/*
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  data->progress.lastshow = 0;
  rc = Curl_pgrsUpdate(data); /* the final (forced) update */
  if(rc)
    return rc;

  if(!(data->progress.flags & PGRS_HIDE) &&
     !data->progress.callback)
    /* only output if we don't use a progress callback and we're not
     * hidden */
    fprintf(data->set.err, "\n");

  data->progress.speeder_c = 0; /* reset the progress meter display */
  return 0;
}








|







136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  data->progress.lastshow = 0;
  rc = Curl_pgrsUpdate(data); /* the final (forced) update */
  if(rc)
    return rc;

  if(!(data->progress.flags & PGRS_HIDE) &&
     !data->progress.callback)
    /* only output if we do not use a progress callback and we are not
     * hidden */
    fprintf(data->set.err, "\n");

  data->progress.speeder_c = 0; /* reset the progress meter display */
  return 0;
}

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    break;
  case TIMER_PRETRANSFER:
    delta = &data->progress.t_pretransfer;
    break;
  case TIMER_STARTTRANSFER:
    delta = &data->progress.t_starttransfer;
    /* prevent updating t_starttransfer unless:
     *   1) this is the first time we're setting t_starttransfer
     *   2) a redirect has occurred since the last time t_starttransfer was set
     * This prevents repeated invocations of the function from incorrectly
     * changing the t_starttransfer time.
     */
    if(data->progress.is_t_startransfer_set) {
      return;
    }







|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    break;
  case TIMER_PRETRANSFER:
    delta = &data->progress.t_pretransfer;
    break;
  case TIMER_STARTTRANSFER:
    delta = &data->progress.t_starttransfer;
    /* prevent updating t_starttransfer unless:
     *   1) this is the first time we are setting t_starttransfer
     *   2) a redirect has occurred since the last time t_starttransfer was set
     * This prevents repeated invocations of the function from incorrectly
     * changing the t_starttransfer time.
     */
    if(data->progress.is_t_startransfer_set) {
      return;
    }
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  /* clear all bits except HIDE and HEADERS_OUT */
  data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
  Curl_ratelimit(data, data->progress.start);
}

/*
 * This is used to handle speed limits, calculating how many milliseconds to
 * wait until we're back under the speed limit, if needed.
 *
 * The way it works is by having a "starting point" (time & amount of data
 * transferred by then) used in the speed computation, to be used instead of
 * the start of the transfer.  This starting point is regularly moved as
 * transfer goes on, to keep getting accurate values (instead of average over
 * the entire transfer).
 *
 * This function takes the current amount of data transferred, the amount at
 * the starting point, the limit (in bytes/s), the time of the starting point
 * and the current time.
 *







|



|







261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  /* clear all bits except HIDE and HEADERS_OUT */
  data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
  Curl_ratelimit(data, data->progress.start);
}

/*
 * This is used to handle speed limits, calculating how many milliseconds to
 * wait until we are back under the speed limit, if needed.
 *
 * The way it works is by having a "starting point" (time & amount of data
 * transferred by then) used in the speed computation, to be used instead of
 * the start of the transfer. This starting point is regularly moved as
 * transfer goes on, to keep getting accurate values (instead of average over
 * the entire transfer).
 *
 * This function takes the current amount of data transferred, the amount at
 * the starting point, the limit (in bytes/s), the time of the starting point
 * and the current time.
 *
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
}

/*
 * Update the timestamp and sizestamp to use for rate limit calculations.
 */
void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
{
  /* don't set a new stamp unless the time since last update is long enough */
  if(data->set.max_recv_speed) {
    if(Curl_timediff(now, data->progress.dl_limit_start) >=
       MIN_RATE_LIMIT_PERIOD) {
      data->progress.dl_limit_start = now;
      data->progress.dl_limit_size = data->progress.downloaded;
    }
  }







|







332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
}

/*
 * Update the timestamp and sizestamp to use for rate limit calculations.
 */
void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
{
  /* do not set a new stamp unless the time since last update is long enough */
  if(data->set.max_recv_speed) {
    if(Curl_timediff(now, data->progress.dl_limit_start) >=
       MIN_RATE_LIMIT_PERIOD) {
      data->progress.dl_limit_start = now;
      data->progress.dl_limit_size = data->progress.downloaded;
    }
  }
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    return (size * 1000000) / us;
  else if(us >= 1000000)
    return size / (us / 1000000);
  else
    return CURL_OFF_T_MAX;
}

/* returns TRUE if it's time to show the progress meter */
static bool progress_calc(struct Curl_easy *data, struct curltime now)
{
  bool timetoshow = FALSE;
  struct Progress * const p = &data->progress;

  /* The time spent so far (from the start) in microseconds */
  p->timespent = Curl_timediff_us(now, p->start);







|







395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    return (size * 1000000) / us;
  else if(us >= 1000000)
    return size / (us / 1000000);
  else
    return CURL_OFF_T_MAX;
}

/* returns TRUE if it is time to show the progress meter */
static bool progress_calc(struct Curl_easy *data, struct curltime now)
{
  bool timetoshow = FALSE;
  struct Progress * const p = &data->progress;

  /* The time spent so far (from the start) in microseconds */
  p->timespent = Curl_timediff_us(now, p->start);
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
    /* advance our speeder_c counter, which is increased every time we get
       here and we expect it to never wrap as 2^32 is a lot of seconds! */
    p->speeder_c++;

    /* figure out how many index entries of data we have stored in our speeder
       array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
       transfer. Imagine, after one second we have filled in two entries,
       after two seconds we've filled in three entries etc. */
    countindex = ((p->speeder_c >= CURR_TIME)? CURR_TIME:p->speeder_c) - 1;

    /* first of all, we don't do this if there's no counted seconds yet */
    if(countindex) {
      int checkindex;
      timediff_t span_ms;
      curl_off_t amount;

      /* Get the index position to compare with the 'nowindex' position.
         Get the oldest entry possible. While we have less than CURR_TIME







|


|







427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
    /* advance our speeder_c counter, which is increased every time we get
       here and we expect it to never wrap as 2^32 is a lot of seconds! */
    p->speeder_c++;

    /* figure out how many index entries of data we have stored in our speeder
       array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
       transfer. Imagine, after one second we have filled in two entries,
       after two seconds we have filled in three entries etc. */
    countindex = ((p->speeder_c >= CURR_TIME)? CURR_TIME:p->speeder_c) - 1;

    /* first of all, we do not do this if there is no counted seconds yet */
    if(countindex) {
      int checkindex;
      timediff_t span_ms;
      curl_off_t amount;

      /* Get the index position to compare with the 'nowindex' position.
         Get the oldest entry possible. While we have less than CURR_TIME
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
#endif


/*
 * Curl_pgrsUpdate() returns 0 for success or the value returned by the
 * progress callback!
 */
int Curl_pgrsUpdate(struct Curl_easy *data)
{
  struct curltime now = Curl_now(); /* what time is it */
  bool showprogress = progress_calc(data, now);
  if(!(data->progress.flags & PGRS_HIDE)) {
    if(data->set.fxferinfo) {
      int result;
      /* There's a callback set, call that */
      Curl_set_in_callback(data, true);
      result = data->set.fxferinfo(data->set.progress_client,
                                   data->progress.size_dl,
                                   data->progress.downloaded,
                                   data->progress.size_ul,
                                   data->progress.uploaded);
      Curl_set_in_callback(data, false);







|

<
<



|







583
584
585
586
587
588
589
590
591


592
593
594
595
596
597
598
599
600
601
602
#endif


/*
 * Curl_pgrsUpdate() returns 0 for success or the value returned by the
 * progress callback!
 */
static int pgrsupdate(struct Curl_easy *data, bool showprogress)
{


  if(!(data->progress.flags & PGRS_HIDE)) {
    if(data->set.fxferinfo) {
      int result;
      /* There is a callback set, call that */
      Curl_set_in_callback(data, true);
      result = data->set.fxferinfo(data->set.progress_client,
                                   data->progress.size_dl,
                                   data->progress.downloaded,
                                   data->progress.size_ul,
                                   data->progress.uploaded);
      Curl_set_in_callback(data, false);
627
628
629
630
631
632
633

















    if(showprogress)
      progress_meter(data);
  }

  return 0;
}























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647

    if(showprogress)
      progress_meter(data);
  }

  return 0;
}

int Curl_pgrsUpdate(struct Curl_easy *data)
{
  struct curltime now = Curl_now(); /* what time is it */
  bool showprogress = progress_calc(data, now);
  return pgrsupdate(data, showprogress);
}

/*
 * Update all progress, do not do progress meter/callbacks.
 */
void Curl_pgrsUpdate_nometer(struct Curl_easy *data)
{
  struct curltime now = Curl_now(); /* what time is it */
  (void)progress_calc(data, now);
}
Changes to jni/curl/lib/progress.h.
50
51
52
53
54
55
56


57
58
59
60
61
62
63

/* It is fine to not check the return code if 'size' is set to 0 */
CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);

void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
int Curl_pgrsUpdate(struct Curl_easy *data);


void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer);
timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
                                  curl_off_t startsize,
                                  curl_off_t limit,
                                  struct curltime start,
                                  struct curltime now);







>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

/* It is fine to not check the return code if 'size' is set to 0 */
CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);

void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
int Curl_pgrsUpdate(struct Curl_easy *data);
void Curl_pgrsUpdate_nometer(struct Curl_easy *data);

void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer);
timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
                                  curl_off_t startsize,
                                  curl_off_t limit,
                                  struct curltime start,
                                  struct curltime now);
Changes to jni/curl/lib/rand.c.
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
{
  CURLcode result = CURLE_OK;
  static unsigned int randseed;
  static bool seeded = FALSE;

#ifdef CURLDEBUG
  char *force_entropy = getenv("CURL_ENTROPY");
  if(force_entropy) {
    if(!seeded) {
      unsigned int seed = 0;
      size_t elen = strlen(force_entropy);
      size_t clen = sizeof(seed);
      size_t min = elen < clen ? elen : clen;







|







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
{
  CURLcode result = CURLE_OK;
  static unsigned int randseed;
  static bool seeded = FALSE;

#ifdef DEBUGBUILD
  char *force_entropy = getenv("CURL_ENTROPY");
  if(force_entropy) {
    if(!seeded) {
      unsigned int seed = 0;
      size_t elen = strlen(force_entropy);
      size_t clen = sizeof(seed);
      size_t min = elen < clen ? elen : clen;
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    *rnd = (unsigned int)arc4random();
    return CURLE_OK;
  }
#endif

#if defined(RANDOM_FILE) && !defined(_WIN32)
  if(!seeded) {
    /* if there's a random file to read a seed from, use it */
    int fd = open(RANDOM_FILE, O_RDONLY);
    if(fd > -1) {
      /* read random data into the randseed variable */
      ssize_t nread = read(fd, &randseed, sizeof(randseed));
      if(nread == sizeof(randseed))
        seeded = TRUE;
      close(fd);







|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    *rnd = (unsigned int)arc4random();
    return CURLE_OK;
  }
#endif

#if defined(RANDOM_FILE) && !defined(_WIN32)
  if(!seeded) {
    /* if there is a random file to read a seed from, use it */
    int fd = open(RANDOM_FILE, O_RDONLY);
    if(fd > -1) {
      /* read random data into the randseed variable */
      ssize_t nread = read(fd, &randseed, sizeof(randseed));
      if(nread == sizeof(randseed))
        seeded = TRUE;
      close(fd);
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
static const char alnum[] =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
                         size_t num)
{
  CURLcode result = CURLE_OK;
  const int alnumspace = sizeof(alnum) - 1;
  unsigned int r;
  DEBUGASSERT(num > 1);

  num--; /* save one for null-termination */

  while(num) {
    do {
      result = randit(data, &r);
      if(result)
        return result;
    } while(r >= (UINT_MAX - UINT_MAX % alnumspace));

    *rnd++ = alnum[r % alnumspace];
    num--;
  }
  *rnd = 0;

  return result;
}







|












|






278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
static const char alnum[] =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
                         size_t num)
{
  CURLcode result = CURLE_OK;
  const unsigned int alnumspace = sizeof(alnum) - 1;
  unsigned int r;
  DEBUGASSERT(num > 1);

  num--; /* save one for null-termination */

  while(num) {
    do {
      result = randit(data, &r);
      if(result)
        return result;
    } while(r >= (UINT_MAX - UINT_MAX % alnumspace));

    *rnd++ = (unsigned char)alnum[r % alnumspace];
    num--;
  }
  *rnd = 0;

  return result;
}
Changes to jni/curl/lib/rename.c.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "curl_memory.h"
#include "memdebug.h"

/* return 0 on success, 1 on error */
int Curl_rename(const char *oldpath, const char *newpath)
{
#ifdef _WIN32
  /* rename() on Windows doesn't overwrite, so we can't use it here.
     MoveFileEx() will overwrite and is usually atomic, however it fails
     when there are open handles to the file. */
  const int max_wait_ms = 1000;
  struct curltime start = Curl_now();
  TCHAR *tchar_oldpath = curlx_convert_UTF8_to_tchar((char *)oldpath);
  TCHAR *tchar_newpath = curlx_convert_UTF8_to_tchar((char *)newpath);
  for(;;) {







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "curl_memory.h"
#include "memdebug.h"

/* return 0 on success, 1 on error */
int Curl_rename(const char *oldpath, const char *newpath)
{
#ifdef _WIN32
  /* rename() on Windows does not overwrite, so we cannot use it here.
     MoveFileEx() will overwrite and is usually atomic, however it fails
     when there are open handles to the file. */
  const int max_wait_ms = 1000;
  struct curltime start = Curl_now();
  TCHAR *tchar_oldpath = curlx_convert_UTF8_to_tchar((char *)oldpath);
  TCHAR *tchar_newpath = curlx_convert_UTF8_to_tchar((char *)newpath);
  for(;;) {
Changes to jni/curl/lib/request.c.
50
51
52
53
54
55
56

57
58
59
60
61
62
63
{
  CURLcode result;

  req->done = FALSE;
  req->upload_done = FALSE;
  req->download_done = FALSE;
  req->ignorebody = FALSE;

  req->bytecount = 0;
  req->writebytecount = 0;
  req->header = TRUE; /* assume header */
  req->headerline = 0;
  req->headerbytecount = 0;
  req->allheadercount =  0;
  req->deductheadercount = 0;







>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
{
  CURLcode result;

  req->done = FALSE;
  req->upload_done = FALSE;
  req->download_done = FALSE;
  req->ignorebody = FALSE;
  req->shutdown = FALSE;
  req->bytecount = 0;
  req->writebytecount = 0;
  req->header = TRUE; /* assume header */
  req->headerline = 0;
  req->headerbytecount = 0;
  req->allheadercount =  0;
  req->deductheadercount = 0;
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158




159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210

void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
{
  struct curltime t0 = {0, 0};

  /* This is a bit ugly. `req->p` is a union and we assume we can
   * free this safely without leaks. */
  Curl_safefree(req->p.http);
  Curl_safefree(req->newurl);
  Curl_client_reset(data);
  if(req->sendbuf_init)
    Curl_bufq_reset(&req->sendbuf);

#ifndef CURL_DISABLE_DOH
  if(req->doh) {
    Curl_close(&req->doh->probe[0].easy);
    Curl_close(&req->doh->probe[1].easy);
  }
#endif
  /* Can no longer memset() this struct as we need to keep some state */
  req->size = -1;
  req->maxdownload = -1;
  req->bytecount = 0;
  req->writebytecount = 0;
  req->start = t0;
  req->headerbytecount = 0;
  req->allheadercount =  0;
  req->deductheadercount = 0;
  req->headerline = 0;
  req->offset = 0;
  req->httpcode = 0;
  req->keepon = 0;
  req->upgr101 = UPGR101_INIT;
  req->timeofdoc = 0;
  req->bodywrites = 0;
  req->location = NULL;
  req->newurl = NULL;
#ifndef CURL_DISABLE_COOKIES
  req->setcookies = 0;
#endif
  req->header = FALSE;
  req->content_range = FALSE;
  req->download_done = FALSE;
  req->eos_written = FALSE;
  req->eos_read = FALSE;
  req->upload_done = FALSE;
  req->upload_aborted = FALSE;
  req->ignorebody = FALSE;
  req->http_bodyless = FALSE;
  req->chunk = FALSE;
  req->ignore_cl = FALSE;
  req->upload_chunky = FALSE;
  req->getheader = FALSE;
  req->no_body = data->set.opt_no_body;
  req->authneg = FALSE;




}

void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
{
  /* This is a bit ugly. `req->p` is a union and we assume we can
   * free this safely without leaks. */
  Curl_safefree(req->p.http);
  Curl_safefree(req->newurl);
  if(req->sendbuf_init)
    Curl_bufq_free(&req->sendbuf);
  Curl_client_cleanup(data);

#ifndef CURL_DISABLE_DOH
  if(req->doh) {
    Curl_close(&req->doh->probe[0].easy);
    Curl_close(&req->doh->probe[1].easy);
    Curl_dyn_free(&req->doh->probe[0].serverdoh);
    Curl_dyn_free(&req->doh->probe[1].serverdoh);
    curl_slist_free_all(req->doh->headers);
    Curl_safefree(req->doh);
  }
#endif
}

static CURLcode xfer_send(struct Curl_easy *data,
                          const char *buf, size_t blen,
                          size_t hds_len, size_t *pnwritten)
{
  CURLcode result = CURLE_OK;

  *pnwritten = 0;
#ifdef CURLDEBUG
  {
    /* Allow debug builds to override this logic to force short initial
       sends
     */
    char *p = getenv("CURL_SMALLREQSEND");
    if(p) {
      size_t altsize = (size_t)strtoul(p, NULL, 10);
      if(altsize && altsize < blen)
        blen = altsize;
    }
  }
#endif
  /* Make sure this doesn't send more body bytes than what the max send
     speed says. The headers do not count to the max speed. */
  if(data->set.max_send_speed) {
    size_t body_bytes = blen - hds_len;
    if((curl_off_t)body_bytes > data->set.max_send_speed)
      blen = hds_len + (size_t)data->set.max_send_speed;
  }








|






<
|
<
<
















<




















>
>
>
>






|






<
<
<
<
<
<
|
<










|












|







105
106
107
108
109
110
111
112
113
114
115
116
117
118

119


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172






173

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
{
  struct curltime t0 = {0, 0};

  /* This is a bit ugly. `req->p` is a union and we assume we can
   * free this safely without leaks. */
  Curl_safefree(req->p.ftp);
  Curl_safefree(req->newurl);
  Curl_client_reset(data);
  if(req->sendbuf_init)
    Curl_bufq_reset(&req->sendbuf);

#ifndef CURL_DISABLE_DOH

  Curl_doh_close(data);


#endif
  /* Can no longer memset() this struct as we need to keep some state */
  req->size = -1;
  req->maxdownload = -1;
  req->bytecount = 0;
  req->writebytecount = 0;
  req->start = t0;
  req->headerbytecount = 0;
  req->allheadercount =  0;
  req->deductheadercount = 0;
  req->headerline = 0;
  req->offset = 0;
  req->httpcode = 0;
  req->keepon = 0;
  req->upgr101 = UPGR101_INIT;
  req->timeofdoc = 0;

  req->location = NULL;
  req->newurl = NULL;
#ifndef CURL_DISABLE_COOKIES
  req->setcookies = 0;
#endif
  req->header = FALSE;
  req->content_range = FALSE;
  req->download_done = FALSE;
  req->eos_written = FALSE;
  req->eos_read = FALSE;
  req->upload_done = FALSE;
  req->upload_aborted = FALSE;
  req->ignorebody = FALSE;
  req->http_bodyless = FALSE;
  req->chunk = FALSE;
  req->ignore_cl = FALSE;
  req->upload_chunky = FALSE;
  req->getheader = FALSE;
  req->no_body = data->set.opt_no_body;
  req->authneg = FALSE;
  req->shutdown = FALSE;
#ifdef USE_HYPER
  req->bodywritten = FALSE;
#endif
}

void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
{
  /* This is a bit ugly. `req->p` is a union and we assume we can
   * free this safely without leaks. */
  Curl_safefree(req->p.ftp);
  Curl_safefree(req->newurl);
  if(req->sendbuf_init)
    Curl_bufq_free(&req->sendbuf);
  Curl_client_cleanup(data);

#ifndef CURL_DISABLE_DOH






  Curl_doh_cleanup(data);

#endif
}

static CURLcode xfer_send(struct Curl_easy *data,
                          const char *buf, size_t blen,
                          size_t hds_len, size_t *pnwritten)
{
  CURLcode result = CURLE_OK;

  *pnwritten = 0;
#ifdef DEBUGBUILD
  {
    /* Allow debug builds to override this logic to force short initial
       sends
     */
    char *p = getenv("CURL_SMALLREQSEND");
    if(p) {
      size_t altsize = (size_t)strtoul(p, NULL, 10);
      if(altsize && altsize < blen)
        blen = altsize;
    }
  }
#endif
  /* Make sure this does not send more body bytes than what the max send
     speed says. The headers do not count to the max speed. */
  if(data->set.max_send_speed) {
    size_t body_bytes = blen - hds_len;
    if((curl_off_t)body_bytes > data->set.max_send_speed)
      blen = hds_len + (size_t)data->set.max_send_speed;
  }

247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  return result;
}

static CURLcode req_set_upload_done(struct Curl_easy *data)
{
  DEBUGASSERT(!data->req.upload_done);
  data->req.upload_done = TRUE;
  data->req.keepon &= ~(KEEP_SEND|KEEP_SEND_TIMED); /* we're done sending */

  Curl_creader_done(data, data->req.upload_aborted);

  if(data->req.upload_aborted) {
    if(data->req.writebytecount)
      infof(data, "abort upload after having sent %" CURL_FORMAT_CURL_OFF_T
            " bytes", data->req.writebytecount);







|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  return result;
}

static CURLcode req_set_upload_done(struct Curl_easy *data)
{
  DEBUGASSERT(!data->req.upload_done);
  data->req.upload_done = TRUE;
  data->req.keepon &= ~(KEEP_SEND|KEEP_SEND_TIMED); /* we are done sending */

  Curl_creader_done(data, data->req.upload_aborted);

  if(data->req.upload_aborted) {
    if(data->req.writebytecount)
      infof(data, "abort upload after having sent %" CURL_FORMAT_CURL_OFF_T
            " bytes", data->req.writebytecount);
287
288
289
290
291
292
293








294
295
296
297
298
299
300
    if(!Curl_bufq_is_empty(&data->req.sendbuf)) {
      return CURLE_AGAIN;
    }
  }

  if(!data->req.upload_done && data->req.eos_read &&
     Curl_bufq_is_empty(&data->req.sendbuf)) {








    return req_set_upload_done(data);
  }
  return CURLE_OK;
}

static ssize_t add_from_client(void *reader_ctx,
                               unsigned char *buf, size_t buflen,







>
>
>
>
>
>
>
>







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
    if(!Curl_bufq_is_empty(&data->req.sendbuf)) {
      return CURLE_AGAIN;
    }
  }

  if(!data->req.upload_done && data->req.eos_read &&
     Curl_bufq_is_empty(&data->req.sendbuf)) {
    if(data->req.shutdown) {
      bool done;
      result = Curl_xfer_send_shutdown(data, &done);
      if(result)
        return result;
      if(!done)
        return CURLE_AGAIN;
    }
    return req_set_upload_done(data);
  }
  return CURLE_OK;
}

static ssize_t add_from_client(void *reader_ctx,
                               unsigned char *buf, size_t buflen,
Changes to jni/curl/lib/request.h.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  UPGR101_H2,                 /* upgrade to HTTP/2 requested */
  UPGR101_RECEIVED,           /* 101 response received */
  UPGR101_WORKING             /* talking upgraded protocol */
};


/*
 * Request specific data in the easy handle (Curl_easy).  Previously,
 * these members were on the connectdata struct but since a conn struct may
 * now be shared between different Curl_easys, we store connection-specific
 * data here. This struct only keeps stuff that's interesting for *this*
 * request, as it will be cleared between multiple ones
 */
struct SingleRequest {
  curl_off_t size;        /* -1 if unknown at this point */
  curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
                             -1 means unlimited */
  curl_off_t bytecount;         /* total number of bytes read */
  curl_off_t writebytecount;    /* number of bytes written */

  struct curltime start;         /* transfer started at this time */
  unsigned int headerbytecount;  /* received server headers (not CONNECT
                                    headers) */
  unsigned int allheadercount;   /* all received headers (server + CONNECT) */
  unsigned int deductheadercount; /* this amount of bytes doesn't count when
                                     we check if anything has been transferred
                                     at the end of a connection. We use this
                                     counter to make only a 100 reply (without
                                     a following second response code) result
                                     in a CURLE_GOT_NOTHING error code */
  int headerline;               /* counts header lines to better track the
                                   first one */







|


|













|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  UPGR101_H2,                 /* upgrade to HTTP/2 requested */
  UPGR101_RECEIVED,           /* 101 response received */
  UPGR101_WORKING             /* talking upgraded protocol */
};


/*
 * Request specific data in the easy handle (Curl_easy). Previously,
 * these members were on the connectdata struct but since a conn struct may
 * now be shared between different Curl_easys, we store connection-specific
 * data here. This struct only keeps stuff that is interesting for *this*
 * request, as it will be cleared between multiple ones
 */
struct SingleRequest {
  curl_off_t size;        /* -1 if unknown at this point */
  curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
                             -1 means unlimited */
  curl_off_t bytecount;         /* total number of bytes read */
  curl_off_t writebytecount;    /* number of bytes written */

  struct curltime start;         /* transfer started at this time */
  unsigned int headerbytecount;  /* received server headers (not CONNECT
                                    headers) */
  unsigned int allheadercount;   /* all received headers (server + CONNECT) */
  unsigned int deductheadercount; /* this amount of bytes does not count when
                                     we check if anything has been transferred
                                     at the end of a connection. We use this
                                     counter to make only a 100 reply (without
                                     a following second response code) result
                                     in a CURLE_GOT_NOTHING error code */
  int headerline;               /* counts header lines to better track the
                                   first one */
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  struct Curl_cwriter *writer_stack;
  /* Client Reader stack, handles transfer- and content-encodings, protocol
   * checks, pausing by client callbacks. */
  struct Curl_creader *reader_stack;
  struct bufq sendbuf; /* data which needs to be send to the server */
  size_t sendbuf_hds_len; /* amount of header bytes in sendbuf */
  time_t timeofdoc;
  long bodywrites;
  char *location;   /* This points to an allocated version of the Location:
                       header data */
  char *newurl;     /* Set to the new URL to use when a redirect or a retry is
                       wanted */

  /* Allocated protocol-specific data. Each protocol handler makes sure this
     points to data it needs. */
  union {
    struct FILEPROTO *file;
    struct FTP *ftp;
    struct HTTP *http;
    struct IMAP *imap;
    struct ldapreqinfo *ldap;
    struct MQTT *mqtt;
    struct POP3 *pop3;
    struct RTSP *rtsp;
    struct smb_request *smb;
    struct SMTP *smtp;







<










<







89
90
91
92
93
94
95

96
97
98
99
100
101
102
103
104
105

106
107
108
109
110
111
112
  struct Curl_cwriter *writer_stack;
  /* Client Reader stack, handles transfer- and content-encodings, protocol
   * checks, pausing by client callbacks. */
  struct Curl_creader *reader_stack;
  struct bufq sendbuf; /* data which needs to be send to the server */
  size_t sendbuf_hds_len; /* amount of header bytes in sendbuf */
  time_t timeofdoc;

  char *location;   /* This points to an allocated version of the Location:
                       header data */
  char *newurl;     /* Set to the new URL to use when a redirect or a retry is
                       wanted */

  /* Allocated protocol-specific data. Each protocol handler makes sure this
     points to data it needs. */
  union {
    struct FILEPROTO *file;
    struct FTP *ftp;

    struct IMAP *imap;
    struct ldapreqinfo *ldap;
    struct MQTT *mqtt;
    struct POP3 *pop3;
    struct RTSP *rtsp;
    struct smb_request *smb;
    struct SMTP *smtp;
143
144
145
146
147
148
149




150
151
152
153
154
155
156
  BIT(getheader);    /* TRUE if header parsing is wanted */
  BIT(no_body);      /* the response has no body */
  BIT(authneg);      /* TRUE when the auth phase has started, which means
                        that we are creating a request with an auth header,
                        but it is not the final request in the auth
                        negotiation. */
  BIT(sendbuf_init); /* sendbuf is initialized */




};

/**
 * Initialize the state of the request for first use.
 */
void Curl_req_init(struct SingleRequest *req);








>
>
>
>







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  BIT(getheader);    /* TRUE if header parsing is wanted */
  BIT(no_body);      /* the response has no body */
  BIT(authneg);      /* TRUE when the auth phase has started, which means
                        that we are creating a request with an auth header,
                        but it is not the final request in the auth
                        negotiation. */
  BIT(sendbuf_init); /* sendbuf is initialized */
  BIT(shutdown);     /* request end will shutdown connection */
#ifdef USE_HYPER
  BIT(bodywritten);
#endif
};

/**
 * Initialize the state of the request for first use.
 */
void Curl_req_init(struct SingleRequest *req);

Changes to jni/curl/lib/rtsp.c.
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
                                      struct connectdata *conn);
static unsigned int rtsp_conncheck(struct Curl_easy *data,
                                   struct connectdata *check,
                                   unsigned int checks_to_perform);

/* this returns the socket to wait for in the DO and DOING state for the multi
   interface and then we're always _sending_ a request and thus we wait for
   the single socket to become writable only */
static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
                           curl_socket_t *socks)
{
  /* write mode */
  (void)data;
  socks[0] = conn->sock[FIRSTSOCKET];







|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
                                      struct connectdata *conn);
static unsigned int rtsp_conncheck(struct Curl_easy *data,
                                   struct connectdata *check,
                                   unsigned int checks_to_perform);

/* this returns the socket to wait for in the DO and DOING state for the multi
   interface and then we are always _sending_ a request and thus we wait for
   the single socket to become writable only */
static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
                           curl_socket_t *socks)
{
  /* write mode */
  (void)data;
  socks[0] = conn->sock[FIRSTSOCKET];
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
    data->state.first_remote_protocol = conn->handler->protocol;
  }

  /* Setup the 'p_request' pointer to the proper p_request string
   * Since all RTSP requests are included here, there is no need to
   * support custom requests like HTTP.
   **/
  data->req.no_body = TRUE; /* most requests don't contain a body */
  switch(rtspreq) {
  default:
    failf(data, "Got invalid RTSP request");
    return CURLE_BAD_FUNCTION_ARGUMENT;
  case RTSPREQ_OPTIONS:
    p_request = "OPTIONS";
    break;







|







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
    data->state.first_remote_protocol = conn->handler->protocol;
  }

  /* Setup the 'p_request' pointer to the proper p_request string
   * Since all RTSP requests are included here, there is no need to
   * support custom requests like HTTP.
   **/
  data->req.no_body = TRUE; /* most requests do not contain a body */
  switch(rtspreq) {
  default:
    failf(data, "Got invalid RTSP request");
    return CURLE_BAD_FUNCTION_ARGUMENT;
  case RTSPREQ_OPTIONS:
    p_request = "OPTIONS";
    break;
306
307
308
309
310
311
312
313
314
315
316
317
318

319

320
321
322
323
324
325
326
    break;
  case RTSPREQ_LAST:
    failf(data, "Got invalid RTSP request: RTSPREQ_LAST");
    return CURLE_BAD_FUNCTION_ARGUMENT;
  }

  if(rtspreq == RTSPREQ_RECEIVE) {
    Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, -1);
    goto out;
  }

  p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
  if(!p_session_id &&

     (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {

    failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
          p_request);
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    goto out;
  }

  /* Stream URI. Default to server '*' if not specified */







|





>
|
>







306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
    break;
  case RTSPREQ_LAST:
    failf(data, "Got invalid RTSP request: RTSPREQ_LAST");
    return CURLE_BAD_FUNCTION_ARGUMENT;
  }

  if(rtspreq == RTSPREQ_RECEIVE) {
    Curl_xfer_setup1(data, CURL_XFER_RECV, -1, TRUE);
    goto out;
  }

  p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
  if(!p_session_id &&
     (rtspreq & ~(Curl_RtspReq)(RTSPREQ_OPTIONS |
                                RTSPREQ_DESCRIBE |
                                RTSPREQ_SETUP))) {
    failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
          p_request);
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    goto out;
  }

  /* Stream URI. Default to server '*' if not specified */
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  }

  /* Finish the request buffer */
  result = Curl_dyn_add(&req_buffer, "\r\n");
  if(result)
    goto out;

  Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);

  /* issue the request */
  result = Curl_req_send(data, &req_buffer);
  if(result) {
    failf(data, "Failed sending RTSP request");
    goto out;
  }







|







574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
  }

  /* Finish the request buffer */
  result = Curl_dyn_add(&req_buffer, "\r\n");
  if(result)
    goto out;

  Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);

  /* issue the request */
  result = Curl_req_send(data, &req_buffer);
  if(result) {
    failf(data, "Failed sending RTSP request");
    goto out;
  }
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
      failf(data, "Got a blank Session ID");
      return CURLE_RTSP_SESSION_ERROR;
    }

    /* Find the end of Session ID
     *
     * Allow any non whitespace content, up to the field separator or end of
     * line. RFC 2326 isn't 100% clear on the session ID and for example
     * gstreamer does url-encoded session ID's not covered by the standard.
     */
    end = start;
    while(*end && *end != ';' && !ISSPACE(*end))
      end++;
    idlen = end - start;








|







948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
      failf(data, "Got a blank Session ID");
      return CURLE_RTSP_SESSION_ERROR;
    }

    /* Find the end of Session ID
     *
     * Allow any non whitespace content, up to the field separator or end of
     * line. RFC 2326 is not 100% clear on the session ID and for example
     * gstreamer does url-encoded session ID's not covered by the standard.
     */
    end = start;
    while(*end && *end != ';' && !ISSPACE(*end))
      end++;
    idlen = end - start;

Changes to jni/curl/lib/rtsp.h.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  BIT(in_header);
};

/****************************************************************************
 * RTSP unique setup
 ***************************************************************************/
struct RTSP {
  /*
   * http_wrapper MUST be the first element of this structure for the wrap
   * logic to work. In this way, we get a cheap polymorphism because
   * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec
   *
   * HTTP functions can safely treat this as an HTTP struct, but RTSP aware
   * functions can also index into the later elements.
   */
  struct HTTP http_wrapper; /* wrap HTTP to do the heavy lifting */

  long CSeq_sent; /* CSeq of this request */
  long CSeq_recv; /* CSeq received */
};


#endif /* HEADER_CURL_RTSP_H */







<
<
<
<
<
<
<
<
<
<






58
59
60
61
62
63
64










65
66
67
68
69
70
  BIT(in_header);
};

/****************************************************************************
 * RTSP unique setup
 ***************************************************************************/
struct RTSP {










  long CSeq_sent; /* CSeq of this request */
  long CSeq_recv; /* CSeq received */
};


#endif /* HEADER_CURL_RTSP_H */
Changes to jni/curl/lib/select.c.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49




50
51
52
53
54
55
56
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#elif defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
#error "We can't compile without select() or poll() support."
#endif

#ifdef MSDOS
#include <dos.h>  /* delay() */
#endif

#include <curl/curl.h>

#include "urldata.h"
#include "connect.h"
#include "select.h"
#include "timediff.h"
#include "warnless.h"





/*
 * Internal function used for waiting a specific amount of ms
 * in Curl_socket_check() and Curl_poll() when no file descriptor
 * is provided to wait on, just being used to delay execution.
 * WinSock select() and poll() timeout mechanisms need a valid
 * socket descriptor in a not null file descriptor set to work.







|













>
>
>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#elif defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
#error "We cannot compile without select() or poll() support."
#endif

#ifdef MSDOS
#include <dos.h>  /* delay() */
#endif

#include <curl/curl.h>

#include "urldata.h"
#include "connect.h"
#include "select.h"
#include "timediff.h"
#include "warnless.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

/*
 * Internal function used for waiting a specific amount of ms
 * in Curl_socket_check() and Curl_poll() when no file descriptor
 * is provided to wait on, just being used to delay execution.
 * WinSock select() and poll() timeout mechanisms need a valid
 * socket descriptor in a not null file descriptor set to work.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#if defined(MSDOS)
  delay(timeout_ms);
#elif defined(_WIN32)
  /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
#if TIMEDIFF_T_MAX >= ULONG_MAX
  if(timeout_ms >= ULONG_MAX)
    timeout_ms = ULONG_MAX-1;
    /* don't use ULONG_MAX, because that is equal to INFINITE */
#endif
  Sleep((ULONG)timeout_ms);
#else
#if defined(HAVE_POLL_FINE)
  /* prevent overflow, timeout_ms is typecast to int. */
#if TIMEDIFF_T_MAX > INT_MAX
  if(timeout_ms > INT_MAX)







|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#if defined(MSDOS)
  delay(timeout_ms);
#elif defined(_WIN32)
  /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
#if TIMEDIFF_T_MAX >= ULONG_MAX
  if(timeout_ms >= ULONG_MAX)
    timeout_ms = ULONG_MAX-1;
    /* do not use ULONG_MAX, because that is equal to INFINITE */
#endif
  Sleep((ULONG)timeout_ms);
#else
#if defined(HAVE_POLL_FINE)
  /* prevent overflow, timeout_ms is typecast to int. */
#if TIMEDIFF_T_MAX > INT_MAX
  if(timeout_ms > INT_MAX)
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
                      fd_set *fds_err,       /* sockets with errors */
                      timediff_t timeout_ms) /* milliseconds to wait */
{
  struct timeval pending_tv;
  struct timeval *ptimeout;

#ifdef USE_WINSOCK
  /* WinSock select() can't handle zero events.  See the comment below. */
  if((!fds_read || fds_read->fd_count == 0) &&
     (!fds_write || fds_write->fd_count == 0) &&
     (!fds_err || fds_err->fd_count == 0)) {
    /* no sockets, just wait */
    return Curl_wait_ms(timeout_ms);
  }
#endif

  ptimeout = curlx_mstotv(&pending_tv, timeout_ms);

#ifdef USE_WINSOCK
  /* WinSock select() must not be called with an fd_set that contains zero
    fd flags, or it will return WSAEINVAL.  But, it also can't be called
    with no fd_sets at all!  From the documentation:

    Any two of the parameters, readfds, writefds, or exceptfds, can be
    given as null. At least one must be non-null, and any non-null
    descriptor set must contain at least one handle to a socket.

    It is unclear why WinSock doesn't just handle this for us instead of
    calling this an error. Luckily, with WinSock, we can _also_ ask how
    many bits are set on an fd_set. So, let's just check it beforehand.
  */
  return select((int)maxfd + 1,
                fds_read && fds_read->fd_count ? fds_read : NULL,
                fds_write && fds_write->fd_count ? fds_write : NULL,
                fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
#else
  return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
#endif
}

#endif

/*
 * Wait for read or write events on a set of file descriptors. It uses poll()
 * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
 * otherwise select() is used.  An error is returned if select() is being used
 * and a file descriptor is too large for FD_SETSIZE.
 *
 * A negative timeout value makes this function wait indefinitely,
 * unless no valid file descriptor is given, when this happens the
 * negative timeout is ignored and the function times out immediately.
 *
 * Return values:







|












|






|

















|







131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
                      fd_set *fds_err,       /* sockets with errors */
                      timediff_t timeout_ms) /* milliseconds to wait */
{
  struct timeval pending_tv;
  struct timeval *ptimeout;

#ifdef USE_WINSOCK
  /* WinSock select() cannot handle zero events. See the comment below. */
  if((!fds_read || fds_read->fd_count == 0) &&
     (!fds_write || fds_write->fd_count == 0) &&
     (!fds_err || fds_err->fd_count == 0)) {
    /* no sockets, just wait */
    return Curl_wait_ms(timeout_ms);
  }
#endif

  ptimeout = curlx_mstotv(&pending_tv, timeout_ms);

#ifdef USE_WINSOCK
  /* WinSock select() must not be called with an fd_set that contains zero
    fd flags, or it will return WSAEINVAL. But, it also cannot be called
    with no fd_sets at all!  From the documentation:

    Any two of the parameters, readfds, writefds, or exceptfds, can be
    given as null. At least one must be non-null, and any non-null
    descriptor set must contain at least one handle to a socket.

    It is unclear why WinSock does not just handle this for us instead of
    calling this an error. Luckily, with WinSock, we can _also_ ask how
    many bits are set on an fd_set. So, let's just check it beforehand.
  */
  return select((int)maxfd + 1,
                fds_read && fds_read->fd_count ? fds_read : NULL,
                fds_write && fds_write->fd_count ? fds_write : NULL,
                fds_err && fds_err->fd_count ? fds_err : NULL, ptimeout);
#else
  return select((int)maxfd + 1, fds_read, fds_write, fds_err, ptimeout);
#endif
}

#endif

/*
 * Wait for read or write events on a set of file descriptors. It uses poll()
 * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
 * otherwise select() is used. An error is returned if select() is being used
 * and a file descriptor is too large for FD_SETSIZE.
 *
 * A negative timeout value makes this function wait indefinitely,
 * unless no valid file descriptor is given, when this happens the
 * negative timeout is ignored and the function times out immediately.
 *
 * Return values:
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  if(writefd != CURL_SOCKET_BAD) {
    pfd[num].fd = writefd;
    pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI;
    pfd[num].revents = 0;
    num++;
  }

  r = Curl_poll(pfd, num, timeout_ms);
  if(r <= 0)
    return r;

  r = 0;
  num = 0;
  if(readfd0 != CURL_SOCKET_BAD) {
    if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))







|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  if(writefd != CURL_SOCKET_BAD) {
    pfd[num].fd = writefd;
    pfd[num].events = POLLWRNORM|POLLOUT|POLLPRI;
    pfd[num].revents = 0;
    num++;
  }

  r = Curl_poll(pfd, (unsigned int)num, timeout_ms);
  if(r <= 0)
    return r;

  r = 0;
  num = 0;
  if(readfd0 != CURL_SOCKET_BAD) {
    if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
      r |= CURL_CSELECT_ERR;
  }

  return r;
}

/*
 * This is a wrapper around poll().  If poll() does not exist, then
 * select() is used instead.  An error is returned if select() is
 * being used and a file descriptor is too large for FD_SETSIZE.
 * A negative timeout value makes this function wait indefinitely,
 * unless no valid file descriptor is given, when this happens the
 * negative timeout is ignored and the function times out immediately.
 *
 * Return values:
 *   -1 = system call error or fd >= FD_SETSIZE







|
|







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
      r |= CURL_CSELECT_ERR;
  }

  return r;
}

/*
 * This is a wrapper around poll(). If poll() does not exist, then
 * select() is used instead. An error is returned if select() is
 * being used and a file descriptor is too large for FD_SETSIZE.
 * A negative timeout value makes this function wait indefinitely,
 * unless no valid file descriptor is given, when this happens the
 * negative timeout is ignored and the function times out immediately.
 *
 * Return values:
 *   -1 = system call error or fd >= FD_SETSIZE
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
        FD_SET(ufds[i].fd, &fds_write);
      if(ufds[i].events & (POLLRDBAND|POLLPRI))
        FD_SET(ufds[i].fd, &fds_err);
    }
  }

  /*
     Note also that WinSock ignores the first argument, so we don't worry
     about the fact that maxfd is computed incorrectly with WinSock (since
     curl_socket_t is unsigned in such cases and thus -1 is the largest
     value).
  */
  r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
  if(r <= 0) {
    if((r == -1) && (SOCKERRNO == EINTR))







|







357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
        FD_SET(ufds[i].fd, &fds_write);
      if(ufds[i].events & (POLLRDBAND|POLLPRI))
        FD_SET(ufds[i].fd, &fds_err);
    }
  }

  /*
     Note also that WinSock ignores the first argument, so we do not worry
     about the fact that maxfd is computed incorrectly with WinSock (since
     curl_socket_t is unsigned in such cases and thus -1 is the largest
     value).
  */
  r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
  if(r <= 0) {
    if((r == -1) && (SOCKERRNO == EINTR))
397
398
399
400
401
402
403
















































































































































      r++;
  }

#endif  /* HAVE_POLL_FINE */

  return r;
}























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
      r++;
  }

#endif  /* HAVE_POLL_FINE */

  return r;
}

void Curl_pollfds_init(struct curl_pollfds *cpfds,
                       struct pollfd *static_pfds,
                       unsigned int static_count)
{
  DEBUGASSERT(cpfds);
  memset(cpfds, 0, sizeof(*cpfds));
  if(static_pfds && static_count) {
    cpfds->pfds = static_pfds;
    cpfds->count = static_count;
  }
}

void Curl_pollfds_cleanup(struct curl_pollfds *cpfds)
{
  DEBUGASSERT(cpfds);
  if(cpfds->allocated_pfds) {
    free(cpfds->pfds);
  }
  memset(cpfds, 0, sizeof(*cpfds));
}

static CURLcode cpfds_increase(struct curl_pollfds *cpfds, unsigned int inc)
{
  struct pollfd *new_fds;
  unsigned int new_count = cpfds->count + inc;

  new_fds = calloc(new_count, sizeof(struct pollfd));
  if(!new_fds)
    return CURLE_OUT_OF_MEMORY;

  memcpy(new_fds, cpfds->pfds, cpfds->count * sizeof(struct pollfd));
  if(cpfds->allocated_pfds)
    free(cpfds->pfds);
  cpfds->pfds = new_fds;
  cpfds->count = new_count;
  cpfds->allocated_pfds = TRUE;
  return CURLE_OK;
}

static CURLcode cpfds_add_sock(struct curl_pollfds *cpfds,
                               curl_socket_t sock, short events, bool fold)
{
  int i;

  if(fold && cpfds->n <= INT_MAX) {
    for(i = (int)cpfds->n - 1; i >= 0; --i) {
      if(sock == cpfds->pfds[i].fd) {
        cpfds->pfds[i].events |= events;
        return CURLE_OK;
      }
    }
  }
  /* not folded, add new entry */
  if(cpfds->n >= cpfds->count) {
    if(cpfds_increase(cpfds, 100))
      return CURLE_OUT_OF_MEMORY;
  }
  cpfds->pfds[cpfds->n].fd = sock;
  cpfds->pfds[cpfds->n].events = events;
  ++cpfds->n;
  return CURLE_OK;
}

CURLcode Curl_pollfds_add_sock(struct curl_pollfds *cpfds,
                               curl_socket_t sock, short events)
{
  return cpfds_add_sock(cpfds, sock, events, FALSE);
}

CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
                             struct easy_pollset *ps)
{
  size_t i;

  DEBUGASSERT(cpfds);
  DEBUGASSERT(ps);
  for(i = 0; i < ps->num; i++) {
    short events = 0;
    if(ps->actions[i] & CURL_POLL_IN)
      events |= POLLIN;
    if(ps->actions[i] & CURL_POLL_OUT)
      events |= POLLOUT;
    if(events) {
      if(cpfds_add_sock(cpfds, ps->sockets[i], events, TRUE))
        return CURLE_OUT_OF_MEMORY;
    }
  }
  return CURLE_OK;
}

void Curl_waitfds_init(struct curl_waitfds *cwfds,
                       struct curl_waitfd *static_wfds,
                       unsigned int static_count)
{
  DEBUGASSERT(cwfds);
  DEBUGASSERT(static_wfds);
  memset(cwfds, 0, sizeof(*cwfds));
  cwfds->wfds = static_wfds;
  cwfds->count = static_count;
}

static CURLcode cwfds_add_sock(struct curl_waitfds *cwfds,
                               curl_socket_t sock, short events)
{
  int i;

  if(cwfds->n <= INT_MAX) {
    for(i = (int)cwfds->n - 1; i >= 0; --i) {
      if(sock == cwfds->wfds[i].fd) {
        cwfds->wfds[i].events |= events;
        return CURLE_OK;
      }
    }
  }
  /* not folded, add new entry */
  if(cwfds->n >= cwfds->count)
    return CURLE_OUT_OF_MEMORY;
  cwfds->wfds[cwfds->n].fd = sock;
  cwfds->wfds[cwfds->n].events = events;
  ++cwfds->n;
  return CURLE_OK;
}

CURLcode Curl_waitfds_add_ps(struct curl_waitfds *cwfds,
                             struct easy_pollset *ps)
{
  size_t i;

  DEBUGASSERT(cwfds);
  DEBUGASSERT(ps);
  for(i = 0; i < ps->num; i++) {
    short events = 0;
    if(ps->actions[i] & CURL_POLL_IN)
      events |= CURL_WAIT_POLLIN;
    if(ps->actions[i] & CURL_POLL_OUT)
      events |= CURL_WAIT_POLLOUT;
    if(events) {
      if(cwfds_add_sock(cwfds, ps->sockets[i], events))
        return CURLE_OUT_OF_MEMORY;
    }
  }
  return CURLE_OK;
}
Changes to jni/curl/lib/select.h.
106
107
108
109
110
111
112

































113
114
#define VERIFY_SOCK(x) do {                     \
    if(!VALID_SOCK(x) || !FDSET_SOCK(x)) {      \
      SET_SOCKERRNO(EINVAL);                    \
      return -1;                                \
    }                                           \
  } while(0)
#endif


































#endif /* HEADER_CURL_SELECT_H */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#define VERIFY_SOCK(x) do {                     \
    if(!VALID_SOCK(x) || !FDSET_SOCK(x)) {      \
      SET_SOCKERRNO(EINVAL);                    \
      return -1;                                \
    }                                           \
  } while(0)
#endif

struct curl_pollfds {
  struct pollfd *pfds;
  unsigned int n;
  unsigned int count;
  BIT(allocated_pfds);
};

void Curl_pollfds_init(struct curl_pollfds *cpfds,
                       struct pollfd *static_pfds,
                       unsigned int static_count);

void Curl_pollfds_cleanup(struct curl_pollfds *cpfds);

CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
                             struct easy_pollset *ps);

CURLcode Curl_pollfds_add_sock(struct curl_pollfds *cpfds,
                               curl_socket_t sock, short events);

struct curl_waitfds {
  struct curl_waitfd *wfds;
  unsigned int n;
  unsigned int count;
};

void Curl_waitfds_init(struct curl_waitfds *cwfds,
                       struct curl_waitfd *static_wfds,
                       unsigned int static_count);

CURLcode Curl_waitfds_add_ps(struct curl_waitfds *cwfds,
                             struct easy_pollset *ps);


#endif /* HEADER_CURL_SELECT_H */
Changes to jni/curl/lib/sendf.c.
285
286
287
288
289
290
291







292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311

312

313
314
315
316
317
318
319
      excess_len = nbytes - wmax;
      nwrite = wmax;
    }

    if(nwrite == wmax) {
      data->req.download_done = TRUE;
    }







  }

  /* Error on too large filesize is handled below, after writing
   * the permitted bytes */
  if(data->set.max_filesize) {
    size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
    if(nwrite > wmax) {
      nwrite = wmax;
    }
  }

  if(!data->req.ignorebody && (nwrite || (type & CLIENTWRITE_EOS))) {
    result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
    CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu) -> %d",
                   type, nbytes, result);
    if(result)
      return result;
  }
  /* Update stats, write and report progress */
  data->req.bytecount += nwrite;

  ++data->req.bodywrites;

  result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
  if(result)
    return result;

  if(excess_len) {
    if(!data->req.ignorebody) {
      infof(data,







>
>
>
>
>
>
>




















>
|
>







285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
      excess_len = nbytes - wmax;
      nwrite = wmax;
    }

    if(nwrite == wmax) {
      data->req.download_done = TRUE;
    }

    if((type & CLIENTWRITE_EOS) && !data->req.no_body &&
       (data->req.maxdownload > data->req.bytecount)) {
      failf(data, "end of response with %" CURL_FORMAT_CURL_OFF_T
            " bytes missing", data->req.maxdownload - data->req.bytecount);
      return CURLE_PARTIAL_FILE;
    }
  }

  /* Error on too large filesize is handled below, after writing
   * the permitted bytes */
  if(data->set.max_filesize) {
    size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
    if(nwrite > wmax) {
      nwrite = wmax;
    }
  }

  if(!data->req.ignorebody && (nwrite || (type & CLIENTWRITE_EOS))) {
    result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
    CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu) -> %d",
                   type, nbytes, result);
    if(result)
      return result;
  }
  /* Update stats, write and report progress */
  data->req.bytecount += nwrite;
#ifdef USE_HYPER
  data->req.bodywritten = TRUE;
#endif
  result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
  if(result)
    return result;

  if(excess_len) {
    if(!data->req.ignorebody) {
      infof(data,
592
593
594
595
596
597
598








599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617

618
619
620
621
622
623
624
CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
                                  struct Curl_creader *reader)
{
  (void)data;
  (void)reader;
  return CURLE_OK;
}









void Curl_creader_def_done(struct Curl_easy *data,
                           struct Curl_creader *reader, int premature)
{
  (void)data;
  (void)reader;
  (void)premature;
}

struct cr_in_ctx {
  struct Curl_creader super;
  curl_read_callback read_cb;
  void *cb_user_data;
  curl_off_t total_len;
  curl_off_t read_len;
  CURLcode error_result;
  BIT(seen_eos);
  BIT(errored);
  BIT(has_used_cb);

};

static CURLcode cr_in_init(struct Curl_easy *data, struct Curl_creader *reader)
{
  struct cr_in_ctx *ctx = reader->ctx;
  (void)data;
  ctx->read_cb = data->state.fread_func;







>
>
>
>
>
>
>
>



















>







601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
                                  struct Curl_creader *reader)
{
  (void)data;
  (void)reader;
  return CURLE_OK;
}

bool Curl_creader_def_is_paused(struct Curl_easy *data,
                                struct Curl_creader *reader)
{
  (void)data;
  (void)reader;
  return FALSE;
}

void Curl_creader_def_done(struct Curl_easy *data,
                           struct Curl_creader *reader, int premature)
{
  (void)data;
  (void)reader;
  (void)premature;
}

struct cr_in_ctx {
  struct Curl_creader super;
  curl_read_callback read_cb;
  void *cb_user_data;
  curl_off_t total_len;
  curl_off_t read_len;
  CURLcode error_result;
  BIT(seen_eos);
  BIT(errored);
  BIT(has_used_cb);
  BIT(is_paused);
};

static CURLcode cr_in_init(struct Curl_easy *data, struct Curl_creader *reader)
{
  struct cr_in_ctx *ctx = reader->ctx;
  (void)data;
  ctx->read_cb = data->state.fread_func;
632
633
634
635
636
637
638


639
640
641
642
643
644
645
static CURLcode cr_in_read(struct Curl_easy *data,
                           struct Curl_creader *reader,
                           char *buf, size_t blen,
                           size_t *pnread, bool *peos)
{
  struct cr_in_ctx *ctx = reader->ctx;
  size_t nread;



  /* Once we have errored, we will return the same error forever */
  if(ctx->errored) {
    *pnread = 0;
    *peos = FALSE;
    return ctx->error_result;
  }







>
>







650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
static CURLcode cr_in_read(struct Curl_easy *data,
                           struct Curl_creader *reader,
                           char *buf, size_t blen,
                           size_t *pnread, bool *peos)
{
  struct cr_in_ctx *ctx = reader->ctx;
  size_t nread;

  ctx->is_paused = FALSE;

  /* Once we have errored, we will return the same error forever */
  if(ctx->errored) {
    *pnread = 0;
    *peos = FALSE;
    return ctx->error_result;
  }
684
685
686
687
688
689
690
691
692
693
694
695
696


697
698
699
700
701
702
703
    ctx->errored = TRUE;
    ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
    return CURLE_ABORTED_BY_CALLBACK;

  case CURL_READFUNC_PAUSE:
    if(data->conn->handler->flags & PROTOPT_NONETWORK) {
      /* protocols that work without network cannot be paused. This is
         actually only FILE:// just now, and it can't pause since the transfer
         isn't done using the "normal" procedure. */
      failf(data, "Read callback asked for PAUSE when not supported");
      return CURLE_READ_ERROR;
    }
    /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */


    data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
    *pnread = 0;
    *peos = FALSE;
    break; /* nothing was read */

  default:
    if(nread > blen) {







|
|




>
>







704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
    ctx->errored = TRUE;
    ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
    return CURLE_ABORTED_BY_CALLBACK;

  case CURL_READFUNC_PAUSE:
    if(data->conn->handler->flags & PROTOPT_NONETWORK) {
      /* protocols that work without network cannot be paused. This is
         actually only FILE:// just now, and it cannot pause since the transfer
         is not done using the "normal" procedure. */
      failf(data, "Read callback asked for PAUSE when not supported");
      return CURLE_READ_ERROR;
    }
    /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
    CURL_TRC_READ(data, "cr_in_read, callback returned CURL_READFUNC_PAUSE");
    ctx->is_paused = TRUE;
    data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
    *pnread = 0;
    *peos = FALSE;
    break; /* nothing was read */

  default:
    if(nread > blen) {
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  if(seekerr != CURL_SEEKFUNC_OK) {
    curl_off_t passed = 0;

    if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
      failf(data, "Could not seek stream");
      return CURLE_READ_ERROR;
    }
    /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
    do {
      char scratch[4*1024];
      size_t readthisamountnow =
        (offset - passed > (curl_off_t)sizeof(scratch)) ?
        sizeof(scratch) :
        curlx_sotouz(offset - passed);
      size_t actuallyread;







|







782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
  if(seekerr != CURL_SEEKFUNC_OK) {
    curl_off_t passed = 0;

    if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
      failf(data, "Could not seek stream");
      return CURLE_READ_ERROR;
    }
    /* when seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
    do {
      char scratch[4*1024];
      size_t readthisamountnow =
        (offset - passed > (curl_off_t)sizeof(scratch)) ?
        sizeof(scratch) :
        curlx_sotouz(offset - passed);
      size_t actuallyread;
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
    ctx->total_len -= offset;

    if(ctx->total_len <= 0) {
      failf(data, "File already completely uploaded");
      return CURLE_PARTIAL_FILE;
    }
  }
  /* we've passed, proceed as normal */
  return CURLE_OK;
}

static CURLcode cr_in_rewind(struct Curl_easy *data,
                             struct Curl_creader *reader)
{
  struct cr_in_ctx *ctx = reader->ctx;







|







816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
    ctx->total_len -= offset;

    if(ctx->total_len <= 0) {
      failf(data, "File already completely uploaded");
      return CURLE_PARTIAL_FILE;
    }
  }
  /* we have passed, proceed as normal */
  return CURLE_OK;
}

static CURLcode cr_in_rewind(struct Curl_easy *data,
                             struct Curl_creader *reader)
{
  struct cr_in_ctx *ctx = reader->ctx;
846
847
848
849
850
851
852
853
854
855
856
857
858
















859
860
861
862
863
864
865
866
867
868
869

870
871
872
873
874
875
876
                    (int)err, (int)errno);
      if(-1 != err)
        /* successful rewind */
        return CURLE_OK;
    }

    /* no callback set or failure above, makes us fail at once */
    failf(data, "necessary data rewind wasn't possible");
    return CURLE_SEND_FAIL_REWIND;
  }
  return CURLE_OK;
}


















static const struct Curl_crtype cr_in = {
  "cr-in",
  cr_in_init,
  cr_in_read,
  Curl_creader_def_close,
  cr_in_needs_rewind,
  cr_in_total_length,
  cr_in_resume_from,
  cr_in_rewind,
  Curl_creader_def_unpause,

  Curl_creader_def_done,
  sizeof(struct cr_in_ctx)
};

CURLcode Curl_creader_create(struct Curl_creader **preader,
                             struct Curl_easy *data,
                             const struct Curl_crtype *crt,







|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










|
>







868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
                    (int)err, (int)errno);
      if(-1 != err)
        /* successful rewind */
        return CURLE_OK;
    }

    /* no callback set or failure above, makes us fail at once */
    failf(data, "necessary data rewind was not possible");
    return CURLE_SEND_FAIL_REWIND;
  }
  return CURLE_OK;
}

static CURLcode cr_in_unpause(struct Curl_easy *data,
                              struct Curl_creader *reader)
{
  struct cr_in_ctx *ctx = reader->ctx;
  (void)data;
  ctx->is_paused = FALSE;
  return CURLE_OK;
}

static bool cr_in_is_paused(struct Curl_easy *data,
                            struct Curl_creader *reader)
{
  struct cr_in_ctx *ctx = reader->ctx;
  (void)data;
  return ctx->is_paused;
}

static const struct Curl_crtype cr_in = {
  "cr-in",
  cr_in_init,
  cr_in_read,
  Curl_creader_def_close,
  cr_in_needs_rewind,
  cr_in_total_length,
  cr_in_resume_from,
  cr_in_rewind,
  cr_in_unpause,
  cr_in_is_paused,
  Curl_creader_def_done,
  sizeof(struct cr_in_ctx)
};

CURLcode Curl_creader_create(struct Curl_creader **preader,
                             struct Curl_easy *data,
                             const struct Curl_crtype *crt,
975
976
977
978
979
980
981
982
983
984
985
986
987
988






989
990
991
992
993
994
995
      result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
      if(!result)
        result = Curl_bufq_cwrite(&ctx->buf, STRCONST("\r\n"), &n);
      if(result)
        return result;
      start = i + 1;
      if(!data->set.crlf && (data->state.infilesize != -1)) {
        /* we're here only because FTP is in ASCII mode...
           bump infilesize for the LF we just added */
        data->state.infilesize++;
        /* comment: this might work for FTP, but in HTTP we could not change
         * the content length after having started the request... */
      }
    }






  }

  DEBUGASSERT(!Curl_bufq_is_empty(&ctx->buf));
  *peos = FALSE;
  result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
  if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
    /* no more data, read all, done. */







|






>
>
>
>
>
>







1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
      result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
      if(!result)
        result = Curl_bufq_cwrite(&ctx->buf, STRCONST("\r\n"), &n);
      if(result)
        return result;
      start = i + 1;
      if(!data->set.crlf && (data->state.infilesize != -1)) {
        /* we are here only because FTP is in ASCII mode...
           bump infilesize for the LF we just added */
        data->state.infilesize++;
        /* comment: this might work for FTP, but in HTTP we could not change
         * the content length after having started the request... */
      }
    }

    if(start < i) { /* leftover */
      result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
      if(result)
        return result;
    }
  }

  DEBUGASSERT(!Curl_bufq_is_empty(&ctx->buf));
  *peos = FALSE;
  result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
  if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
    /* no more data, read all, done. */
1018
1019
1020
1021
1022
1023
1024

1025
1026
1027
1028
1029
1030
1031
  cr_lc_read,
  cr_lc_close,
  Curl_creader_def_needs_rewind,
  cr_lc_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,

  Curl_creader_def_done,
  sizeof(struct cr_lc_ctx)
};

static CURLcode cr_lc_add(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;







>







1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
  cr_lc_read,
  cr_lc_close,
  Curl_creader_def_needs_rewind,
  cr_lc_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,
  Curl_creader_def_is_paused,
  Curl_creader_def_done,
  sizeof(struct cr_lc_ctx)
};

static CURLcode cr_lc_add(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;
1191
1192
1193
1194
1195
1196
1197

1198
1199
1200
1201
1202
1203
1204
  cr_null_read,
  Curl_creader_def_close,
  Curl_creader_def_needs_rewind,
  cr_null_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,

  Curl_creader_def_done,
  sizeof(struct Curl_creader)
};

CURLcode Curl_creader_set_null(struct Curl_easy *data)
{
  struct Curl_creader *r;







>







1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
  cr_null_read,
  Curl_creader_def_close,
  Curl_creader_def_needs_rewind,
  cr_null_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,
  Curl_creader_def_is_paused,
  Curl_creader_def_done,
  sizeof(struct Curl_creader)
};

CURLcode Curl_creader_set_null(struct Curl_easy *data)
{
  struct Curl_creader *r;
1290
1291
1292
1293
1294
1295
1296

1297
1298
1299
1300
1301
1302
1303
  cr_buf_read,
  Curl_creader_def_close,
  cr_buf_needs_rewind,
  cr_buf_total_length,
  cr_buf_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,

  Curl_creader_def_done,
  sizeof(struct cr_buf_ctx)
};

CURLcode Curl_creader_set_buf(struct Curl_easy *data,
                               const char *buf, size_t blen)
{







>







1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
  cr_buf_read,
  Curl_creader_def_close,
  cr_buf_needs_rewind,
  cr_buf_total_length,
  cr_buf_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,
  Curl_creader_def_is_paused,
  Curl_creader_def_done,
  sizeof(struct cr_buf_ctx)
};

CURLcode Curl_creader_set_buf(struct Curl_easy *data,
                               const char *buf, size_t blen)
{
1351
1352
1353
1354
1355
1356
1357












1358
1359
1360
1361
1362
1363
1364
    result = reader->crt->unpause(data, reader);
    if(result)
      break;
    reader = reader->next;
  }
  return result;
}













void Curl_creader_done(struct Curl_easy *data, int premature)
{
  struct Curl_creader *reader = data->req.reader_stack;
  while(reader) {
    reader->crt->done(data, reader, premature);
    reader = reader->next;







>
>
>
>
>
>
>
>
>
>
>
>







1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
    result = reader->crt->unpause(data, reader);
    if(result)
      break;
    reader = reader->next;
  }
  return result;
}

bool Curl_creader_is_paused(struct Curl_easy *data)
{
  struct Curl_creader *reader = data->req.reader_stack;

  while(reader) {
    if(reader->crt->is_paused(data, reader))
      return TRUE;
    reader = reader->next;
  }
  return FALSE;
}

void Curl_creader_done(struct Curl_easy *data, int premature)
{
  struct Curl_creader *reader = data->req.reader_stack;
  while(reader) {
    reader->crt->done(data, reader, premature);
    reader = reader->next;
Changes to jni/curl/lib/sendf.h.
214
215
216
217
218
219
220

221
222
223
224
225
226
227
  bool (*needs_rewind)(struct Curl_easy *data, struct Curl_creader *reader);
  curl_off_t (*total_length)(struct Curl_easy *data,
                             struct Curl_creader *reader);
  CURLcode (*resume_from)(struct Curl_easy *data,
                          struct Curl_creader *reader, curl_off_t offset);
  CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader);
  CURLcode (*unpause)(struct Curl_easy *data, struct Curl_creader *reader);

  void (*done)(struct Curl_easy *data,
               struct Curl_creader *reader, int premature);
  size_t creader_size;  /* sizeof() allocated struct Curl_creader */
};

/* Phase a reader operates at. */
typedef enum {







>







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  bool (*needs_rewind)(struct Curl_easy *data, struct Curl_creader *reader);
  curl_off_t (*total_length)(struct Curl_easy *data,
                             struct Curl_creader *reader);
  CURLcode (*resume_from)(struct Curl_easy *data,
                          struct Curl_creader *reader, curl_off_t offset);
  CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader);
  CURLcode (*unpause)(struct Curl_easy *data, struct Curl_creader *reader);
  bool (*is_paused)(struct Curl_easy *data, struct Curl_creader *reader);
  void (*done)(struct Curl_easy *data,
               struct Curl_creader *reader, int premature);
  size_t creader_size;  /* sizeof() allocated struct Curl_creader */
};

/* Phase a reader operates at. */
typedef enum {
264
265
266
267
268
269
270


271
272
273
274
275
276
277
CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
                                      struct Curl_creader *reader,
                                      curl_off_t offset);
CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
                                 struct Curl_creader *reader);
CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
                                  struct Curl_creader *reader);


void Curl_creader_def_done(struct Curl_easy *data,
                           struct Curl_creader *reader, int premature);

/**
 * Convenience method for calling `reader->do_read()` that
 * checks for NULL reader.
 */







>
>







265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
                                      struct Curl_creader *reader,
                                      curl_off_t offset);
CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
                                 struct Curl_creader *reader);
CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
                                  struct Curl_creader *reader);
bool Curl_creader_def_is_paused(struct Curl_easy *data,
                                struct Curl_creader *reader);
void Curl_creader_def_done(struct Curl_easy *data,
                           struct Curl_creader *reader, int premature);

/**
 * Convenience method for calling `reader->do_read()` that
 * checks for NULL reader.
 */
371
372
373
374
375
376
377





378
379
380
381
382
383
384
CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset);

/**
 * Unpause all installed readers.
 */
CURLcode Curl_creader_unpause(struct Curl_easy *data);






/**
 * Tell all client readers that they are done.
 */
void Curl_creader_done(struct Curl_easy *data, int premature);

/**
 * Look up an installed client reader on `data` by its type.







>
>
>
>
>







374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset);

/**
 * Unpause all installed readers.
 */
CURLcode Curl_creader_unpause(struct Curl_easy *data);

/**
 * Return TRUE iff any of the installed readers is paused.
 */
bool Curl_creader_is_paused(struct Curl_easy *data);

/**
 * Tell all client readers that they are done.
 */
void Curl_creader_done(struct Curl_easy *data, int premature);

/**
 * Look up an installed client reader on `data` by its type.
Changes to jni/curl/lib/setopt.c.
134
135
136
137
138
139
140
141




































142
143
144
145
146
147
148
149
150
  *userp = user;

  free(*passwdp);
  *passwdp = passwd;

  return CURLE_OK;
}





































#define C_SSLVERSION_VALUE(x) (x & 0xffff)
#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)

static CURLcode protocol2num(const char *str, curl_prot_t *val)
{
  /*
   * We are asked to cherry-pick protocols, so play it safe and disallow all
   * protocols to start with, and re-add the wanted ones back in.
   */








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  *userp = user;

  free(*passwdp);
  *passwdp = passwd;

  return CURLE_OK;
}

static CURLcode setstropt_interface(
  char *option, char **devp, char **ifacep, char **hostp)
{
  char *dev = NULL;
  char *iface = NULL;
  char *host = NULL;
  size_t len;
  CURLcode result;

  DEBUGASSERT(devp);
  DEBUGASSERT(ifacep);
  DEBUGASSERT(hostp);

  /* Parse the interface details */
  if(!option || !*option)
    return CURLE_BAD_FUNCTION_ARGUMENT;
  len = strlen(option);
  if(len > 255)
    return CURLE_BAD_FUNCTION_ARGUMENT;

  result = Curl_parse_interface(option, len, &dev, &iface, &host);
  if(result)
    return result;

  free(*devp);
  *devp = dev;

  free(*ifacep);
  *ifacep = iface;

  free(*hostp);
  *hostp = host;

  return CURLE_OK;
}

#define C_SSLVERSION_VALUE(x) (x & 0xffff)
#define C_SSLVERSION_MAX_VALUE(x) ((unsigned long)x & 0xffff0000)

static CURLcode protocol2num(const char *str, curl_prot_t *val)
{
  /*
   * We are asked to cherry-pick protocols, so play it safe and disallow all
   * protocols to start with, and re-add the wanted ones back in.
   */
199
200
201
202
203
204
205

206
207
208
209
210
211
212



213
214
215
216
217
218
219
      return CURLE_BAD_FUNCTION_ARGUMENT;
    else if(arg > INT_MAX)
      arg = INT_MAX;

    data->set.dns_cache_timeout = (int)arg;
    break;
  case CURLOPT_CA_CACHE_TIMEOUT:

    arg = va_arg(param, long);
    if(arg < -1)
      return CURLE_BAD_FUNCTION_ARGUMENT;
    else if(arg > INT_MAX)
      arg = INT_MAX;

    data->set.general_ssl.ca_cache_timeout = (int)arg;



    break;
  case CURLOPT_DNS_USE_GLOBAL_CACHE:
    /* deprecated */
    break;
  case CURLOPT_SSL_CIPHER_LIST:
    /* set a list of cipher we want to use in the SSL connection */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],







>
|
|
|
|
|

|
>
>
>







235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
      return CURLE_BAD_FUNCTION_ARGUMENT;
    else if(arg > INT_MAX)
      arg = INT_MAX;

    data->set.dns_cache_timeout = (int)arg;
    break;
  case CURLOPT_CA_CACHE_TIMEOUT:
    if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) {
      arg = va_arg(param, long);
      if(arg < -1)
        return CURLE_BAD_FUNCTION_ARGUMENT;
      else if(arg > INT_MAX)
        arg = INT_MAX;

      data->set.general_ssl.ca_cache_timeout = (int)arg;
    }
    else
      return CURLE_NOT_BUILT_IN;
    break;
  case CURLOPT_DNS_USE_GLOBAL_CACHE:
    /* deprecated */
    break;
  case CURLOPT_SSL_CIPHER_LIST:
    /* set a list of cipher we want to use in the SSL connection */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
      data->set.method = HTTPREQ_HEAD;
    else if(data->set.method == HTTPREQ_HEAD)
      data->set.method = HTTPREQ_GET;
#endif
    break;
  case CURLOPT_FAILONERROR:
    /*
     * Don't output the >=400 error code HTML-page, but instead only
     * return error.
     */
    data->set.http_fail_on_error = (0 != va_arg(param, long));
    break;
  case CURLOPT_KEEP_SENDING_ON_ERROR:
    data->set.http_keep_sending_on_error = (0 != va_arg(param, long));
    break;







|







348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
      data->set.method = HTTPREQ_HEAD;
    else if(data->set.method == HTTPREQ_HEAD)
      data->set.method = HTTPREQ_GET;
#endif
    break;
  case CURLOPT_FAILONERROR:
    /*
     * Do not output the >=400 error code HTML-page, but instead only
     * return error.
     */
    data->set.http_fail_on_error = (0 != va_arg(param, long));
    break;
  case CURLOPT_KEEP_SENDING_ON_ERROR:
    data->set.http_keep_sending_on_error = (0 != va_arg(param, long));
    break;
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
      if(option != CURLOPT_SSLVERSION)
        primary = &data->set.proxy_ssl.primary;
#endif

      arg = va_arg(param, long);

      version = C_SSLVERSION_VALUE(arg);
      version_max = C_SSLVERSION_MAX_VALUE(arg);

      if(version < CURL_SSLVERSION_DEFAULT ||
         version == CURL_SSLVERSION_SSLv2 ||
         version == CURL_SSLVERSION_SSLv3 ||
         version >= CURL_SSLVERSION_LAST ||
         version_max < CURL_SSLVERSION_MAX_NONE ||
         version_max >= CURL_SSLVERSION_MAX_LAST)







|







497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
      if(option != CURLOPT_SSLVERSION)
        primary = &data->set.proxy_ssl.primary;
#endif

      arg = va_arg(param, long);

      version = C_SSLVERSION_VALUE(arg);
      version_max = (long)C_SSLVERSION_MAX_VALUE(arg);

      if(version < CURL_SSLVERSION_DEFAULT ||
         version == CURL_SSLVERSION_SSLv2 ||
         version == CURL_SSLVERSION_SSLv3 ||
         version >= CURL_SSLVERSION_LAST ||
         version_max < CURL_SSLVERSION_MAX_NONE ||
         version_max >= CURL_SSLVERSION_MAX_LAST)
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592

  case CURLOPT_ACCEPT_ENCODING:
    /*
     * String to use at the value of Accept-Encoding header.
     *
     * If the encoding is set to "" we use an Accept-Encoding header that
     * encompasses all the encodings we support.
     * If the encoding is set to NULL we don't send an Accept-Encoding header
     * and ignore an received Content-Encoding header.
     *
     */
    argptr = va_arg(param, char *);
    if(argptr && !*argptr) {
      char all[256];
      Curl_all_content_encodings(all, sizeof(all));







|







618
619
620
621
622
623
624
625
626
627
628
629
630
631
632

  case CURLOPT_ACCEPT_ENCODING:
    /*
     * String to use at the value of Accept-Encoding header.
     *
     * If the encoding is set to "" we use an Accept-Encoding header that
     * encompasses all the encodings we support.
     * If the encoding is set to NULL we do not send an Accept-Encoding header
     * and ignore an received Content-Encoding header.
     *
     */
    argptr = va_arg(param, char *);
    if(argptr && !*argptr) {
      char all[256];
      Curl_all_content_encodings(all, sizeof(all));
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
         extended in a future */
      return CURLE_BAD_FUNCTION_ARGUMENT;
    data->set.keep_post = arg & CURL_REDIR_POST_ALL;
    break;

  case CURLOPT_POST:
    /* Does this option serve a purpose anymore? Yes it does, when
       CURLOPT_POSTFIELDS isn't used and the POST data is read off the
       callback! */
    if(va_arg(param, long)) {
      data->set.method = HTTPREQ_POST;
      data->set.opt_no_body = FALSE; /* this is implied */
    }
    else
      data->set.method = HTTPREQ_GET;







|







682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
         extended in a future */
      return CURLE_BAD_FUNCTION_ARGUMENT;
    data->set.keep_post = arg & CURL_REDIR_POST_ALL;
    break;

  case CURLOPT_POST:
    /* Does this option serve a purpose anymore? Yes it does, when
       CURLOPT_POSTFIELDS is not used and the POST data is read off the
       callback! */
    if(va_arg(param, long)) {
      data->set.method = HTTPREQ_POST;
      data->set.opt_no_body = FALSE; /* this is implied */
    }
    else
      data->set.method = HTTPREQ_GET;
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
     */
    argptr = (char *)va_arg(param, void *);
    if(argptr) {
      struct curl_slist *cl;
      /* general protection against mistakes and abuse */
      if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
        return CURLE_BAD_FUNCTION_ARGUMENT;
      /* append the cookie file name to the list of file names, and deal with
         them later */
      cl = curl_slist_append(data->state.cookielist, argptr);
      if(!cl) {
        curl_slist_free_all(data->state.cookielist);
        data->state.cookielist = NULL;
        return CURLE_OUT_OF_MEMORY;
      }
      data->state.cookielist = cl; /* store the list for later use */
    }
    else {
      /* clear the list of cookie files */
      curl_slist_free_all(data->state.cookielist);
      data->state.cookielist = NULL;

      if(!data->share || !data->share->cookies) {
        /* throw away all existing cookies if this isn't a shared cookie
           container */
        Curl_cookie_clearall(data->cookies);
        Curl_cookie_cleanup(data->cookies);
      }
      /* disable the cookie engine */
      data->cookies = NULL;
    }
    break;

  case CURLOPT_COOKIEJAR:
    /*
     * Set cookie file name to dump all cookies to when we're done.
     */
    result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
                            va_arg(param, char *));
    if(!result) {
      /*
       * Activate the cookie parser. This may or may not already
       * have been made.







|















|











|







785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
     */
    argptr = (char *)va_arg(param, void *);
    if(argptr) {
      struct curl_slist *cl;
      /* general protection against mistakes and abuse */
      if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
        return CURLE_BAD_FUNCTION_ARGUMENT;
      /* append the cookie filename to the list of filenames, and deal with
         them later */
      cl = curl_slist_append(data->state.cookielist, argptr);
      if(!cl) {
        curl_slist_free_all(data->state.cookielist);
        data->state.cookielist = NULL;
        return CURLE_OUT_OF_MEMORY;
      }
      data->state.cookielist = cl; /* store the list for later use */
    }
    else {
      /* clear the list of cookie files */
      curl_slist_free_all(data->state.cookielist);
      data->state.cookielist = NULL;

      if(!data->share || !data->share->cookies) {
        /* throw away all existing cookies if this is not a shared cookie
           container */
        Curl_cookie_clearall(data->cookies);
        Curl_cookie_cleanup(data->cookies);
      }
      /* disable the cookie engine */
      data->cookies = NULL;
    }
    break;

  case CURLOPT_COOKIEJAR:
    /*
     * Set cookie filename to dump all cookies to when we are done.
     */
    result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
                            va_arg(param, char *));
    if(!result) {
      /*
       * Activate the cookie parser. This may or may not already
       * have been made.
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
    arg = va_arg(param, long);
    if(arg < 0)
      return CURLE_BAD_FUNCTION_ARGUMENT;
    data->set.expect_100_timeout = arg;
    break;

  case CURLOPT_HTTP09_ALLOWED:
    arg = va_arg(param, unsigned long);
    if(arg > 1L)
      return CURLE_BAD_FUNCTION_ARGUMENT;
#ifdef USE_HYPER
    /* Hyper does not support HTTP/0.9 */
    if(arg)
      return CURLE_BAD_FUNCTION_ARGUMENT;
#else







|







964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
    arg = va_arg(param, long);
    if(arg < 0)
      return CURLE_BAD_FUNCTION_ARGUMENT;
    data->set.expect_100_timeout = arg;
    break;

  case CURLOPT_HTTP09_ALLOWED:
    arg = (long)va_arg(param, unsigned long);
    if(arg > 1L)
      return CURLE_BAD_FUNCTION_ARGUMENT;
#ifdef USE_HYPER
    /* Hyper does not support HTTP/0.9 */
    if(arg)
      return CURLE_BAD_FUNCTION_ARGUMENT;
#else
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
    data->state.authhost.iestyle = !!(auth & CURLAUTH_DIGEST_IE);

    if(auth & CURLAUTH_DIGEST_IE) {
      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
    }

    /* switch off bits we can't support */
#ifndef USE_NTLM
    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
#endif
#ifndef USE_SPNEGO
    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
                                    GSS-API or SSPI */
#endif







|







1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
    data->state.authhost.iestyle = !!(auth & CURLAUTH_DIGEST_IE);

    if(auth & CURLAUTH_DIGEST_IE) {
      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
    }

    /* switch off bits we cannot support */
#ifndef USE_NTLM
    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
#endif
#ifndef USE_SPNEGO
    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
                                    GSS-API or SSPI */
#endif
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
  case CURLOPT_CUSTOMREQUEST:
    /*
     * Set a custom string to use as request
     */
    result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST],
                            va_arg(param, char *));

    /* we don't set
       data->set.method = HTTPREQ_CUSTOM;
       here, we continue as if we were using the already set type
       and this just changes the actual request keyword */
    break;

#ifndef CURL_DISABLE_PROXY
  case CURLOPT_HTTPPROXYTUNNEL:







|







1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
  case CURLOPT_CUSTOMREQUEST:
    /*
     * Set a custom string to use as request
     */
    result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST],
                            va_arg(param, char *));

    /* we do not set
       data->set.method = HTTPREQ_CUSTOM;
       here, we continue as if we were using the already set type
       and this just changes the actual request keyword */
    break;

#ifndef CURL_DISABLE_PROXY
  case CURLOPT_HTTPPROXYTUNNEL:
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
       rest we need to handle it as normal DIGEST */
    data->state.authproxy.iestyle = !!(auth & CURLAUTH_DIGEST_IE);

    if(auth & CURLAUTH_DIGEST_IE) {
      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
    }
    /* switch off bits we can't support */
#ifndef USE_NTLM
    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
#endif
#ifndef USE_SPNEGO
    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
                                    GSS-API or SSPI */
#endif







|







1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
       rest we need to handle it as normal DIGEST */
    data->state.authproxy.iestyle = !!(auth & CURLAUTH_DIGEST_IE);

    if(auth & CURLAUTH_DIGEST_IE) {
      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
    }
    /* switch off bits we cannot support */
#ifndef USE_NTLM
    auth &= ~CURLAUTH_NTLM;    /* no NTLM support */
#endif
#ifndef USE_SPNEGO
    auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
                                    GSS-API or SSPI */
#endif
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
  break;

  case CURLOPT_PROXY:
    /*
     * Set proxy server:port to use as proxy.
     *
     * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
     * we explicitly say that we don't want to use a proxy
     * (even though there might be environment variables saying so).
     *
     * Setting it to NULL, means no proxy but allows the environment variables
     * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
     */
    result = Curl_setstropt(&data->set.str[STRING_PROXY],
                            va_arg(param, char *));
    break;

  case CURLOPT_PRE_PROXY:
    /*
     * Set proxy server:port to use as SOCKS proxy.
     *
     * If the proxy is set to "" or NULL we explicitly say that we don't want
     * to use the socks proxy.
     */
    result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY],
                            va_arg(param, char *));
    break;

  case CURLOPT_PROXYTYPE:







|













|







1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
  break;

  case CURLOPT_PROXY:
    /*
     * Set proxy server:port to use as proxy.
     *
     * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
     * we explicitly say that we do not want to use a proxy
     * (even though there might be environment variables saying so).
     *
     * Setting it to NULL, means no proxy but allows the environment variables
     * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
     */
    result = Curl_setstropt(&data->set.str[STRING_PROXY],
                            va_arg(param, char *));
    break;

  case CURLOPT_PRE_PROXY:
    /*
     * Set proxy server:port to use as SOCKS proxy.
     *
     * If the proxy is set to "" or NULL we explicitly say that we do not want
     * to use the socks proxy.
     */
    result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY],
                            va_arg(param, char *));
    break;

  case CURLOPT_PROXYTYPE:
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
    result = setstropt_userpwd(va_arg(param, char *),
                               &data->set.str[STRING_USERNAME],
                               &data->set.str[STRING_PASSWORD]);
    break;

  case CURLOPT_USERNAME:
    /*
     * authentication user name to use in the operation
     */
    result = Curl_setstropt(&data->set.str[STRING_USERNAME],
                            va_arg(param, char *));
    break;
  case CURLOPT_PASSWORD:
    /*
     * authentication password to use in the operation







|







1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
    result = setstropt_userpwd(va_arg(param, char *),
                               &data->set.str[STRING_USERNAME],
                               &data->set.str[STRING_PASSWORD]);
    break;

  case CURLOPT_USERNAME:
    /*
     * authentication username to use in the operation
     */
    result = Curl_setstropt(&data->set.str[STRING_USERNAME],
                            va_arg(param, char *));
    break;
  case CURLOPT_PASSWORD:
    /*
     * authentication password to use in the operation
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
     *
     * Prefix the HOST with plus sign (+) to have the entry expire just like
     * automatically added entries.
     *
     * Prefix the HOST with dash (-) to _remove_ the entry from the cache.
     *
     * This API can remove any entry from the DNS cache, but only entries
     * that aren't actually in use right now will be pruned immediately.
     */
    data->set.resolve = va_arg(param, struct curl_slist *);
    data->state.resolve = data->set.resolve;
    break;
  case CURLOPT_PROGRESSFUNCTION:
    /*
     * Progress callback function







|







1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
     *
     * Prefix the HOST with plus sign (+) to have the entry expire just like
     * automatically added entries.
     *
     * Prefix the HOST with dash (-) to _remove_ the entry from the cache.
     *
     * This API can remove any entry from the DNS cache, but only entries
     * that are not actually in use right now will be pruned immediately.
     */
    data->set.resolve = va_arg(param, struct curl_slist *);
    data->state.resolve = data->set.resolve;
    break;
  case CURLOPT_PROGRESSFUNCTION:
    /*
     * Progress callback function
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
                              REJECT_ZERO);
    free(u);
    free(p);
  }
    break;
  case CURLOPT_PROXYUSERNAME:
    /*
     * authentication user name to use in the operation
     */
    result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME],
                            va_arg(param, char *));
    break;
  case CURLOPT_PROXYPASSWORD:
    /*
     * authentication password to use in the operation







|







1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
                              REJECT_ZERO);
    free(u);
    free(p);
  }
    break;
  case CURLOPT_PROXYUSERNAME:
    /*
     * authentication username to use in the operation
     */
    result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME],
                            va_arg(param, char *));
    break;
  case CURLOPT_PROXYPASSWORD:
    /*
     * authentication password to use in the operation
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
    break;
  case CURLOPT_DEBUGFUNCTION:
    /*
     * stderr write callback.
     */
    data->set.fdebug = va_arg(param, curl_debug_callback);
    /*
     * if the callback provided is NULL, it'll use the default callback
     */
    break;
  case CURLOPT_DEBUGDATA:
    /*
     * Set to a void * that should receive all error writes. This
     * defaults to CURLOPT_STDERR for normal operations.
     */







|







1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
    break;
  case CURLOPT_DEBUGFUNCTION:
    /*
     * stderr write callback.
     */
    data->set.fdebug = va_arg(param, curl_debug_callback);
    /*
     * if the callback provided is NULL, it will use the default callback
     */
    break;
  case CURLOPT_DEBUGDATA:
    /*
     * Set to a void * that should receive all error writes. This
     * defaults to CURLOPT_STDERR for normal operations.
     */
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
    /*
     * I/O control data pointer. Might be NULL.
     */
    data->set.ioctl_client = va_arg(param, void *);
    break;
  case CURLOPT_SSLCERT:
    /*
     * String that holds file name of the SSL certificate to use
     */
    result = Curl_setstropt(&data->set.str[STRING_CERT],
                            va_arg(param, char *));
    break;
  case CURLOPT_SSLCERT_BLOB:
    /*
     * Blob that holds file content of the SSL certificate to use
     */
    result = Curl_setblobopt(&data->set.blobs[BLOB_CERT],
                             va_arg(param, struct curl_blob *));
    break;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_SSLCERT:
    /*
     * String that holds file name of the SSL certificate to use for proxy
     */
    result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
                            va_arg(param, char *));
    break;
  case CURLOPT_PROXY_SSLCERT_BLOB:
    /*
     * Blob that holds file content of the SSL certificate to use for proxy







|














|







1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
    /*
     * I/O control data pointer. Might be NULL.
     */
    data->set.ioctl_client = va_arg(param, void *);
    break;
  case CURLOPT_SSLCERT:
    /*
     * String that holds filename of the SSL certificate to use
     */
    result = Curl_setstropt(&data->set.str[STRING_CERT],
                            va_arg(param, char *));
    break;
  case CURLOPT_SSLCERT_BLOB:
    /*
     * Blob that holds file content of the SSL certificate to use
     */
    result = Curl_setblobopt(&data->set.blobs[BLOB_CERT],
                             va_arg(param, struct curl_blob *));
    break;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_SSLCERT:
    /*
     * String that holds filename of the SSL certificate to use for proxy
     */
    result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
                            va_arg(param, char *));
    break;
  case CURLOPT_PROXY_SSLCERT_BLOB:
    /*
     * Blob that holds file content of the SSL certificate to use for proxy
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
     */
    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
                            va_arg(param, char *));
    break;
#endif
  case CURLOPT_SSLKEY:
    /*
     * String that holds file name of the SSL key to use
     */
    result = Curl_setstropt(&data->set.str[STRING_KEY],
                            va_arg(param, char *));
    break;
  case CURLOPT_SSLKEY_BLOB:
    /*
     * Blob that holds file content of the SSL key to use
     */
    result = Curl_setblobopt(&data->set.blobs[BLOB_KEY],
                             va_arg(param, struct curl_blob *));
    break;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_SSLKEY:
    /*
     * String that holds file name of the SSL key to use for proxy
     */
    result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
                            va_arg(param, char *));
    break;
  case CURLOPT_PROXY_SSLKEY_BLOB:
    /*
     * Blob that holds file content of the SSL key to use for proxy







|














|







1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
     */
    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
                            va_arg(param, char *));
    break;
#endif
  case CURLOPT_SSLKEY:
    /*
     * String that holds filename of the SSL key to use
     */
    result = Curl_setstropt(&data->set.str[STRING_KEY],
                            va_arg(param, char *));
    break;
  case CURLOPT_SSLKEY_BLOB:
    /*
     * Blob that holds file content of the SSL key to use
     */
    result = Curl_setblobopt(&data->set.blobs[BLOB_KEY],
                             va_arg(param, struct curl_blob *));
    break;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_SSLKEY:
    /*
     * String that holds filename of the SSL key to use for proxy
     */
    result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
                            va_arg(param, char *));
    break;
  case CURLOPT_PROXY_SSLKEY_BLOB:
    /*
     * Blob that holds file content of the SSL key to use for proxy
1873
1874
1875
1876
1877
1878
1879

1880
1881


1882
1883
1884
1885
1886
1887
1888
    break;
#endif
  case CURLOPT_INTERFACE:
    /*
     * Set what interface or address/hostname to bind the socket to when
     * performing an operation and thus what from-IP your connection will use.
     */

    result = Curl_setstropt(&data->set.str[STRING_DEVICE],
                            va_arg(param, char *));


    break;
#ifndef CURL_DISABLE_BINDLOCAL
  case CURLOPT_LOCALPORT:
    /*
     * Set what local port to bind the socket to when performing an operation.
     */
    arg = va_arg(param, long);







>
|
<
>
>







1913
1914
1915
1916
1917
1918
1919
1920
1921

1922
1923
1924
1925
1926
1927
1928
1929
1930
    break;
#endif
  case CURLOPT_INTERFACE:
    /*
     * Set what interface or address/hostname to bind the socket to when
     * performing an operation and thus what from-IP your connection will use.
     */
    result = setstropt_interface(va_arg(param, char *),
                                 &data->set.str[STRING_DEVICE],

                                 &data->set.str[STRING_INTERFACE],
                                 &data->set.str[STRING_BINDHOST]);
    break;
#ifndef CURL_DISABLE_BINDLOCAL
  case CURLOPT_LOCALPORT:
    /*
     * Set what local port to bind the socket to when performing an operation.
     */
    arg = va_arg(param, long);
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975

    /* Update the current connection proxy_ssl_config. */
    Curl_ssl_conn_config_update(data, TRUE);
    break;
#endif
  case CURLOPT_SSL_VERIFYHOST:
    /*
     * Enable verification of the host name in the peer certificate
     */
    arg = va_arg(param, long);

    /* Obviously people are not reading documentation and too many thought
       this argument took a boolean when it wasn't and misused it.
       Treat 1 and 2 the same */
    data->set.ssl.primary.verifyhost = !!(arg & 3);

    /* Update the current connection ssl_config. */
    Curl_ssl_conn_config_update(data, FALSE);
    break;
#ifndef CURL_DISABLE_DOH
  case CURLOPT_DOH_SSL_VERIFYHOST:
    /*
     * Enable verification of the host name in the peer certificate for DoH
     */
    arg = va_arg(param, long);

    /* Treat both 1 and 2 as TRUE */
    data->set.doh_verifyhost = !!(arg & 3);
    break;
#endif
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_SSL_VERIFYHOST:
    /*
     * Enable verification of the host name in the peer certificate for proxy
     */
    arg = va_arg(param, long);

    /* Treat both 1 and 2 as TRUE */
    data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE);
    /* Update the current connection proxy_ssl_config. */
    Curl_ssl_conn_config_update(data, TRUE);







|




|









|










|







1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017

    /* Update the current connection proxy_ssl_config. */
    Curl_ssl_conn_config_update(data, TRUE);
    break;
#endif
  case CURLOPT_SSL_VERIFYHOST:
    /*
     * Enable verification of the hostname in the peer certificate
     */
    arg = va_arg(param, long);

    /* Obviously people are not reading documentation and too many thought
       this argument took a boolean when it was not and misused it.
       Treat 1 and 2 the same */
    data->set.ssl.primary.verifyhost = !!(arg & 3);

    /* Update the current connection ssl_config. */
    Curl_ssl_conn_config_update(data, FALSE);
    break;
#ifndef CURL_DISABLE_DOH
  case CURLOPT_DOH_SSL_VERIFYHOST:
    /*
     * Enable verification of the hostname in the peer certificate for DoH
     */
    arg = va_arg(param, long);

    /* Treat both 1 and 2 as TRUE */
    data->set.doh_verifyhost = !!(arg & 3);
    break;
#endif
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_SSL_VERIFYHOST:
    /*
     * Enable verification of the hostname in the peer certificate for proxy
     */
    arg = va_arg(param, long);

    /* Treat both 1 and 2 as TRUE */
    data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE);
    /* Update the current connection proxy_ssl_config. */
    Curl_ssl_conn_config_update(data, TRUE);
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;
  case CURLOPT_PINNEDPUBLICKEY:
    /*
     * Set pinned public key for SSL connection.
     * Specify file name of the public key in DER format.
     */
#ifdef USE_SSL
    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
                              va_arg(param, char *));
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_PINNEDPUBLICKEY:
    /*
     * Set pinned public key for SSL connection.
     * Specify file name of the public key in DER format.
     */
#ifdef USE_SSL
    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
                              va_arg(param, char *));
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;
#endif
  case CURLOPT_CAINFO:
    /*
     * Set CA info for SSL connection. Specify file name of the CA certificate
     */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
                            va_arg(param, char *));
    break;
  case CURLOPT_CAINFO_BLOB:
    /*
     * Blob that holds CA info for SSL connection.







|













|












|







2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;
  case CURLOPT_PINNEDPUBLICKEY:
    /*
     * Set pinned public key for SSL connection.
     * Specify filename of the public key in DER format.
     */
#ifdef USE_SSL
    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
                              va_arg(param, char *));
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_PINNEDPUBLICKEY:
    /*
     * Set pinned public key for SSL connection.
     * Specify filename of the public key in DER format.
     */
#ifdef USE_SSL
    if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
                              va_arg(param, char *));
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;
#endif
  case CURLOPT_CAINFO:
    /*
     * Set CA info for SSL connection. Specify filename of the CA certificate
     */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
                            va_arg(param, char *));
    break;
  case CURLOPT_CAINFO_BLOB:
    /*
     * Blob that holds CA info for SSL connection.
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
    }
    else
#endif
      return CURLE_NOT_BUILT_IN;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_CAINFO:
    /*
     * Set CA info SSL connection for proxy. Specify file name of the
     * CA certificate
     */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
                            va_arg(param, char *));
    break;
  case CURLOPT_PROXY_CAINFO_BLOB:
    /*







|







2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
    }
    else
#endif
      return CURLE_NOT_BUILT_IN;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_CAINFO:
    /*
     * Set CA info SSL connection for proxy. Specify filename of the
     * CA certificate
     */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
                            va_arg(param, char *));
    break;
  case CURLOPT_PROXY_CAINFO_BLOB:
    /*
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;
#endif
  case CURLOPT_CRLFILE:
    /*
     * Set CRL file info for SSL connection. Specify file name of the CRL
     * to check certificates revocation
     */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE],
                            va_arg(param, char *));
    break;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_CRLFILE:
    /*
     * Set CRL file info for SSL connection for proxy. Specify file name of the
     * CRL to check certificates revocation
     */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
                            va_arg(param, char *));
    break;
#endif
  case CURLOPT_ISSUERCERT:







|








|







2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
    else
#endif
      result = CURLE_NOT_BUILT_IN;
    break;
#endif
  case CURLOPT_CRLFILE:
    /*
     * Set CRL file info for SSL connection. Specify filename of the CRL
     * to check certificates revocation
     */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE],
                            va_arg(param, char *));
    break;
#ifndef CURL_DISABLE_PROXY
  case CURLOPT_PROXY_CRLFILE:
    /*
     * Set CRL file info for SSL connection for proxy. Specify filename of the
     * CRL to check certificates revocation
     */
    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
                            va_arg(param, char *));
    break;
#endif
  case CURLOPT_ISSUERCERT:
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
     */
    data->set.telnet_options = va_arg(param, struct curl_slist *);
    break;
#endif
  case CURLOPT_BUFFERSIZE:
    /*
     * The application kindly asks for a differently sized receive buffer.
     * If it seems reasonable, we'll use it.
     */
    arg = va_arg(param, long);

    if(arg > READBUFFER_MAX)
      arg = READBUFFER_MAX;
    else if(arg < 1)
      arg = READBUFFER_SIZE;







|







2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
     */
    data->set.telnet_options = va_arg(param, struct curl_slist *);
    break;
#endif
  case CURLOPT_BUFFERSIZE:
    /*
     * The application kindly asks for a differently sized receive buffer.
     * If it seems reasonable, we will use it.
     */
    arg = va_arg(param, long);

    if(arg > READBUFFER_MAX)
      arg = READBUFFER_MAX;
    else if(arg < 1)
      arg = READBUFFER_SIZE;
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500

2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
    /*
     * socket callback data pointer. Might be NULL.
     */
    data->set.closesocket_client = va_arg(param, void *);
    break;

  case CURLOPT_SSL_SESSIONID_CACHE:
    data->set.ssl.primary.sessionid = (0 != va_arg(param, long));
#ifndef CURL_DISABLE_PROXY
    data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;

#endif
    break;

#ifdef USE_SSH
    /* we only include SSH options if explicitly built to support SSH */
  case CURLOPT_SSH_AUTH_TYPES:
    data->set.ssh_auth_types = (unsigned int)va_arg(param, long);
    break;

  case CURLOPT_SSH_PUBLIC_KEYFILE:
    /*
     * Use this file instead of the $HOME/.ssh/id_dsa.pub file
     */
    result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],







|

|
>






|







2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
    /*
     * socket callback data pointer. Might be NULL.
     */
    data->set.closesocket_client = va_arg(param, void *);
    break;

  case CURLOPT_SSL_SESSIONID_CACHE:
    data->set.ssl.primary.cache_session = (0 != va_arg(param, long));
#ifndef CURL_DISABLE_PROXY
    data->set.proxy_ssl.primary.cache_session =
      data->set.ssl.primary.cache_session;
#endif
    break;

#ifdef USE_SSH
    /* we only include SSH options if explicitly built to support SSH */
  case CURLOPT_SSH_AUTH_TYPES:
    data->set.ssh_auth_types = (int)va_arg(param, long);
    break;

  case CURLOPT_SSH_PUBLIC_KEYFILE:
    /*
     * Use this file instead of the $HOME/.ssh/id_dsa.pub file
     */
    result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
     */
    result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
                            va_arg(param, char *));
    break;

  case CURLOPT_SSH_KNOWNHOSTS:
    /*
     * Store the file name to read known hosts from.
     */
    result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
                            va_arg(param, char *));
    break;
#ifdef USE_LIBSSH2
  case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
    /*







|







2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
     */
    result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
                            va_arg(param, char *));
    break;

  case CURLOPT_SSH_KNOWNHOSTS:
    /*
     * Store the filename to read known hosts from.
     */
    result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
                            va_arg(param, char *));
    break;
#ifdef USE_LIBSSH2
  case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
    /*
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
    /*
     * disable libcurl transfer encoding is used
     */
#ifndef USE_HYPER
    data->set.http_te_skip = (0 == va_arg(param, long));
    break;
#else
    return CURLE_NOT_BUILT_IN; /* hyper doesn't support */
#endif

  case CURLOPT_HTTP_CONTENT_DECODING:
    /*
     * raw data passed to the application when content encoding is used
     */
    data->set.http_ce_skip = (0 == va_arg(param, long));







|







2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
    /*
     * disable libcurl transfer encoding is used
     */
#ifndef USE_HYPER
    data->set.http_te_skip = (0 == va_arg(param, long));
    break;
#else
    return CURLE_NOT_BUILT_IN; /* hyper does not support */
#endif

  case CURLOPT_HTTP_CONTENT_DECODING:
    /*
     * raw data passed to the application when content encoding is used
     */
    data->set.http_ce_skip = (0 == va_arg(param, long));
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
#endif

#ifdef USE_IPV6
  case CURLOPT_ADDRESS_SCOPE:
    /*
     * Use this scope id when using IPv6
     * We always get longs when passed plain numericals so we should check
     * that the value fits into an unsigned 32 bit integer.
     */
    uarg = va_arg(param, unsigned long);
#if SIZEOF_LONG > 4
    if(uarg > UINT_MAX)
      return CURLE_BAD_FUNCTION_ARGUMENT;
#endif
    data->set.scope_id = (unsigned int)uarg;







|







2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
#endif

#ifdef USE_IPV6
  case CURLOPT_ADDRESS_SCOPE:
    /*
     * Use this scope id when using IPv6
     * We always get longs when passed plain numericals so we should check
     * that the value fits into an unsigned 32-bit integer.
     */
    uarg = va_arg(param, unsigned long);
#if SIZEOF_LONG > 4
    if(uarg > UINT_MAX)
      return CURLE_BAD_FUNCTION_ARGUMENT;
#endif
    data->set.scope_id = (unsigned int)uarg;
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
    result = protocol2num(argptr, &data->set.redir_protocols);
    if(result)
      return result;
    break;
  }

  case CURLOPT_DEFAULT_PROTOCOL:
    /* Set the protocol to use when the URL doesn't include any protocol */
    result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
                            va_arg(param, char *));
    break;
#ifndef CURL_DISABLE_SMTP
  case CURLOPT_MAIL_FROM:
    /* Set the SMTP mail originator */
    result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM],







|







2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
    result = protocol2num(argptr, &data->set.redir_protocols);
    if(result)
      return result;
    break;
  }

  case CURLOPT_DEFAULT_PROTOCOL:
    /* Set the protocol to use when the URL does not include any protocol */
    result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
                            va_arg(param, char *));
    break;
#ifndef CURL_DISABLE_SMTP
  case CURLOPT_MAIL_FROM:
    /* Set the SMTP mail originator */
    result = Curl_setstropt(&data->set.str[STRING_MAIL_FROM],
2914
2915
2916
2917
2918
2919
2920








2921
2922
2923
2924
2925
2926
2927
    arg = va_arg(param, long);
    if(arg < 0)
      return CURLE_BAD_FUNCTION_ARGUMENT;
    else if(arg > INT_MAX)
      arg = INT_MAX;
    data->set.tcp_keepintvl = (int)arg;
    break;








  case CURLOPT_TCP_FASTOPEN:
#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \
   defined(TCP_FASTOPEN_CONNECT)
    data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
#else
    result = CURLE_NOT_BUILT_IN;
#endif







>
>
>
>
>
>
>
>







2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
    arg = va_arg(param, long);
    if(arg < 0)
      return CURLE_BAD_FUNCTION_ARGUMENT;
    else if(arg > INT_MAX)
      arg = INT_MAX;
    data->set.tcp_keepintvl = (int)arg;
    break;
  case CURLOPT_TCP_KEEPCNT:
    arg = va_arg(param, long);
    if(arg < 0)
      return CURLE_BAD_FUNCTION_ARGUMENT;
    else if(arg > INT_MAX)
      arg = INT_MAX;
    data->set.tcp_keepcnt = (int)arg;
    break;
  case CURLOPT_TCP_FASTOPEN:
#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \
   defined(TCP_FASTOPEN_CONNECT)
    data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
#else
    result = CURLE_NOT_BUILT_IN;
#endif
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
        return CURLE_OUT_OF_MEMORY;
    }
    argptr = va_arg(param, char *);
    if(argptr) {
      result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
      if(result)
        return result;
      /* this needs to build a list of file names to read from, so that it can
         read them later, as we might get a shared HSTS handle to load them
         into */
      h = curl_slist_append(data->state.hstslist, argptr);
      if(!h) {
        curl_slist_free_all(data->state.hstslist);
        data->state.hstslist = NULL;
        return CURLE_OUT_OF_MEMORY;







|







3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
        return CURLE_OUT_OF_MEMORY;
    }
    argptr = va_arg(param, char *);
    if(argptr) {
      result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
      if(result)
        return result;
      /* this needs to build a list of filenames to read from, so that it can
         read them later, as we might get a shared HSTS handle to load them
         into */
      h = curl_slist_append(data->state.hstslist, argptr);
      if(!h) {
        curl_slist_free_all(data->state.hstslist);
        data->state.hstslist = NULL;
        return CURLE_OUT_OF_MEMORY;
Changes to jni/curl/lib/setup-os400.h.
41
42
43
44
45
46
47


48
49
50
51
52
53
54
/* System API wrapper prototypes & definitions to support ASCII parameters. */

#include <sys/socket.h>
#include <netdb.h>
#include <gskssl.h>
#include <qsoasync.h>
#include <gssapi.h>



extern int Curl_getaddrinfo_a(const char *nodename,
                              const char *servname,
                              const struct addrinfo *hints,
                              struct addrinfo **res);
#define getaddrinfo             Curl_getaddrinfo_a








>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* System API wrapper prototypes & definitions to support ASCII parameters. */

#include <sys/socket.h>
#include <netdb.h>
#include <gskssl.h>
#include <qsoasync.h>
#include <gssapi.h>

#ifdef BUILDING_LIBCURL

extern int Curl_getaddrinfo_a(const char *nodename,
                              const char *servname,
                              const struct addrinfo *hints,
                              struct addrinfo **res);
#define getaddrinfo             Curl_getaddrinfo_a

136
137
138
139
140
141
142
143


144
#ifdef HAVE_LIBZ
#define zlibVersion             Curl_os400_zlibVersion
#define inflateInit_            Curl_os400_inflateInit_
#define inflateInit2_           Curl_os400_inflateInit2_
#define inflate                 Curl_os400_inflate
#define inflateEnd              Curl_os400_inflateEnd
#endif



#endif /* HEADER_CURL_SETUP_OS400_H */








>
>

138
139
140
141
142
143
144
145
146
147
148
#ifdef HAVE_LIBZ
#define zlibVersion             Curl_os400_zlibVersion
#define inflateInit_            Curl_os400_inflateInit_
#define inflateInit2_           Curl_os400_inflateInit2_
#define inflate                 Curl_os400_inflate
#define inflateEnd              Curl_os400_inflateEnd
#endif

#endif /* BUILDING_LIBCURL */

#endif /* HEADER_CURL_SETUP_OS400_H */
Changes to jni/curl/lib/setup-vms.h.
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

static struct passwd vms_passwd_cache;

static struct passwd *vms_getpwuid(uid_t uid)
{
  struct passwd *my_passwd;

/* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */
#ifdef __DECC
#   if __INITIAL_POINTER_SIZE
  __char_ptr32 unix_path;
#   else
  char *unix_path;
#   endif
#else







|







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

static struct passwd vms_passwd_cache;

static struct passwd *vms_getpwuid(uid_t uid)
{
  struct passwd *my_passwd;

/* Hack needed to support 64-bit builds, decc_getpwnam is 32-bit only */
#ifdef __DECC
#   if __INITIAL_POINTER_SIZE
  __char_ptr32 unix_path;
#   else
  char *unix_path;
#   endif
#else
Changes to jni/curl/lib/setup-win32.h.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#  define USE_WINSOCK 2
#endif

/*
 * Include header files for windows builds before redefining anything.
 * Use this preprocessor block only to include or exclude windows.h,
 * winsock2.h or ws2tcpip.h. Any other windows thing belongs
 * to any other further and independent block.  Under Cygwin things work
 * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
 * never be included when __CYGWIN__ is defined.
 */

#ifdef _WIN32
#  if defined(UNICODE) && !defined(_UNICODE)
#    error "UNICODE is defined but _UNICODE is not defined"
#  endif
#  if defined(_UNICODE) && !defined(UNICODE)
#    error "_UNICODE is defined but UNICODE is not defined"
#  endif
/*
 * Don't include unneeded stuff in Windows headers to avoid compiler
 * warnings and macro clashes.
 * Make sure to define this macro before including any Windows headers.
 */
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN
#  endif
#  ifndef NOGDI







|












|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#  define USE_WINSOCK 2
#endif

/*
 * Include header files for windows builds before redefining anything.
 * Use this preprocessor block only to include or exclude windows.h,
 * winsock2.h or ws2tcpip.h. Any other windows thing belongs
 * to any other further and independent block. Under Cygwin things work
 * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
 * never be included when __CYGWIN__ is defined.
 */

#ifdef _WIN32
#  if defined(UNICODE) && !defined(_UNICODE)
#    error "UNICODE is defined but _UNICODE is not defined"
#  endif
#  if defined(_UNICODE) && !defined(UNICODE)
#    error "_UNICODE is defined but UNICODE is not defined"
#  endif
/*
 * Do not include unneeded stuff in Windows headers to avoid compiler
 * warnings and macro clashes.
 * Make sure to define this macro before including any Windows headers.
 */
#  ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN
#  endif
#  ifndef NOGDI
Changes to jni/curl/lib/sha256.c.
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
};

/* Various logical functions */
#define RORc(x, y) \
(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
   ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
#define Ch(x,y,z)   (z ^ (x & (y ^ z)))
#define Maj(x,y,z)  (((x | y) & z) | (x & y))
#define S(x, n)     RORc((x), (n))
#define R(x, n)     (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x)   (S(x, 2) ^ S(x, 13) ^ S(x, 22))
#define Sigma1(x)   (S(x, 6) ^ S(x, 11) ^ S(x, 25))
#define Gamma0(x)   (S(x, 7) ^ S(x, 18) ^ R(x, 3))
#define Gamma1(x)   (S(x, 17) ^ S(x, 19) ^ R(x, 10))

/* Compress 512-bits */
static int sha256_compress(struct sha256_state *md,
                           unsigned char *buf)
{
  unsigned long S[8], W[64];
  int i;







|
|
|
|
|
|
|
|







330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
  0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
};

/* Various logical functions */
#define RORc(x, y) \
(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
   ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
#define Sha256_Ch(x,y,z)  (z ^ (x & (y ^ z)))
#define Sha256_Maj(x,y,z) (((x | y) & z) | (x & y))
#define Sha256_S(x, n)    RORc((x), (n))
#define Sha256_R(x, n)    (((x)&0xFFFFFFFFUL)>>(n))
#define Sigma0(x)         (Sha256_S(x, 2) ^ Sha256_S(x, 13) ^ Sha256_S(x, 22))
#define Sigma1(x)         (Sha256_S(x, 6) ^ Sha256_S(x, 11) ^ Sha256_S(x, 25))
#define Gamma0(x)         (Sha256_S(x, 7) ^ Sha256_S(x, 18) ^ Sha256_R(x, 3))
#define Gamma1(x)         (Sha256_S(x, 17) ^ Sha256_S(x, 19) ^ Sha256_R(x, 10))

/* Compress 512-bits */
static int sha256_compress(struct sha256_state *md,
                           unsigned char *buf)
{
  unsigned long S[8], W[64];
  int i;
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  /* fill W[16..63] */
  for(i = 16; i < 64; i++) {
    W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
      W[i - 16];
  }

  /* Compress */
#define RND(a,b,c,d,e,f,g,h,i)                                          \
  do {                                                                  \
    unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];       \
    unsigned long t1 = Sigma0(a) + Maj(a, b, c);                        \
    d += t0;                                                            \
    h = t0 + t1;                                                        \
  } while(0)

  for(i = 0; i < 64; ++i) {
    unsigned long t;
    RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
    t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
    S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;







|
|
|
|
|
|







360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
  /* fill W[16..63] */
  for(i = 16; i < 64; i++) {
    W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
      W[i - 16];
  }

  /* Compress */
#define RND(a,b,c,d,e,f,g,h,i)                                           \
  do {                                                                   \
    unsigned long t0 = h + Sigma1(e) + Sha256_Ch(e, f, g) + K[i] + W[i]; \
    unsigned long t1 = Sigma0(a) + Sha256_Maj(a, b, c);                  \
    d += t0;                                                             \
    h = t0 + t1;                                                         \
  } while(0)

  for(i = 0; i < 64; ++i) {
    unsigned long t;
    RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
    t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
    S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  /* Increase the length of the message */
  md->length += md->curlen * 8;

  /* Append the '1' bit */
  md->buf[md->curlen++] = (unsigned char)0x80;

  /* If the length is currently above 56 bytes we append zeros
   * then compress.  Then we can fall back to padding zeros and length
   * encoding like normal.
   */
  if(md->curlen > 56) {
    while(md->curlen < 64) {
      md->buf[md->curlen++] = (unsigned char)0;
    }
    sha256_compress(md, md->buf);







|







463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  /* Increase the length of the message */
  md->length += md->curlen * 8;

  /* Append the '1' bit */
  md->buf[md->curlen++] = (unsigned char)0x80;

  /* If the length is currently above 56 bytes we append zeros
   * then compress. Then we can fall back to padding zeros and length
   * encoding like normal.
   */
  if(md->curlen > 56) {
    while(md->curlen < 64) {
      md->buf[md->curlen++] = (unsigned char)0;
    }
    sha256_compress(md, md->buf);
538
539
540
541
542
543
544
545
    64,
    /* Result size. */
    32
  }
};


#endif /* AWS, DIGEST, or libSSH2 */







|
538
539
540
541
542
543
544
545
    64,
    /* Result size. */
    32
  }
};


#endif /* AWS, DIGEST, or libssh2 */
Changes to jni/curl/lib/share.c.
22
23
24
25
26
27
28

29
30
31
32
33
34
35
 *
 ***************************************************************************/

#include "curl_setup.h"

#include <curl/curl.h>
#include "urldata.h"

#include "share.h"
#include "psl.h"
#include "vtls/vtls.h"
#include "hsts.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"







>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 ***************************************************************************/

#include "curl_setup.h"

#include <curl/curl.h>
#include "urldata.h"
#include "connect.h"
#include "share.h"
#include "psl.h"
#include "vtls/vtls.h"
#include "hsts.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  void *ptr;
  CURLSHcode res = CURLSHE_OK;

  if(!GOOD_SHARE_HANDLE(share))
    return CURLSHE_INVALID;

  if(share->dirty)
    /* don't allow setting options while one or more handles are already
       using this share */
    return CURLSHE_IN_USE;

  va_start(param, option);

  switch(option) {
  case CURLSHOPT_SHARE:







|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  void *ptr;
  CURLSHcode res = CURLSHE_OK;

  if(!GOOD_SHARE_HANDLE(share))
    return CURLSHE_INVALID;

  if(share->dirty)
    /* do not allow setting options while one or more handles are already
       using this share */
    return CURLSHE_IN_USE;

  va_start(param, option);

  switch(option) {
  case CURLSHOPT_SHARE:
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
      }
#else
      res = CURLSHE_NOT_BUILT_IN;
#endif
      break;

    case CURL_LOCK_DATA_CONNECT:
      if(Curl_conncache_init(&share->conn_cache, 103))
        res = CURLSHE_NOMEM;
      break;

    case CURL_LOCK_DATA_PSL:
#ifndef USE_LIBPSL
      res = CURLSHE_NOT_BUILT_IN;
#endif







|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
      }
#else
      res = CURLSHE_NOT_BUILT_IN;
#endif
      break;

    case CURL_LOCK_DATA_CONNECT:
      if(Curl_conncache_init(&share->conn_cache, NULL, 103))
        res = CURLSHE_NOMEM;
      break;

    case CURL_LOCK_DATA_PSL:
#ifndef USE_LIBPSL
      res = CURLSHE_NOT_BUILT_IN;
#endif
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  if(!share)
    return CURLSHE_INVALID;

  if(share->specifier & (unsigned int)(1<<type)) {
    if(share->lockfunc) /* only call this if set! */
      share->lockfunc(data, type, accesstype, share->clientdata);
  }
  /* else if we don't share this, pretend successful lock */

  return CURLSHE_OK;
}

CURLSHcode
Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
{







|







265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  if(!share)
    return CURLSHE_INVALID;

  if(share->specifier & (unsigned int)(1<<type)) {
    if(share->lockfunc) /* only call this if set! */
      share->lockfunc(data, type, accesstype, share->clientdata);
  }
  /* else if we do not share this, pretend successful lock */

  return CURLSHE_OK;
}

CURLSHcode
Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
{
Changes to jni/curl/lib/share.h.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "psl.h"
#include "urldata.h"
#include "conncache.h"

#define CURL_GOOD_SHARE 0x7e117a1e
#define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE)

/* this struct is libcurl-private, don't export details */
struct Curl_share {
  unsigned int magic; /* CURL_GOOD_SHARE */
  unsigned int specifier;
  volatile unsigned int dirty;

  curl_lock_function lockfunc;
  curl_unlock_function unlockfunc;







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "psl.h"
#include "urldata.h"
#include "conncache.h"

#define CURL_GOOD_SHARE 0x7e117a1e
#define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE)

/* this struct is libcurl-private, do not export details */
struct Curl_share {
  unsigned int magic; /* CURL_GOOD_SHARE */
  unsigned int specifier;
  volatile unsigned int dirty;

  curl_lock_function lockfunc;
  curl_unlock_function unlockfunc;
Changes to jni/curl/lib/smb.c.
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
                                          len));
  memcpy((char *)h->magic, "\xffSMB", 4);
  h->command = cmd;
  h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES;
  h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME);
  h->uid = smb_swap16(smbc->uid);
  h->tid = smb_swap16(req->tid);
  pid = getpid();
  h->pid_high = smb_swap16((unsigned short)(pid >> 16));
  h->pid = smb_swap16((unsigned short) pid);
}

static CURLcode smb_send(struct Curl_easy *data, size_t len,
                         size_t upload_size)
{







|







555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
                                          len));
  memcpy((char *)h->magic, "\xffSMB", 4);
  h->command = cmd;
  h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES;
  h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME);
  h->uid = smb_swap16(smbc->uid);
  h->tid = smb_swap16(req->tid);
  pid = (unsigned int)getpid();
  h->pid_high = smb_swap16((unsigned short)(pid >> 16));
  h->pid = smb_swap16((unsigned short) pid);
}

static CURLcode smb_send(struct Curl_easy *data, size_t len,
                         size_t upload_size)
{
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
    if(data->req.bytecount >= data->req.size)
      next_state = SMB_CLOSE;
    else
      next_state = SMB_UPLOAD;
    break;

  case SMB_CLOSE:
    /* We don't care if the close failed, proceed to tree disconnect anyway */
    next_state = SMB_TREE_DISCONNECT;
    break;

  case SMB_TREE_DISCONNECT:
    next_state = SMB_DONE;
    break;








|







1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
    if(data->req.bytecount >= data->req.size)
      next_state = SMB_CLOSE;
    else
      next_state = SMB_UPLOAD;
    break;

  case SMB_CLOSE:
    /* We do not care if the close failed, proceed to tree disconnect anyway */
    next_state = SMB_TREE_DISCONNECT;
    break;

  case SMB_TREE_DISCONNECT:
    next_state = SMB_DONE;
    break;

Changes to jni/curl/lib/smtp.c.
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct SMTP *smtp = data->req.p.smtp;

  if(smtp->rcpt) {
    /* We notify the server we are sending UTF-8 data if a) it supports the
       SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
       either the local address or host name parts. This is regardless of
       whether the host name is encoded using IDN ACE */
    bool utf8 = FALSE;

    if((!smtp->custom) || (!smtp->custom[0])) {
      char *address = NULL;
      struct hostname host = { NULL, NULL, NULL, NULL };

      /* Parse the mailbox to verify into the local address and host name
         parts, converting the host name to an IDN A-label if necessary */
      result = smtp_parse_address(smtp->rcpt->data,
                                  &address, &host);
      if(result)
        return result;

      /* Establish whether we should report SMTPUTF8 to the server for this
         mailbox as per RFC-6531 sect. 3.1 point 6 */
      utf8 = (conn->proto.smtpc.utf8_supported) &&
             ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
              (!Curl_is_ASCII_name(host.name)));

      /* Send the VRFY command (Note: The host name part may be absent when the
         host is a local system) */
      result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "VRFY %s%s%s%s",
                             address,
                             host.name ? "@" : "",
                             host.name ? host.name : "",
                             utf8 ? " SMTPUTF8" : "");








|
|






|
|











|







530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct SMTP *smtp = data->req.p.smtp;

  if(smtp->rcpt) {
    /* We notify the server we are sending UTF-8 data if a) it supports the
       SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
       either the local address or hostname parts. This is regardless of
       whether the hostname is encoded using IDN ACE */
    bool utf8 = FALSE;

    if((!smtp->custom) || (!smtp->custom[0])) {
      char *address = NULL;
      struct hostname host = { NULL, NULL, NULL, NULL };

      /* Parse the mailbox to verify into the local address and hostname
         parts, converting the hostname to an IDN A-label if necessary */
      result = smtp_parse_address(smtp->rcpt->data,
                                  &address, &host);
      if(result)
        return result;

      /* Establish whether we should report SMTPUTF8 to the server for this
         mailbox as per RFC-6531 sect. 3.1 point 6 */
      utf8 = (conn->proto.smtpc.utf8_supported) &&
             ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
              (!Curl_is_ASCII_name(host.name)));

      /* Send the VRFY command (Note: The hostname part may be absent when the
         host is a local system) */
      result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "VRFY %s%s%s%s",
                             address,
                             host.name ? "@" : "",
                             host.name ? host.name : "",
                             utf8 ? " SMTPUTF8" : "");

603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  char *auth = NULL;
  char *size = NULL;
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;

  /* We notify the server we are sending UTF-8 data if a) it supports the
     SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
     either the local address or host name parts. This is regardless of
     whether the host name is encoded using IDN ACE */
  bool utf8 = FALSE;

  /* Calculate the FROM parameter */
  if(data->set.str[STRING_MAIL_FROM]) {
    char *address = NULL;
    struct hostname host = { NULL, NULL, NULL, NULL };

    /* Parse the FROM mailbox into the local address and host name parts,
       converting the host name to an IDN A-label if necessary */
    result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
                                &address, &host);
    if(result)
      goto out;

    /* Establish whether we should report SMTPUTF8 to the server for this
       mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
    utf8 = (conn->proto.smtpc.utf8_supported) &&
           ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
            (!Curl_is_ASCII_name(host.name)));

    if(host.name) {
      from = aprintf("<%s@%s>", address, host.name);

      Curl_free_idnconverted_hostname(&host);
    }
    else
      /* An invalid mailbox was provided but we'll simply let the server worry
         about that and reply with a 501 error */
      from = aprintf("<%s>", address);

    free(address);
  }
  else
    /* Null reverse-path, RFC-5321, sect. 3.6.3 */
    from = strdup("<>");

  if(!from) {
    result = CURLE_OUT_OF_MEMORY;
    goto out;
  }

  /* Calculate the optional AUTH parameter */
  if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
    if(data->set.str[STRING_MAIL_AUTH][0] != '\0') {
      char *address = NULL;
      struct hostname host = { NULL, NULL, NULL, NULL };

      /* Parse the AUTH mailbox into the local address and host name parts,
         converting the host name to an IDN A-label if necessary */
      result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
                                  &address, &host);
      if(result)
        goto out;

      /* Establish whether we should report SMTPUTF8 to the server for this
         mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
      if((!utf8) && (conn->proto.smtpc.utf8_supported) &&
         ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
          (!Curl_is_ASCII_name(host.name))))
        utf8 = TRUE;

      if(host.name) {
        auth = aprintf("<%s@%s>", address, host.name);

        Curl_free_idnconverted_hostname(&host);
      }
      else
        /* An invalid mailbox was provided but we'll simply let the server
           worry about it */
        auth = aprintf("<%s>", address);
      free(address);
    }
    else
      /* Empty AUTH, RFC-2554, sect. 5 */
      auth = strdup("<>");

    if(!auth) {
      result = CURLE_OUT_OF_MEMORY;
      goto out;
    }
  }

#ifndef CURL_DISABLE_MIME
  /* Prepare the mime data if some. */
  if(data->set.mimepost.kind != MIMEKIND_NONE) {
    /* Use the whole structure as data. */
    data->set.mimepost.flags &= ~MIME_BODY_ONLY;

    /* Add external headers and mime version. */
    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
    result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
                                       NULL, MIMESTRATEGY_MAIL);

    if(!result)







|
|







|
|

















|
|



















|
|


















|


















|







603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  char *auth = NULL;
  char *size = NULL;
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;

  /* We notify the server we are sending UTF-8 data if a) it supports the
     SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
     either the local address or hostname parts. This is regardless of
     whether the hostname is encoded using IDN ACE */
  bool utf8 = FALSE;

  /* Calculate the FROM parameter */
  if(data->set.str[STRING_MAIL_FROM]) {
    char *address = NULL;
    struct hostname host = { NULL, NULL, NULL, NULL };

    /* Parse the FROM mailbox into the local address and hostname parts,
       converting the hostname to an IDN A-label if necessary */
    result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
                                &address, &host);
    if(result)
      goto out;

    /* Establish whether we should report SMTPUTF8 to the server for this
       mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
    utf8 = (conn->proto.smtpc.utf8_supported) &&
           ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
            (!Curl_is_ASCII_name(host.name)));

    if(host.name) {
      from = aprintf("<%s@%s>", address, host.name);

      Curl_free_idnconverted_hostname(&host);
    }
    else
      /* An invalid mailbox was provided but we will simply let the server
         worry about that and reply with a 501 error */
      from = aprintf("<%s>", address);

    free(address);
  }
  else
    /* Null reverse-path, RFC-5321, sect. 3.6.3 */
    from = strdup("<>");

  if(!from) {
    result = CURLE_OUT_OF_MEMORY;
    goto out;
  }

  /* Calculate the optional AUTH parameter */
  if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
    if(data->set.str[STRING_MAIL_AUTH][0] != '\0') {
      char *address = NULL;
      struct hostname host = { NULL, NULL, NULL, NULL };

      /* Parse the AUTH mailbox into the local address and hostname parts,
         converting the hostname to an IDN A-label if necessary */
      result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
                                  &address, &host);
      if(result)
        goto out;

      /* Establish whether we should report SMTPUTF8 to the server for this
         mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
      if((!utf8) && (conn->proto.smtpc.utf8_supported) &&
         ((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
          (!Curl_is_ASCII_name(host.name))))
        utf8 = TRUE;

      if(host.name) {
        auth = aprintf("<%s@%s>", address, host.name);

        Curl_free_idnconverted_hostname(&host);
      }
      else
        /* An invalid mailbox was provided but we will simply let the server
           worry about it */
        auth = aprintf("<%s>", address);
      free(address);
    }
    else
      /* Empty AUTH, RFC-2554, sect. 5 */
      auth = strdup("<>");

    if(!auth) {
      result = CURLE_OUT_OF_MEMORY;
      goto out;
    }
  }

#ifndef CURL_DISABLE_MIME
  /* Prepare the mime data if some. */
  if(data->set.mimepost.kind != MIMEKIND_NONE) {
    /* Use the whole structure as data. */
    data->set.mimepost.flags &= ~(unsigned int)MIME_BODY_ONLY;

    /* Add external headers and mime version. */
    curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
    result = Curl_mime_prepare_headers(data, &data->set.mimepost, NULL,
                                       NULL, MIMESTRATEGY_MAIL);

    if(!result)
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750

    if(!size) {
      result = CURLE_OUT_OF_MEMORY;
      goto out;
    }
  }

  /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8
     based address then quickly scan through the recipient list and check if
     any there do, as we need to correctly identify our support for SMTPUTF8
     in the envelope, as per RFC-6531 sect. 3.4 */
  if(conn->proto.smtpc.utf8_supported && !utf8) {
    struct SMTP *smtp = data->req.p.smtp;
    struct curl_slist *rcpt = smtp->rcpt;

    while(rcpt && !utf8) {
      /* Does the host name contain non-ASCII characters? */
      if(!Curl_is_ASCII_name(rcpt->data))
        utf8 = TRUE;

      rcpt = rcpt->next;
    }
  }








|








|







727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750

    if(!size) {
      result = CURLE_OUT_OF_MEMORY;
      goto out;
    }
  }

  /* If the mailboxes in the FROM and AUTH parameters do not include a UTF-8
     based address then quickly scan through the recipient list and check if
     any there do, as we need to correctly identify our support for SMTPUTF8
     in the envelope, as per RFC-6531 sect. 3.4 */
  if(conn->proto.smtpc.utf8_supported && !utf8) {
    struct SMTP *smtp = data->req.p.smtp;
    struct curl_slist *rcpt = smtp->rcpt;

    while(rcpt && !utf8) {
      /* Does the hostname contain non-ASCII characters? */
      if(!Curl_is_ASCII_name(rcpt->data))
        utf8 = TRUE;

      rcpt = rcpt->next;
    }
  }

786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct SMTP *smtp = data->req.p.smtp;
  char *address = NULL;
  struct hostname host = { NULL, NULL, NULL, NULL };

  /* Parse the recipient mailbox into the local address and host name parts,
     converting the host name to an IDN A-label if necessary */
  result = smtp_parse_address(smtp->rcpt->data,
                              &address, &host);
  if(result)
    return result;

  /* Send the RCPT TO command */
  if(host.name)
    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s@%s>",
                           address, host.name);
  else
    /* An invalid mailbox was provided but we'll simply let the server worry
       about that and reply with a 501 error */
    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s>",
                           address);

  Curl_free_idnconverted_hostname(&host);
  free(address);








|
|










|







786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct SMTP *smtp = data->req.p.smtp;
  char *address = NULL;
  struct hostname host = { NULL, NULL, NULL, NULL };

  /* Parse the recipient mailbox into the local address and hostname parts,
     converting the hostname to an IDN A-label if necessary */
  result = smtp_parse_address(smtp->rcpt->data,
                              &address, &host);
  if(result)
    return result;

  /* Send the RCPT TO command */
  if(host.name)
    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s@%s>",
                           address, host.name);
  else
    /* An invalid mailbox was provided but we will simply let the server worry
       about that and reply with a 501 error */
    result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s>",
                           address);

  Curl_free_idnconverted_hostname(&host);
  free(address);

954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
        line += wordlen;
        len -= wordlen;
      }
    }

    if(smtpcode != 1) {
      if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
        /* We don't have a SSL/TLS connection yet, but SSL is requested */
        if(smtpc->tls_supported)
          /* Switch to TLS connection now */
          result = smtp_perform_starttls(data, conn);
        else if(data->set.use_ssl == CURLUSESSL_TRY)
          /* Fallback and carry on with authentication */
          result = smtp_perform_authentication(data);
        else {







|







954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
        line += wordlen;
        len -= wordlen;
      }
    }

    if(smtpcode != 1) {
      if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
        /* We do not have a SSL/TLS connection yet, but SSL is requested */
        if(smtpc->tls_supported)
          /* Switch to TLS connection now */
          result = smtp_perform_starttls(data, conn);
        else if(data->set.use_ssl == CURLUSESSL_TRY)
          /* Fallback and carry on with authentication */
          result = smtp_perform_authentication(data);
        else {
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  bool is_smtp_err = FALSE;
  bool is_smtp_blocking_err = FALSE;

  (void)instate; /* no use for this yet */

  is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;

  /* If there's multiple RCPT TO to be issued, it's possible to ignore errors
     and proceed with only the valid addresses. */
  is_smtp_blocking_err =
    (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;

  if(is_smtp_err) {
    /* Remembering the last failure which we can report if all "RCPT TO" have
       failed and we cannot proceed. */







|







1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
  bool is_smtp_err = FALSE;
  bool is_smtp_blocking_err = FALSE;

  (void)instate; /* no use for this yet */

  is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;

  /* If there is multiple RCPT TO to be issued, it is possible to ignore errors
     and proceed with only the valid addresses. */
  is_smtp_blocking_err =
    (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;

  if(is_smtp_err) {
    /* Remembering the last failure which we can report if all "RCPT TO" have
       failed and we cannot proceed. */
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
  if(!is_smtp_blocking_err) {
    smtp->rcpt = smtp->rcpt->next;

    if(smtp->rcpt)
      /* Send the next RCPT TO command */
      result = smtp_perform_rcpt_to(data);
    else {
      /* We weren't able to issue a successful RCPT TO command while going
         over recipients (potentially multiple). Sending back last error. */
      if(!smtp->rcpt_had_ok) {
        failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error);
        result = CURLE_SEND_ERROR;
      }
      else {
        /* Send the DATA command */







|







1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
  if(!is_smtp_blocking_err) {
    smtp->rcpt = smtp->rcpt->next;

    if(smtp->rcpt)
      /* Send the next RCPT TO command */
      result = smtp_perform_rcpt_to(data);
    else {
      /* We were not able to issue a successful RCPT TO command while going
         over recipients (potentially multiple). Sending back last error. */
      if(!smtp->rcpt_had_ok) {
        failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error);
        result = CURLE_SEND_ERROR;
      }
      else {
        /* Send the DATA command */
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
    result = CURLE_SEND_ERROR;
  }
  else {
    /* Set the progress upload size */
    Curl_pgrsSetUploadSize(data, data->state.infilesize);

    /* SMTP upload */
    Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);

    /* End of DO phase */
    smtp_state(data, SMTP_STOP);
  }

  return result;
}







|







1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
    result = CURLE_SEND_ERROR;
  }
  else {
    /* Set the progress upload size */
    Curl_pgrsSetUploadSize(data, data->state.infilesize);

    /* SMTP upload */
    Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);

    /* End of DO phase */
    smtp_state(data, SMTP_STOP);
  }

  return result;
}
1198
1199
1200
1201
1202
1203
1204

1205
1206
1207
1208
1209
1210
1211
  CURLcode result = CURLE_OK;
  int smtpcode;
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  struct pingpong *pp = &smtpc->pp;
  size_t nread = 0;

  /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */

  if(smtpc->state == SMTP_UPGRADETLS)
    return smtp_perform_upgrade_tls(data);

  /* Flush any data that needs to be sent */
  if(pp->sendleft)
    return Curl_pp_flushsend(data, pp);








>







1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
  CURLcode result = CURLE_OK;
  int smtpcode;
  struct smtp_conn *smtpc = &conn->proto.smtpc;
  struct pingpong *pp = &smtpc->pp;
  size_t nread = 0;

  /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
upgrade_tls:
  if(smtpc->state == SMTP_UPGRADETLS)
    return smtp_perform_upgrade_tls(data);

  /* Flush any data that needs to be sent */
  if(pp->sendleft)
    return Curl_pp_flushsend(data, pp);

1234
1235
1236
1237
1238
1239
1240




1241
1242
1243
1244
1245
1246
1247

    case SMTP_HELO:
      result = smtp_state_helo_resp(data, smtpcode, smtpc->state);
      break;

    case SMTP_STARTTLS:
      result = smtp_state_starttls_resp(data, smtpcode, smtpc->state);




      break;

    case SMTP_AUTH:
      result = smtp_state_auth_resp(data, smtpcode, smtpc->state);
      break;

    case SMTP_COMMAND:







>
>
>
>







1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252

    case SMTP_HELO:
      result = smtp_state_helo_resp(data, smtpcode, smtpc->state);
      break;

    case SMTP_STARTTLS:
      result = smtp_state_starttls_resp(data, smtpcode, smtpc->state);
      /* During UPGRADETLS, leave the read loop as we need to connect
       * (e.g. TLS handshake) before we continue sending/receiving. */
      if(!result && (smtpc->state == SMTP_UPGRADETLS))
        goto upgrade_tls;
      break;

    case SMTP_AUTH:
      result = smtp_state_auth_resp(data, smtpcode, smtpc->state);
      break;

    case SMTP_COMMAND:
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
  }

  *dophase_done = FALSE; /* not done yet */

  /* Store the first recipient (or NULL if not specified) */
  smtp->rcpt = data->set.mail_rcpt;

  /* Track of whether we've successfully sent at least one RCPT TO command */
  smtp->rcpt_had_ok = FALSE;

  /* Track of the last error we've received by sending RCPT TO command */
  smtp->rcpt_last_error = 0;

  /* Initial data character is the first character in line: it is implicitly
     preceded by a virtual CRLF. */
  smtp->trailing_crlf = TRUE;
  smtp->eob = 2;








|


|







1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  }

  *dophase_done = FALSE; /* not done yet */

  /* Store the first recipient (or NULL if not specified) */
  smtp->rcpt = data->set.mail_rcpt;

  /* Track of whether we have successfully sent at least one RCPT TO command */
  smtp->rcpt_had_ok = FALSE;

  /* Track of the last error we have received by sending RCPT TO command */
  smtp->rcpt_last_error = 0;

  /* Initial data character is the first character in line: it is implicitly
     preceded by a virtual CRLF. */
  smtp->trailing_crlf = TRUE;
  smtp->eob = 2;

1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
{
  struct SMTP *smtp = data->req.p.smtp;

  (void)connected;

  if(smtp->transfer != PPTRANSFER_BODY)
    /* no data to transfer */
    Curl_xfer_setup(data, -1, -1, FALSE, -1);

  return CURLE_OK;
}

/* Called from multi.c while DOing */
static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
{







|







1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
{
  struct SMTP *smtp = data->req.p.smtp;

  (void)connected;

  if(smtp->transfer != PPTRANSFER_BODY)
    /* no data to transfer */
    Curl_xfer_setup_nop(data);

  return CURLE_OK;
}

/* Called from multi.c while DOing */
static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
{
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
}

/***********************************************************************
 *
 * smtp_parse_address()
 *
 * Parse the fully qualified mailbox address into a local address part and the
 * host name, converting the host name to an IDN A-label, as per RFC-5890, if
 * necessary.
 *
 * Parameters:
 *
 * conn  [in]              - The connection handle.
 * fqma  [in]              - The fully qualified mailbox address (which may or
 *                           may not contain UTF-8 characters).
 * address        [in/out] - A new allocated buffer which holds the local
 *                           address part of the mailbox. This buffer must be
 *                           free'ed by the caller.
 * host           [in/out] - The host name structure that holds the original,
 *                           and optionally encoded, host name.
 *                           Curl_free_idnconverted_hostname() must be called
 *                           once the caller has finished with the structure.
 *
 * Returns CURLE_OK on success.
 *
 * Notes:
 *
 * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor
 * that conversion then we shall return success. This allow the caller to send
 * the data to the server as a U-label (as per RFC-6531 sect. 3.2).
 *
 * If an mailbox '@' separator cannot be located then the mailbox is considered
 * to be either a local mailbox or an invalid mailbox (depending on what the
 * calling function deems it to be) then the input will simply be returned in
 * the address part with the host name being NULL.
 */
static CURLcode smtp_parse_address(const char *fqma, char **address,
                                   struct hostname *host)
{
  CURLcode result = CURLE_OK;
  size_t length;

  /* Duplicate the fully qualified email address so we can manipulate it,
     ensuring it doesn't contain the delimiters if specified */
  char *dup = strdup(fqma[0] == '<' ? fqma + 1  : fqma);
  if(!dup)
    return CURLE_OUT_OF_MEMORY;

  length = strlen(dup);
  if(length) {
    if(dup[length - 1] == '>')
      dup[length - 1] = '\0';
  }

  /* Extract the host name from the address (if we can) */
  host->name = strpbrk(dup, "@");
  if(host->name) {
    *host->name = '\0';
    host->name = host->name + 1;

    /* Attempt to convert the host name to IDN ACE */
    (void) Curl_idnconvert_hostname(host);

    /* If Curl_idnconvert_hostname() fails then we shall attempt to continue
       and send the host name using UTF-8 rather than as 7-bit ACE (which is
       our preference) */
  }

  /* Extract the local address from the mailbox */
  *address = dup;

  return result;







|










|
|







|






|








|










|





|



|







1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
}

/***********************************************************************
 *
 * smtp_parse_address()
 *
 * Parse the fully qualified mailbox address into a local address part and the
 * hostname, converting the hostname to an IDN A-label, as per RFC-5890, if
 * necessary.
 *
 * Parameters:
 *
 * conn  [in]              - The connection handle.
 * fqma  [in]              - The fully qualified mailbox address (which may or
 *                           may not contain UTF-8 characters).
 * address        [in/out] - A new allocated buffer which holds the local
 *                           address part of the mailbox. This buffer must be
 *                           free'ed by the caller.
 * host           [in/out] - The hostname structure that holds the original,
 *                           and optionally encoded, hostname.
 *                           Curl_free_idnconverted_hostname() must be called
 *                           once the caller has finished with the structure.
 *
 * Returns CURLE_OK on success.
 *
 * Notes:
 *
 * Should a UTF-8 hostname require conversion to IDN ACE and we cannot honor
 * that conversion then we shall return success. This allow the caller to send
 * the data to the server as a U-label (as per RFC-6531 sect. 3.2).
 *
 * If an mailbox '@' separator cannot be located then the mailbox is considered
 * to be either a local mailbox or an invalid mailbox (depending on what the
 * calling function deems it to be) then the input will simply be returned in
 * the address part with the hostname being NULL.
 */
static CURLcode smtp_parse_address(const char *fqma, char **address,
                                   struct hostname *host)
{
  CURLcode result = CURLE_OK;
  size_t length;

  /* Duplicate the fully qualified email address so we can manipulate it,
     ensuring it does not contain the delimiters if specified */
  char *dup = strdup(fqma[0] == '<' ? fqma + 1  : fqma);
  if(!dup)
    return CURLE_OUT_OF_MEMORY;

  length = strlen(dup);
  if(length) {
    if(dup[length - 1] == '>')
      dup[length - 1] = '\0';
  }

  /* Extract the hostname from the address (if we can) */
  host->name = strpbrk(dup, "@");
  if(host->name) {
    *host->name = '\0';
    host->name = host->name + 1;

    /* Attempt to convert the hostname to IDN ACE */
    (void) Curl_idnconvert_hostname(host);

    /* If Curl_idnconvert_hostname() fails then we shall attempt to continue
       and send the hostname using UTF-8 rather than as 7-bit ACE (which is
       our preference) */
  }

  /* Extract the local address from the mailbox */
  *address = dup;

  return result;
1921
1922
1923
1924
1925
1926
1927

1928
1929
1930
1931
1932
1933
1934
  cr_eob_read,
  cr_eob_close,
  Curl_creader_def_needs_rewind,
  cr_eob_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,

  Curl_creader_def_done,
  sizeof(struct cr_eob_ctx)
};

static CURLcode cr_eob_add(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;







>







1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
  cr_eob_read,
  cr_eob_close,
  Curl_creader_def_needs_rewind,
  cr_eob_total_length,
  Curl_creader_def_resume_from,
  Curl_creader_def_rewind,
  Curl_creader_def_unpause,
  Curl_creader_def_is_paused,
  Curl_creader_def_done,
  sizeof(struct cr_eob_ctx)
};

static CURLcode cr_eob_add(struct Curl_easy *data)
{
  struct Curl_creader *reader = NULL;
Changes to jni/curl/lib/socketpair.c.
23
24
25
26
27
28
29















30

31

32
33
34
35
36
37
38
39
40
41
42
43
44








45


46
47
48
49
50
51






















52
53
54
55
56
57
58
 ***************************************************************************/

#include "curl_setup.h"
#include "socketpair.h"
#include "urldata.h"
#include "rand.h"
















#if defined(HAVE_PIPE) && defined(HAVE_FCNTL)

#include <fcntl.h>


int Curl_pipe(curl_socket_t socks[2])
{
  if(pipe(socks))
    return -1;

  if(fcntl(socks[0], F_SETFD, FD_CLOEXEC) ||
     fcntl(socks[1], F_SETFD, FD_CLOEXEC) ) {
    close(socks[0]);
    close(socks[1]);
    socks[0] = socks[1] = CURL_SOCKET_BAD;
    return -1;
  }











  return 0;
}
#endif


#if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR)






















#ifdef _WIN32
/*
 * This is a socketpair() implementation for Windows.
 */
#include <string.h>
#include <io.h>
#else







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>

>

|



|







>
>
>
>
>
>
>
>
|
>
>





|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
 ***************************************************************************/

#include "curl_setup.h"
#include "socketpair.h"
#include "urldata.h"
#include "rand.h"

#if defined(USE_EVENTFD)
#ifdef HAVE_SYS_EVENTFD_H
#include <sys/eventfd.h>
#endif

int Curl_eventfd(curl_socket_t socks[2], bool nonblocking)
{
  int efd = eventfd(0, nonblocking ? EFD_CLOEXEC | EFD_NONBLOCK : EFD_CLOEXEC);
  if(efd == -1) {
    socks[0] = socks[1] = CURL_SOCKET_BAD;
    return -1;
  }
  socks[0] = socks[1] = efd;
  return 0;
}
#elif defined(HAVE_PIPE)
#ifdef HAVE_FCNTL
#include <fcntl.h>
#endif

int Curl_pipe(curl_socket_t socks[2], bool nonblocking)
{
  if(pipe(socks))
    return -1;
#ifdef HAVE_FCNTL
  if(fcntl(socks[0], F_SETFD, FD_CLOEXEC) ||
     fcntl(socks[1], F_SETFD, FD_CLOEXEC) ) {
    close(socks[0]);
    close(socks[1]);
    socks[0] = socks[1] = CURL_SOCKET_BAD;
    return -1;
  }
#endif
  if(nonblocking) {
    if(curlx_nonblock(socks[0], TRUE) < 0 ||
       curlx_nonblock(socks[1], TRUE) < 0) {
      close(socks[0]);
      close(socks[1]);
      socks[0] = socks[1] = CURL_SOCKET_BAD;
      return -1;
    }
  }

  return 0;
}
#endif


#ifndef CURL_DISABLE_SOCKETPAIR
#ifdef HAVE_SOCKETPAIR
int Curl_socketpair(int domain, int type, int protocol,
                    curl_socket_t socks[2], bool nonblocking)
{
#ifdef SOCK_NONBLOCK
  type = nonblocking ? type | SOCK_NONBLOCK : type;
#endif
  if(socketpair(domain, type, protocol, socks))
    return -1;
#ifndef SOCK_NONBLOCK
  if(nonblocking) {
    if(curlx_nonblock(socks[0], TRUE) < 0 ||
       curlx_nonblock(socks[1], TRUE) < 0) {
      close(socks[0]);
      close(socks[1]);
      return -1;
    }
  }
#endif
  return 0;
}
#else /* !HAVE_SOCKETPAIR */
#ifdef _WIN32
/*
 * This is a socketpair() implementation for Windows.
 */
#include <string.h>
#include <io.h>
#else
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

int Curl_socketpair(int domain, int type, int protocol,
                    curl_socket_t socks[2])
{
  union {
    struct sockaddr_in inaddr;
    struct sockaddr addr;
  } a;
  curl_socket_t listener;
  curl_socklen_t addrlen = sizeof(a.inaddr);







|







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"

int Curl_socketpair(int domain, int type, int protocol,
                    curl_socket_t socks[2], bool nonblocking)
{
  union {
    struct sockaddr_in inaddr;
    struct sockaddr addr;
  } a;
  curl_socket_t listener;
  curl_socklen_t addrlen = sizeof(a.inaddr);
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  a.inaddr.sin_family = AF_INET;
  a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  a.inaddr.sin_port = 0;

  socks[0] = socks[1] = CURL_SOCKET_BAD;

#if defined(_WIN32) || defined(__CYGWIN__)
  /* don't set SO_REUSEADDR on Windows */
  (void)reuse;
#ifdef SO_EXCLUSIVEADDRUSE
  {
    int exclusive = 1;
    if(setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
                  (char *)&exclusive, (curl_socklen_t)sizeof(exclusive)) == -1)
      goto error;







|







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  a.inaddr.sin_family = AF_INET;
  a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  a.inaddr.sin_port = 0;

  socks[0] = socks[1] = CURL_SOCKET_BAD;

#if defined(_WIN32) || defined(__CYGWIN__)
  /* do not set SO_REUSEADDR on Windows */
  (void)reuse;
#ifdef SO_EXCLUSIVEADDRUSE
  {
    int exclusive = 1;
    if(setsockopt(listener, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
                  (char *)&exclusive, (curl_socklen_t)sizeof(exclusive)) == -1)
      goto error;
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    goto error;
  socks[0] = socket(AF_INET, SOCK_STREAM, 0);
  if(socks[0] == CURL_SOCKET_BAD)
    goto error;
  if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1)
    goto error;

  /* use non-blocking accept to make sure we don't block forever */
  if(curlx_nonblock(listener, TRUE) < 0)
    goto error;
  pfd[0].fd = listener;
  pfd[0].events = POLLIN;
  pfd[0].revents = 0;
  (void)Curl_poll(pfd, 1, 1000); /* one second */
  socks[1] = accept(listener, NULL, NULL);







|







179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    goto error;
  socks[0] = socket(AF_INET, SOCK_STREAM, 0);
  if(socks[0] == CURL_SOCKET_BAD)
    goto error;
  if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1)
    goto error;

  /* use non-blocking accept to make sure we do not block forever */
  if(curlx_nonblock(listener, TRUE) < 0)
    goto error;
  pfd[0].fd = listener;
  pfd[0].events = POLLIN;
  pfd[0].revents = 0;
  (void)Curl_poll(pfd, 1, 1000); /* one second */
  socks[1] = accept(listener, NULL, NULL);
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
      pfd[0].events = POLLIN;
      pfd[0].revents = 0;
      (void)Curl_poll(pfd, 1, 1000); /* one second */

      nread = sread(socks[1], p, s);
      if(nread == -1) {
        int sockerr = SOCKERRNO;
        /* Don't block forever */
        if(Curl_timediff(Curl_now(), start) > (60 * 1000))
          goto error;
        if(
#ifdef WSAEWOULDBLOCK
          /* This is how Windows does it */
          (WSAEWOULDBLOCK == sockerr)
#else







|







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
      pfd[0].events = POLLIN;
      pfd[0].revents = 0;
      (void)Curl_poll(pfd, 1, 1000); /* one second */

      nread = sread(socks[1], p, s);
      if(nread == -1) {
        int sockerr = SOCKERRNO;
        /* Do not block forever */
        if(Curl_timediff(Curl_now(), start) > (60 * 1000))
          goto error;
        if(
#ifdef WSAEWOULDBLOCK
          /* This is how Windows does it */
          (WSAEWOULDBLOCK == sockerr)
#else
194
195
196
197
198
199
200




201
202
203
204
205
206
207
208
209
210
211
      }
      if(memcmp(rnd, check, sizeof(check)))
        goto error;
      break;
    } while(1);
  }





  sclose(listener);
  return 0;

error:
  sclose(listener);
  sclose(socks[0]);
  sclose(socks[1]);
  return -1;
}

#endif /* ! HAVE_SOCKETPAIR */







>
>
>
>









|
|
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
      }
      if(memcmp(rnd, check, sizeof(check)))
        goto error;
      break;
    } while(1);
  }

  if(nonblocking)
    if(curlx_nonblock(socks[0], TRUE) < 0 ||
       curlx_nonblock(socks[1], TRUE) < 0)
      goto error;
  sclose(listener);
  return 0;

error:
  sclose(listener);
  sclose(socks[0]);
  sclose(socks[1]);
  return -1;
}
#endif
#endif /* !CURL_DISABLE_SOCKETPAIR */
Changes to jni/curl/lib/socketpair.h.
22
23
24
25
26
27
28



























29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"




























#ifdef HAVE_PIPE

#define wakeup_write  write
#define wakeup_read   read
#define wakeup_close  close
#define wakeup_create(p) Curl_pipe(p)

#ifdef HAVE_FCNTL
#include <curl/curl.h>
int Curl_pipe(curl_socket_t socks[2]);
#else
#define Curl_pipe(p) pipe(p)
#endif

#else /* HAVE_PIPE */

#define wakeup_write     swrite
#define wakeup_read      sread
#define wakeup_close     sclose

#if defined(USE_UNIX_SOCKETS) && defined(HAVE_SOCKETPAIR)
#define SOCKETPAIR_FAMILY AF_UNIX
#elif !defined(HAVE_SOCKETPAIR)
#define SOCKETPAIR_FAMILY 0 /* not used */
#else
#error "unsupported unix domain and socketpair build combo"
#endif

#ifdef SOCK_CLOEXEC
#define SOCKETPAIR_TYPE (SOCK_STREAM | SOCK_CLOEXEC)
#else
#define SOCKETPAIR_TYPE SOCK_STREAM
#endif

#define wakeup_create(p)\
Curl_socketpair(SOCKETPAIR_FAMILY, SOCKETPAIR_TYPE, 0, p)

#endif /* HAVE_PIPE */


#ifndef HAVE_SOCKETPAIR
#include <curl/curl.h>

int Curl_socketpair(int domain, int type, int protocol,
                    curl_socket_t socks[2]);
#else
#define Curl_socketpair(a,b,c,d) socketpair(a,b,c,d)
#endif

#endif /* HEADER_CURL_SOCKETPAIR_H */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|




|

<

|
<
<
<

|



















|
|

|

<
|



|
<
<



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

63
64



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

91
92
93
94
95


96
97
98
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(HAVE_EVENTFD) && \
    defined(__x86_64__) && \
    defined(__aarch64__) && \
    defined(__ia64__) && \
    defined(__ppc64__) && \
    defined(__mips64) && \
    defined(__sparc64__) && \
    defined(__riscv_64e) && \
    defined(__s390x__)

/* Use eventfd only with 64-bit CPU architectures because eventfd has a
 * stringent rule of requiring the 8-byte buffer when calling read(2) and
 * write(2) on it. In some rare cases, the C standard library implementation
 * on a 32-bit system might choose to define uint64_t as a 32-bit type for
 * various reasons (memory limitations, compatibility with older code),
 * which makes eventfd broken.
 */
#define USE_EVENTFD 1

#define wakeup_write  write
#define wakeup_read   read
#define wakeup_close  close
#define wakeup_create(p,nb) Curl_eventfd(p,nb)

#include <curl/curl.h>
int Curl_eventfd(curl_socket_t socks[2], bool nonblocking);

#elif defined(HAVE_PIPE)

#define wakeup_write  write
#define wakeup_read   read
#define wakeup_close  close
#define wakeup_create(p,nb) Curl_pipe(p,nb)


#include <curl/curl.h>
int Curl_pipe(curl_socket_t socks[2], bool nonblocking);




#else /* !USE_EVENTFD && !HAVE_PIPE */

#define wakeup_write     swrite
#define wakeup_read      sread
#define wakeup_close     sclose

#if defined(USE_UNIX_SOCKETS) && defined(HAVE_SOCKETPAIR)
#define SOCKETPAIR_FAMILY AF_UNIX
#elif !defined(HAVE_SOCKETPAIR)
#define SOCKETPAIR_FAMILY 0 /* not used */
#else
#error "unsupported unix domain and socketpair build combo"
#endif

#ifdef SOCK_CLOEXEC
#define SOCKETPAIR_TYPE (SOCK_STREAM | SOCK_CLOEXEC)
#else
#define SOCKETPAIR_TYPE SOCK_STREAM
#endif

#define wakeup_create(p,nb)\
Curl_socketpair(SOCKETPAIR_FAMILY, SOCKETPAIR_TYPE, 0, p, nb)

#endif /* USE_EVENTFD */


#ifndef CURL_DISABLE_SOCKETPAIR
#include <curl/curl.h>

int Curl_socketpair(int domain, int type, int protocol,
                    curl_socket_t socks[2], bool nonblocking);


#endif

#endif /* HEADER_CURL_SOCKETPAIR_H */
Changes to jni/curl/lib/socks.c.
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
      timeout_ms = TIMEDIFF_T_MAX;
    if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) {
      result = ~CURLE_OK;
      break;
    }
    nread = Curl_conn_cf_recv(cf->next, data, buf, buffersize, &err);
    if(nread <= 0) {
      result = err;
      if(CURLE_AGAIN == err)
        continue;
      if(err) {
        break;
      }
    }








|







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
      timeout_ms = TIMEDIFF_T_MAX;
    if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) {
      result = ~CURLE_OK;
      break;
    }
    nread = Curl_conn_cf_recv(cf->next, data, buf, buffersize, &err);
    if(nread <= 0) {
      result = (int)err;
      if(CURLE_AGAIN == err)
        continue;
      if(err) {
        break;
      }
    }

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
    "REQ_READ_MORE",
    "DONE"
  };
#endif

  (void)data;
  if(oldstate == state)
    /* don't bother when the new state is the same as the old state */
    return;

  sx->state = state;

#ifdef DEBUG_AND_VERBOSE
  infof(data,
        "SXSTATE: %s => %s; line %d",







|







190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
    "REQ_READ_MORE",
    "DONE"
  };
#endif

  (void)data;
  if(oldstate == state)
    /* do not bother when the new state is the same as the old state */
    return;

  sx->state = state;

#ifdef DEBUG_AND_VERBOSE
  infof(data,
        "SXSTATE: %s => %s; line %d",
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
        infof(data, "SOCKS4 non-blocking resolve of %s", sx->hostname);
        return CURLPX_OK;
      }
      sxstate(sx, data, CONNECT_RESOLVED);
      goto CONNECT_RESOLVED;
    }

    /* socks4a doesn't resolve anything locally */
    sxstate(sx, data, CONNECT_REQ_INIT);
    goto CONNECT_REQ_INIT;

  case CONNECT_RESOLVING:
    /* check if we have the name resolved by now */
    dns = Curl_fetch_addr(data, sx->hostname, conn->primary.remote_port);








|







331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
        infof(data, "SOCKS4 non-blocking resolve of %s", sx->hostname);
        return CURLPX_OK;
      }
      sxstate(sx, data, CONNECT_RESOLVED);
      goto CONNECT_RESOLVED;
    }

    /* socks4a does not resolve anything locally */
    sxstate(sx, data, CONNECT_REQ_INIT);
    goto CONNECT_REQ_INIT;

  case CONNECT_RESOLVING:
    /* check if we have the name resolved by now */
    dns = Curl_fetch_addr(data, sx->hostname, conn->primary.remote_port);

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
    }
    FALLTHROUGH();
  case CONNECT_RESOLVED:
CONNECT_RESOLVED:
  {
    struct Curl_addrinfo *hp = NULL;
    /*
     * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
     * returns a Curl_addrinfo pointer that may not always look the same.
     */
    if(dns) {
      hp = dns->addr;

      /* scan for the first IPv4 address */
      while(hp && (hp->ai_family != AF_INET))







|







361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
    }
    FALLTHROUGH();
  case CONNECT_RESOLVED:
CONNECT_RESOLVED:
  {
    struct Curl_addrinfo *hp = NULL;
    /*
     * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
     * returns a Curl_addrinfo pointer that may not always look the same.
     */
    if(dns) {
      hp = dns->addr;

      /* scan for the first IPv4 address */
      while(hp && (hp->ai_family != AF_INET))
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
    socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
    if(sx->proxy_user) {
      size_t plen = strlen(sx->proxy_user);
      if(plen > 255) {
        /* there is no real size limit to this field in the protocol, but
           SOCKS5 limits the proxy user field to 255 bytes and it seems likely
           that a longer field is either a mistake or malicious input */
        failf(data, "Too long SOCKS proxy user name");
        return CURLPX_LONG_USER;
      }
      /* copy the proxy name WITH trailing zero */
      memcpy(socksreq + 8, sx->proxy_user, plen + 1);
    }

    /*







|







409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
    socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
    if(sx->proxy_user) {
      size_t plen = strlen(sx->proxy_user);
      if(plen > 255) {
        /* there is no real size limit to this field in the protocol, but
           SOCKS5 limits the proxy user field to 255 bytes and it seems likely
           that a longer field is either a mistake or malicious input */
        failf(data, "Too long SOCKS proxy username");
        return CURLPX_LONG_USER;
      }
      /* copy the proxy name WITH trailing zero */
      memcpy(socksreq + 8, sx->proxy_user, plen + 1);
    }

    /*
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
        socksreq[7] = 1;
        /* append hostname */
        hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */
        if((hostnamelen <= 255) &&
           (packetsize + hostnamelen < sizeof(sx->buffer)))
          strcpy((char *)socksreq + packetsize, sx->hostname);
        else {
          failf(data, "SOCKS4: too long host name");
          return CURLPX_LONG_HOSTNAME;
        }
        packetsize += hostnamelen;
      }
      sx->outp = socksreq;
      DEBUGASSERT(packetsize <= sizeof(sx->buffer));
      sx->outstanding = packetsize;







|







436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
        socksreq[7] = 1;
        /* append hostname */
        hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */
        if((hostnamelen <= 255) &&
           (packetsize + hostnamelen < sizeof(sx->buffer)))
          strcpy((char *)socksreq + packetsize, sx->hostname);
        else {
          failf(data, "SOCKS4: too long hostname");
          return CURLPX_LONG_HOSTNAME;
        }
        packetsize += hostnamelen;
      }
      sx->outp = socksreq;
      DEBUGASSERT(packetsize <= sizeof(sx->buffer));
      sx->outstanding = packetsize;
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  /* Result */
  switch(socksreq[1]) {
  case 90:
    infof(data, "SOCKS4%s request granted.", protocol4a?"a":"");
    break;
  case 91:
    failf(data,
          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected or failed.",
          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
          (unsigned char)socksreq[1]);
    return CURLPX_REQUEST_FAILED;
  case 92:
    failf(data,
          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected because SOCKS server cannot connect to "
          "identd on the client.",
          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
          (unsigned char)socksreq[1]);
    return CURLPX_IDENTD;
  case 93:
    failf(data,
          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected because the client program and identd "
          "report different user-ids.",
          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
          (unsigned char)socksreq[1]);
    return CURLPX_IDENTD_DIFFER;
  default:
    failf(data,
          "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", Unknown.",
          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
          (unsigned char)socksreq[1]);
    return CURLPX_UNKNOWN_FAIL;
  }

  return CURLPX_OK; /* Proxy was successful! */
}

/*
 * This function logs in to a SOCKS5 proxy and sends the specifics to the final
 * destination server.
 */
static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
                               struct socks_state *sx,
                               struct Curl_easy *data)
{
  /*
    According to the RFC1928, section "6.  Replies". This is what a SOCK5
    replies:

        +----+-----+-------+------+----------+----------+
        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+







|







|








|








|



















|







512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
  /* Result */
  switch(socksreq[1]) {
  case 90:
    infof(data, "SOCKS4%s request granted.", protocol4a?"a":"");
    break;
  case 91:
    failf(data,
          "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected or failed.",
          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
          (unsigned char)socksreq[1]);
    return CURLPX_REQUEST_FAILED;
  case 92:
    failf(data,
          "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected because SOCKS server cannot connect to "
          "identd on the client.",
          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
          (unsigned char)socksreq[1]);
    return CURLPX_IDENTD;
  case 93:
    failf(data,
          "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", request rejected because the client program and identd "
          "report different user-ids.",
          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
          (unsigned char)socksreq[1]);
    return CURLPX_IDENTD_DIFFER;
  default:
    failf(data,
          "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
          ", Unknown.",
          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
          (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
          (unsigned char)socksreq[1]);
    return CURLPX_UNKNOWN_FAIL;
  }

  return CURLPX_OK; /* Proxy was successful! */
}

/*
 * This function logs in to a SOCKS5 proxy and sends the specifics to the final
 * destination server.
 */
static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
                               struct socks_state *sx,
                               struct Curl_easy *data)
{
  /*
    According to the RFC1928, section "6. Replies". This is what a SOCK5
    replies:

        +----+-----+-------+------+----------+----------+
        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
        +----+-----+-------+------+----------+----------+
        | 1  |  1  | X'00' |  1   | Variable |    2     |
        +----+-----+-------+------+----------+----------+
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
#endif

  default: /* do nothing! */
    break;

CONNECT_AUTH_INIT:
  case CONNECT_AUTH_INIT: {
    /* Needs user name and password */
    size_t proxy_user_len, proxy_password_len;
    if(sx->proxy_user && sx->proxy_password) {
      proxy_user_len = strlen(sx->proxy_user);
      proxy_password_len = strlen(sx->proxy_password);
    }
    else {
      proxy_user_len = 0;







|







710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
#endif

  default: /* do nothing! */
    break;

CONNECT_AUTH_INIT:
  case CONNECT_AUTH_INIT: {
    /* Needs username and password */
    size_t proxy_user_len, proxy_password_len;
    if(sx->proxy_user && sx->proxy_password) {
      proxy_user_len = strlen(sx->proxy_user);
      proxy_password_len = strlen(sx->proxy_password);
    }
    else {
      proxy_user_len = 0;
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
     */
    len = 0;
    socksreq[len++] = 1;    /* username/pw subnegotiation version */
    socksreq[len++] = (unsigned char) proxy_user_len;
    if(sx->proxy_user && proxy_user_len) {
      /* the length must fit in a single byte */
      if(proxy_user_len > 255) {
        failf(data, "Excessive user name length for proxy auth");
        return CURLPX_LONG_USER;
      }
      memcpy(socksreq + len, sx->proxy_user, proxy_user_len);
    }
    len += proxy_user_len;
    socksreq[len++] = (unsigned char) proxy_password_len;
    if(sx->proxy_password && proxy_password_len) {







|







734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
     */
    len = 0;
    socksreq[len++] = 1;    /* username/pw subnegotiation version */
    socksreq[len++] = (unsigned char) proxy_user_len;
    if(sx->proxy_user && proxy_user_len) {
      /* the length must fit in a single byte */
      if(proxy_user_len > 255) {
        failf(data, "Excessive username length for proxy auth");
        return CURLPX_LONG_USER;
      }
      memcpy(socksreq + len, sx->proxy_user, proxy_user_len);
    }
    len += proxy_user_len;
    socksreq[len++] = (unsigned char) proxy_password_len;
    if(sx->proxy_password && proxy_password_len) {
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
      failf(data,
            "SOCKS5 reply has wrong version, version should be 5.");
      return CURLPX_BAD_VERSION;
    }
    else if(socksreq[1]) { /* Anything besides 0 is an error */
      CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
      int code = socksreq[1];
      failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
            sx->hostname, (unsigned char)socksreq[1]);
      if(code < 9) {
        /* RFC 1928 section 6 lists: */
        static const CURLproxycode lookup[] = {
          CURLPX_OK,
          CURLPX_REPLY_GENERAL_SERVER_FAILURE,
          CURLPX_REPLY_NOT_ALLOWED,







|







986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
      failf(data,
            "SOCKS5 reply has wrong version, version should be 5.");
      return CURLPX_BAD_VERSION;
    }
    else if(socksreq[1]) { /* Anything besides 0 is an error */
      CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
      int code = socksreq[1];
      failf(data, "cannot complete SOCKS5 connection to %s. (%d)",
            sx->hostname, (unsigned char)socksreq[1]);
      if(code < 9) {
        /* RFC 1928 section 6 lists: */
        static const CURLproxycode lookup[] = {
          CURLPX_OK,
          CURLPX_REPLY_GENERAL_SERVER_FAILURE,
          CURLPX_REPLY_NOT_ALLOWED,
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  if(sxstate) {
    free(sxstate);
    cf->ctx = NULL;
  }
}

/* After a TCP connection to the proxy has been verified, this function does
   the next magic steps. If 'done' isn't set TRUE, it is not done yet and
   must be called again.

   Note: this function's sub-functions call failf()

*/
static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,







|







1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  if(sxstate) {
    free(sxstate);
    cf->ctx = NULL;
  }
}

/* After a TCP connection to the proxy has been verified, this function does
   the next magic steps. If 'done' is not set TRUE, it is not done yet and
   must be called again.

   Note: this function's sub-functions call failf()

*/
static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
1245
1246
1247
1248
1249
1250
1251

1252
1253
1254
1255
1256
1257
1258
struct Curl_cftype Curl_cft_socks_proxy = {
  "SOCKS-PROXYY",
  CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
  0,
  socks_proxy_cf_destroy,
  socks_proxy_cf_connect,
  socks_proxy_cf_close,

  socks_cf_get_host,
  socks_cf_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,







>







1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
struct Curl_cftype Curl_cft_socks_proxy = {
  "SOCKS-PROXYY",
  CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
  0,
  socks_proxy_cf_destroy,
  socks_proxy_cf_connect,
  socks_proxy_cf_close,
  Curl_cf_def_shutdown,
  socks_cf_get_host,
  socks_cf_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
Changes to jni/curl/lib/socks_gssapi.c.
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
    failf(data, "Failed to create service name.");
    gss_release_name(&gss_status, &server);
    return CURLE_COULDNT_CONNECT;
  }

  (void)curlx_nonblock(sock, FALSE);

  /* As long as we need to keep sending some context info, and there's no  */
  /* errors, keep sending it...                                            */
  for(;;) {
    gss_major_status = Curl_gss_init_sec_context(data,
                                                 &gss_minor_status,
                                                 &gss_context,
                                                 server,
                                                 &Curl_krb5_mech_oid,







|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
    failf(data, "Failed to create service name.");
    gss_release_name(&gss_status, &server);
    return CURLE_COULDNT_CONNECT;
  }

  (void)curlx_nonblock(sock, FALSE);

  /* As long as we need to keep sending some context info, and there is no  */
  /* errors, keep sending it...                                            */
  for(;;) {
    gss_major_status = Curl_gss_init_sec_context(data,
                                                 &gss_minor_status,
                                                 &gss_context,
                                                 server,
                                                 &Curl_krb5_mech_oid,
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
      failf(data, "Failed to initial GSS-API token.");
      return CURLE_COULDNT_CONNECT;
    }

    if(gss_send_token.length) {
      socksreq[0] = 1;    /* GSS-API subnegotiation version */
      socksreq[1] = 1;    /* authentication message type */
      us_length = htons((short)gss_send_token.length);
      memcpy(socksreq + 2, &us_length, sizeof(short));

      nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
      if(code || (4 != nwritten)) {
        failf(data, "Failed to send GSS-API authentication request.");
        gss_release_name(&gss_status, &server);
        gss_release_buffer(&gss_status, &gss_recv_token);







|







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
      failf(data, "Failed to initial GSS-API token.");
      return CURLE_COULDNT_CONNECT;
    }

    if(gss_send_token.length) {
      socksreq[0] = 1;    /* GSS-API subnegotiation version */
      socksreq[1] = 1;    /* authentication message type */
      us_length = htons((unsigned short)gss_send_token.length);
      memcpy(socksreq + 2, &us_length, sizeof(short));

      nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
      if(code || (4 != nwritten)) {
        failf(data, "Failed to send GSS-API authentication request.");
        gss_release_name(&gss_status, &server);
        gss_release_buffer(&gss_status, &gss_recv_token);
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  gss_major_status = gss_inquire_context(&gss_minor_status, gss_context,
                                         &gss_client_name, NULL, NULL, NULL,
                                         NULL, NULL, NULL);
  if(check_gss_err(data, gss_major_status,
                   gss_minor_status, "gss_inquire_context")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
                                      &gss_send_token, NULL);
  if(check_gss_err(data, gss_major_status,
                   gss_minor_status, "gss_display_name")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  user = malloc(gss_send_token.length + 1);
  if(!user) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);







|









|







302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  gss_major_status = gss_inquire_context(&gss_minor_status, gss_context,
                                         &gss_client_name, NULL, NULL, NULL,
                                         NULL, NULL, NULL);
  if(check_gss_err(data, gss_major_status,
                   gss_minor_status, "gss_inquire_context")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    failf(data, "Failed to determine username.");
    return CURLE_COULDNT_CONNECT;
  }
  gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
                                      &gss_send_token, NULL);
  if(check_gss_err(data, gss_major_status,
                   gss_minor_status, "gss_display_name")) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
    failf(data, "Failed to determine username.");
    return CURLE_COULDNT_CONNECT;
  }
  user = malloc(gss_send_token.length + 1);
  if(!user) {
    gss_delete_sec_context(&gss_status, &gss_context, NULL);
    gss_release_name(&gss_status, &gss_client_name);
    gss_release_buffer(&gss_status, &gss_send_token);
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
   *
   *  - "len" is the length of the "token" field in octets
   *
   *  - "token" is the GSS-API encapsulated protection level
   *
   * The token is produced by encapsulating an octet containing the
   * required protection level using gss_seal()/gss_wrap() with conf_req
   * set to FALSE.  The token is verified using gss_unseal()/
   * gss_unwrap().
   *
   */
  if(data->set.socks5_gssapi_nec) {
    us_length = htons((short)1);
    memcpy(socksreq + 2, &us_length, sizeof(short));
  }







|







373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
   *
   *  - "len" is the length of the "token" field in octets
   *
   *  - "token" is the GSS-API encapsulated protection level
   *
   * The token is produced by encapsulating an octet containing the
   * required protection level using gss_seal()/gss_wrap() with conf_req
   * set to FALSE. The token is verified using gss_unseal()/
   * gss_unwrap().
   *
   */
  if(data->set.socks5_gssapi_nec) {
    us_length = htons((short)1);
    memcpy(socksreq + 2, &us_length, sizeof(short));
  }
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to wrap GSS-API encryption value into token.");
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_send_token);

    us_length = htons((short)gss_w_token.length);
    memcpy(socksreq + 2, &us_length, sizeof(short));
  }

  nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
  if(code  || (4 != nwritten)) {
    failf(data, "Failed to send GSS-API encryption request.");
    gss_release_buffer(&gss_status, &gss_w_token);







|







402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
      gss_release_buffer(&gss_status, &gss_w_token);
      gss_delete_sec_context(&gss_status, &gss_context, NULL);
      failf(data, "Failed to wrap GSS-API encryption value into token.");
      return CURLE_COULDNT_CONNECT;
    }
    gss_release_buffer(&gss_status, &gss_send_token);

    us_length = htons((unsigned short)gss_w_token.length);
    memcpy(socksreq + 2, &us_length, sizeof(short));
  }

  nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
  if(code  || (4 != nwritten)) {
    failf(data, "Failed to send GSS-API encryption request.");
    gss_release_buffer(&gss_status, &gss_w_token);
Changes to jni/curl/lib/socks_sspi.c.
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
    free(service_name);
    s_pSecFn->FreeCredentialsHandle(&cred_handle);
    return CURLE_COULDNT_CONNECT;
  }

  (void)curlx_nonblock(sock, FALSE);

  /* As long as we need to keep sending some context info, and there's no  */
  /* errors, keep sending it...                                            */
  for(;;) {
    TCHAR *sname;

    sname = curlx_convert_UTF8_to_tchar(service_name);
    if(!sname)
      return CURLE_OUT_OF_MEMORY;







|







154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
    free(service_name);
    s_pSecFn->FreeCredentialsHandle(&cred_handle);
    return CURLE_COULDNT_CONNECT;
  }

  (void)curlx_nonblock(sock, FALSE);

  /* As long as we need to keep sending some context info, and there is no  */
  /* errors, keep sending it...                                            */
  for(;;) {
    TCHAR *sname;

    sname = curlx_convert_UTF8_to_tchar(service_name);
    if(!sname)
      return CURLE_OUT_OF_MEMORY;
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
      failf(data, "Failed to initialise security context.");
      return CURLE_COULDNT_CONNECT;
    }

    if(sspi_send_token.cbBuffer) {
      socksreq[0] = 1;    /* GSS-API subnegotiation version */
      socksreq[1] = 1;    /* authentication message type */
      us_length = htons((short)sspi_send_token.cbBuffer);
      memcpy(socksreq + 2, &us_length, sizeof(short));

      written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
      if(code || (4 != written)) {
        failf(data, "Failed to send SSPI authentication request.");
        free(service_name);
        if(sspi_send_token.pvBuffer)







|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
      failf(data, "Failed to initialise security context.");
      return CURLE_COULDNT_CONNECT;
    }

    if(sspi_send_token.cbBuffer) {
      socksreq[0] = 1;    /* GSS-API subnegotiation version */
      socksreq[1] = 1;    /* authentication message type */
      us_length = htons((unsigned short)sspi_send_token.cbBuffer);
      memcpy(socksreq + 2, &us_length, sizeof(short));

      written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
      if(code || (4 != written)) {
        failf(data, "Failed to send SSPI authentication request.");
        free(service_name);
        if(sspi_send_token.pvBuffer)
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  status = s_pSecFn->QueryCredentialsAttributes(&cred_handle,
                                                SECPKG_CRED_ATTR_NAMES,
                                                &names);
  s_pSecFn->FreeCredentialsHandle(&cred_handle);
  if(check_sspi_err(data, status, "QueryCredentialAttributes")) {
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    s_pSecFn->FreeContextBuffer(names.sUserName);
    failf(data, "Failed to determine user name.");
    return CURLE_COULDNT_CONNECT;
  }
  else {
#ifndef CURL_DISABLE_VERBOSE_STRINGS
    char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName);
    infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
          (user_utf8 ? user_utf8 : "(unknown)"));







|







324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  status = s_pSecFn->QueryCredentialsAttributes(&cred_handle,
                                                SECPKG_CRED_ATTR_NAMES,
                                                &names);
  s_pSecFn->FreeCredentialsHandle(&cred_handle);
  if(check_sspi_err(data, status, "QueryCredentialAttributes")) {
    s_pSecFn->DeleteSecurityContext(&sspi_context);
    s_pSecFn->FreeContextBuffer(names.sUserName);
    failf(data, "Failed to determine username.");
    return CURLE_COULDNT_CONNECT;
  }
  else {
#ifndef CURL_DISABLE_VERBOSE_STRINGS
    char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName);
    infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
          (user_utf8 ? user_utf8 : "(unknown)"));
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
   *
   *  - "len" is the length of the "token" field in octets
   *
   *  - "token" is the GSS-API encapsulated protection level
   *
   * The token is produced by encapsulating an octet containing the
   * required protection level using gss_seal()/gss_wrap() with conf_req
   * set to FALSE.  The token is verified using gss_unseal()/
   * gss_unwrap().
   *
   */

  if(data->set.socks5_gssapi_nec) {
    us_length = htons((short)1);
    memcpy(socksreq + 2, &us_length, sizeof(short));
  }
  else {
    status = s_pSecFn->QueryContextAttributes(&sspi_context,
                                              SECPKG_ATTR_SIZES,
                                              &sspi_sizes);
    if(check_sspi_err(data, status, "QueryContextAttributes")) {







|





|







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
   *
   *  - "len" is the length of the "token" field in octets
   *
   *  - "token" is the GSS-API encapsulated protection level
   *
   * The token is produced by encapsulating an octet containing the
   * required protection level using gss_seal()/gss_wrap() with conf_req
   * set to FALSE. The token is verified using gss_unseal()/
   * gss_unwrap().
   *
   */

  if(data->set.socks5_gssapi_nec) {
    us_length = htons((unsigned short)1);
    memcpy(socksreq + 2, &us_length, sizeof(short));
  }
  else {
    status = s_pSecFn->QueryContextAttributes(&sspi_context,
                                              SECPKG_ATTR_SIZES,
                                              &sspi_sizes);
    if(check_sspi_err(data, status, "QueryContextAttributes")) {
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    sspi_w_token[1].pvBuffer = NULL;
    sspi_w_token[1].cbBuffer = 0;
    s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
    sspi_w_token[2].pvBuffer = NULL;
    sspi_w_token[2].cbBuffer = 0;

    us_length = htons((short)sspi_send_token.cbBuffer);
    memcpy(socksreq + 2, &us_length, sizeof(short));
  }

  written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
  if(code || (4 != written)) {
    failf(data, "Failed to send SSPI encryption request.");
    if(sspi_send_token.pvBuffer)







|







468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
    sspi_w_token[1].pvBuffer = NULL;
    sspi_w_token[1].cbBuffer = 0;
    s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
    sspi_w_token[2].pvBuffer = NULL;
    sspi_w_token[2].cbBuffer = 0;

    us_length = htons((unsigned short)sspi_send_token.cbBuffer);
    memcpy(socksreq + 2, &us_length, sizeof(short));
  }

  written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
  if(code || (4 != written)) {
    failf(data, "Failed to send SSPI encryption request.");
    if(sspi_send_token.pvBuffer)
Changes to jni/curl/lib/splay.c.
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  r->smaller = t->larger;
  t->smaller = N.larger;
  t->larger = N.smaller;

  return t;
}

/* Insert key i into the tree t.  Return a pointer to the resulting tree or
 * NULL if something went wrong.
 *
 * @unittest: 1309
 */
struct Curl_tree *Curl_splayinsert(struct curltime i,
                                   struct Curl_tree *t,
                                   struct Curl_tree *node)







|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  r->smaller = t->larger;
  t->smaller = N.larger;
  t->larger = N.smaller;

  return t;
}

/* Insert key i into the tree t. Return a pointer to the resulting tree or
 * NULL if something went wrong.
 *
 * @unittest: 1309
 */
struct Curl_tree *Curl_splayinsert(struct curltime i,
                                   struct Curl_tree *t,
                                   struct Curl_tree *node)
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  /* no identical nodes (yet), we are the only one in the list of nodes */
  node->samen = node;
  node->samep = node;
  return node;
}

/* Finds and deletes the best-fit node from the tree. Return a pointer to the
   resulting tree.  best-fit means the smallest node if it is not larger than
   the key */
struct Curl_tree *Curl_splaygetbest(struct curltime i,
                                    struct Curl_tree *t,
                                    struct Curl_tree **removed)
{
  static const struct curltime tv_zero = {0, 0};
  struct Curl_tree *x;







|







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  /* no identical nodes (yet), we are the only one in the list of nodes */
  node->samen = node;
  node->samep = node;
  return node;
}

/* Finds and deletes the best-fit node from the tree. Return a pointer to the
   resulting tree. best-fit means the smallest node if it is not larger than
   the key */
struct Curl_tree *Curl_splaygetbest(struct curltime i,
                                    struct Curl_tree *t,
                                    struct Curl_tree **removed)
{
  static const struct curltime tv_zero = {0, 0};
  struct Curl_tree *x;
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  x = t->larger;
  *removed = t;

  return x;
}


/* Deletes the very node we point out from the tree if it's there. Stores a
 * pointer to the new resulting tree in 'newroot'.
 *
 * Returns zero on success and non-zero on errors!
 * When returning error, it does not touch the 'newroot' pointer.
 *
 * NOTE: when the last node of the tree is removed, there's no tree left so
 * 'newroot' will be made to point to NULL.
 *
 * @unittest: 1309
 */
int Curl_splayremove(struct Curl_tree *t,
                     struct Curl_tree *removenode,
                     struct Curl_tree **newroot)







|





|







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  x = t->larger;
  *removed = t;

  return x;
}


/* Deletes the very node we point out from the tree if it is there. Stores a
 * pointer to the new resulting tree in 'newroot'.
 *
 * Returns zero on success and non-zero on errors!
 * When returning error, it does not touch the 'newroot' pointer.
 *
 * NOTE: when the last node of the tree is removed, there is no tree left so
 * 'newroot' will be made to point to NULL.
 *
 * @unittest: 1309
 */
int Curl_splayremove(struct Curl_tree *t,
                     struct Curl_tree *removenode,
                     struct Curl_tree **newroot)
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
    return 0;
  }

  t = Curl_splay(removenode->key, t);

  /* First make sure that we got the same root node as the one we want
     to remove, as otherwise we might be trying to remove a node that
     isn't actually in the tree.

     We cannot just compare the keys here as a double remove in quick
     succession of a node with key != KEY_NOTUSED && same != NULL
     could return the same key but a different node. */
  if(t != removenode)
    return 2;

  /* Check if there is a list with identical sizes, as then we're trying to
     remove the root node of a list of nodes with identical keys. */
  x = t->samen;
  if(x != t) {
    /* 'x' is the new root node, we just make it use the root node's
       smaller/larger links */

    x->key = t->key;







|







|







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
    return 0;
  }

  t = Curl_splay(removenode->key, t);

  /* First make sure that we got the same root node as the one we want
     to remove, as otherwise we might be trying to remove a node that
     is not actually in the tree.

     We cannot just compare the keys here as a double remove in quick
     succession of a node with key != KEY_NOTUSED && same != NULL
     could return the same key but a different node. */
  if(t != removenode)
    return 2;

  /* Check if there is a list with identical sizes, as then we are trying to
     remove the root node of a list of nodes with identical keys. */
  x = t->samen;
  if(x != t) {
    /* 'x' is the new root node, we just make it use the root node's
       smaller/larger links */

    x->key = t->key;
Changes to jni/curl/lib/splay.h.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

struct Curl_tree {
  struct Curl_tree *smaller; /* smaller node */
  struct Curl_tree *larger;  /* larger node */
  struct Curl_tree *samen;   /* points to the next node with identical key */
  struct Curl_tree *samep;   /* points to the prev node with identical key */
  struct curltime key;        /* this node's "sort" key */
  void *payload;             /* data the splay code doesn't care about */
};

struct Curl_tree *Curl_splay(struct curltime i,
                             struct Curl_tree *t);

struct Curl_tree *Curl_splayinsert(struct curltime key,
                                   struct Curl_tree *t,







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

struct Curl_tree {
  struct Curl_tree *smaller; /* smaller node */
  struct Curl_tree *larger;  /* larger node */
  struct Curl_tree *samen;   /* points to the next node with identical key */
  struct Curl_tree *samep;   /* points to the prev node with identical key */
  struct curltime key;        /* this node's "sort" key */
  void *payload;             /* data the splay code does not care about */
};

struct Curl_tree *Curl_splay(struct curltime i,
                             struct Curl_tree *t);

struct Curl_tree *Curl_splayinsert(struct curltime key,
                                   struct Curl_tree *t,
Changes to jni/curl/lib/strcase.c.
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
 * further explanations as to why this function is necessary.
 */

static int casecompare(const char *first, const char *second)
{
  while(*first && *second) {
    if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
      /* get out of the loop as soon as they don't match */
      return 0;
    first++;
    second++;
  }
  /* If we're here either the strings are the same or the length is different.
     We can just test if the "current" character is non-zero for one and zero
     for the other. Note that the characters may not be exactly the same even
     if they match, we only want to compare zero-ness. */
  return !*first == !*second;
}

/* --- public function --- */







|




|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
 * further explanations as to why this function is necessary.
 */

static int casecompare(const char *first, const char *second)
{
  while(*first && *second) {
    if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
      /* get out of the loop as soon as they do not match */
      return 0;
    first++;
    second++;
  }
  /* If we are here either the strings are the same or the length is different.
     We can just test if the "current" character is non-zero for one and zero
     for the other. Note that the characters may not be exactly the same even
     if they match, we only want to compare zero-ness. */
  return !*first == !*second;
}

/* --- public function --- */
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  if(first && second)
    /* both pointers point to something then compare them */
    return ncasecompare(first, second, max);

  /* if both pointers are NULL then treat them as equal if max is non-zero */
  return (NULL == first && NULL == second && max);
}
/* Copy an upper case version of the string from src to dest.  The
 * strings may overlap.  No more than n characters of the string are copied
 * (including any NUL) and the destination string will NOT be
 * NUL-terminated if that limit is reached.
 */
void Curl_strntoupper(char *dest, const char *src, size_t n)
{
  if(n < 1)
    return;

  do {
    *dest++ = Curl_raw_toupper(*src);
  } while(*src++ && --n);
}

/* Copy a lower case version of the string from src to dest.  The
 * strings may overlap.  No more than n characters of the string are copied
 * (including any NUL) and the destination string will NOT be
 * NUL-terminated if that limit is reached.
 */
void Curl_strntolower(char *dest, const char *src, size_t n)
{
  if(n < 1)
    return;







|
|













|
|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  if(first && second)
    /* both pointers point to something then compare them */
    return ncasecompare(first, second, max);

  /* if both pointers are NULL then treat them as equal if max is non-zero */
  return (NULL == first && NULL == second && max);
}
/* Copy an upper case version of the string from src to dest. The
 * strings may overlap. No more than n characters of the string are copied
 * (including any NUL) and the destination string will NOT be
 * NUL-terminated if that limit is reached.
 */
void Curl_strntoupper(char *dest, const char *src, size_t n)
{
  if(n < 1)
    return;

  do {
    *dest++ = Curl_raw_toupper(*src);
  } while(*src++ && --n);
}

/* Copy a lower case version of the string from src to dest. The
 * strings may overlap. No more than n characters of the string are copied
 * (including any NUL) and the destination string will NOT be
 * NUL-terminated if that limit is reached.
 */
void Curl_strntolower(char *dest, const char *src, size_t n)
{
  if(n < 1)
    return;
Changes to jni/curl/lib/strerror.c.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    return "URL using bad/illegal format or missing URL";

  case CURLE_NOT_BUILT_IN:
    return "A requested feature, protocol or option was not found built-in in"
      " this libcurl due to a build-time decision.";

  case CURLE_COULDNT_RESOLVE_PROXY:
    return "Couldn't resolve proxy name";

  case CURLE_COULDNT_RESOLVE_HOST:
    return "Couldn't resolve host name";

  case CURLE_COULDNT_CONNECT:
    return "Couldn't connect to server";

  case CURLE_WEIRD_SERVER_REPLY:
    return "Weird server reply";

  case CURLE_REMOTE_ACCESS_DENIED:
    return "Access denied to remote resource";








|


|


|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    return "URL using bad/illegal format or missing URL";

  case CURLE_NOT_BUILT_IN:
    return "A requested feature, protocol or option was not found built-in in"
      " this libcurl due to a build-time decision.";

  case CURLE_COULDNT_RESOLVE_PROXY:
    return "Could not resolve proxy name";

  case CURLE_COULDNT_RESOLVE_HOST:
    return "Could not resolve hostname";

  case CURLE_COULDNT_CONNECT:
    return "Could not connect to server";

  case CURLE_WEIRD_SERVER_REPLY:
    return "Weird server reply";

  case CURLE_REMOTE_ACCESS_DENIED:
    return "Access denied to remote resource";

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  case CURLE_FTP_WEIRD_PASV_REPLY:
    return "FTP: unknown PASV reply";

  case CURLE_FTP_WEIRD_227_FORMAT:
    return "FTP: unknown 227 response format";

  case CURLE_FTP_CANT_GET_HOST:
    return "FTP: can't figure out the host in the PASV response";

  case CURLE_HTTP2:
    return "Error in the HTTP2 framing layer";

  case CURLE_FTP_COULDNT_SET_TYPE:
    return "FTP: couldn't set file type";

  case CURLE_PARTIAL_FILE:
    return "Transferred a partial file";

  case CURLE_FTP_COULDNT_RETR_FILE:
    return "FTP: couldn't retrieve (RETR failed) the specified file";

  case CURLE_QUOTE_ERROR:
    return "Quote command returned error";

  case CURLE_HTTP_RETURNED_ERROR:
    return "HTTP response code said error";








|





|





|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  case CURLE_FTP_WEIRD_PASV_REPLY:
    return "FTP: unknown PASV reply";

  case CURLE_FTP_WEIRD_227_FORMAT:
    return "FTP: unknown 227 response format";

  case CURLE_FTP_CANT_GET_HOST:
    return "FTP: cannot figure out the host in the PASV response";

  case CURLE_HTTP2:
    return "Error in the HTTP2 framing layer";

  case CURLE_FTP_COULDNT_SET_TYPE:
    return "FTP: could not set file type";

  case CURLE_PARTIAL_FILE:
    return "Transferred a partial file";

  case CURLE_FTP_COULDNT_RETR_FILE:
    return "FTP: could not retrieve (RETR failed) the specified file";

  case CURLE_QUOTE_ERROR:
    return "Quote command returned error";

  case CURLE_HTTP_RETURNED_ERROR:
    return "HTTP response code said error";

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  case CURLE_HTTP_POST_ERROR:
    return "Internal problem setting up the POST";

  case CURLE_SSL_CONNECT_ERROR:
    return "SSL connect error";

  case CURLE_BAD_DOWNLOAD_RESUME:
    return "Couldn't resume download";

  case CURLE_FILE_COULDNT_READ_FILE:
    return "Couldn't read a file:// file";

  case CURLE_LDAP_CANNOT_BIND:
    return "LDAP: cannot bind";

  case CURLE_LDAP_SEARCH_FAILED:
    return "LDAP: search failed";








|


|







154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  case CURLE_HTTP_POST_ERROR:
    return "Internal problem setting up the POST";

  case CURLE_SSL_CONNECT_ERROR:
    return "SSL connect error";

  case CURLE_BAD_DOWNLOAD_RESUME:
    return "Could not resume download";

  case CURLE_FILE_COULDNT_READ_FILE:
    return "Could not read a file:// file";

  case CURLE_LDAP_CANNOT_BIND:
    return "LDAP: cannot bind";

  case CURLE_LDAP_SEARCH_FAILED:
    return "LDAP: search failed";

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  case CURLE_RECV_ERROR:
    return "Failure when receiving data from the peer";

  case CURLE_SSL_CERTPROBLEM:
    return "Problem with the local SSL certificate";

  case CURLE_SSL_CIPHER:
    return "Couldn't use specified SSL cipher";

  case CURLE_PEER_FAILED_VERIFICATION:
    return "SSL peer certificate or SSH remote key was not OK";

  case CURLE_SSL_CACERT_BADFILE:
    return "Problem with the SSL CA cert (path? access rights?)";








|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  case CURLE_RECV_ERROR:
    return "Failure when receiving data from the peer";

  case CURLE_SSL_CERTPROBLEM:
    return "Problem with the local SSL certificate";

  case CURLE_SSL_CIPHER:
    return "Could not use specified SSL cipher";

  case CURLE_PEER_FAILED_VERIFICATION:
    return "SSL peer certificate or SSH remote key was not OK";

  case CURLE_SSL_CACERT_BADFILE:
    return "Problem with the SSL CA cert (path? access rights?)";

341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  case CURLE_OBSOLETE76:
  case CURL_LAST:
    break;
  }
  /*
   * By using a switch, gcc -Wall will complain about enum values
   * which do not appear, helping keep this function up-to-date.
   * By using gcc -Wall -Werror, you can't forget.
   *
   * A table would not have the same benefit.  Most compilers will
   * generate code very similar to a table in any case, so there
   * is little performance gain from a table.  And something is broken
   * for the user's application, anyways, so does it matter how fast
   * it _doesn't_ work?
   *
   * The line number for the error will be near this comment, which
   * is why it is here, and not at the start of the switch.
   */
  return "Unknown error";
#else
  if(!error)
    return "No error";
  else
    return "Error";







|

|
|
|
|
<

|
|







341
342
343
344
345
346
347
348
349
350
351
352
353

354
355
356
357
358
359
360
361
362
363
  case CURLE_OBSOLETE76:
  case CURL_LAST:
    break;
  }
  /*
   * By using a switch, gcc -Wall will complain about enum values
   * which do not appear, helping keep this function up-to-date.
   * By using gcc -Wall -Werror, you cannot forget.
   *
   * A table would not have the same benefit. Most compilers will generate
   * code very similar to a table in any case, so there is little performance
   * gain from a table. Something is broken for the user's application,
   * anyways, so does it matter how fast it _does not_ work?

   *
   * The line number for the error will be near this comment, which is why it
   * is here, and not at the start of the switch.
   */
  return "Unknown error";
#else
  if(!error)
    return "No error";
  else
    return "Error";
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
  *wbuf = L'\0';

  /* We return the local codepage version of the error string because if it is
     output to the user's terminal it will likely be with functions which
     expect the local codepage (eg fprintf, failf, infof).
     FormatMessageW -> wcstombs is used for Windows CE compatibility. */
  if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
                     FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err,
                    LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
    size_t written = wcstombs(buf, wbuf, buflen - 1);
    if(written != (size_t)-1)
      buf[written] = '\0';
    else
      *buf = '\0';
  }







|







790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
  *wbuf = L'\0';

  /* We return the local codepage version of the error string because if it is
     output to the user's terminal it will likely be with functions which
     expect the local codepage (eg fprintf, failf, infof).
     FormatMessageW -> wcstombs is used for Windows CE compatibility. */
  if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
                     FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
                    LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
    size_t written = wcstombs(buf, wbuf, buflen - 1);
    if(written != (size_t)-1)
      buf[written] = '\0';
    else
      *buf = '\0';
  }
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835

/*
 * Our thread-safe and smart strerror() replacement.
 *
 * The 'err' argument passed in to this function MUST be a true errno number
 * as reported on this system. We do no range checking on the number before
 * we pass it to the "number-to-message" conversion function and there might
 * be systems that don't do proper range checking in there themselves.
 *
 * We don't do range checking (on systems other than Windows) since there is
 * no good reliable and portable way to do it.
 *
 * On Windows different types of error codes overlap. This function has an
 * order of preference when trying to match error codes:
 * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError).
 *
 * It may be more correct to call one of the variant functions instead:







|

|







818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834

/*
 * Our thread-safe and smart strerror() replacement.
 *
 * The 'err' argument passed in to this function MUST be a true errno number
 * as reported on this system. We do no range checking on the number before
 * we pass it to the "number-to-message" conversion function and there might
 * be systems that do not do proper range checking in there themselves.
 *
 * We do not do range checking (on systems other than Windows) since there is
 * no good reliable and portable way to do it.
 *
 * On Windows different types of error codes overlap. This function has an
 * order of preference when trying to match error codes:
 * CRT (errno), Winsock (WSAGetLastError), Windows API (GetLastError).
 *
 * It may be more correct to call one of the variant functions instead:
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
  else
#endif
  {
    if(
#ifdef USE_WINSOCK
       !get_winsock_error(err, buf, buflen) &&
#endif
       !get_winapi_error((DWORD)err, buf, buflen))
      msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
  }
#else /* not Windows coming up */

#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
 /*
  * The POSIX-style strerror_r() may set errno to ERANGE if insufficient







|







860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
  else
#endif
  {
    if(
#ifdef USE_WINSOCK
       !get_winsock_error(err, buf, buflen) &&
#endif
       !get_winapi_error(err, buf, buflen))
      msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
  }
#else /* not Windows coming up */

#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
 /*
  * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954

  if(!buflen)
    return NULL;

  *buf = '\0';

#ifndef CURL_DISABLE_VERBOSE_STRINGS
  if(!get_winapi_error(err, buf, buflen)) {
    msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
  }
#else
  {
    const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
    if(strlen(txt) < buflen)
      strcpy(buf, txt);







|







939
940
941
942
943
944
945
946
947
948
949
950
951
952
953

  if(!buflen)
    return NULL;

  *buf = '\0';

#ifndef CURL_DISABLE_VERBOSE_STRINGS
  if(!get_winapi_error((int)err, buf, buflen)) {
    msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
  }
#else
  {
    const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
    if(strlen(txt) < buflen)
      strcpy(buf, txt);
Changes to jni/curl/lib/strtok.c.
61
62
63
64
65
66
67
68
    return start; /* return the position where the string starts */
  }

  /* we ended up on a null byte, there are no more strings to find! */
  return NULL;
}

#endif /* this was only compiled if strtok_r wasn't present */







|
61
62
63
64
65
66
67
68
    return start; /* return the position where the string starts */
  }

  /* we ended up on a null byte, there are no more strings to find! */
  return NULL;
}

#endif /* this was only compiled if strtok_r was not present */
Changes to jni/curl/lib/strtoofft.c.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

#include "strtoofft.h"

/*
 * NOTE:
 *
 * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
 * could use in case strtoll() doesn't exist...  See
 * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
 */

#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
#  ifdef HAVE_STRTOLL
#    define strtooff strtoll
#  else







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

#include "strtoofft.h"

/*
 * NOTE:
 *
 * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
 * could use in case strtoll() does not exist... See
 * https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
 */

#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
#  ifdef HAVE_STRTOLL
#    define strtooff strtoll
#  else
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
static const char valchars[] =
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
#endif

static int get_char(char c, int base);

/**
 * Custom version of the strtooff function.  This extracts a curl_off_t
 * value from the given input string and returns it.
 */
static curl_off_t strtooff(const char *nptr, char **endptr, int base)
{
  char *end;
  bool is_negative = FALSE;
  bool overflow = FALSE;







|







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
static const char valchars[] =
            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
#endif

static int get_char(char c, int base);

/**
 * Custom version of the strtooff function. This extracts a curl_off_t
 * value from the given input string and returns it.
 */
static curl_off_t strtooff(const char *nptr, char **endptr, int base)
{
  char *end;
  bool is_negative = FALSE;
  bool overflow = FALSE;
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  else if(end[0] == '0') {
    if(base == 8 || base == 0) {
      end++;
      base = 8;
    }
  }

  /* Matching strtol, if the base is 0 and it doesn't look like
   * the number is octal or hex, we assume it's base 10.
   */
  if(base == 0) {
    base = 10;
  }

  /* Loop handling digits. */
  for(i = get_char(end[0], base);







|
|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  else if(end[0] == '0') {
    if(base == 8 || base == 0) {
      end++;
      base = 8;
    }
  }

  /* Matching strtol, if the base is 0 and it does not look like
   * the number is octal or hex, we assume it is base 10.
   */
  if(base == 0) {
    base = 10;
  }

  /* Loop handling digits. */
  for(i = get_char(end[0], base);
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
 * Returns the value of c in the given base, or -1 if c cannot
 * be interpreted properly in that base (i.e., is out of range,
 * is a null, etc.).
 *
 * @param c     the character to interpret according to base
 * @param base  the base in which to interpret c
 *
 * @return  the value of c in base, or -1 if c isn't in range
 */
static int get_char(char c, int base)
{
#ifndef NO_RANGE_TEST
  int value = -1;
  if(c <= '9' && c >= '0') {
    value = c - '0';







|







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
 * Returns the value of c in the given base, or -1 if c cannot
 * be interpreted properly in that base (i.e., is out of range,
 * is a null, etc.).
 *
 * @param c     the character to interpret according to base
 * @param base  the base in which to interpret c
 *
 * @return  the value of c in base, or -1 if c is not in range
 */
static int get_char(char c, int base)
{
#ifndef NO_RANGE_TEST
  int value = -1;
  if(c <= '9' && c >= '0') {
    value = c - '0';
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

  if(value >= base) {
    value = -1;
  }

  return value;
}
#endif  /* Only present if we need strtoll, but don't have it. */

/*
 * Parse a *positive* up to 64 bit number written in ascii.
 */
CURLofft curlx_strtoofft(const char *str, char **endp, int base,
                         curl_off_t *num)
{
  char *end = NULL;
  curl_off_t number;
  errno = 0;
  *num = 0; /* clear by default */
  DEBUGASSERT(base); /* starting now, avoid base zero */

  while(*str && ISBLANK(*str))
    str++;
  if(('-' == *str) || (ISSPACE(*str))) {
    if(endp)
      *endp = (char *)str; /* didn't actually move */
    return CURL_OFFT_INVAL; /* nothing parsed */
  }
  number = strtooff(str, &end, base);
  if(endp)
    *endp = end;
  if(errno == ERANGE)
    /* overflow/underflow */







|


|














|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

  if(value >= base) {
    value = -1;
  }

  return value;
}
#endif  /* Only present if we need strtoll, but do not have it. */

/*
 * Parse a *positive* up to 64-bit number written in ascii.
 */
CURLofft curlx_strtoofft(const char *str, char **endp, int base,
                         curl_off_t *num)
{
  char *end = NULL;
  curl_off_t number;
  errno = 0;
  *num = 0; /* clear by default */
  DEBUGASSERT(base); /* starting now, avoid base zero */

  while(*str && ISBLANK(*str))
    str++;
  if(('-' == *str) || (ISSPACE(*str))) {
    if(endp)
      *endp = (char *)str; /* did not actually move */
    return CURL_OFFT_INVAL; /* nothing parsed */
  }
  number = strtooff(str, &end, base);
  if(endp)
    *endp = end;
  if(errno == ERANGE)
    /* overflow/underflow */
Changes to jni/curl/lib/strtoofft.h.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

#include "curl_setup.h"

/*
 * Determine which string to integral data type conversion function we use
 * to implement string conversion to our curl_off_t integral data type.
 *
 * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use
 * an underlying data type which might be 'long', 'int64_t', 'long long' or
 * '__int64' and more remotely other data types.
 *
 * On systems where the size of curl_off_t is greater than the size of 'long'
 * the conversion function to use is strtoll() if it is available, otherwise,
 * we emulate its functionality with our own clone.
 *







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

#include "curl_setup.h"

/*
 * Determine which string to integral data type conversion function we use
 * to implement string conversion to our curl_off_t integral data type.
 *
 * Notice that curl_off_t might be 64 or 32 bits wide, and that it might use
 * an underlying data type which might be 'long', 'int64_t', 'long long' or
 * '__int64' and more remotely other data types.
 *
 * On systems where the size of curl_off_t is greater than the size of 'long'
 * the conversion function to use is strtoll() if it is available, otherwise,
 * we emulate its functionality with our own clone.
 *
Changes to jni/curl/lib/system_win32.c.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    WSADATA wsaData;
    int res;

    wVersionRequested = MAKEWORD(2, 2);
    res = WSAStartup(wVersionRequested, &wsaData);

    if(res)
      /* Tell the user that we couldn't find a usable */
      /* winsock.dll.     */
      return CURLE_FAILED_INIT;

    /* Confirm that the Windows Sockets DLL supports what we need.*/
    /* Note that if the DLL supports versions greater */
    /* than wVersionRequested, it will still return */
    /* wVersionRequested in wVersion. wHighVersion contains the */
    /* highest supported version. */

    if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
       HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
      /* Tell the user that we couldn't find a usable */

      /* winsock.dll. */
      WSACleanup();
      return CURLE_FAILED_INIT;
    }
    /* The Windows Sockets DLL is acceptable. Proceed. */
#elif defined(USE_LWIPSOCK)







|











|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
    WSADATA wsaData;
    int res;

    wVersionRequested = MAKEWORD(2, 2);
    res = WSAStartup(wVersionRequested, &wsaData);

    if(res)
      /* Tell the user that we could not find a usable */
      /* winsock.dll.     */
      return CURLE_FAILED_INIT;

    /* Confirm that the Windows Sockets DLL supports what we need.*/
    /* Note that if the DLL supports versions greater */
    /* than wVersionRequested, it will still return */
    /* wVersionRequested in wVersion. wHighVersion contains the */
    /* highest supported version. */

    if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
       HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
      /* Tell the user that we could not find a usable */

      /* winsock.dll. */
      WSACleanup();
      return CURLE_FAILED_INIT;
    }
    /* The Windows Sockets DLL is acceptable. Proceed. */
#elif defined(USE_LWIPSOCK)
108
109
110
111
112
113
114



115

116
117
118
119
120
121
122
                          (GetProcAddress(s_hIpHlpApiDll, "if_nametoindex")));

    if(pIfNameToIndex)
      Curl_if_nametoindex = pIfNameToIndex;
  }

#ifdef USE_WINSOCK



  ws2_32Dll = GetModuleHandleA("ws2_32");

  if(ws2_32Dll) {
    Curl_FreeAddrInfoExW = CURLX_FUNCTION_CAST(FREEADDRINFOEXW_FN,
      GetProcAddress(ws2_32Dll, "FreeAddrInfoExW"));
    Curl_GetAddrInfoExCancel = CURLX_FUNCTION_CAST(GETADDRINFOEXCANCEL_FN,
      GetProcAddress(ws2_32Dll, "GetAddrInfoExCancel"));
    Curl_GetAddrInfoExW = CURLX_FUNCTION_CAST(GETADDRINFOEXW_FN,
      GetProcAddress(ws2_32Dll, "GetAddrInfoExW"));







>
>
>

>







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
                          (GetProcAddress(s_hIpHlpApiDll, "if_nametoindex")));

    if(pIfNameToIndex)
      Curl_if_nametoindex = pIfNameToIndex;
  }

#ifdef USE_WINSOCK
#ifdef CURL_WINDOWS_APP
  ws2_32Dll = Curl_load_library(TEXT("ws2_32.dll"));
#else
  ws2_32Dll = GetModuleHandleA("ws2_32");
#endif
  if(ws2_32Dll) {
    Curl_FreeAddrInfoExW = CURLX_FUNCTION_CAST(FREEADDRINFOEXW_FN,
      GetProcAddress(ws2_32Dll, "FreeAddrInfoExW"));
    Curl_GetAddrInfoExCancel = CURLX_FUNCTION_CAST(GETADDRINFOEXCANCEL_FN,
      GetProcAddress(ws2_32Dll, "GetAddrInfoExCancel"));
    Curl_GetAddrInfoExW = CURLX_FUNCTION_CAST(GETADDRINFOEXW_FN,
      GetProcAddress(ws2_32Dll, "GetAddrInfoExW"));
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
 */
HMODULE Curl_load_library(LPCTSTR filename)
{
#ifndef CURL_WINDOWS_APP
  HMODULE hModule = NULL;
  LOADLIBRARYEX_FN pLoadLibraryEx = NULL;

  /* Get a handle to kernel32 so we can access it's functions at runtime */
  HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
  if(!hKernel32)
    return NULL;

  /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
     and above */
  pLoadLibraryEx =
    CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN,
                        (GetProcAddress(hKernel32, LOADLIBARYEX)));

  /* Detect if there's already a path in the filename and load the library if
     there is. Note: Both back slashes and forward slashes have been supported
     since the earlier days of DOS at an API level although they are not
     supported by command prompt */
  if(_tcspbrk(filename, TEXT("\\/"))) {
    /** !checksrc! disable BANNEDFUNC 1 **/
    hModule = pLoadLibraryEx ?
      pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :







|










|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
 */
HMODULE Curl_load_library(LPCTSTR filename)
{
#ifndef CURL_WINDOWS_APP
  HMODULE hModule = NULL;
  LOADLIBRARYEX_FN pLoadLibraryEx = NULL;

  /* Get a handle to kernel32 so we can access it is functions at runtime */
  HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
  if(!hKernel32)
    return NULL;

  /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
     and above */
  pLoadLibraryEx =
    CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN,
                        (GetProcAddress(hKernel32, LOADLIBARYEX)));

  /* Detect if there is already a path in the filename and load the library if
     there is. Note: Both back slashes and forward slashes have been supported
     since the earlier days of DOS at an API level although they are not
     supported by command prompt */
  if(_tcspbrk(filename, TEXT("\\/"))) {
    /** !checksrc! disable BANNEDFUNC 1 **/
    hModule = pLoadLibraryEx ?
      pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
257
258
259
260
261
262
263
264
265
266
267
268
269












270

      }
      free(path);
    }
  }
  return hModule;
#else
  /* the Universal Windows Platform (UWP) can't do this */
  (void)filename;
  return NULL;
#endif
}













#endif /* _WIN32 */







|





>
>
>
>
>
>
>
>
>
>
>
>

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286

      }
      free(path);
    }
  }
  return hModule;
#else
  /* the Universal Windows Platform (UWP) cannot do this */
  (void)filename;
  return NULL;
#endif
}

bool Curl_win32_impersonating(void)
{
#ifndef CURL_WINDOWS_APP
  HANDLE token = NULL;
  if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &token)) {
    CloseHandle(token);
    return TRUE;
  }
#endif
  return FALSE;
}

#endif /* _WIN32 */
Changes to jni/curl/lib/system_win32.h.
23
24
25
26
27
28
29


30
31
32
33
34
35
36
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#ifdef _WIN32



extern LARGE_INTEGER Curl_freq;
extern bool Curl_isVistaOrGreater;
extern bool Curl_isWindows8OrGreater;

CURLcode Curl_win32_init(long flags);
void Curl_win32_cleanup(long init_flags);







>
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#ifdef _WIN32

#include <curl/curl.h>

extern LARGE_INTEGER Curl_freq;
extern bool Curl_isVistaOrGreater;
extern bool Curl_isWindows8OrGreater;

CURLcode Curl_win32_init(long flags);
void Curl_win32_cleanup(long init_flags);
63
64
65
66
67
68
69


70
71
72
73
74
75
76
77
typedef int (WSAAPI *GETADDRINFOEXW_FN)(PCWSTR, PCWSTR, DWORD, LPGUID,
  const ADDRINFOEXW_*, ADDRINFOEXW_**, struct timeval*, LPOVERLAPPED,
  LOOKUP_COMPLETION_FN, LPHANDLE);

extern FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW;
extern GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel;
extern GETADDRINFOEXW_FN Curl_GetAddrInfoExW;



/* This is used to dynamically load DLLs */
HMODULE Curl_load_library(LPCTSTR filename);
#else  /* _WIN32 */
#define Curl_win32_init(x) CURLE_OK
#endif /* !_WIN32 */

#endif /* HEADER_CURL_SYSTEM_WIN32_H */







>
>








65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
typedef int (WSAAPI *GETADDRINFOEXW_FN)(PCWSTR, PCWSTR, DWORD, LPGUID,
  const ADDRINFOEXW_*, ADDRINFOEXW_**, struct timeval*, LPOVERLAPPED,
  LOOKUP_COMPLETION_FN, LPHANDLE);

extern FREEADDRINFOEXW_FN Curl_FreeAddrInfoExW;
extern GETADDRINFOEXCANCEL_FN Curl_GetAddrInfoExCancel;
extern GETADDRINFOEXW_FN Curl_GetAddrInfoExW;

bool Curl_win32_impersonating(void);

/* This is used to dynamically load DLLs */
HMODULE Curl_load_library(LPCTSTR filename);
#else  /* _WIN32 */
#define Curl_win32_init(x) CURLE_OK
#endif /* !_WIN32 */

#endif /* HEADER_CURL_SYSTEM_WIN32_H */
Changes to jni/curl/lib/telnet.c.
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
static CURLcode check_telnet_options(struct Curl_easy *data)
{
  struct curl_slist *head;
  struct curl_slist *beg;
  struct TELNET *tn = data->req.p.telnet;
  CURLcode result = CURLE_OK;

  /* Add the user name as an environment variable if it
     was given on the command line */
  if(data->state.aptr.user) {
    char buffer[256];
    if(str_is_nonascii(data->conn->user)) {
      DEBUGF(infof(data, "set a non ASCII user name in telnet"));
      return CURLE_BAD_FUNCTION_ARGUMENT;
    }
    msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user);
    beg = curl_slist_append(tn->telnet_vars, buffer);
    if(!beg) {
      curl_slist_free_all(tn->telnet_vars);
      tn->telnet_vars = NULL;







|




|







794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
static CURLcode check_telnet_options(struct Curl_easy *data)
{
  struct curl_slist *head;
  struct curl_slist *beg;
  struct TELNET *tn = data->req.p.telnet;
  CURLcode result = CURLE_OK;

  /* Add the username as an environment variable if it
     was given on the command line */
  if(data->state.aptr.user) {
    char buffer[256];
    if(str_is_nonascii(data->conn->user)) {
      DEBUGF(infof(data, "set a non ASCII username in telnet"));
      return CURLE_BAD_FUNCTION_ARGUMENT;
    }
    msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user);
    beg = curl_slist_append(tn->telnet_vars, buffer);
    if(!beg) {
      curl_slist_free_all(tn->telnet_vars);
      tn->telnet_vars = NULL;
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
          CURL_SB_ACCUM(tn, c);
        break;

      case CURL_TS_SE:
        if(c != CURL_SE) {
          if(c != CURL_IAC) {
            /*
             * This is an error.  We only expect to get "IAC IAC" or "IAC SE".
             * Several things may have happened.  An IAC was not doubled, the
             * IAC SE was left off, or another option got inserted into the
             * suboption are all possibilities.  If we assume that the IAC was
             * not doubled, and really the IAC SE was left off, we could get
             * into an infinite loop here.  So, instead, we terminate the
             * suboption, and process the partial suboption if we can.
             */
            CURL_SB_ACCUM(tn, CURL_IAC);
            CURL_SB_ACCUM(tn, c);
            tn->subpointer -= 2;
            CURL_SB_TERM(tn);








|
|

|

|







1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
          CURL_SB_ACCUM(tn, c);
        break;

      case CURL_TS_SE:
        if(c != CURL_SE) {
          if(c != CURL_IAC) {
            /*
             * This is an error. We only expect to get "IAC IAC" or "IAC SE".
             * Several things may have happened. An IAC was not doubled, the
             * IAC SE was left off, or another option got inserted into the
             * suboption are all possibilities. If we assume that the IAC was
             * not doubled, and really the IAC SE was left off, we could get
             * into an infinite loop here. So, instead, we terminate the
             * suboption, and process the partial suboption if we can.
             */
            CURL_SB_ACCUM(tn, CURL_IAC);
            CURL_SB_ACCUM(tn, c);
            tn->subpointer -= 2;
            CURL_SB_TERM(tn);

1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
  objs[0] = event_handle;
  objs[1] = stdin_handle;

  /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
     else use the old WaitForMultipleObjects() way */
  if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
     data->set.is_fread_set) {
    /* Don't wait for stdin_handle, just wait for event_handle */
    obj_count = 1;
    /* Check stdin_handle per 100 milliseconds */
    wait_timeout = 100;
  }
  else {
    obj_count = 2;
    wait_timeout = 1000;







|







1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
  objs[0] = event_handle;
  objs[1] = stdin_handle;

  /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
     else use the old WaitForMultipleObjects() way */
  if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
     data->set.is_fread_set) {
    /* Do not wait for stdin_handle, just wait for event_handle */
    obj_count = 1;
    /* Check stdin_handle per 100 milliseconds */
    wait_timeout = 100;
  }
  else {
    obj_count = 2;
    wait_timeout = 1000;
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
          result = CURLE_READ_ERROR;
        }
        break;
      }
      if(events.lNetworkEvents & FD_READ) {
        /* read data from network */
        result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
        /* read would've blocked. Loop again */
        if(result == CURLE_AGAIN)
          break;
        /* returned not-zero, this an error */
        else if(result) {
          keepon = FALSE;
          break;
        }







|







1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
          result = CURLE_READ_ERROR;
        }
        break;
      }
      if(events.lNetworkEvents & FD_READ) {
        /* read data from network */
        result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
        /* read would have blocked. Loop again */
        if(result == CURLE_AGAIN)
          break;
        /* returned not-zero, this an error */
        else if(result) {
          keepon = FALSE;
          break;
        }
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
        result = telrcv(data, (unsigned char *) buffer, nread);
        if(result) {
          keepon = FALSE;
          break;
        }

        /* Negotiate if the peer has started negotiating,
           otherwise don't. We don't want to speak telnet with
           non-telnet servers, like POP or SMTP. */
        if(tn->please_negotiate && !tn->already_negotiated) {
          negotiate(data);
          tn->already_negotiated = 1;
        }
      }
      if(events.lNetworkEvents & FD_CLOSE) {







|







1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
        result = telrcv(data, (unsigned char *) buffer, nread);
        if(result) {
          keepon = FALSE;
          break;
        }

        /* Negotiate if the peer has started negotiating,
           otherwise do not. We do not want to speak telnet with
           non-telnet servers, like POP or SMTP. */
        if(tn->please_negotiate && !tn->already_negotiated) {
          negotiate(data);
          tn->already_negotiated = 1;
        }
      }
      if(events.lNetworkEvents & FD_CLOSE) {
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
      result = CURLE_RECV_ERROR;
      keepon = FALSE;
    }
  }

  while(keepon) {
    DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt));
    switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
    case -1:                    /* error, stop reading */
      keepon = FALSE;
      continue;
    case 0:                     /* timeout */
      pfd[0].revents = 0;
      pfd[1].revents = 0;
      FALLTHROUGH();
    default:                    /* read! */
      if(pfd[0].revents & POLLIN) {
        /* read data from network */
        result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
        /* read would've blocked. Loop again */
        if(result == CURLE_AGAIN)
          break;
        /* returned not-zero, this an error */
        if(result) {
          keepon = FALSE;
          /* TODO: in test 1452, macOS sees a ECONNRESET sometimes?
           * Is this the telnet test server not shutting down the socket







|











|







1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
      result = CURLE_RECV_ERROR;
      keepon = FALSE;
    }
  }

  while(keepon) {
    DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt));
    switch(Curl_poll(pfd, (unsigned int)poll_cnt, interval_ms)) {
    case -1:                    /* error, stop reading */
      keepon = FALSE;
      continue;
    case 0:                     /* timeout */
      pfd[0].revents = 0;
      pfd[1].revents = 0;
      FALLTHROUGH();
    default:                    /* read! */
      if(pfd[0].revents & POLLIN) {
        /* read data from network */
        result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
        /* read would have blocked. Loop again */
        if(result == CURLE_AGAIN)
          break;
        /* returned not-zero, this an error */
        if(result) {
          keepon = FALSE;
          /* TODO: in test 1452, macOS sees a ECONNRESET sometimes?
           * Is this the telnet test server not shutting down the socket
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
          result = telrcv(data, (unsigned char *)buffer, nread);
        if(result) {
          keepon = FALSE;
          break;
        }

        /* Negotiate if the peer has started negotiating,
           otherwise don't. We don't want to speak telnet with
           non-telnet servers, like POP or SMTP. */
        if(tn->please_negotiate && !tn->already_negotiated) {
          negotiate(data);
          tn->already_negotiated = 1;
        }
      }








|







1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
          result = telrcv(data, (unsigned char *)buffer, nread);
        if(result) {
          keepon = FALSE;
          break;
        }

        /* Negotiate if the peer has started negotiating,
           otherwise do not. We do not want to speak telnet with
           non-telnet servers, like POP or SMTP. */
        if(tn->please_negotiate && !tn->already_negotiated) {
          negotiate(data);
          tn->already_negotiated = 1;
        }
      }

1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
    if(Curl_pgrsUpdate(data)) {
      result = CURLE_ABORTED_BY_CALLBACK;
      break;
    }
  }
#endif
  /* mark this as "no further transfer wanted" */
  Curl_xfer_setup(data, -1, -1, FALSE, -1);

  return result;
}
#endif







|




1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
    if(Curl_pgrsUpdate(data)) {
      result = CURLE_ABORTED_BY_CALLBACK;
      break;
    }
  }
#endif
  /* mark this as "no further transfer wanted" */
  Curl_xfer_setup_nop(data);

  return result;
}
#endif
Changes to jni/curl/lib/tftp.c.
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

  infof(state->data,
        "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T
        ", retry %d maxtry %d",
        (int)state->state, timeout_ms, state->retry_time, state->retry_max);

  /* init RX time */
  time(&state->rx_time);

  return CURLE_OK;
}

/**********************************************************
 *
 * tftp_set_send_first







|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

  infof(state->data,
        "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T
        ", retry %d maxtry %d",
        (int)state->state, timeout_ms, state->retry_time, state->retry_max);

  /* init RX time */
  state->rx_time = time(NULL);

  return CURLE_OK;
}

/**********************************************************
 *
 * tftp_set_send_first
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325

static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
                                      const char *ptr, int len)
{
  const char *tmp = ptr;
  struct Curl_easy *data = state->data;

  /* if OACK doesn't contain blksize option, the default (512) must be used */
  state->blksize = TFTP_BLKSIZE_DEFAULT;

  while(tmp < ptr + len) {
    const char *option, *value;

    tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
    if(!tmp) {







|







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325

static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
                                      const char *ptr, int len)
{
  const char *tmp = ptr;
  struct Curl_easy *data = state->data;

  /* if OACK does not contain blksize option, the default (512) must be used */
  state->blksize = TFTP_BLKSIZE_DEFAULT;

  while(tmp < ptr + len) {
    const char *option, *value;

    tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
    if(!tmp) {
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
      }
      else if(blksize < TFTP_BLKSIZE_MIN) {
        failf(data, "%s (%d)", "blksize is smaller than min supported",
              TFTP_BLKSIZE_MIN);
        return CURLE_TFTP_ILLEGAL;
      }
      else if(blksize > state->requested_blksize) {
        /* could realloc pkt buffers here, but the spec doesn't call out
         * support for the server requesting a bigger blksize than the client
         * requests */
        failf(data, "%s (%ld)",
              "server requested blksize larger than allocated", blksize);
        return CURLE_TFTP_ILLEGAL;
      }








|







345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
      }
      else if(blksize < TFTP_BLKSIZE_MIN) {
        failf(data, "%s (%d)", "blksize is smaller than min supported",
              TFTP_BLKSIZE_MIN);
        return CURLE_TFTP_ILLEGAL;
      }
      else if(blksize > state->requested_blksize) {
        /* could realloc pkt buffers here, but the spec does not call out
         * support for the server requesting a bigger blksize than the client
         * requests */
        failf(data, "%s (%ld)",
              "server requested blksize larger than allocated", blksize);
        return CURLE_TFTP_ILLEGAL;
      }

457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
        Curl_pgrsSetUploadSize(data, data->state.infilesize);
    }
    else {
      /* If we are downloading, send an RRQ */
      setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
    }
    /* As RFC3617 describes the separator slash is not actually part of the
       file name so we skip the always-present first letter of the path
       string. */
    result = Curl_urldecode(&state->data->state.up.path[1], 0,
                            &filename, NULL, REJECT_ZERO);
    if(result)
      return result;

    if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
      failf(data, "TFTP file name too long");
      free(filename);
      return CURLE_TFTP_ILLEGAL; /* too long file name field */
    }

    msnprintf((char *)state->spacket.data + 2,
              state->blksize,
              "%s%c%s%c", filename, '\0',  mode, '\0');
    sbytes = 4 + strlen(filename) + strlen(mode);








|







|

|







457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
        Curl_pgrsSetUploadSize(data, data->state.infilesize);
    }
    else {
      /* If we are downloading, send an RRQ */
      setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
    }
    /* As RFC3617 describes the separator slash is not actually part of the
       filename so we skip the always-present first letter of the path
       string. */
    result = Curl_urldecode(&state->data->state.up.path[1], 0,
                            &filename, NULL, REJECT_ZERO);
    if(result)
      return result;

    if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
      failf(data, "TFTP filename too long");
      free(filename);
      return CURLE_TFTP_ILLEGAL; /* too long filename field */
    }

    msnprintf((char *)state->spacket.data + 2,
              state->blksize,
              "%s%c%s%c", filename, '\0',  mode, '\0');
    sbytes = 4 + strlen(filename) + strlen(mode);

524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
    }

    /* the typecase for the 3rd argument is mostly for systems that do
       not have a size_t argument, like older unixes that want an 'int' */
    senddata = sendto(state->sockfd, (void *)state->spacket.data,
                      (SEND_TYPE_ARG3)sbytes, 0,
                      &data->conn->remote_addr->sa_addr,
                      data->conn->remote_addr->addrlen);
    if(senddata != (ssize_t)sbytes) {
      char buffer[STRERROR_LEN];
      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
    }
    free(filename);
    break;








|







524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
    }

    /* the typecase for the 3rd argument is mostly for systems that do
       not have a size_t argument, like older unixes that want an 'int' */
    senddata = sendto(state->sockfd, (void *)state->spacket.data,
                      (SEND_TYPE_ARG3)sbytes, 0,
                      &data->conn->remote_addr->sa_addr,
                      (curl_socklen_t)data->conn->remote_addr->addrlen);
    if(senddata != (ssize_t)sbytes) {
      char buffer[STRERROR_LEN];
      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
    }
    free(filename);
    break;

586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

  switch(event) {

  case TFTP_EVENT_DATA:
    /* Is this the block we expect? */
    rblock = getrpacketblock(&state->rpacket);
    if(NEXT_BLOCKNUM(state->block) == rblock) {
      /* This is the expected block.  Reset counters and ACK it. */
      state->retries = 0;
    }
    else if(state->block == rblock) {
      /* This is the last recently received block again. Log it and ACK it
         again. */
      infof(data, "Received last DATA packet block %d again.", rblock);
    }







|







586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

  switch(event) {

  case TFTP_EVENT_DATA:
    /* Is this the block we expect? */
    rblock = getrpacketblock(&state->rpacket);
    if(NEXT_BLOCKNUM(state->block) == rblock) {
      /* This is the expected block. Reset counters and ACK it. */
      state->retries = 0;
    }
    else if(state->block == rblock) {
      /* This is the last recently received block again. Log it and ACK it
         again. */
      infof(data, "Received last DATA packet block %d again.", rblock);
    }
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    /* Check if completed (That is, a less than full packet is received) */
    if(state->rbytes < (ssize_t)state->blksize + 4) {
      state->state = TFTP_STATE_FIN;
    }
    else {
      state->state = TFTP_STATE_RX;
    }
    time(&state->rx_time);
    break;

  case TFTP_EVENT_OACK:
    /* ACK option acknowledgement so we can move on to data */
    state->block = 0;
    state->retries = 0;
    setpacketevent(&state->spacket, TFTP_EVENT_ACK);
    setpacketblock(&state->spacket, state->block);
    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
                    4, SEND_4TH_ARG,
                    (struct sockaddr *)&state->remote_addr,
                    state->remote_addrlen);
    if(sbytes < 0) {
      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
      return CURLE_SEND_ERROR;
    }

    /* we're ready to RX data */
    state->state = TFTP_STATE_RX;
    time(&state->rx_time);
    break;

  case TFTP_EVENT_TIMEOUT:
    /* Increment the retry count and fail if over the limit */
    state->retries++;
    infof(data,
          "Timeout waiting for block %d ACK.  Retries = %d",
          NEXT_BLOCKNUM(state->block), state->retries);
    if(state->retries > state->retry_max) {
      state->error = TFTP_ERR_TIMEOUT;
      state->state = TFTP_STATE_FIN;
    }
    else {
      /* Resend the previous ACK */







|

















|

|






|







622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    /* Check if completed (That is, a less than full packet is received) */
    if(state->rbytes < (ssize_t)state->blksize + 4) {
      state->state = TFTP_STATE_FIN;
    }
    else {
      state->state = TFTP_STATE_RX;
    }
    state->rx_time = time(NULL);
    break;

  case TFTP_EVENT_OACK:
    /* ACK option acknowledgement so we can move on to data */
    state->block = 0;
    state->retries = 0;
    setpacketevent(&state->spacket, TFTP_EVENT_ACK);
    setpacketblock(&state->spacket, state->block);
    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
                    4, SEND_4TH_ARG,
                    (struct sockaddr *)&state->remote_addr,
                    state->remote_addrlen);
    if(sbytes < 0) {
      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
      return CURLE_SEND_ERROR;
    }

    /* we are ready to RX data */
    state->state = TFTP_STATE_RX;
    state->rx_time = time(NULL);
    break;

  case TFTP_EVENT_TIMEOUT:
    /* Increment the retry count and fail if over the limit */
    state->retries++;
    infof(data,
          "Timeout waiting for block %d ACK. Retries = %d",
          NEXT_BLOCKNUM(state->block), state->retries);
    if(state->retries > state->retry_max) {
      state->error = TFTP_ERR_TIMEOUT;
      state->state = TFTP_STATE_FIN;
    }
    else {
      /* Resend the previous ACK */
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  case TFTP_EVENT_ERROR:
    setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
    setpacketblock(&state->spacket, state->block);
    (void)sendto(state->sockfd, (void *)state->spacket.data,
                 4, SEND_4TH_ARG,
                 (struct sockaddr *)&state->remote_addr,
                 state->remote_addrlen);
    /* don't bother with the return code, but if the socket is still up we
     * should be a good TFTP client and let the server know we're done */
    state->state = TFTP_STATE_FIN;
    break;

  default:
    failf(data, "%s", "tftp_rx: internal error");
    return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
                                  this */







|
|







675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  case TFTP_EVENT_ERROR:
    setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
    setpacketblock(&state->spacket, state->block);
    (void)sendto(state->sockfd, (void *)state->spacket.data,
                 4, SEND_4TH_ARG,
                 (struct sockaddr *)&state->remote_addr,
                 state->remote_addrlen);
    /* do not bother with the return code, but if the socket is still up we
     * should be a good TFTP client and let the server know we are done */
    state->state = TFTP_STATE_FIN;
    break;

  default:
    failf(data, "%s", "tftp_rx: internal error");
    return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
                                  this */
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  case TFTP_EVENT_ACK:
  case TFTP_EVENT_OACK:
    if(event == TFTP_EVENT_ACK) {
      /* Ack the packet */
      int rblock = getrpacketblock(&state->rpacket);

      if(rblock != state->block &&
         /* There's a bug in tftpd-hpa that causes it to send us an ack for
          * 65535 when the block number wraps to 0. So when we're expecting
          * 0, also accept 65535. See
          * https://www.syslinux.org/archives/2010-September/015612.html
          * */
         !(state->block == 0 && rblock == 65535)) {
        /* This isn't the expected block.  Log it and up the retry counter */
        infof(data, "Received ACK for block %d, expecting %d",
              rblock, state->block);
        state->retries++;
        /* Bail out if over the maximum */
        if(state->retries>state->retry_max) {
          failf(data, "tftp_tx: giving up waiting for block %d ack",
                state->block);
          result = CURLE_SEND_ERROR;
        }
        else {
          /* Re-send the data packet */
          sbytes = sendto(state->sockfd, (void *)state->spacket.data,
                          4 + state->sbytes, SEND_4TH_ARG,
                          (struct sockaddr *)&state->remote_addr,
                          state->remote_addrlen);
          /* Check all sbytes were sent */
          if(sbytes<0) {
            failf(data, "%s", Curl_strerror(SOCKERRNO,
                                            buffer, sizeof(buffer)));
            result = CURLE_SEND_ERROR;
          }
        }

        return result;
      }
      /* This is the expected packet.  Reset the counters and send the next
         block */
      time(&state->rx_time);
      state->block++;
    }
    else
      state->block = 1; /* first data block is 1 when using OACK */

    state->retries = 0;
    setpacketevent(&state->spacket, TFTP_EVENT_DATA);







|
|




|












|












|

|







715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  case TFTP_EVENT_ACK:
  case TFTP_EVENT_OACK:
    if(event == TFTP_EVENT_ACK) {
      /* Ack the packet */
      int rblock = getrpacketblock(&state->rpacket);

      if(rblock != state->block &&
         /* There is a bug in tftpd-hpa that causes it to send us an ack for
          * 65535 when the block number wraps to 0. So when we are expecting
          * 0, also accept 65535. See
          * https://www.syslinux.org/archives/2010-September/015612.html
          * */
         !(state->block == 0 && rblock == 65535)) {
        /* This is not the expected block. Log it and up the retry counter */
        infof(data, "Received ACK for block %d, expecting %d",
              rblock, state->block);
        state->retries++;
        /* Bail out if over the maximum */
        if(state->retries>state->retry_max) {
          failf(data, "tftp_tx: giving up waiting for block %d ack",
                state->block);
          result = CURLE_SEND_ERROR;
        }
        else {
          /* Re-send the data packet */
          sbytes = sendto(state->sockfd, (void *)state->spacket.data,
                          4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
                          (struct sockaddr *)&state->remote_addr,
                          state->remote_addrlen);
          /* Check all sbytes were sent */
          if(sbytes<0) {
            failf(data, "%s", Curl_strerror(SOCKERRNO,
                                            buffer, sizeof(buffer)));
            result = CURLE_SEND_ERROR;
          }
        }

        return result;
      }
      /* This is the expected packet. Reset the counters and send the next
         block */
      state->rx_time = time(NULL);
      state->block++;
    }
    else
      state->block = 1; /* first data block is 1 when using OACK */

    state->retries = 0;
    setpacketevent(&state->spacket, TFTP_EVENT_DATA);
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
      if(result)
        return result;
      state->sbytes += (int)cb;
      bufptr += cb;
    } while(state->sbytes < state->blksize && cb);

    sbytes = sendto(state->sockfd, (void *) state->spacket.data,
                    4 + state->sbytes, SEND_4TH_ARG,
                    (struct sockaddr *)&state->remote_addr,
                    state->remote_addrlen);
    /* Check all sbytes were sent */
    if(sbytes<0) {
      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
      return CURLE_SEND_ERROR;
    }
    /* Update the progress meter */
    k->writebytecount += state->sbytes;
    Curl_pgrsSetUploadCounter(data, k->writebytecount);
    break;

  case TFTP_EVENT_TIMEOUT:
    /* Increment the retry counter and log the timeout */
    state->retries++;
    infof(data, "Timeout waiting for block %d ACK. "
          " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
    /* Decide if we've had enough */
    if(state->retries > state->retry_max) {
      state->error = TFTP_ERR_TIMEOUT;
      state->state = TFTP_STATE_FIN;
    }
    else {
      /* Re-send the data packet */
      sbytes = sendto(state->sockfd, (void *)state->spacket.data,
                      4 + state->sbytes, SEND_4TH_ARG,
                      (struct sockaddr *)&state->remote_addr,
                      state->remote_addrlen);
      /* Check all sbytes were sent */
      if(sbytes<0) {
        failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
        return CURLE_SEND_ERROR;
      }
      /* since this was a re-send, we remain at the still byte position */
      Curl_pgrsSetUploadCounter(data, k->writebytecount);
    }
    break;

  case TFTP_EVENT_ERROR:
    state->state = TFTP_STATE_FIN;
    setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
    setpacketblock(&state->spacket, state->block);
    (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
                 (struct sockaddr *)&state->remote_addr,
                 state->remote_addrlen);
    /* don't bother with the return code, but if the socket is still up we
     * should be a good TFTP client and let the server know we're done */
    state->state = TFTP_STATE_FIN;
    break;

  default:
    failf(data, "tftp_tx: internal error, event: %i", (int)(event));
    break;
  }







|

















|







|



















|
|







779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
      if(result)
        return result;
      state->sbytes += (int)cb;
      bufptr += cb;
    } while(state->sbytes < state->blksize && cb);

    sbytes = sendto(state->sockfd, (void *) state->spacket.data,
                    4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
                    (struct sockaddr *)&state->remote_addr,
                    state->remote_addrlen);
    /* Check all sbytes were sent */
    if(sbytes<0) {
      failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
      return CURLE_SEND_ERROR;
    }
    /* Update the progress meter */
    k->writebytecount += state->sbytes;
    Curl_pgrsSetUploadCounter(data, k->writebytecount);
    break;

  case TFTP_EVENT_TIMEOUT:
    /* Increment the retry counter and log the timeout */
    state->retries++;
    infof(data, "Timeout waiting for block %d ACK. "
          " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
    /* Decide if we have had enough */
    if(state->retries > state->retry_max) {
      state->error = TFTP_ERR_TIMEOUT;
      state->state = TFTP_STATE_FIN;
    }
    else {
      /* Re-send the data packet */
      sbytes = sendto(state->sockfd, (void *)state->spacket.data,
                      4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
                      (struct sockaddr *)&state->remote_addr,
                      state->remote_addrlen);
      /* Check all sbytes were sent */
      if(sbytes<0) {
        failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
        return CURLE_SEND_ERROR;
      }
      /* since this was a re-send, we remain at the still byte position */
      Curl_pgrsSetUploadCounter(data, k->writebytecount);
    }
    break;

  case TFTP_EVENT_ERROR:
    state->state = TFTP_STATE_FIN;
    setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
    setpacketblock(&state->spacket, state->block);
    (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
                 (struct sockaddr *)&state->remote_addr,
                 state->remote_addrlen);
    /* do not bother with the return code, but if the socket is still up we
     * should be a good TFTP client and let the server know we are done */
    state->state = TFTP_STATE_FIN;
    break;

  default:
    failf(data, "tftp_tx: internal error, event: %i", (int)(event));
    break;
  }
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  if(!state->spacket.data) {
    state->spacket.data = calloc(1, need_blksize + 2 + 2);

    if(!state->spacket.data)
      return CURLE_OUT_OF_MEMORY;
  }

  /* we don't keep TFTP connections up basically because there's none or very
   * little gain for UDP */
  connclose(conn, "TFTP");

  state->data = data;
  state->sockfd = conn->sock[FIRSTSOCKET];
  state->state = TFTP_STATE_START;
  state->error = TFTP_ERR_NONE;







|







997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  if(!state->spacket.data) {
    state->spacket.data = calloc(1, need_blksize + 2 + 2);

    if(!state->spacket.data)
      return CURLE_OUT_OF_MEMORY;
  }

  /* we do not keep TFTP connections up basically because there is none or very
   * little gain for UDP */
  connclose(conn, "TFTP");

  state->data = data;
  state->sockfd = conn->sock[FIRSTSOCKET];
  state->state = TFTP_STATE_START;
  state->error = TFTP_ERR_NONE;
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
     * when running IPv4-only.
     *
     * Therefore we use the size from the address we connected to, which we
     * assume uses the same IP version and thus hopefully this works for both
     * IPv4 and IPv6...
     */
    int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
                  conn->remote_addr->addrlen);
    if(rc) {
      char buffer[STRERROR_LEN];
      failf(data, "bind() failed; %s",
            Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
      return CURLE_COULDNT_CONNECT;
    }
    conn->bits.bound = TRUE;







|







1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
     * when running IPv4-only.
     *
     * Therefore we use the size from the address we connected to, which we
     * assume uses the same IP version and thus hopefully this works for both
     * IPv4 and IPv6...
     */
    int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
                  (curl_socklen_t)conn->remote_addr->addrlen);
    if(rc) {
      char buffer[STRERROR_LEN];
      failf(data, "bind() failed; %s",
            Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
      return CURLE_COULDNT_CONNECT;
    }
    conn->bits.bound = TRUE;
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
  struct connectdata *conn = data->conn;
  struct tftp_state_data *state = conn->proto.tftpc;

  /* Receive the packet */
  fromlen = sizeof(fromaddr);
  state->rbytes = (int)recvfrom(state->sockfd,
                                (void *)state->rpacket.data,
                                state->blksize + 4,
                                0,
                                (struct sockaddr *)&fromaddr,
                                &fromlen);
  if(state->remote_addrlen == 0) {
    memcpy(&state->remote_addr, &fromaddr, fromlen);
    state->remote_addrlen = fromlen;
  }







|







1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
  struct connectdata *conn = data->conn;
  struct tftp_state_data *state = conn->proto.tftpc;

  /* Receive the packet */
  fromlen = sizeof(fromaddr);
  state->rbytes = (int)recvfrom(state->sockfd,
                                (void *)state->rpacket.data,
                                (RECV_TYPE_ARG3)state->blksize + 4,
                                0,
                                (struct sockaddr *)&fromaddr,
                                &fromlen);
  if(state->remote_addrlen == 0) {
    memcpy(&state->remote_addr, &fromaddr, fromlen);
    state->remote_addrlen = fromlen;
  }
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
  else {
    /* The event is given by the TFTP packet time */
    unsigned short event = getrpacketevent(&state->rpacket);
    state->event = (tftp_event_t)event;

    switch(state->event) {
    case TFTP_EVENT_DATA:
      /* Don't pass to the client empty or retransmitted packets */
      if(state->rbytes > 4 &&
         (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
        result = Curl_client_write(data, CLIENTWRITE_BODY,
                                   (char *)state->rpacket.data + 4,
                                   state->rbytes-4);
        if(result) {
          tftp_state_machine(state, TFTP_EVENT_ERROR);







|







1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
  else {
    /* The event is given by the TFTP packet time */
    unsigned short event = getrpacketevent(&state->rpacket);
    state->event = (tftp_event_t)event;

    switch(state->event) {
    case TFTP_EVENT_DATA:
      /* Do not pass to the client empty or retransmitted packets */
      if(state->rbytes > 4 &&
         (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
        result = Curl_client_write(data, CLIENTWRITE_BODY,
                                   (char *)state->rpacket.data + 4,
                                   state->rbytes-4);
        if(result) {
          tftp_state_machine(state, TFTP_EVENT_ERROR);
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
    state->state = TFTP_STATE_FIN;
    return 0;
  }
  current = time(NULL);
  if(current > state->rx_time + state->retry_time) {
    if(event)
      *event = TFTP_EVENT_TIMEOUT;
    time(&state->rx_time); /* update even though we received nothing */
  }

  return timeout_ms;
}

/**********************************************************
 *







|







1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
    state->state = TFTP_STATE_FIN;
    return 0;
  }
  current = time(NULL);
  if(current > state->rx_time + state->retry_time) {
    if(event)
      *event = TFTP_EVENT_TIMEOUT;
    state->rx_time = time(NULL); /* update even though we received nothing */
  }

  return timeout_ms;
}

/**********************************************************
 *
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
  }
  if(event != TFTP_EVENT_NONE) {
    result = tftp_state_machine(state, event);
    if(result)
      return result;
    *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
    if(*done)
      /* Tell curl we're done */
      Curl_xfer_setup(data, -1, -1, FALSE, -1);
  }
  else {
    /* no timeouts to handle, check our socket */
    int rc = SOCKET_READABLE(state->sockfd, 0);

    if(rc == -1) {
      /* bail out */







|
|







1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
  }
  if(event != TFTP_EVENT_NONE) {
    result = tftp_state_machine(state, event);
    if(result)
      return result;
    *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
    if(*done)
      /* Tell curl we are done */
      Curl_xfer_setup_nop(data);
  }
  else {
    /* no timeouts to handle, check our socket */
    int rc = SOCKET_READABLE(state->sockfd, 0);

    if(rc == -1) {
      /* bail out */
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
      if(result)
        return result;
      result = tftp_state_machine(state, state->event);
      if(result)
        return result;
      *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
      if(*done)
        /* Tell curl we're done */
        Curl_xfer_setup(data, -1, -1, FALSE, -1);
    }
    /* if rc == 0, then select() timed out */
  }

  return result;
}








|
|







1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
      if(result)
        return result;
      result = tftp_state_machine(state, state->event);
      if(result)
        return result;
      *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
      if(*done)
        /* Tell curl we are done */
        Curl_xfer_setup_nop(data);
    }
    /* if rc == 0, then select() timed out */
  }

  return result;
}

1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
  CURLcode result;
  result = tftp_multi_statemach(data, dophase_done);

  if(*dophase_done) {
    DEBUGF(infof(data, "DO phase is complete"));
  }
  else if(!result) {
    /* The multi code doesn't have this logic for the DOING state so we
       provide it for TFTP since it may do the entire transfer in this
       state. */
    if(Curl_pgrsUpdate(data))
      result = CURLE_ABORTED_BY_CALLBACK;
    else
      result = Curl_speedcheck(data, Curl_now());
  }







|







1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
  CURLcode result;
  result = tftp_multi_statemach(data, dophase_done);

  if(*dophase_done) {
    DEBUGF(infof(data, "DO phase is complete"));
  }
  else if(!result) {
    /* The multi code does not have this logic for the DOING state so we
       provide it for TFTP since it may do the entire transfer in this
       state. */
    if(Curl_pgrsUpdate(data))
      result = CURLE_ABORTED_BY_CALLBACK;
    else
      result = Curl_speedcheck(data, Curl_now());
  }
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
                                      struct connectdata *conn)
{
  char *type;

  conn->transport = TRNSPRT_UDP;

  /* TFTP URLs support an extension like ";mode=<typecode>" that
   * we'll try to get now! */
  type = strstr(data->state.up.path, ";mode=");

  if(!type)
    type = strstr(conn->host.rawalloc, ";mode=");

  if(type) {
    char command;







|







1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
                                      struct connectdata *conn)
{
  char *type;

  conn->transport = TRNSPRT_UDP;

  /* TFTP URLs support an extension like ";mode=<typecode>" that
   * we will try to get now! */
  type = strstr(data->state.up.path, ";mode=");

  if(!type)
    type = strstr(conn->host.rawalloc, ";mode=");

  if(type) {
    char command;
Changes to jni/curl/lib/timediff.h.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

/* Use a larger type even for 32 bit time_t systems so that we can keep
   microsecond accuracy in it */
typedef curl_off_t timediff_t;
#define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T

#define TIMEDIFF_T_MAX CURL_OFF_T_MAX
#define TIMEDIFF_T_MIN CURL_OFF_T_MIN








|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

/* Use a larger type even for 32-bit time_t systems so that we can keep
   microsecond accuracy in it */
typedef curl_off_t timediff_t;
#define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T

#define TIMEDIFF_T_MAX CURL_OFF_T_MAX
#define TIMEDIFF_T_MIN CURL_OFF_T_MIN

Changes to jni/curl/lib/timeval.c.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#pragma warning(disable:28159)
#endif
    DWORD milliseconds = GetTickCount();
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

    now.tv_sec = milliseconds / 1000;
    now.tv_usec = (milliseconds % 1000) * 1000;
  }
  return now;
}

#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) ||  \
  defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)








|
|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#pragma warning(disable:28159)
#endif
    DWORD milliseconds = GetTickCount();
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

    now.tv_sec = (time_t)(milliseconds / 1000);
    now.tv_usec = (int)((milliseconds % 1000) * 1000);
  }
  return now;
}

#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) ||  \
  defined(HAVE_CLOCK_GETTIME_MONOTONIC_RAW)

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  struct timeval now;
#endif
  struct curltime cnow;
  struct timespec tsnow;

  /*
  ** clock_gettime() may be defined by Apple's SDK as weak symbol thus
  ** code compiles but fails during run-time if clock_gettime() is
  ** called on unsupported OS version.
  */
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
        (HAVE_BUILTIN_AVAILABLE == 1)
  bool have_clock_gettime = FALSE;
  if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
    have_clock_gettime = TRUE;
#endif

#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
  if(
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) &&    \
        (HAVE_BUILTIN_AVAILABLE == 1)
    have_clock_gettime &&
#endif
    (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) {
    cnow.tv_sec = tsnow.tv_sec;
    cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
  }
  else
#endif

  if(
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
        (HAVE_BUILTIN_AVAILABLE == 1)
    have_clock_gettime &&
#endif
    (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
    cnow.tv_sec = tsnow.tv_sec;
    cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
  }
  /*
  ** Even when the configure process has truly detected monotonic clock
  ** availability, it might happen that it is not actually available at
  ** run-time. When this occurs simply fallback to other time source.
  */
#ifdef HAVE_GETTIMEOFDAY
  else {
    (void)gettimeofday(&now, NULL);
    cnow.tv_sec = now.tv_sec;
    cnow.tv_usec = (unsigned int)now.tv_usec;
  }
#else
  else {
    cnow.tv_sec = time(NULL);
    cnow.tv_usec = 0;
  }
#endif







|

















|











|




|





|







73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  struct timeval now;
#endif
  struct curltime cnow;
  struct timespec tsnow;

  /*
  ** clock_gettime() may be defined by Apple's SDK as weak symbol thus
  ** code compiles but fails during runtime if clock_gettime() is
  ** called on unsupported OS version.
  */
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
        (HAVE_BUILTIN_AVAILABLE == 1)
  bool have_clock_gettime = FALSE;
  if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
    have_clock_gettime = TRUE;
#endif

#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
  if(
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) &&    \
        (HAVE_BUILTIN_AVAILABLE == 1)
    have_clock_gettime &&
#endif
    (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) {
    cnow.tv_sec = tsnow.tv_sec;
    cnow.tv_usec = (int)(tsnow.tv_nsec / 1000);
  }
  else
#endif

  if(
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
        (HAVE_BUILTIN_AVAILABLE == 1)
    have_clock_gettime &&
#endif
    (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
    cnow.tv_sec = tsnow.tv_sec;
    cnow.tv_usec = (int)(tsnow.tv_nsec / 1000);
  }
  /*
  ** Even when the configure process has truly detected monotonic clock
  ** availability, it might happen that it is not actually available at
  ** runtime. When this occurs simply fallback to other time source.
  */
#ifdef HAVE_GETTIMEOFDAY
  else {
    (void)gettimeofday(&now, NULL);
    cnow.tv_sec = now.tv_sec;
    cnow.tv_usec = (int)now.tv_usec;
  }
#else
  else {
    cnow.tv_sec = time(NULL);
    cnow.tv_usec = 0;
  }
#endif
Changes to jni/curl/lib/transfer.c.
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#elif defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

#ifndef HAVE_SOCKET
#error "We can't compile without socket() support!"
#endif

#include "urldata.h"
#include <curl/curl.h>
#include "netrc.h"

#include "content_encoding.h"







|







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#elif defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

#ifndef HAVE_SOCKET
#error "We cannot compile without socket() support!"
#endif

#include "urldata.h"
#include <curl/curl.h>
#include "netrc.h"

#include "content_encoding.h"
155
156
157
158
159
160
161
























162
163
164
165
166
167
168
      return FALSE;
    }
    break;
  }

  return TRUE;
}

























/**
 * Receive raw response data for the transfer.
 * @param data         the transfer
 * @param buf          buffer to keep response data received
 * @param blen         length of `buf`
 * @param eos_reliable if EOS detection in underlying connection is reliable







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
      return FALSE;
    }
    break;
  }

  return TRUE;
}

static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done)
{
  int sockindex;

  if(!data || !data->conn)
    return CURLE_FAILED_INIT;
  if(data->conn->sockfd == CURL_SOCKET_BAD)
    return CURLE_FAILED_INIT;
  sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
  return Curl_conn_shutdown(data, sockindex, done);
}

static bool xfer_recv_shutdown_started(struct Curl_easy *data)
{
  int sockindex;

  if(!data || !data->conn)
    return CURLE_FAILED_INIT;
  if(data->conn->sockfd == CURL_SOCKET_BAD)
    return CURLE_FAILED_INIT;
  sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
  return Curl_shutdown_started(data, sockindex);
}

/**
 * Receive raw response data for the transfer.
 * @param data         the transfer
 * @param buf          buffer to keep response data received
 * @param blen         length of `buf`
 * @param eos_reliable if EOS detection in underlying connection is reliable
182
183
184
185
186
187
188



189

190
191
192
193
194
195
196
197


198
199













200
201
202
203
204
205
206
  if(!eos_reliable && !data->req.header && data->req.size != -1) {
    curl_off_t totalleft = data->req.size - data->req.bytecount;
    if(totalleft <= 0)
      blen = 0;
    else if(totalleft < (curl_off_t)blen)
      blen = (size_t)totalleft;
  }





  if(!blen) {
    /* want nothing - continue as if read nothing. */
    DEBUGF(infof(data, "readwrite_data: we're done"));
    *err = CURLE_OK;
    return 0;
  }

  *err = Curl_xfer_recv(data, buf, blen, &nread);


  if(*err)
    return -1;













  DEBUGASSERT(nread >= 0);
  return nread;
}

/*
 * Go ahead and do a read if we have a readable socket or if
 * the stream was rewound (in which case we have data in a







>
>
>
|
>

|
<

|

|
|
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>







206
207
208
209
210
211
212
213
214
215
216
217
218
219

220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  if(!eos_reliable && !data->req.header && data->req.size != -1) {
    curl_off_t totalleft = data->req.size - data->req.bytecount;
    if(totalleft <= 0)
      blen = 0;
    else if(totalleft < (curl_off_t)blen)
      blen = (size_t)totalleft;
  }
  else if(xfer_recv_shutdown_started(data)) {
    /* we already reveived everything. Do not try more. */
    blen = 0;
  }

  if(!blen) {
    /* want nothing more */

    *err = CURLE_OK;
    nread = 0;
  }
  else {
    *err = Curl_xfer_recv(data, buf, blen, &nread);
  }

  if(*err)
    return -1;
  if(nread == 0) {
    if(data->req.shutdown) {
      bool done;
      *err = xfer_recv_shutdown(data, &done);
      if(*err)
        return -1;
      if(!done) {
        *err = CURLE_AGAIN;
        return -1;
      }
    }
    DEBUGF(infof(data, "readwrite_data: we are done"));
  }
  DEBUGASSERT(nread >= 0);
  return nread;
}

/*
 * Go ahead and do a read if we have a readable socket or if
 * the stream was rewound (in which case we have data in a
267
268
269
270
271
272
273



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297

298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
    if(!blen) {
      /* if we receive 0 or less here, either the data transfer is done or the
         server closed the connection and we bail out from this! */
      if(is_multiplex)
        DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
      else
        DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));



      k->keepon &= ~(KEEP_RECV|KEEP_SEND); /* stop sending as well */
      if(k->eos_written) /* already did write this to client, leave */
        break;
    }
    total_received += blen;

    result = Curl_xfer_write_resp(data, buf, blen, is_eos);
    if(result || data->req.done)
      goto out;

    /* if we are done, we stop receiving. On multiplexed connections,
     * we should read the EOS. Which may arrive as meta data after
     * the bytes. Not taking it in might lead to RST of streams. */
    if((!is_multiplex && data->req.download_done) || is_eos) {
      data->req.keepon &= ~KEEP_RECV;
    }
    /* if we are PAUSEd or stopped receiving, leave the loop */
    if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV))
      break;

  } while(maxloops-- && data_pending(data));

  if(maxloops <= 0) {
    /* did not read until EAGAIN, mark read-again-please */

    data->state.select_bits = CURL_CSELECT_IN;
    if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
      data->state.select_bits |= CURL_CSELECT_OUT;
  }

  if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
     (conn->bits.close || is_multiplex)) {
    /* When we've read the entire thing and the close bit is set, the server
       may now close the connection. If there's now any kind of sending going
       on from our side, we need to stop that immediately. */
    infof(data, "we are done reading and this is set to close, stop send");
    k->keepon &= ~KEEP_SEND; /* no writing anymore either */
    k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */
  }

out:
  Curl_multi_xfer_buf_release(data, xfer_buf);
  if(result)
    DEBUGF(infof(data, "readwrite_data() -> %d", result));
  return result;
}

#if defined(_WIN32) && defined(USE_WINSOCK)
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
#endif

static void win_update_buffer_size(curl_socket_t sockfd)
{
  int result;
  ULONG ideal;
  DWORD ideallen;
  result = WSAIoctl(sockfd, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
                    &ideal, sizeof(ideal), &ideallen, 0, 0);
  if(result == 0) {
    setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
               (const char *)&ideal, sizeof(ideal));
  }
}
#else
#define win_update_buffer_size(x)
#endif

#define curl_upload_refill_watermark(data) \
        ((size_t)((data)->set.upload_buffer_size >> 5))

/*
 * Send data to upload to the server, when the socket is writable.
 */
static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
{
  CURLcode result = CURLE_OK;

  if((data->req.keepon & KEEP_SEND_PAUSE))
    return CURLE_OK;

  /* We should not get here when the sending is already done. It
   * probably means that someone set `data-req.keepon |= KEEP_SEND`
   * when it should not. */
  DEBUGASSERT(!Curl_req_done_sending(data));

  if(!Curl_req_done_sending(data)) {
    *didwhat |= KEEP_SEND;
    result = Curl_req_send_more(data);
    if(result)
      return result;

#if defined(_WIN32) && defined(USE_WINSOCK)
    /* FIXME: this looks like it would fit better into cf-socket.c
     * but then I do not know enough Windows to say... */
    {
      struct curltime n = Curl_now();
      if(Curl_timediff(n, data->conn->last_sndbuf_update) > 1000) {
        win_update_buffer_size(data->conn->writesockfd);
        data->conn->last_sndbuf_update = n;
      }
    }
#endif
  }
  return result;
}

static int select_bits_paused(struct Curl_easy *data, int select_bits)
{
  /* See issue #11982: we really need to be careful not to progress
   * a transfer direction when that direction is paused. Not all parts
   * of our state machine are handling PAUSED transfers correctly. So, we







>
>
>
|



















|

|
|
>







|
|













<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<





<
<










|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
|







309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
























366
367
368
369
370


371
372
373
374
375
376
377
378
379
380
381


382












383
384
385
386
387
388
389
390
    if(!blen) {
      /* if we receive 0 or less here, either the data transfer is done or the
         server closed the connection and we bail out from this! */
      if(is_multiplex)
        DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
      else
        DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
      /* stop receiving and ALL sending as well, including PAUSE and HOLD.
       * We might still be paused on receive client writes though, so
       * keep those bits around. */
      k->keepon &= ~(KEEP_RECV|KEEP_SENDBITS);
      if(k->eos_written) /* already did write this to client, leave */
        break;
    }
    total_received += blen;

    result = Curl_xfer_write_resp(data, buf, blen, is_eos);
    if(result || data->req.done)
      goto out;

    /* if we are done, we stop receiving. On multiplexed connections,
     * we should read the EOS. Which may arrive as meta data after
     * the bytes. Not taking it in might lead to RST of streams. */
    if((!is_multiplex && data->req.download_done) || is_eos) {
      data->req.keepon &= ~KEEP_RECV;
    }
    /* if we are PAUSEd or stopped receiving, leave the loop */
    if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV))
      break;

  } while(maxloops--);

  if((maxloops <= 0) || data_pending(data)) {
    /* did not read until EAGAIN or there is still pending data, mark as
       read-again-please */
    data->state.select_bits = CURL_CSELECT_IN;
    if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
      data->state.select_bits |= CURL_CSELECT_OUT;
  }

  if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
     (conn->bits.close || is_multiplex)) {
    /* When we have read the entire thing and the close bit is set, the server
       may now close the connection. If there is now any kind of sending going
       on from our side, we need to stop that immediately. */
    infof(data, "we are done reading and this is set to close, stop send");
    k->keepon &= ~KEEP_SEND; /* no writing anymore either */
    k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */
  }

out:
  Curl_multi_xfer_buf_release(data, xfer_buf);
  if(result)
    DEBUGF(infof(data, "readwrite_data() -> %d", result));
  return result;
}

























/*
 * Send data to upload to the server, when the socket is writable.
 */
static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
{


  if((data->req.keepon & KEEP_SEND_PAUSE))
    return CURLE_OK;

  /* We should not get here when the sending is already done. It
   * probably means that someone set `data-req.keepon |= KEEP_SEND`
   * when it should not. */
  DEBUGASSERT(!Curl_req_done_sending(data));

  if(!Curl_req_done_sending(data)) {
    *didwhat |= KEEP_SEND;
    return Curl_req_send_more(data);


  }












  return CURLE_OK;
}

static int select_bits_paused(struct Curl_easy *data, int select_bits)
{
  /* See issue #11982: we really need to be careful not to progress
   * a transfer direction when that direction is paused. Not all parts
   * of our state machine are handling PAUSED transfers correctly. So, we
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
  struct connectdata *conn = data->conn;
  struct SingleRequest *k = &data->req;
  CURLcode result;
  struct curltime now;
  int didwhat = 0;
  int select_bits;

  /* Check if client writes had been paused and can resume now. */
  if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
    Curl_conn_ev_data_pause(data, FALSE);
    result = Curl_cwriter_unpause(data);
    if(result)
      goto out;
  }

  if(data->state.select_bits) {
    if(select_bits_paused(data, data->state.select_bits)) {
      /* leave the bits unchanged, so they'll tell us what to do when
       * this transfer gets unpaused. */
      DEBUGF(infof(data, "readwrite, select_bits, early return on PAUSED"));
      result = CURLE_OK;
      goto out;







<
<
<
<
<
<
<
<







410
411
412
413
414
415
416








417
418
419
420
421
422
423
  struct connectdata *conn = data->conn;
  struct SingleRequest *k = &data->req;
  CURLcode result;
  struct curltime now;
  int didwhat = 0;
  int select_bits;









  if(data->state.select_bits) {
    if(select_bits_paused(data, data->state.select_bits)) {
      /* leave the bits unchanged, so they'll tell us what to do when
       * this transfer gets unpaused. */
      DEBUGF(infof(data, "readwrite, select_bits, early return on PAUSED"));
      result = CURLE_OK;
      goto out;
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
    /*
     * The transfer has been performed. Just make some general checks before
     * returning.
     */
    if(!(data->req.no_body) && (k->size != -1) &&
       (k->bytecount != k->size) &&
#ifdef CURL_DO_LINEEND_CONV
       /* Most FTP servers don't adjust their file SIZE response for CRLFs,
          so we'll check to see if the discrepancy can be explained
          by the number of CRLFs we've changed to LFs.
       */
       (k->bytecount != (k->size + data->state.crlf_conversions)) &&
#endif /* CURL_DO_LINEEND_CONV */
       !k->newurl) {
      failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T
            " bytes remaining to read", k->size - k->bytecount);
      result = CURLE_PARTIAL_FILE;







|
|
|







516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
    /*
     * The transfer has been performed. Just make some general checks before
     * returning.
     */
    if(!(data->req.no_body) && (k->size != -1) &&
       (k->bytecount != k->size) &&
#ifdef CURL_DO_LINEEND_CONV
       /* Most FTP servers do not adjust their file SIZE response for CRLFs,
          so we will check to see if the discrepancy can be explained
          by the number of CRLFs we have changed to LFs.
       */
       (k->bytecount != (k->size + data->state.crlf_conversions)) &&
#endif /* CURL_DO_LINEEND_CONV */
       !k->newurl) {
      failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T
            " bytes remaining to read", k->size - k->bytecount);
      result = CURLE_PARTIAL_FILE;
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
 * authentication etc.
 */
CURLcode Curl_pretransfer(struct Curl_easy *data)
{
  CURLcode result;

  if(!data->state.url && !data->set.uh) {
    /* we can't do anything without URL */
    failf(data, "No URL set");
    return CURLE_URL_MALFORMAT;
  }

  /* since the URL may have been redirected in a previous use of this handle */
  if(data->state.url_alloc) {
    /* the already set URL is allocated, free it first! */







|







563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
 * authentication etc.
 */
CURLcode Curl_pretransfer(struct Curl_easy *data)
{
  CURLcode result;

  if(!data->state.url && !data->set.uh) {
    /* we cannot do anything without URL */
    failf(data, "No URL set");
    return CURLE_URL_MALFORMAT;
  }

  /* since the URL may have been redirected in a previous use of this handle */
  if(data->state.url_alloc) {
    /* the already set URL is allocated, free it first! */
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
    if(uc) {
      failf(data, "No URL set");
      return CURLE_URL_MALFORMAT;
    }
  }

  if(data->set.postfields && data->set.set_resume_from) {
    /* we can't */
    failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
    return CURLE_BAD_FUNCTION_ARGUMENT;
  }

  data->state.prefer_ascii = data->set.prefer_ascii;
#ifdef CURL_LIST_ONLY_PROTOCOL
  data->state.list_only = data->set.list_only;







|







587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
    if(uc) {
      failf(data, "No URL set");
      return CURLE_URL_MALFORMAT;
    }
  }

  if(data->set.postfields && data->set.set_resume_from) {
    /* we cannot */
    failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
    return CURLE_BAD_FUNCTION_ARGUMENT;
  }

  data->state.prefer_ascii = data->set.prefer_ascii;
#ifdef CURL_LIST_ONLY_PROTOCOL
  data->state.list_only = data->set.list_only;
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
    }
#endif
    result = Curl_hsts_loadcb(data, data->hsts);
  }

  /*
   * Set user-agent. Used for HTTP, but since we can attempt to tunnel
   * basically anything through an HTTP proxy we can't limit this based on
   * protocol.
   */
  if(data->set.str[STRING_USERAGENT]) {
    Curl_safefree(data->state.aptr.uagent);
    data->state.aptr.uagent =
      aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
    if(!data->state.aptr.uagent)







|







689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
    }
#endif
    result = Curl_hsts_loadcb(data, data->hsts);
  }

  /*
   * Set user-agent. Used for HTTP, but since we can attempt to tunnel
   * basically anything through an HTTP proxy we cannot limit this based on
   * protocol.
   */
  if(data->set.str[STRING_USERAGENT]) {
    Curl_safefree(data->state.aptr.uagent);
    data->state.aptr.uagent =
      aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
    if(!data->state.aptr.uagent)
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
#endif

  data->req.headerbytecount = 0;
  Curl_headers_cleanup(data);
  return result;
}

/*
 * Curl_posttransfer() is called immediately after a transfer ends
 */
CURLcode Curl_posttransfer(struct Curl_easy *data)
{
#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
  /* restore the signal handler for SIGPIPE before we get back */
  if(!data->set.no_signal)
    signal(SIGPIPE, data->state.prev_signal);
#else
  (void)data; /* unused parameter */
#endif

  return CURLE_OK;
}

/*
 * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
 * as given by the remote server and set up the new URL to request.
 *
 * This function DOES NOT FREE the given url.
 */
CURLcode Curl_follow(struct Curl_easy *data,







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







720
721
722
723
724
725
726
















727
728
729
730
731
732
733
#endif

  data->req.headerbytecount = 0;
  Curl_headers_cleanup(data);
  return result;
}

















/*
 * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
 * as given by the remote server and set up the new URL to request.
 *
 * This function DOES NOT FREE the given url.
 */
CURLcode Curl_follow(struct Curl_easy *data,
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
    }
  }

  if((type != FOLLOW_RETRY) &&
     (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
     Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
    /* If this is not redirect due to a 401 or 407 response and an absolute
       URL: don't allow a custom port number */
    disallowport = TRUE;
  }

  DEBUGASSERT(data->state.uh);
  uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
                    (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
                    ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
                    CURLU_ALLOW_SPACE |
                    (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
  if(uc) {
    if(type != FOLLOW_FAKE) {
      failf(data, "The redirect target URL could not be parsed: %s",
            curl_url_strerror(uc));
      return Curl_uc_to_curlcode(uc);
    }








|




|
|
|
|
|







801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
    }
  }

  if((type != FOLLOW_RETRY) &&
     (data->req.httpcode != 401) && (data->req.httpcode != 407) &&
     Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
    /* If this is not redirect due to a 401 or 407 response and an absolute
       URL: do not allow a custom port number */
    disallowport = TRUE;
  }

  DEBUGASSERT(data->state.uh);
  uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (unsigned int)
                    ((type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
                     ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
                     CURLU_ALLOW_SPACE |
                     (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
  if(uc) {
    if(type != FOLLOW_FAKE) {
      failf(data, "The redirect target URL could not be parsed: %s",
            curl_url_strerror(uc));
      return Curl_uc_to_curlcode(uc);
    }

897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
        Curl_safefree(data->state.aptr.user);
        Curl_safefree(data->state.aptr.passwd);
      }
    }
  }

  if(type == FOLLOW_FAKE) {
    /* we're only figuring out the new url if we would've followed locations
       but now we're done so we can get out! */
    data->info.wouldredirect = newurl;

    if(reachedmax) {
      failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
      return CURLE_TOO_MANY_REDIRECTS;
    }
    return CURLE_OK;







|
|







879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
        Curl_safefree(data->state.aptr.user);
        Curl_safefree(data->state.aptr.passwd);
      }
    }
  }

  if(type == FOLLOW_FAKE) {
    /* we are only figuring out the new URL if we would have followed locations
       but now we are done so we can get out! */
    data->info.wouldredirect = newurl;

    if(reachedmax) {
      failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
      return CURLE_TOO_MANY_REDIRECTS;
    }
    return CURLE_OK;
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
       Authorization: XXXX header in the HTTP request code snippet */
    /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
       Proxy-Authorization: XXXX header in the HTTP request code snippet */
    /* 300 - Multiple Choices */
    /* 306 - Not used */
    /* 307 - Temporary Redirect */
  default:  /* for all above (and the unknown ones) */
    /* Some codes are explicitly mentioned since I've checked RFC2616 and they
     * seem to be OK to POST to.
     */
    break;
  case 301: /* Moved Permanently */
    /* (quote from RFC7231, section 6.4.2)
     *
     * Note: For historical reasons, a user agent MAY change the request
     * method from POST to GET for the subsequent request.  If this
     * behavior is undesired, the 307 (Temporary Redirect) status code
     * can be used instead.
     *
     * ----
     *
     * Many webservers expect this, so these servers often answers to a POST
     * request with an error page. To be sure that libcurl gets the page that







|
|






|







917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
       Authorization: XXXX header in the HTTP request code snippet */
    /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
       Proxy-Authorization: XXXX header in the HTTP request code snippet */
    /* 300 - Multiple Choices */
    /* 306 - Not used */
    /* 307 - Temporary Redirect */
  default:  /* for all above (and the unknown ones) */
    /* Some codes are explicitly mentioned since I have checked RFC2616 and
     * they seem to be OK to POST to.
     */
    break;
  case 301: /* Moved Permanently */
    /* (quote from RFC7231, section 6.4.2)
     *
     * Note: For historical reasons, a user agent MAY change the request
     * method from POST to GET for the subsequent request. If this
     * behavior is undesired, the 307 (Temporary Redirect) status code
     * can be used instead.
     *
     * ----
     *
     * Many webservers expect this, so these servers often answers to a POST
     * request with an error page. To be sure that libcurl gets the page that
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
      Curl_creader_set_rewind(data, FALSE);
    }
    break;
  case 302: /* Found */
    /* (quote from RFC7231, section 6.4.3)
     *
     * Note: For historical reasons, a user agent MAY change the request
     * method from POST to GET for the subsequent request.  If this
     * behavior is undesired, the 307 (Temporary Redirect) status code
     * can be used instead.
     *
     * ----
     *
     * Many webservers expect this, so these servers often answers to a POST
     * request with an error page. To be sure that libcurl gets the page that







|







951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
      Curl_creader_set_rewind(data, FALSE);
    }
    break;
  case 302: /* Found */
    /* (quote from RFC7231, section 6.4.3)
     *
     * Note: For historical reasons, a user agent MAY change the request
     * method from POST to GET for the subsequent request. If this
     * behavior is undesired, the 307 (Temporary Redirect) status code
     * can be used instead.
     *
     * ----
     *
     * Many webservers expect this, so these servers often answers to a POST
     * request with an error page. To be sure that libcurl gets the page that
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
      data->state.httpreq = HTTPREQ_GET;
      infof(data, "Switch to %s",
            data->req.no_body?"HEAD":"GET");
    }
    break;
  case 304: /* Not Modified */
    /* 304 means we did a conditional request and it was "Not modified".
     * We shouldn't get any Location: header in this response!
     */
    break;
  case 305: /* Use Proxy */
    /* (quote from RFC2616, section 10.3.6):
     * "The requested resource MUST be accessed through the proxy given
     * by the Location field. The Location field gives the URI of the
     * proxy.  The recipient is expected to repeat this single request
     * via the proxy. 305 responses MUST only be generated by origin
     * servers."
     */
    break;
  }
  Curl_pgrsTime(data, TIMER_REDIRECT);
  Curl_pgrsResetTransferSizes(data);







|






|







992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
      data->state.httpreq = HTTPREQ_GET;
      infof(data, "Switch to %s",
            data->req.no_body?"HEAD":"GET");
    }
    break;
  case 304: /* Not Modified */
    /* 304 means we did a conditional request and it was "Not modified".
     * We should not get any Location: header in this response!
     */
    break;
  case 305: /* Use Proxy */
    /* (quote from RFC2616, section 10.3.6):
     * "The requested resource MUST be accessed through the proxy given
     * by the Location field. The Location field gives the URI of the
     * proxy. The recipient is expected to repeat this single request
     * via the proxy. 305 responses MUST only be generated by origin
     * servers."
     */
    break;
  }
  Curl_pgrsTime(data, TIMER_REDIRECT);
  Curl_pgrsResetTransferSizes(data);
1039
1040
1041
1042
1043
1044
1045
1046
1047

1048
1049
1050
1051
1052
1053
1054
   NOTE: that the *url is malloc()ed. */
CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
{
  struct connectdata *conn = data->conn;
  bool retry = FALSE;
  *url = NULL;

  /* if we're talking upload, we can't do the checks below, unless the protocol
     is HTTP as when uploading over HTTP we will still get a response */

  if(data->state.upload &&
     !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)))
    return CURLE_OK;

  if((data->req.bytecount + data->req.headerbytecount == 0) &&
     conn->bits.reuse &&
     (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))







|
|
>







1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
   NOTE: that the *url is malloc()ed. */
CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
{
  struct connectdata *conn = data->conn;
  bool retry = FALSE;
  *url = NULL;

  /* if we are talking upload, we cannot do the checks below, unless the
     protocol is HTTP as when uploading over HTTP we will still get a
     response */
  if(data->state.upload &&
     !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)))
    return CURLE_OK;

  if((data->req.bytecount + data->req.headerbytecount == 0) &&
     conn->bits.reuse &&
     (!data->req.no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP))
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113


1114
1115
1116
1117
1118
1119
1120
1121
1122

1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141

1142

1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163



























1164
1165
1166
1167
1168
1169
1170
    infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
          data->state.retrycount);
    *url = strdup(data->state.url);
    if(!*url)
      return CURLE_OUT_OF_MEMORY;

    connclose(conn, "retry"); /* close this connection */
    conn->bits.retry = TRUE; /* mark this as a connection we're about
                                to retry. Marking it this way should
                                prevent i.e HTTP transfers to return
                                error just because nothing has been
                                transferred! */
    Curl_creader_set_rewind(data, TRUE);
  }
  return CURLE_OK;
}

/*
 * Curl_xfer_setup() is called to setup some basic properties for the
 * upcoming transfer.
 */
void Curl_xfer_setup(
  struct Curl_easy *data,   /* transfer */
  int sockindex,            /* socket index to read from or -1 */
  curl_off_t size,          /* -1 if unknown at this point */
  bool getheader,           /* TRUE if header parsing is wanted */
  int writesockindex        /* socket index to write to, it may very well be
                               the same we read from. -1 disables */


  )
{
  struct SingleRequest *k = &data->req;
  struct connectdata *conn = data->conn;
  bool want_send = Curl_req_want_send(data);

  DEBUGASSERT(conn != NULL);
  DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
  DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1));


  if(conn->bits.multiplex || conn->httpversion >= 20 || want_send) {
    /* when multiplexing, the read/write sockets need to be the same! */
    conn->sockfd = sockindex == -1 ?
      ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) :
      conn->sock[sockindex];
    conn->writesockfd = conn->sockfd;
    if(want_send)
      /* special and very HTTP-specific */
      writesockindex = FIRSTSOCKET;
  }
  else {
    conn->sockfd = sockindex == -1 ?
      CURL_SOCKET_BAD : conn->sock[sockindex];
    conn->writesockfd = writesockindex == -1 ?
      CURL_SOCKET_BAD:conn->sock[writesockindex];
  }
  k->getheader = getheader;


  k->size = size;


  /* The code sequence below is placed in this function just because all
     necessary input is not always known in do_complete() as this function may
     be called after that */

  if(!k->getheader) {
    k->header = FALSE;
    if(size > 0)
      Curl_pgrsSetDownloadSize(data, size);
  }
  /* we want header and/or body, if neither then don't do this! */
  if(k->getheader || !data->req.no_body) {

    if(sockindex != -1)
      k->keepon |= KEEP_RECV;

    if(writesockindex != -1)
      k->keepon |= KEEP_SEND;
  } /* if(k->getheader || !data->req.no_body) */

}




























CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
                              const char *buf, size_t blen,
                              bool is_eos)
{
  CURLcode result = CURLE_OK;








|










|
<

|




|

>
>









>

















<

>

>










|










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087

1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124

1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
    infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
          data->state.retrycount);
    *url = strdup(data->state.url);
    if(!*url)
      return CURLE_OUT_OF_MEMORY;

    connclose(conn, "retry"); /* close this connection */
    conn->bits.retry = TRUE; /* mark this as a connection we are about
                                to retry. Marking it this way should
                                prevent i.e HTTP transfers to return
                                error just because nothing has been
                                transferred! */
    Curl_creader_set_rewind(data, TRUE);
  }
  return CURLE_OK;
}

/*
 * xfer_setup() is called to setup basic properties for the transfer.

 */
static void xfer_setup(
  struct Curl_easy *data,   /* transfer */
  int sockindex,            /* socket index to read from or -1 */
  curl_off_t size,          /* -1 if unknown at this point */
  bool getheader,           /* TRUE if header parsing is wanted */
  int writesockindex,       /* socket index to write to, it may very well be
                               the same we read from. -1 disables */
  bool shutdown             /* shutdown connection at transfer end. Only
                             * supported when sending OR receiving. */
  )
{
  struct SingleRequest *k = &data->req;
  struct connectdata *conn = data->conn;
  bool want_send = Curl_req_want_send(data);

  DEBUGASSERT(conn != NULL);
  DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
  DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1));
  DEBUGASSERT(!shutdown || (sockindex == -1) || (writesockindex == -1));

  if(conn->bits.multiplex || conn->httpversion >= 20 || want_send) {
    /* when multiplexing, the read/write sockets need to be the same! */
    conn->sockfd = sockindex == -1 ?
      ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) :
      conn->sock[sockindex];
    conn->writesockfd = conn->sockfd;
    if(want_send)
      /* special and very HTTP-specific */
      writesockindex = FIRSTSOCKET;
  }
  else {
    conn->sockfd = sockindex == -1 ?
      CURL_SOCKET_BAD : conn->sock[sockindex];
    conn->writesockfd = writesockindex == -1 ?
      CURL_SOCKET_BAD:conn->sock[writesockindex];
  }


  k->getheader = getheader;
  k->size = size;
  k->shutdown = shutdown;

  /* The code sequence below is placed in this function just because all
     necessary input is not always known in do_complete() as this function may
     be called after that */

  if(!k->getheader) {
    k->header = FALSE;
    if(size > 0)
      Curl_pgrsSetDownloadSize(data, size);
  }
  /* we want header and/or body, if neither then do not do this! */
  if(k->getheader || !data->req.no_body) {

    if(sockindex != -1)
      k->keepon |= KEEP_RECV;

    if(writesockindex != -1)
      k->keepon |= KEEP_SEND;
  } /* if(k->getheader || !data->req.no_body) */

}

void Curl_xfer_setup_nop(struct Curl_easy *data)
{
  xfer_setup(data, -1, -1, FALSE, -1, FALSE);
}

void Curl_xfer_setup1(struct Curl_easy *data,
                      int send_recv,
                      curl_off_t recv_size,
                      bool getheader)
{
  int recv_index = (send_recv & CURL_XFER_RECV)? FIRSTSOCKET : -1;
  int send_index = (send_recv & CURL_XFER_SEND)? FIRSTSOCKET : -1;
  DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
  xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE);
}

void Curl_xfer_setup2(struct Curl_easy *data,
                      int send_recv,
                      curl_off_t recv_size,
                      bool shutdown)
{
  int recv_index = (send_recv & CURL_XFER_RECV)? SECONDARYSOCKET : -1;
  int send_index = (send_recv & CURL_XFER_SEND)? SECONDARYSOCKET : -1;
  DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
  xfer_setup(data, recv_index, recv_size, FALSE, send_index, shutdown);
}

CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
                              const char *buf, size_t blen,
                              bool is_eos)
{
  CURLcode result = CURLE_OK;

1272
1273
1274
1275
1276
1277
1278
























}

CURLcode Curl_xfer_send_close(struct Curl_easy *data)
{
  Curl_conn_ev_data_done_send(data);
  return CURLE_OK;
}































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
}

CURLcode Curl_xfer_send_close(struct Curl_easy *data)
{
  Curl_conn_ev_data_done_send(data);
  return CURLE_OK;
}

CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done)
{
  int sockindex;

  if(!data || !data->conn)
    return CURLE_FAILED_INIT;
  if(data->conn->writesockfd == CURL_SOCKET_BAD)
    return CURLE_FAILED_INIT;
  sockindex = (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]);
  return Curl_conn_shutdown(data, sockindex, done);
}

bool Curl_xfer_is_blocked(struct Curl_easy *data)
{
  bool want_send = ((data)->req.keepon & KEEP_SEND);
  bool want_recv = ((data)->req.keepon & KEEP_RECV);
  if(!want_send)
    return (want_recv && Curl_cwriter_is_paused(data));
  else if(!want_recv)
    return (want_send && Curl_creader_is_paused(data));
  else
    return Curl_creader_is_paused(data) && Curl_cwriter_is_paused(data);
}
Changes to jni/curl/lib/transfer.h.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
char *Curl_checkheaders(const struct Curl_easy *data,
                        const char *thisheader,
                        const size_t thislen);

void Curl_init_CONNECT(struct Curl_easy *data);

CURLcode Curl_pretransfer(struct Curl_easy *data);
CURLcode Curl_posttransfer(struct Curl_easy *data);

typedef enum {
  FOLLOW_NONE,  /* not used within the function, just a placeholder to
                   allow initing to this */
  FOLLOW_FAKE,  /* only records stuff, not actually following */
  FOLLOW_RETRY, /* set if this is a request retry as opposed to a real
                   redirect following */







<







28
29
30
31
32
33
34

35
36
37
38
39
40
41
char *Curl_checkheaders(const struct Curl_easy *data,
                        const char *thisheader,
                        const size_t thislen);

void Curl_init_CONNECT(struct Curl_easy *data);

CURLcode Curl_pretransfer(struct Curl_easy *data);


typedef enum {
  FOLLOW_NONE,  /* not used within the function, just a placeholder to
                   allow initing to this */
  FOLLOW_FAKE,  /* only records stuff, not actually following */
  FOLLOW_RETRY, /* set if this is a request retry as opposed to a real
                   redirect following */
72
73
74
75
76
77
78




79



80
81







82
83
84




85

86



87
88
89
90
91
92
93
94
 * @param hd0      the 0-terminated, single header line
 * @param hdlen    the length of the header line
 * @param is_eos   TRUE iff this is the end of the response
 */
CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
                                 const char *hd0, size_t hdlen, bool is_eos);





/* This sets up a forthcoming transfer */



void Curl_xfer_setup(struct Curl_easy *data,
                     int sockindex,     /* socket index to read from or -1 */







                     curl_off_t size,   /* -1 if unknown at this point */
                     bool getheader,    /* TRUE if header parsing is wanted */
                     int writesockindex /* socket index to write to. May be




                                           the same we read from. -1

                                           disables */



  );

/**
 * Multi has set transfer to DONE. Last chance to trigger
 * missing response things like writing an EOS to the client.
 */
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature);








>
>
>
>
|
>
>
>
|
|
>
>
>
>
>
>
>
|
|
|
>
>
>
>
|
>
|
>
>
>
|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
 * @param hd0      the 0-terminated, single header line
 * @param hdlen    the length of the header line
 * @param is_eos   TRUE iff this is the end of the response
 */
CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
                                 const char *hd0, size_t hdlen, bool is_eos);

#define CURL_XFER_NOP     (0)
#define CURL_XFER_RECV    (1<<(0))
#define CURL_XFER_SEND    (1<<(1))
#define CURL_XFER_SENDRECV (CURL_XFER_RECV|CURL_XFER_SEND)

/**
 * The transfer is neither receiving nor sending now.
 */
void Curl_xfer_setup_nop(struct Curl_easy *data);

/**
 * The transfer will use socket 1 to send/recv. `recv_size` is
 * the amount to receive or -1 if unknown. `getheader` indicates
 * response header processing is expected.
 */
void Curl_xfer_setup1(struct Curl_easy *data,
                      int send_recv,
                      curl_off_t recv_size,
                      bool getheader);

/**
 * The transfer will use socket 2 to send/recv. `recv_size` is
 * the amount to receive or -1 if unknown. With `shutdown` being
 * set, the transfer is only allowed to either send OR receive
 * and the socket 2 connection will be shutdown at the end of
 * the transfer. An unclean shutdown will fail the transfer.
 */
void Curl_xfer_setup2(struct Curl_easy *data,
                      int send_recv,
                      curl_off_t recv_size,
                      bool shutdown);

/**
 * Multi has set transfer to DONE. Last chance to trigger
 * missing response things like writing an EOS to the client.
 */
CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature);

107
108
109
110
111
112
113

114







115
 * Will return CURLE_AGAIN on blocking with (*pnrcvd == 0).
 */
CURLcode Curl_xfer_recv(struct Curl_easy *data,
                        char *buf, size_t blen,
                        ssize_t *pnrcvd);

CURLcode Curl_xfer_send_close(struct Curl_easy *data);









#endif /* HEADER_CURL_TRANSFER_H */







>

>
>
>
>
>
>
>

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
 * Will return CURLE_AGAIN on blocking with (*pnrcvd == 0).
 */
CURLcode Curl_xfer_recv(struct Curl_easy *data,
                        char *buf, size_t blen,
                        ssize_t *pnrcvd);

CURLcode Curl_xfer_send_close(struct Curl_easy *data);
CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done);

/**
 * Return TRUE iff the transfer is not done, but further progress
 * is blocked. For example when it is only receiving and its writer
 * is PAUSED.
 */
bool Curl_xfer_is_blocked(struct Curl_easy *data);

#endif /* HEADER_CURL_TRANSFER_H */
Changes to jni/curl/lib/url.c.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#endif

#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif

#ifndef HAVE_SOCKET
#error "We can't compile without socket() support!"
#endif

#include <limits.h>

#include "doh.h"
#include "urldata.h"
#include "netrc.h"







|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#endif

#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif

#ifndef HAVE_SOCKET
#error "We cannot compile without socket() support!"
#endif

#include <limits.h>

#include "doh.h"
#include "urldata.h"
#include "netrc.h"
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#ifdef USE_NGHTTP2
static void data_priority_cleanup(struct Curl_easy *data);
#else
#define data_priority_cleanup(x)
#endif

/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
 * more than just a few bytes to play with. Don't let it become too small or
 * bad things will happen.
 */
#if READBUFFER_SIZE < READBUFFER_MIN
# error READBUFFER_SIZE is too small
#endif

#ifdef USE_UNIX_SOCKETS







|







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#ifdef USE_NGHTTP2
static void data_priority_cleanup(struct Curl_easy *data);
#else
#define data_priority_cleanup(x)
#endif

/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
 * more than just a few bytes to play with. Do not let it become too small or
 * bad things will happen.
 */
#if READBUFFER_SIZE < READBUFFER_MIN
# error READBUFFER_SIZE is too small
#endif

#ifdef USE_UNIX_SOCKETS
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
                      the multi handle, since that function uses the magic
                      field! */

  if(data->state.rangestringalloc)
    free(data->state.range);

  /* freed here just in case DONE wasn't called */
  Curl_req_free(&data->req, data);

  /* Close down all open SSL info and sessions */
  Curl_ssl_close_all(data);
  Curl_safefree(data->state.first_host);
  Curl_safefree(data->state.scratch);
  Curl_ssl_free_certinfo(data);







|







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
                      the multi handle, since that function uses the magic
                      field! */

  if(data->state.rangestringalloc)
    free(data->state.range);

  /* freed here just in case DONE was not called */
  Curl_req_free(&data->req, data);

  /* Close down all open SSL info and sessions */
  Curl_ssl_close_all(data);
  Curl_safefree(data->state.first_host);
  Curl_safefree(data->state.scratch);
  Curl_ssl_free_certinfo(data);
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

  /* use fread as default function to read input */
  set->fread_func_set = (curl_read_callback)fread;
  set->is_fread_set = 0;

  set->seek_client = ZERO_NULL;

  set->filesize = -1;        /* we don't know the size */
  set->postfieldsize = -1;   /* unknown size */
  set->maxredirs = 30;       /* sensible default */

  set->method = HTTPREQ_GET; /* Default HTTP request */
#ifndef CURL_DISABLE_RTSP
  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
#endif







|







361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

  /* use fread as default function to read input */
  set->fread_func_set = (curl_read_callback)fread;
  set->is_fread_set = 0;

  set->seek_client = ZERO_NULL;

  set->filesize = -1;        /* we do not know the size */
  set->postfieldsize = -1;   /* unknown size */
  set->maxredirs = 30;       /* sensible default */

  set->method = HTTPREQ_GET; /* Default HTTP request */
#ifndef CURL_DISABLE_RTSP
  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
#endif
463
464
465
466
467
468
469

470
471
472
473
474
475
476
  set->chunk_bgn      = ZERO_NULL;
  set->chunk_end      = ZERO_NULL;
  set->fnmatch = ZERO_NULL;
#endif
  set->tcp_keepalive = FALSE;
  set->tcp_keepintvl = 60;
  set->tcp_keepidle = 60;

  set->tcp_fastopen = FALSE;
  set->tcp_nodelay = TRUE;
  set->ssl_enable_alpn = TRUE;
  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
  set->sep_headers = TRUE; /* separated header lists by default */
  set->buffer_size = READBUFFER_SIZE;
  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;







>







463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  set->chunk_bgn      = ZERO_NULL;
  set->chunk_end      = ZERO_NULL;
  set->fnmatch = ZERO_NULL;
#endif
  set->tcp_keepalive = FALSE;
  set->tcp_keepintvl = 60;
  set->tcp_keepidle = 60;
  set->tcp_keepcnt = 9;
  set->tcp_fastopen = FALSE;
  set->tcp_nodelay = TRUE;
  set->ssl_enable_alpn = TRUE;
  set->expect_100_timeout = 1000L; /* Wait for a second by default. */
  set->sep_headers = TRUE; /* separated header lists by default */
  set->buffer_size = READBUFFER_SIZE;
  set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
  }
  else
    *curl = data;

  return result;
}

static void conn_shutdown(struct Curl_easy *data)
{
  DEBUGASSERT(data);
  infof(data, "Closing connection");

  /* possible left-overs from the async name resolvers */
  Curl_resolver_cancel(data);

  Curl_conn_close(data, SECONDARYSOCKET);
  Curl_conn_close(data, FIRSTSOCKET);
}

static void conn_free(struct Curl_easy *data, struct connectdata *conn)
{
  size_t i;

  DEBUGASSERT(conn);

  for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
    Curl_conn_cf_discard_all(data, conn, (int)i);







<
<
<
<
<
<
<
<
<
<
<
<
|







552
553
554
555
556
557
558












559
560
561
562
563
564
565
566
  }
  else
    *curl = data;

  return result;
}













void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
{
  size_t i;

  DEBUGASSERT(conn);

  for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
    Curl_conn_cf_discard_all(data, conn, (int)i);
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
#endif
  Curl_safefree(conn->user);
  Curl_safefree(conn->passwd);
  Curl_safefree(conn->sasl_authzid);
  Curl_safefree(conn->options);
  Curl_safefree(conn->oauth_bearer);
  Curl_safefree(conn->host.rawalloc); /* host name buffer */
  Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
  Curl_safefree(conn->hostname_resolve);
  Curl_safefree(conn->secondaryhostname);
  Curl_safefree(conn->localdev);
  Curl_ssl_conn_config_cleanup(conn);

#ifdef USE_UNIX_SOCKETS
  Curl_safefree(conn->unix_domain_socket);







|
|







579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
  Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
#endif
  Curl_safefree(conn->user);
  Curl_safefree(conn->passwd);
  Curl_safefree(conn->sasl_authzid);
  Curl_safefree(conn->options);
  Curl_safefree(conn->oauth_bearer);
  Curl_safefree(conn->host.rawalloc); /* hostname buffer */
  Curl_safefree(conn->conn_to_host.rawalloc); /* hostname buffer */
  Curl_safefree(conn->hostname_resolve);
  Curl_safefree(conn->secondaryhostname);
  Curl_safefree(conn->localdev);
  Curl_ssl_conn_config_cleanup(conn);

#ifdef USE_UNIX_SOCKETS
  Curl_safefree(conn->unix_domain_socket);
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642

643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
 * killing of a dead old connection.
 *
 * A connection needs an easy handle when closing down. We support this passed
 * in separately since the connection to get closed here is often already
 * disassociated from an easy handle.
 *
 * This function MUST NOT reset state in the Curl_easy struct if that
 * isn't strictly bound to the life-time of *this* particular connection.
 *
 */

void Curl_disconnect(struct Curl_easy *data,
                     struct connectdata *conn, bool dead_connection)
{
  /* there must be a connection to close */
  DEBUGASSERT(conn);

  /* it must be removed from the connection cache */
  DEBUGASSERT(!conn->bundle);

  /* there must be an associated transfer */
  DEBUGASSERT(data);

  /* the transfer must be detached from the connection */
  DEBUGASSERT(!data->conn);

  DEBUGF(infof(data, "Curl_disconnect(conn #%"
         CURL_FORMAT_CURL_OFF_T ", dead=%d)",
         conn->connection_id, dead_connection));

  /*
   * If this connection isn't marked to force-close, leave it open if there
   * are other users of it
   */
  if(CONN_INUSE(conn) && !dead_connection) {
    DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
    return;
  }

  if(conn->dns_entry) {
    Curl_resolv_unlock(data, conn->dns_entry);
    conn->dns_entry = NULL;
  }

  /* Cleanup NTLM connection-related data */
  Curl_http_auth_cleanup_ntlm(conn);

  /* Cleanup NEGOTIATE connection-related data */
  Curl_http_auth_cleanup_negotiate(conn);

  if(conn->connect_only)
    /* treat the connection as dead in CONNECT_ONLY situations */
    dead_connection = TRUE;

  /* temporarily attach the connection to this transfer handle for the
     disconnect and shutdown */
  Curl_attach_connection(data, conn);

  if(conn->handler && conn->handler->disconnect)
    /* This is set if protocol-specific cleanups should be made */
    conn->handler->disconnect(data, conn, dead_connection);

  conn_shutdown(data);

  /* detach it again */
  Curl_detach_connection(data);

  conn_free(data, conn);
}

/*
 * IsMultiplexingPossible()
 *
 * Return a bitmask with the available multiplexing options for the given
 * requested connection.







|
<

<

|














|
|
>

|


|
















|
|

<
<
<
<
<
<
|
<
<
<
<
<
<
<







603
604
605
606
607
608
609
610

611

612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654






655







656
657
658
659
660
661
662
 * killing of a dead old connection.
 *
 * A connection needs an easy handle when closing down. We support this passed
 * in separately since the connection to get closed here is often already
 * disassociated from an easy handle.
 *
 * This function MUST NOT reset state in the Curl_easy struct if that
 * is not strictly bound to the life-time of *this* particular connection.

 */

void Curl_disconnect(struct Curl_easy *data,
                     struct connectdata *conn, bool aborted)
{
  /* there must be a connection to close */
  DEBUGASSERT(conn);

  /* it must be removed from the connection cache */
  DEBUGASSERT(!conn->bundle);

  /* there must be an associated transfer */
  DEBUGASSERT(data);

  /* the transfer must be detached from the connection */
  DEBUGASSERT(!data->conn);

  DEBUGF(infof(data, "Curl_disconnect(conn #%"
         CURL_FORMAT_CURL_OFF_T ", aborted=%d)",
         conn->connection_id, aborted));

  /*
   * If this connection is not marked to force-close, leave it open if there
   * are other users of it
   */
  if(CONN_INUSE(conn) && !aborted) {
    DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
    return;
  }

  if(conn->dns_entry) {
    Curl_resolv_unlock(data, conn->dns_entry);
    conn->dns_entry = NULL;
  }

  /* Cleanup NTLM connection-related data */
  Curl_http_auth_cleanup_ntlm(conn);

  /* Cleanup NEGOTIATE connection-related data */
  Curl_http_auth_cleanup_negotiate(conn);

  if(conn->connect_only)
    /* treat the connection as aborted in CONNECT_ONLY situations */
    aborted = TRUE;







  Curl_conncache_disconnect(data, conn, aborted);







}

/*
 * IsMultiplexingPossible()
 *
 * Return a bitmask with the available multiplexing options for the given
 * requested connection.
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
     so do not use it here! */
  if(Curl_timestrcmp(data->user, needle->user) ||
     Curl_timestrcmp(data->passwd, needle->passwd))
    return FALSE;
  return TRUE;
}
#else
/* disabled, won't get called */
#define proxy_info_matches(x,y) FALSE
#define socks_proxy_info_matches(x,y) FALSE
#endif

/* A connection has to have been idle for a shorter time than 'maxage_conn'
   (the success rate is just too low after this), or created less than
   'maxlifetime_conn' ago, to be subject for reuse. */







|







706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
     so do not use it here! */
  if(Curl_timestrcmp(data->user, needle->user) ||
     Curl_timestrcmp(data->passwd, needle->passwd))
    return FALSE;
  return TRUE;
}
#else
/* disabled, will not get called */
#define proxy_info_matches(x,y) FALSE
#define socks_proxy_info_matches(x,y) FALSE
#endif

/* A connection has to have been idle for a shorter time than 'maxage_conn'
   (the success rate is just too low after this), or created less than
   'maxlifetime_conn' ago, to be subject for reuse. */
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
 *
 * Returns TRUE if the connection was dead and pruned.
 */
static bool prune_if_dead(struct connectdata *conn,
                          struct Curl_easy *data)
{
  if(!CONN_INUSE(conn)) {
    /* The check for a dead socket makes sense only if the connection isn't in
       use */
    bool dead;
    struct curltime now = Curl_now();
    if(conn_maxage(data, conn, now)) {
      /* avoid check if already too old */
      dead = TRUE;
    }







|







757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
 *
 * Returns TRUE if the connection was dead and pruned.
 */
static bool prune_if_dead(struct connectdata *conn,
                          struct Curl_easy *data)
{
  if(!CONN_INUSE(conn)) {
    /* The check for a dead socket makes sense only if the connection is not in
       use */
    bool dead;
    struct curltime now = Curl_now();
    if(conn_maxage(data, conn, now)) {
      /* avoid check if already too old */
      dead = TRUE;
    }
819
820
821
822
823
824
825

826
827
828
829
830
831
832
         * that we expect - in general - no waiting input data. Input
         * waiting might be a TLS Notify Close, for example. We reject
         * that.
         * For protocols where data from other end may arrive at
         * any time (HTTP/2 PING for example), the protocol handler needs
         * to install its own `connection_check` callback.
         */

        dead = TRUE;
      }
      Curl_detach_connection(data);
    }

    if(dead) {
      /* remove connection from cache */







>







794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
         * that we expect - in general - no waiting input data. Input
         * waiting might be a TLS Notify Close, for example. We reject
         * that.
         * For protocols where data from other end may arrive at
         * any time (HTTP/2 PING for example), the protocol handler needs
         * to install its own `connection_check` callback.
         */
        DEBUGF(infof(data, "connection has input pending, not reusable"));
        dead = TRUE;
      }
      Curl_detach_connection(data);
    }

    if(dead) {
      /* remove connection from cache */
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
    struct connectdata *pruned = NULL;
    while(Curl_conncache_foreach(data, data->state.conn_cache, &pruned,
                                 call_prune_if_dead)) {
      /* unlocked */

      /* connection previously removed from cache in prune_if_dead() */

      /* disconnect it */
      Curl_disconnect(data, pruned, TRUE);
    }
    CONNCACHE_LOCK(data);
    data->state.conn_cache->last_cleanup = now;
    CONNCACHE_UNLOCK(data);
  }
}








|
|







852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
    struct connectdata *pruned = NULL;
    while(Curl_conncache_foreach(data, data->state.conn_cache, &pruned,
                                 call_prune_if_dead)) {
      /* unlocked */

      /* connection previously removed from cache in prune_if_dead() */

      /* disconnect it, do not treat as aborted */
      Curl_disconnect(data, pruned, FALSE);
    }
    CONNCACHE_LOCK(data);
    data->state.conn_cache->last_cleanup = now;
    CONNCACHE_UNLOCK(data);
  }
}

957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976

  /* We can only multiplex iff the transfer allows it AND we know
   * that the server we want to talk to supports it as well. */
  canmultiplex = FALSE;
  if(IsMultiplexingPossible(data, needle)) {
    if(bundle->multiuse == BUNDLE_UNKNOWN) {
      if(data->set.pipewait) {
        infof(data, "Server doesn't support multiplex yet, wait");
        *waitpipe = TRUE;
        CONNCACHE_UNLOCK(data);
        return FALSE; /* no reuse */
      }
      infof(data, "Server doesn't support multiplex (yet)");
    }
    else if(bundle->multiuse == BUNDLE_MULTIPLEX) {
      if(Curl_multiplex_wanted(data->multi))
        canmultiplex = TRUE;
      else
        infof(data, "Could multiplex, but not asked to");
    }







|




|







933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952

  /* We can only multiplex iff the transfer allows it AND we know
   * that the server we want to talk to supports it as well. */
  canmultiplex = FALSE;
  if(IsMultiplexingPossible(data, needle)) {
    if(bundle->multiuse == BUNDLE_UNKNOWN) {
      if(data->set.pipewait) {
        infof(data, "Server does not support multiplex yet, wait");
        *waitpipe = TRUE;
        CONNCACHE_UNLOCK(data);
        return FALSE; /* no reuse */
      }
      infof(data, "Server does not support multiplex (yet)");
    }
    else if(bundle->multiuse == BUNDLE_MULTIPLEX) {
      if(Curl_multiplex_wanted(data->multi))
        canmultiplex = TRUE;
      else
        infof(data, "Could multiplex, but not asked to");
    }
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
       && data->set.ipver != check->ip_version) {
      /* skip because the connection is not via the requested IP version */
      continue;
    }

    if(!canmultiplex) {
      if(Curl_resolver_asynch() &&
         /* remote_ip[0] is NUL only if the resolving of the name hasn't
            completed yet and until then we don't reuse this connection */
         !check->primary.remote_ip[0])
        continue;
    }

    if(CONN_INUSE(check)) {
      if(!canmultiplex) {
        /* transfer can't be multiplexed and check is in use */
        continue;
      }
      else {
        /* Could multiplex, but not when check belongs to another multi */
        struct Curl_llist_element *e = check->easyq.head;
        struct Curl_easy *entry = e->ptr;
        if(entry->multi != data->multi)
          continue;
      }
    }

    if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
      foundPendingCandidate = TRUE;
      /* Don't pick a connection that hasn't connected yet */
      infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
            " isn't open enough, can't reuse", check->connection_id);
      continue;
    }

    /* `check` is connected. if it is in use and does not support multiplex,
     * we cannot use it. */
    if(!check->bits.multiplex && CONN_INUSE(check))
      continue;







|
|






|













|

|







973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
       && data->set.ipver != check->ip_version) {
      /* skip because the connection is not via the requested IP version */
      continue;
    }

    if(!canmultiplex) {
      if(Curl_resolver_asynch() &&
         /* remote_ip[0] is NUL only if the resolving of the name has not
            completed yet and until then we do not reuse this connection */
         !check->primary.remote_ip[0])
        continue;
    }

    if(CONN_INUSE(check)) {
      if(!canmultiplex) {
        /* transfer cannot be multiplexed and check is in use */
        continue;
      }
      else {
        /* Could multiplex, but not when check belongs to another multi */
        struct Curl_llist_element *e = check->easyq.head;
        struct Curl_easy *entry = e->ptr;
        if(entry->multi != data->multi)
          continue;
      }
    }

    if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
      foundPendingCandidate = TRUE;
      /* Do not pick a connection that has not connected yet */
      infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
            " is not open enough, cannot reuse", check->connection_id);
      continue;
    }

    /* `check` is connected. if it is in use and does not support multiplex,
     * we cannot use it. */
    if(!check->bits.multiplex && CONN_INUSE(check))
      continue;
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
    }
    else if(check->unix_domain_socket)
      continue;
#endif

    if((needle->handler->flags&PROTOPT_SSL) !=
       (check->handler->flags&PROTOPT_SSL))
      /* don't do mixed SSL and non-SSL connections */
      if(get_protocol_family(check->handler) !=
         needle->handler->protocol || !check->bits.tls_upgraded)
        /* except protocols that have been upgraded via TLS */
        continue;

    if(needle->bits.conn_to_host != check->bits.conn_to_host)
      /* don't mix connections that use the "connect to host" feature and
       * connections that don't use this feature */
      continue;

    if(needle->bits.conn_to_port != check->bits.conn_to_port)
      /* don't mix connections that use the "connect to port" feature and
       * connections that don't use this feature */
      continue;

#ifndef CURL_DISABLE_PROXY
    if(needle->bits.httpproxy != check->bits.httpproxy ||
       needle->bits.socksproxy != check->bits.socksproxy)
      continue;








|






|
|



|
|







1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
    }
    else if(check->unix_domain_socket)
      continue;
#endif

    if((needle->handler->flags&PROTOPT_SSL) !=
       (check->handler->flags&PROTOPT_SSL))
      /* do not do mixed SSL and non-SSL connections */
      if(get_protocol_family(check->handler) !=
         needle->handler->protocol || !check->bits.tls_upgraded)
        /* except protocols that have been upgraded via TLS */
        continue;

    if(needle->bits.conn_to_host != check->bits.conn_to_host)
      /* do not mix connections that use the "connect to host" feature and
       * connections that do not use this feature */
      continue;

    if(needle->bits.conn_to_port != check->bits.conn_to_port)
      /* do not mix connections that use the "connect to port" feature and
       * connections that do not use this feature */
      continue;

#ifndef CURL_DISABLE_PROXY
    if(needle->bits.httpproxy != check->bits.httpproxy ||
       needle->bits.socksproxy != check->bits.socksproxy)
      continue;

1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
        /* https proxies come in different types, http/1.1, h2, ... */
        if(needle->http_proxy.proxytype != check->http_proxy.proxytype)
          continue;
        /* match SSL config to proxy */
        if(!Curl_ssl_conn_config_match(data, check, TRUE)) {
          DEBUGF(infof(data,
            "Connection #%" CURL_FORMAT_CURL_OFF_T
            " has different SSL proxy parameters, can't reuse",
            check->connection_id));
          continue;
        }
        /* the SSL config to the server, which may apply here is checked
         * further below */
      }
    }
#endif

    if(h2upgrade && !check->httpversion && canmultiplex) {
      if(data->set.pipewait) {
        infof(data, "Server upgrade doesn't support multiplex yet, wait");
        *waitpipe = TRUE;
        CONNCACHE_UNLOCK(data);
        return FALSE; /* no reuse */
      }
      infof(data, "Server upgrade cannot be used");
      continue; /* can't be used atm */
    }

    if(needle->localdev || needle->localport) {
      /* If we are bound to a specific local end (IP+port), we must not
         reuse a random other one, although if we didn't ask for a
         particular one we can reuse one that was bound.

         This comparison is a bit rough and too strict. Since the input
         parameters can be specified in numerous ways and still end up the
         same it would take a lot of processing to make it really accurate.
         Instead, this matching will assume that reuses of bound connections
         will most likely also reuse the exact same binding parameters and
         missing out a few edge cases shouldn't hurt anyone very much.
      */
      if((check->localport != needle->localport) ||
         (check->localportrange != needle->localportrange) ||
         (needle->localdev &&
          (!check->localdev || strcmp(check->localdev, needle->localdev))))
        continue;
    }

    if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
      /* This protocol requires credentials per connection,
         so verify that we're using the same name and password as well */
      if(Curl_timestrcmp(needle->user, check->user) ||
         Curl_timestrcmp(needle->passwd, check->passwd) ||
         Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
         Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
        /* one of them was different */
        continue;
      }







|











|





|




|







|










|







1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
        /* https proxies come in different types, http/1.1, h2, ... */
        if(needle->http_proxy.proxytype != check->http_proxy.proxytype)
          continue;
        /* match SSL config to proxy */
        if(!Curl_ssl_conn_config_match(data, check, TRUE)) {
          DEBUGF(infof(data,
            "Connection #%" CURL_FORMAT_CURL_OFF_T
            " has different SSL proxy parameters, cannot reuse",
            check->connection_id));
          continue;
        }
        /* the SSL config to the server, which may apply here is checked
         * further below */
      }
    }
#endif

    if(h2upgrade && !check->httpversion && canmultiplex) {
      if(data->set.pipewait) {
        infof(data, "Server upgrade does not support multiplex yet, wait");
        *waitpipe = TRUE;
        CONNCACHE_UNLOCK(data);
        return FALSE; /* no reuse */
      }
      infof(data, "Server upgrade cannot be used");
      continue; /* cannot be used atm */
    }

    if(needle->localdev || needle->localport) {
      /* If we are bound to a specific local end (IP+port), we must not
         reuse a random other one, although if we did not ask for a
         particular one we can reuse one that was bound.

         This comparison is a bit rough and too strict. Since the input
         parameters can be specified in numerous ways and still end up the
         same it would take a lot of processing to make it really accurate.
         Instead, this matching will assume that reuses of bound connections
         will most likely also reuse the exact same binding parameters and
         missing out a few edge cases should not hurt anyone very much.
      */
      if((check->localport != needle->localport) ||
         (check->localportrange != needle->localportrange) ||
         (needle->localdev &&
          (!check->localdev || strcmp(check->localdev, needle->localdev))))
        continue;
    }

    if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
      /* This protocol requires credentials per connection,
         so verify that we are using the same name and password as well */
      if(Curl_timestrcmp(needle->user, check->user) ||
         Curl_timestrcmp(needle->passwd, check->passwd) ||
         Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
         Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
        /* one of them was different */
        continue;
      }
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
         (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
         (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
        continue;
    }
#endif

    /* Additional match requirements if talking TLS OR
     * not talking to a HTTP proxy OR using a tunnel through a proxy */
    if((needle->handler->flags&PROTOPT_SSL)
#ifndef CURL_DISABLE_PROXY
       || !needle->bits.httpproxy || needle->bits.tunnel_proxy
#endif
      ) {
      /* Talking the same protocol scheme or a TLS upgraded protocol in the
       * same protocol family? */







|







1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
         (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
         (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
        continue;
    }
#endif

    /* Additional match requirements if talking TLS OR
     * not talking to an HTTP proxy OR using a tunnel through a proxy */
    if((needle->handler->flags&PROTOPT_SSL)
#ifndef CURL_DISABLE_PROXY
       || !needle->bits.httpproxy || needle->bits.tunnel_proxy
#endif
      ) {
      /* Talking the same protocol scheme or a TLS upgraded protocol in the
       * same protocol family? */
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
        continue;

      /* If talking TLS, check needs to use the same SSL options. */
      if((needle->handler->flags & PROTOPT_SSL) &&
         !Curl_ssl_conn_config_match(data, check, FALSE)) {
        DEBUGF(infof(data,
                     "Connection #%" CURL_FORMAT_CURL_OFF_T
                     " has different SSL parameters, can't reuse",
                     check->connection_id));
        continue;
      }
    }

#if defined(USE_NTLM)
    /* If we are looking for an HTTP+NTLM connection, check if this is







|







1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
        continue;

      /* If talking TLS, check needs to use the same SSL options. */
      if((needle->handler->flags & PROTOPT_SSL) &&
         !Curl_ssl_conn_config_match(data, check, FALSE)) {
        DEBUGF(infof(data,
                     "Connection #%" CURL_FORMAT_CURL_OFF_T
                     " has different SSL parameters, cannot reuse",
                     check->connection_id));
        continue;
      }
    }

#if defined(USE_NTLM)
    /* If we are looking for an HTTP+NTLM connection, check if this is
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
           that can be reused and "upgraded" to NTLM */
        if(check->http_ntlm_state == NTLMSTATE_NONE)
          chosen = check;
        continue;
      }
    }
    else if(check->http_ntlm_state != NTLMSTATE_NONE) {
      /* Connection is using NTLM auth but we don't want NTLM */
      continue;
    }

#ifndef CURL_DISABLE_PROXY
    /* Same for Proxy NTLM authentication */
    if(wantProxyNTLMhttp) {
      /* Both check->http_proxy.user and check->http_proxy.passwd can be
       * NULL */
      if(!check->http_proxy.user || !check->http_proxy.passwd)
        continue;

      if(Curl_timestrcmp(needle->http_proxy.user,
                         check->http_proxy.user) ||
         Curl_timestrcmp(needle->http_proxy.passwd,
                         check->http_proxy.passwd))
        continue;
    }
    else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
      /* Proxy connection is using NTLM auth but we don't want NTLM */
      continue;
    }
#endif
    if(wantNTLMhttp || wantProxyNTLMhttp) {
      /* Credentials are already checked, we may use this connection.
       * With NTLM being weird as it is, we MUST use a
       * connection where it has already been fully negotiated.







|


















|







1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
           that can be reused and "upgraded" to NTLM */
        if(check->http_ntlm_state == NTLMSTATE_NONE)
          chosen = check;
        continue;
      }
    }
    else if(check->http_ntlm_state != NTLMSTATE_NONE) {
      /* Connection is using NTLM auth but we do not want NTLM */
      continue;
    }

#ifndef CURL_DISABLE_PROXY
    /* Same for Proxy NTLM authentication */
    if(wantProxyNTLMhttp) {
      /* Both check->http_proxy.user and check->http_proxy.passwd can be
       * NULL */
      if(!check->http_proxy.user || !check->http_proxy.passwd)
        continue;

      if(Curl_timestrcmp(needle->http_proxy.user,
                         check->http_proxy.user) ||
         Curl_timestrcmp(needle->http_proxy.passwd,
                         check->http_proxy.passwd))
        continue;
    }
    else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
      /* Proxy connection is using NTLM auth but we do not want NTLM */
      continue;
    }
#endif
    if(wantNTLMhttp || wantProxyNTLMhttp) {
      /* Credentials are already checked, we may use this connection.
       * With NTLM being weird as it is, we MUST use a
       * connection where it has already been fully negotiated.
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
      continue;
    }
#endif

    if(CONN_INUSE(check)) {
      DEBUGASSERT(canmultiplex);
      DEBUGASSERT(check->bits.multiplex);
      /* If multiplexed, make sure we don't go over concurrency limit */
      if(CONN_INUSE(check) >=
              Curl_multi_max_concurrent_streams(data->multi)) {
        infof(data, "client side MAX_CONCURRENT_STREAMS reached"
              ", skip (%zu)", CONN_INUSE(check));
        continue;
      }
      if(CONN_INUSE(check) >=
              Curl_conn_get_max_concurrent(data, check, FIRSTSOCKET)) {
        infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
              CONN_INUSE(check));
        continue;
      }
      /* When not multiplexed, we have a match here! */
      infof(data, "Multiplexed connection found");
    }
    else if(prune_if_dead(check, data)) {
      /* disconnect it */
      Curl_disconnect(data, check, TRUE);
      continue;
    }

    /* We have found a connection. Let's stop searching. */
    chosen = check;
    break;
  } /* loop over connection bundle */







|
















|
|







1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
      continue;
    }
#endif

    if(CONN_INUSE(check)) {
      DEBUGASSERT(canmultiplex);
      DEBUGASSERT(check->bits.multiplex);
      /* If multiplexed, make sure we do not go over concurrency limit */
      if(CONN_INUSE(check) >=
              Curl_multi_max_concurrent_streams(data->multi)) {
        infof(data, "client side MAX_CONCURRENT_STREAMS reached"
              ", skip (%zu)", CONN_INUSE(check));
        continue;
      }
      if(CONN_INUSE(check) >=
              Curl_conn_get_max_concurrent(data, check, FIRSTSOCKET)) {
        infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
              CONN_INUSE(check));
        continue;
      }
      /* When not multiplexed, we have a match here! */
      infof(data, "Multiplexed connection found");
    }
    else if(prune_if_dead(check, data)) {
      /* disconnect it, do not treat as aborted */
      Curl_disconnect(data, check, FALSE);
      continue;
    }

    /* We have found a connection. Let's stop searching. */
    chosen = check;
    break;
  } /* loop over connection bundle */
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
  conn->sockfd = CURL_SOCKET_BAD;
  conn->writesockfd = CURL_SOCKET_BAD;
  conn->connection_id = -1;    /* no ID */
  conn->primary.remote_port = -1; /* unknown at this point */
  conn->remote_port = -1; /* unknown at this point */

  /* Default protocol-independent behavior doesn't support persistent
     connections, so we set this to force-close. Protocols that support
     this need to set this to FALSE in their "curl_do" functions. */
  connclose(conn, "Default to force-close");

  /* Store creation time to help future close decision making */
  conn->created = Curl_now();








|







1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
  conn->sockfd = CURL_SOCKET_BAD;
  conn->writesockfd = CURL_SOCKET_BAD;
  conn->connection_id = -1;    /* no ID */
  conn->primary.remote_port = -1; /* unknown at this point */
  conn->remote_port = -1; /* unknown at this point */

  /* Default protocol-independent behavior does not support persistent
     connections, so we set this to force-close. Protocols that support
     this need to set this to FALSE in their "curl_do" functions. */
  connclose(conn, "Default to force-close");

  /* Store creation time to help future close decision making */
  conn->created = Curl_now();

1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
  if(len && (len <= 7)) {
    const char *s = scheme;
    size_t l = len;
    const struct Curl_handler *h;
    unsigned int c = 978;
    while(l) {
      c <<= 5;
      c += Curl_raw_tolower(*s);
      s++;
      l--;
    }

    h = protocols[c % 67];
    if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len])
      return h;







|







1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
  if(len && (len <= 7)) {
    const char *s = scheme;
    size_t l = len;
    const struct Curl_handler *h;
    unsigned int c = 978;
    while(l) {
      c <<= 5;
      c += (unsigned int)Curl_raw_tolower(*s);
      s++;
      l--;
    }

    h = protocols[c % 67];
    if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len])
      return h;
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
      /* Perform setup complement if some. */
      conn->handler = conn->given = p;
      /* 'port' and 'remote_port' are set in setup_connection_internals() */
      return CURLE_OK;
    }
  }

  /* The protocol was not found in the table, but we don't have to assign it
     to anything since it is already assigned to a dummy-struct in the
     create_conn() function when the connectdata struct is allocated. */
  failf(data, "Protocol \"%s\" %s%s", protostr,
        p ? "disabled" : "not supported",
        data->state.this_is_a_follow ? " (in redirect)":"");

  return CURLE_UNSUPPORTED_PROTOCOL;







|







1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
      /* Perform setup complement if some. */
      conn->handler = conn->given = p;
      /* 'port' and 'remote_port' are set in setup_connection_internals() */
      return CURLE_OK;
    }
  }

  /* The protocol was not found in the table, but we do not have to assign it
     to anything since it is already assigned to a dummy-struct in the
     create_conn() function when the connectdata struct is allocated. */
  failf(data, "Protocol \"%s\" %s%s", protostr,
        p ? "disabled" : "not supported",
        data->state.this_is_a_follow ? " (in redirect)":"");

  return CURLE_UNSUPPORTED_PROTOCOL;
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
      free(data->state.url);
    data->state.url = url;
    data->state.url_alloc = TRUE;
  }

  if(!use_set_uh) {
    char *newurl;
    uc = curl_url_set(uh, CURLUPART_URL, data->state.url,
                      CURLU_GUESS_SCHEME |
                      CURLU_NON_SUPPORT_SCHEME |
                      (data->set.disallow_username_in_url ?
                       CURLU_DISALLOW_USER : 0) |
                      (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
    if(uc) {
      failf(data, "URL rejected: %s", curl_url_strerror(uc));
      return Curl_uc_to_curlcode(uc);
    }

    /* after it was parsed, get the generated normalized version */
    uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);







|
|
|
|
|
|







1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
      free(data->state.url);
    data->state.url = url;
    data->state.url_alloc = TRUE;
  }

  if(!use_set_uh) {
    char *newurl;
    uc = curl_url_set(uh, CURLUPART_URL, data->state.url, (unsigned int)
                      (CURLU_GUESS_SCHEME |
                       CURLU_NON_SUPPORT_SCHEME |
                       (data->set.disallow_username_in_url ?
                        CURLU_DISALLOW_USER : 0) |
                       (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
    if(uc) {
      failf(data, "URL rejected: %s", curl_url_strerror(uc));
      return Curl_uc_to_curlcode(uc);
    }

    /* after it was parsed, get the generated normalized version */
    uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855

  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
  if(uc) {
    if(!strcasecompare("file", data->state.up.scheme))
      return CURLE_OUT_OF_MEMORY;
  }
  else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
    failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN);
    return CURLE_URL_MALFORMAT;
  }
  hostname = data->state.up.hostname;

  if(hostname && hostname[0] == '[') {
    /* This looks like an IPv6 address literal. See if there is an address
       scope. */
    size_t hlen;
    conn->bits.ipv6_ip = TRUE;
    /* cut off the brackets! */
    hostname++;
    hlen = strlen(hostname);
    hostname[hlen - 1] = 0;

    zonefrom_url(uh, data, conn);
  }

  /* make sure the connect struct gets its own copy of the host name */
  conn->host.rawalloc = strdup(hostname ? hostname : "");
  if(!conn->host.rawalloc)
    return CURLE_OUT_OF_MEMORY;
  conn->host.name = conn->host.rawalloc;

  /*************************************************************
   * IDN-convert the hostnames







|

















|







1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831

  uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
  if(uc) {
    if(!strcasecompare("file", data->state.up.scheme))
      return CURLE_OUT_OF_MEMORY;
  }
  else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
    failf(data, "Too long hostname (maximum is %d)", MAX_URL_LEN);
    return CURLE_URL_MALFORMAT;
  }
  hostname = data->state.up.hostname;

  if(hostname && hostname[0] == '[') {
    /* This looks like an IPv6 address literal. See if there is an address
       scope. */
    size_t hlen;
    conn->bits.ipv6_ip = TRUE;
    /* cut off the brackets! */
    hostname++;
    hlen = strlen(hostname);
    hostname[hlen - 1] = 0;

    zonefrom_url(uh, data, conn);
  }

  /* make sure the connect struct gets its own copy of the hostname */
  conn->host.rawalloc = strdup(hostname ? hostname : "");
  if(!conn->host.rawalloc)
    return CURLE_OUT_OF_MEMORY;
  conn->host.name = conn->host.rawalloc;

  /*************************************************************
   * IDN-convert the hostnames
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
#endif

  result = findprotocol(data, conn, data->state.up.scheme);
  if(result)
    return result;

  /*
   * User name and password set with their own options override the
   * credentials possibly set in the URL.
   */
  if(!data->set.str[STRING_PASSWORD]) {
    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
    if(!uc) {
      char *decoded;
      result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,







|







1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
#endif

  result = findprotocol(data, conn, data->state.up.scheme);
  if(result)
    return result;

  /*
   * username and password set with their own options override the
   * credentials possibly set in the URL.
   */
  if(!data->set.str[STRING_PASSWORD]) {
    uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
    if(!uc) {
      char *decoded;
      result = Curl_urldecode(data->state.up.password, 0, &decoded, NULL,
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
        return result;
    }
    else if(uc != CURLUE_NO_PASSWORD)
      return Curl_uc_to_curlcode(uc);
  }

  if(!data->set.str[STRING_USERNAME]) {
    /* we don't use the URL API's URL decoder option here since it rejects
       control codes and we want to allow them for some schemes in the user
       and password fields */
    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
    if(!uc) {
      char *decoded;
      result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
                              conn->handler->flags&PROTOPT_USERPWDCTRL ?







|







1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
        return result;
    }
    else if(uc != CURLUE_NO_PASSWORD)
      return Curl_uc_to_curlcode(uc);
  }

  if(!data->set.str[STRING_USERNAME]) {
    /* we do not use the URL API's URL decoder option here since it rejects
       control codes and we want to allow them for some schemes in the user
       and password fields */
    uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
    if(!uc) {
      char *decoded;
      result = Curl_urldecode(data->state.up.user, 0, &decoded, NULL,
                              conn->handler->flags&PROTOPT_USERPWDCTRL ?
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
#endif

  return CURLE_OK;
}


/*
 * If we're doing a resumed transfer, we need to setup our stuff
 * properly.
 */
static CURLcode setup_range(struct Curl_easy *data)
{
  struct UrlState *s = &data->state;
  s->resume_from = data->set.set_resume_from;
  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {







|







1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
#endif

  return CURLE_OK;
}


/*
 * If we are doing a resumed transfer, we need to setup our stuff
 * properly.
 */
static CURLcode setup_range(struct Curl_easy *data)
{
  struct UrlState *s = &data->state;
  s->resume_from = data->set.set_resume_from;
  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
   *   not be proxied, or an asterisk to override
   *   all proxy variables)
   * all_proxy=http://some.server.dom:port/
   *   (seems to exist for the CERN www lib. Probably
   *   the first to check for.)
   *
   * For compatibility, the all-uppercase versions of these variables are
   * checked if the lowercase versions don't exist.
   */
  char proxy_env[20];
  char *envp = proxy_env;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
  (void)data;
#endif

  msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy", conn->handler->scheme);

  /* read the protocol proxy: */
  proxy = curl_getenv(proxy_env);

  /*
   * We don't try the uppercase version of HTTP_PROXY because of
   * security reasons:
   *
   * When curl is used in a webserver application
   * environment (cgi or php), this environment variable can
   * be controlled by the web server user by setting the
   * http header 'Proxy:' to some value.
   *







|













|







2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
   *   not be proxied, or an asterisk to override
   *   all proxy variables)
   * all_proxy=http://some.server.dom:port/
   *   (seems to exist for the CERN www lib. Probably
   *   the first to check for.)
   *
   * For compatibility, the all-uppercase versions of these variables are
   * checked if the lowercase versions do not exist.
   */
  char proxy_env[20];
  char *envp = proxy_env;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
  (void)data;
#endif

  msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy", conn->handler->scheme);

  /* read the protocol proxy: */
  proxy = curl_getenv(proxy_env);

  /*
   * We do not try the uppercase version of HTTP_PROXY because of
   * security reasons:
   *
   * When curl is used in a webserver application
   * environment (cgi or php), this environment variable can
   * be controlled by the web server user by setting the
   * http header 'Proxy:' to some value.
   *
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147

  return proxy;
}
#endif /* CURL_DISABLE_HTTP */

/*
 * If this is supposed to use a proxy, we need to figure out the proxy
 * host name, so that we can reuse an existing connection
 * that may exist registered to the same proxy host.
 */
static CURLcode parse_proxy(struct Curl_easy *data,
                            struct connectdata *conn, char *proxy,
                            curl_proxytype proxytype)
{
  char *portptr = NULL;







|







2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123

  return proxy;
}
#endif /* CURL_DISABLE_HTTP */

/*
 * If this is supposed to use a proxy, we need to figure out the proxy
 * hostname, so that we can reuse an existing connection
 * that may exist registered to the same proxy host.
 */
static CURLcode parse_proxy(struct Curl_easy *data,
                            struct connectdata *conn, char *proxy,
                            curl_proxytype proxytype)
{
  char *portptr = NULL;
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
  if(port >= 0) {
    proxyinfo->port = port;
    if(conn->primary.remote_port < 0 || sockstype ||
       !conn->socks_proxy.host.rawalloc)
      conn->primary.remote_port = port;
  }

  /* now, clone the proxy host name */
  uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
  if(uc) {
    result = CURLE_OUT_OF_MEMORY;
    goto error;
  }
#ifdef USE_UNIX_SOCKETS
  if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {







|







2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
  if(port >= 0) {
    proxyinfo->port = port;
    if(conn->primary.remote_port < 0 || sockstype ||
       !conn->socks_proxy.host.rawalloc)
      conn->primary.remote_port = port;
  }

  /* now, clone the proxy hostname */
  uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
  if(uc) {
    result = CURLE_OUT_OF_MEMORY;
    goto error;
  }
#ifdef USE_UNIX_SOCKETS
  if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) {
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
                                              struct connectdata *conn)
{
  char *proxy = NULL;
  char *socksproxy = NULL;
  char *no_proxy = NULL;
  CURLcode result = CURLE_OK;
  bool spacesep = FALSE;

  /*************************************************************
   * Extract the user and password from the authentication string
   *************************************************************/
  if(conn->bits.proxy_user_passwd) {
    result = parse_proxy_auth(data, conn);
    if(result)







<







2346
2347
2348
2349
2350
2351
2352

2353
2354
2355
2356
2357
2358
2359
static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
                                              struct connectdata *conn)
{
  char *proxy = NULL;
  char *socksproxy = NULL;
  char *no_proxy = NULL;
  CURLcode result = CURLE_OK;


  /*************************************************************
   * Extract the user and password from the authentication string
   *************************************************************/
  if(conn->bits.proxy_user_passwd) {
    result = parse_proxy_auth(data, conn);
    if(result)
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
    }
    if(no_proxy) {
      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
    }
  }

  if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
                        data->set.str[STRING_NOPROXY] : no_proxy,
                        &spacesep)) {
    Curl_safefree(proxy);
    Curl_safefree(socksproxy);
  }
#ifndef CURL_DISABLE_HTTP
  else if(!proxy && !socksproxy)
    /* if the host is not in the noproxy list, detect proxy. */
    proxy = detect_proxy(data, conn);
#endif /* CURL_DISABLE_HTTP */
  if(spacesep)
    infof(data, "space-separated NOPROXY patterns are deprecated");

  Curl_safefree(no_proxy);

#ifdef USE_UNIX_SOCKETS
  /* For the time being do not mix proxy and unix domain sockets. See #1274 */
  if(proxy && conn->unix_domain_socket) {
    free(proxy);
    proxy = NULL;
  }
#endif

  if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
    free(proxy);  /* Don't bother with an empty proxy string or if the
                     protocol doesn't work with network */
    proxy = NULL;
  }
  if(socksproxy && (!*socksproxy ||
                    (conn->handler->flags & PROTOPT_NONETWORK))) {
    free(socksproxy);  /* Don't bother with an empty socks proxy string or if
                          the protocol doesn't work with network */
    socksproxy = NULL;
  }

  /***********************************************************************
   * If this is supposed to use a proxy, we need to figure out the proxy host
   * name, proxy type and port number, so that we can reuse an existing
   * connection that may exist registered to the same proxy host.







|
<








<
<
<











|
|




|
|







2392
2393
2394
2395
2396
2397
2398
2399

2400
2401
2402
2403
2404
2405
2406
2407



2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
    }
    if(no_proxy) {
      infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
    }
  }

  if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
                        data->set.str[STRING_NOPROXY] : no_proxy)) {

    Curl_safefree(proxy);
    Curl_safefree(socksproxy);
  }
#ifndef CURL_DISABLE_HTTP
  else if(!proxy && !socksproxy)
    /* if the host is not in the noproxy list, detect proxy. */
    proxy = detect_proxy(data, conn);
#endif /* CURL_DISABLE_HTTP */



  Curl_safefree(no_proxy);

#ifdef USE_UNIX_SOCKETS
  /* For the time being do not mix proxy and unix domain sockets. See #1274 */
  if(proxy && conn->unix_domain_socket) {
    free(proxy);
    proxy = NULL;
  }
#endif

  if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
    free(proxy);  /* Do not bother with an empty proxy string or if the
                     protocol does not work with network */
    proxy = NULL;
  }
  if(socksproxy && (!*socksproxy ||
                    (conn->handler->flags & PROTOPT_NONETWORK))) {
    free(socksproxy);  /* Do not bother with an empty socks proxy string or if
                          the protocol does not work with network */
    socksproxy = NULL;
  }

  /***********************************************************************
   * If this is supposed to use a proxy, we need to figure out the proxy host
   * name, proxy type and port number, so that we can reuse an existing
   * connection that may exist registered to the same proxy host.
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
  else {
    conn->bits.socksproxy = FALSE;
    conn->bits.httpproxy = FALSE;
  }
  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;

  if(!conn->bits.proxy) {
    /* we aren't using the proxy after all... */
    conn->bits.proxy = FALSE;
    conn->bits.httpproxy = FALSE;
    conn->bits.socksproxy = FALSE;
    conn->bits.proxy_user_passwd = FALSE;
    conn->bits.tunnel_proxy = FALSE;
    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
       to signal that CURLPROXY_HTTPS is not used for this connection */







|







2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
  else {
    conn->bits.socksproxy = FALSE;
    conn->bits.httpproxy = FALSE;
  }
  conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;

  if(!conn->bits.proxy) {
    /* we are not using the proxy after all... */
    conn->bits.proxy = FALSE;
    conn->bits.httpproxy = FALSE;
    conn->bits.socksproxy = FALSE;
    conn->bits.proxy_user_passwd = FALSE;
    conn->bits.tunnel_proxy = FALSE;
    /* CURLPROXY_HTTPS does not have its own flag in conn->bits, yet we need
       to signal that CURLPROXY_HTTPS is not used for this connection */
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
  return result;
}
#endif /* CURL_DISABLE_PROXY */

/*
 * Curl_parse_login_details()
 *
 * This is used to parse a login string for user name, password and options in
 * the following formats:
 *
 *   user
 *   user:password
 *   user:password;options
 *   user;options
 *   user;options:password







|







2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
  return result;
}
#endif /* CURL_DISABLE_PROXY */

/*
 * Curl_parse_login_details()
 *
 * This is used to parse a login string for username, password and options in
 * the following formats:
 *
 *   user
 *   user:password
 *   user:password;options
 *   user;options
 *   user;options:password
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
  }
  conn->bits.netrc = FALSE;
  if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
    int ret;
    bool url_provided = FALSE;

    if(data->state.aptr.user) {
      /* there was a user name in the URL. Use the URL decoded version */
      userp = &data->state.aptr.user;
      url_provided = TRUE;
    }

    ret = Curl_parsenetrc(conn->host.name,
                          userp, passwdp,
                          data->set.str[STRING_NETRC_FILE]);







|







2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
  }
  conn->bits.netrc = FALSE;
  if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
    int ret;
    bool url_provided = FALSE;

    if(data->state.aptr.user) {
      /* there was a username in the URL. Use the URL decoded version */
      userp = &data->state.aptr.user;
      url_provided = TRUE;
    }

    ret = Curl_parsenetrc(conn->host.name,
                          userp, passwdp,
                          data->set.str[STRING_NETRC_FILE]);
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
    }
  }

  return CURLE_OK;
}

/*
 * Set the login details so they're available in the connection
 */
static CURLcode set_login(struct Curl_easy *data,
                          struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  const char *setuser = CURL_DEFAULT_USER;
  const char *setpasswd = CURL_DEFAULT_PASSWORD;







|







2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
    }
  }

  return CURLE_OK;
}

/*
 * Set the login details so they are available in the connection
 */
static CURLcode set_login(struct Curl_easy *data,
                          struct connectdata *conn)
{
  CURLcode result = CURLE_OK;
  const char *setuser = CURL_DEFAULT_USER;
  const char *setpasswd = CURL_DEFAULT_PASSWORD;
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
    }
    if(*ptr == ']')
      /* yeps, it ended nicely with a bracket as well */
      *ptr++ = '\0';
    else
      infof(data, "Invalid IPv6 address format");
    portptr = ptr;
    /* Note that if this didn't end with a bracket, we still advanced the
     * hostptr first, but I can't see anything wrong with that as no host
     * name nor a numeric can legally start with a bracket.
     */
#else
    failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
    result = CURLE_NOT_BUILT_IN;
    goto error;
#endif
  }

  /* Get port number off server.com:1080 */
  host_portno = strchr(portptr, ':');
  if(host_portno) {
    char *endp = NULL;
    *host_portno = '\0'; /* cut off number from host name */
    host_portno++;
    if(*host_portno) {
      long portparse = strtol(host_portno, &endp, 10);
      if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
        failf(data, "No valid port number in connect to host string (%s)",
              host_portno);
        result = CURLE_SETOPT_OPTION_SYNTAX;
        goto error;
      }
      else
        port = (int)portparse; /* we know it will fit */
    }
  }

  /* now, clone the cleaned host name */
  DEBUGASSERT(hostptr);
  *hostname_result = strdup(hostptr);
  if(!*hostname_result) {
    result = CURLE_OUT_OF_MEMORY;
    goto error;
  }








|
|













|














|







2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
    }
    if(*ptr == ']')
      /* yeps, it ended nicely with a bracket as well */
      *ptr++ = '\0';
    else
      infof(data, "Invalid IPv6 address format");
    portptr = ptr;
    /* Note that if this did not end with a bracket, we still advanced the
     * hostptr first, but I cannot see anything wrong with that as no host
     * name nor a numeric can legally start with a bracket.
     */
#else
    failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
    result = CURLE_NOT_BUILT_IN;
    goto error;
#endif
  }

  /* Get port number off server.com:1080 */
  host_portno = strchr(portptr, ':');
  if(host_portno) {
    char *endp = NULL;
    *host_portno = '\0'; /* cut off number from hostname */
    host_portno++;
    if(*host_portno) {
      long portparse = strtol(host_portno, &endp, 10);
      if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
        failf(data, "No valid port number in connect to host string (%s)",
              host_portno);
        result = CURLE_SETOPT_OPTION_SYNTAX;
        goto error;
      }
      else
        port = (int)portparse; /* we know it will fit */
    }
  }

  /* now, clone the cleaned hostname */
  DEBUGASSERT(hostptr);
  *hostname_result = strdup(hostptr);
  if(!*hostname_result) {
    result = CURLE_OUT_OF_MEMORY;
    goto error;
  }

3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038

    conn_to_host = conn_to_host->next;
  }

#ifndef CURL_DISABLE_ALTSVC
  if(data->asi && !host && (port == -1) &&
     ((conn->handler->protocol == CURLPROTO_HTTPS) ||
#ifdef CURLDEBUG
      /* allow debug builds to circumvent the HTTPS restriction */
      getenv("CURL_ALTSVC_HTTP")
#else
      0
#endif
       )) {
    /* no connect_to match, try alt-svc! */







|







2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009

    conn_to_host = conn_to_host->next;
  }

#ifndef CURL_DISABLE_ALTSVC
  if(data->asi && !host && (port == -1) &&
     ((conn->handler->protocol == CURLPROTO_HTTPS) ||
#ifdef DEBUGBUILD
      /* allow debug builds to circumvent the HTTPS restriction */
      getenv("CURL_ALTSVC_HTTP")
#else
      0
#endif
       )) {
    /* no connect_to match, try alt-svc! */
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
        case ALPN_h2:
          conn->httpversion = 20;
          break;
        case ALPN_h3:
          conn->transport = TRNSPRT_QUIC;
          conn->httpversion = 30;
          break;
        default: /* shouldn't be possible */
          break;
        }
      }
    }
  }
#endif








|







3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
        case ALPN_h2:
          conn->httpversion = 20;
          break;
        case ALPN_h3:
          conn->transport = TRNSPRT_QUIC;
          conn->httpversion = 30;
          break;
        default: /* should not be possible */
          break;
        }
      }
    }
  }
#endif

3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
                               bool *async)
{
  DEBUGASSERT(conn);
  DEBUGASSERT(data);

  /* Resolve the name of the server or proxy */
  if(conn->bits.reuse) {
    /* We're reusing the connection - no need to resolve anything, and
       idnconvert_hostname() was called already in create_conn() for the reuse
       case. */
    *async = FALSE;
    return CURLE_OK;
  }

  return resolve_fresh(data, conn, async);
}

/*
 * Cleanup the connection `temp`, just allocated for `data`, before using the
 * previously `existing` one for `data`.  All relevant info is copied over
 * and `temp` is freed.
 */
static void reuse_conn(struct Curl_easy *data,
                       struct connectdata *temp,
                       struct connectdata *existing)
{
  /* get the user+password information from the temp struct since it may
   * be new for this request even when we reuse an existing connection */
  if(temp->user) {
    /* use the new user name and password though */
    Curl_safefree(existing->user);
    Curl_safefree(existing->passwd);
    existing->user = temp->user;
    existing->passwd = temp->passwd;
    temp->user = NULL;
    temp->passwd = NULL;
  }

#ifndef CURL_DISABLE_PROXY
  existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
  if(existing->bits.proxy_user_passwd) {
    /* use the new proxy user name and proxy password though */
    Curl_safefree(existing->http_proxy.user);
    Curl_safefree(existing->socks_proxy.user);
    Curl_safefree(existing->http_proxy.passwd);
    Curl_safefree(existing->socks_proxy.passwd);
    existing->http_proxy.user = temp->http_proxy.user;
    existing->socks_proxy.user = temp->socks_proxy.user;
    existing->http_proxy.passwd = temp->http_proxy.passwd;







|











|









|











|







3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
                               bool *async)
{
  DEBUGASSERT(conn);
  DEBUGASSERT(data);

  /* Resolve the name of the server or proxy */
  if(conn->bits.reuse) {
    /* We are reusing the connection - no need to resolve anything, and
       idnconvert_hostname() was called already in create_conn() for the reuse
       case. */
    *async = FALSE;
    return CURLE_OK;
  }

  return resolve_fresh(data, conn, async);
}

/*
 * Cleanup the connection `temp`, just allocated for `data`, before using the
 * previously `existing` one for `data`. All relevant info is copied over
 * and `temp` is freed.
 */
static void reuse_conn(struct Curl_easy *data,
                       struct connectdata *temp,
                       struct connectdata *existing)
{
  /* get the user+password information from the temp struct since it may
   * be new for this request even when we reuse an existing connection */
  if(temp->user) {
    /* use the new username and password though */
    Curl_safefree(existing->user);
    Curl_safefree(existing->passwd);
    existing->user = temp->user;
    existing->passwd = temp->passwd;
    temp->user = NULL;
    temp->passwd = NULL;
  }

#ifndef CURL_DISABLE_PROXY
  existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
  if(existing->bits.proxy_user_passwd) {
    /* use the new proxy username and proxy password though */
    Curl_safefree(existing->http_proxy.user);
    Curl_safefree(existing->socks_proxy.user);
    Curl_safefree(existing->http_proxy.passwd);
    Curl_safefree(existing->socks_proxy.passwd);
    existing->http_proxy.user = temp->http_proxy.user;
    existing->socks_proxy.user = temp->socks_proxy.user;
    existing->http_proxy.passwd = temp->http_proxy.passwd;
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
  existing->remote_port = temp->remote_port;
  Curl_safefree(existing->hostname_resolve);

  existing->hostname_resolve = temp->hostname_resolve;
  temp->hostname_resolve = NULL;

  /* reuse init */
  existing->bits.reuse = TRUE; /* yes, we're reusing here */

  conn_free(data, temp);
}

/**
 * create_conn() sets up a new connectdata struct, or reuses an already
 * existing one, and resolves host name.
 *
 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
 * response will be coming asynchronously. If *async is FALSE, the name is
 * already resolved.
 *
 * @param data The sessionhandle pointer
 * @param in_connect is set to the next connection data pointer







|

|




|







3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
  existing->remote_port = temp->remote_port;
  Curl_safefree(existing->hostname_resolve);

  existing->hostname_resolve = temp->hostname_resolve;
  temp->hostname_resolve = NULL;

  /* reuse init */
  existing->bits.reuse = TRUE; /* yes, we are reusing here */

  Curl_conn_free(data, temp);
}

/**
 * create_conn() sets up a new connectdata struct, or reuses an already
 * existing one, and resolves hostname.
 *
 * if this function returns CURLE_OK and *async is set to TRUE, the resolve
 * response will be coming asynchronously. If *async is FALSE, the name is
 * already resolved.
 *
 * @param data The sessionhandle pointer
 * @param in_connect is set to the next connection data pointer
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
   * we figured out what/if proxy to use.
   *************************************************************/
  result = setup_connection_internals(data, conn);
  if(result)
    goto out;

  /***********************************************************************
   * file: is a special case in that it doesn't need a network connection
   ***********************************************************************/
#ifndef CURL_DISABLE_FILE
  if(conn->handler->flags & PROTOPT_NONETWORK) {
    bool done;
    /* this is supposed to be the connect function so we better at least check
       that the file is present here! */
    DEBUGASSERT(conn->handler->connect_it);
    Curl_persistconninfo(data, conn, NULL);
    result = conn->handler->connect_it(data, &done);

    /* Setup a "faked" transfer that'll do nothing */
    if(!result) {
      Curl_attach_connection(data, conn);
      result = Curl_conncache_add_conn(data);
      if(result)
        goto out;

      /*
       * Setup whatever necessary for a resumed transfer
       */
      result = setup_range(data);
      if(result) {
        DEBUGASSERT(conn->handler->done);
        /* we ignore the return code for the protocol-specific DONE */
        (void)conn->handler->done(data, result, FALSE);
        goto out;
      }
      Curl_xfer_setup(data, -1, -1, FALSE, -1);
    }

    /* since we skip do_init() */
    Curl_init_do(data, conn);

    goto out;
  }







|










|
















|







3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
   * we figured out what/if proxy to use.
   *************************************************************/
  result = setup_connection_internals(data, conn);
  if(result)
    goto out;

  /***********************************************************************
   * file: is a special case in that it does not need a network connection
   ***********************************************************************/
#ifndef CURL_DISABLE_FILE
  if(conn->handler->flags & PROTOPT_NONETWORK) {
    bool done;
    /* this is supposed to be the connect function so we better at least check
       that the file is present here! */
    DEBUGASSERT(conn->handler->connect_it);
    Curl_persistconninfo(data, conn, NULL);
    result = conn->handler->connect_it(data, &done);

    /* Setup a "faked" transfer that will do nothing */
    if(!result) {
      Curl_attach_connection(data, conn);
      result = Curl_conncache_add_conn(data);
      if(result)
        goto out;

      /*
       * Setup whatever necessary for a resumed transfer
       */
      result = setup_range(data);
      if(result) {
        DEBUGASSERT(conn->handler->done);
        /* we ignore the return code for the protocol-specific DONE */
        (void)conn->handler->done(data, result, FALSE);
        goto out;
      }
      Curl_xfer_setup_nop(data);
    }

    /* since we skip do_init() */
    Curl_init_do(data, conn);

    goto out;
  }
3663
3664
3665
3666
3667
3668
3669
3670






3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
       (Curl_conncache_size(data) >= max_total_connections)) {
      struct connectdata *conn_candidate;

      /* The cache is full. Let's see if we can kill a connection. */
      conn_candidate = Curl_conncache_extract_oldest(data);
      if(conn_candidate)
        Curl_disconnect(data, conn_candidate, FALSE);
      else {






        infof(data, "No connections available in cache");
        connections_available = FALSE;
      }
    }

    if(!connections_available) {
      infof(data, "No connections available.");

      conn_free(data, conn);
      *in_connect = NULL;

      result = CURLE_NO_CONNECTION_AVAILABLE;
      goto out;
    }
    else {
      /*







|
>
>
>
>
>
>
|
|
|





|







3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
       (Curl_conncache_size(data) >= max_total_connections)) {
      struct connectdata *conn_candidate;

      /* The cache is full. Let's see if we can kill a connection. */
      conn_candidate = Curl_conncache_extract_oldest(data);
      if(conn_candidate)
        Curl_disconnect(data, conn_candidate, FALSE);
      else
#ifndef CURL_DISABLE_DOH
        if(data->set.dohfor)
          infof(data, "Allowing DoH to override max connection limit");
        else
#endif
        {
          infof(data, "No connections available in cache");
          connections_available = FALSE;
        }
    }

    if(!connections_available) {
      infof(data, "No connections available.");

      Curl_conn_free(data, conn);
      *in_connect = NULL;

      result = CURLE_NO_CONNECTION_AVAILABLE;
      goto out;
    }
    else {
      /*
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
      Curl_attach_connection(data, conn);
      result = Curl_conncache_add_conn(data);
      if(result)
        goto out;
    }

#if defined(USE_NTLM)
    /* If NTLM is requested in a part of this connection, make sure we don't
       assume the state is fine as this is a fresh connection and NTLM is
       connection based. */
    if((data->state.authhost.picked & CURLAUTH_NTLM) &&
       data->state.authhost.done) {
      infof(data, "NTLM picked AND auth done set, clear picked");
      data->state.authhost.picked = CURLAUTH_NONE;
      data->state.authhost.done = FALSE;







|







3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
      Curl_attach_connection(data, conn);
      result = Curl_conncache_add_conn(data);
      if(result)
        goto out;
    }

#if defined(USE_NTLM)
    /* If NTLM is requested in a part of this connection, make sure we do not
       assume the state is fine as this is a fresh connection and NTLM is
       connection based. */
    if((data->state.authhost.picked & CURLAUTH_NTLM) &&
       data->state.authhost.done) {
      infof(data, "NTLM picked AND auth done set, clear picked");
      data->state.authhost.picked = CURLAUTH_NONE;
      data->state.authhost.done = FALSE;
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
    *protocol_done = TRUE;
    return result;
  }

#ifndef CURL_DISABLE_PROXY
  /* set proxy_connect_closed to false unconditionally already here since it
     is used strictly to provide extra information to a parent function in the
     case of proxy CONNECT failures and we must make sure we don't have it
     lingering set from a previous invoke */
  conn->bits.proxy_connect_closed = FALSE;
#endif

#ifdef CURL_DO_LINEEND_CONV
  data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
#endif /* CURL_DO_LINEEND_CONV */







|







3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
    *protocol_done = TRUE;
    return result;
  }

#ifndef CURL_DISABLE_PROXY
  /* set proxy_connect_closed to false unconditionally already here since it
     is used strictly to provide extra information to a parent function in the
     case of proxy CONNECT failures and we must make sure we do not have it
     lingering set from a previous invoke */
  conn->bits.proxy_connect_closed = FALSE;
#endif

#ifdef CURL_DO_LINEEND_CONV
  data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
#endif /* CURL_DO_LINEEND_CONV */
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
  result = create_conn(data, &conn, asyncp);

  if(!result) {
    if(CONN_INUSE(conn) > 1)
      /* multiplexed */
      *protocol_done = TRUE;
    else if(!*asyncp) {
      /* DNS resolution is done: that's either because this is a reused
         connection, in which case DNS was unnecessary, or because DNS
         really did finish already (synch resolver/fast async resolve) */
      result = Curl_setup_conn(data, protocol_done);
    }
  }

  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
    return result;
  }
  else if(result && conn) {
    /* We're not allowed to return failure with memory left allocated in the
       connectdata struct, free those here */
    Curl_detach_connection(data);
    Curl_conncache_remove_conn(data, conn, TRUE);
    Curl_disconnect(data, conn, TRUE);
  }

  return result;







|










|







3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
  result = create_conn(data, &conn, asyncp);

  if(!result) {
    if(CONN_INUSE(conn) > 1)
      /* multiplexed */
      *protocol_done = TRUE;
    else if(!*asyncp) {
      /* DNS resolution is done: that is either because this is a reused
         connection, in which case DNS was unnecessary, or because DNS
         really did finish already (synch resolver/fast async resolve) */
      result = Curl_setup_conn(data, protocol_done);
    }
  }

  if(result == CURLE_NO_CONNECTION_AVAILABLE) {
    return result;
  }
  else if(result && conn) {
    /* We are not allowed to return failure with memory left allocated in the
       connectdata struct, free those here */
    Curl_detach_connection(data);
    Curl_conncache_remove_conn(data, conn, TRUE);
    Curl_disconnect(data, conn, TRUE);
  }

  return result;
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861

CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
  /* if this is a pushed stream, we need this: */
  CURLcode result;

  if(conn) {
    conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
                                   use */
    /* if the protocol used doesn't support wildcards, switch it off */
    if(data->state.wildcardmatch &&
       !(conn->handler->flags & PROTOPT_WILDCARD))
      data->state.wildcardmatch = FALSE;
  }

  data->state.done = FALSE; /* *_done() is not called yet */








|

|







3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838

CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
  /* if this is a pushed stream, we need this: */
  CURLcode result;

  if(conn) {
    conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
                                   use */
    /* if the protocol used does not support wildcards, switch it off */
    if(data->state.wildcardmatch &&
       !(conn->handler->flags & PROTOPT_WILDCARD))
      data->state.wildcardmatch = FALSE;
  }

  data->state.done = FALSE; /* *_done() is not called yet */

Changes to jni/curl/lib/url.h.
34
35
36
37
38
39
40
41
42
43

44
45
46
47
48
49
50
CURLcode Curl_init_userdefined(struct Curl_easy *data);

void Curl_freeset(struct Curl_easy *data);
CURLcode Curl_uc_to_curlcode(CURLUcode uc);
CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
void Curl_disconnect(struct Curl_easy *data,
                     struct connectdata *, bool dead_connection);
CURLcode Curl_setup_conn(struct Curl_easy *data,
                         bool *protocol_done);

CURLcode Curl_parse_login_details(const char *login, const size_t len,
                                  char **userptr, char **passwdptr,
                                  char **optionsptr);

/* Get protocol handler for a URI scheme
 * @param scheme URI scheme, case-insensitive
 * @return NULL of handler not found







|


>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
CURLcode Curl_init_userdefined(struct Curl_easy *data);

void Curl_freeset(struct Curl_easy *data);
CURLcode Curl_uc_to_curlcode(CURLUcode uc);
CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
void Curl_disconnect(struct Curl_easy *data,
                     struct connectdata *, bool aborted);
CURLcode Curl_setup_conn(struct Curl_easy *data,
                         bool *protocol_done);
void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn);
CURLcode Curl_parse_login_details(const char *login, const size_t len,
                                  char **userptr, char **passwdptr,
                                  char **optionsptr);

/* Get protocol handler for a URI scheme
 * @param scheme URI scheme, case-insensitive
 * @return NULL of handler not found
Changes to jni/curl/lib/urlapi-int.h.
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "curl_setup.h"

size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
                            bool guess_scheme);

CURLUcode Curl_url_set_authority(CURLU *u, const char *authority);

#ifdef DEBUGBUILD
CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
                          bool has_scheme);
#endif

#endif /* HEADER_CURL_URLAPI_INT_H */







|
|
|



26
27
28
29
30
31
32
33
34
35
36
37
38
#include "curl_setup.h"

size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
                            bool guess_scheme);

CURLUcode Curl_url_set_authority(CURLU *u, const char *authority);

#ifdef UNITTESTS
UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
                                   bool has_scheme);
#endif

#endif /* HEADER_CURL_URLAPI_INT_H */
Changes to jni/curl/lib/urlapi.c.
78
79
80
81
82
83
84

85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  char *port;
  char *path;
  char *query;
  char *fragment;
  unsigned short portnum; /* the numerical version (if 'port' is set) */
  BIT(query_present);    /* to support blank */
  BIT(fragment_present); /* to support blank */

};

#define DEFAULT_SCHEME "https"

static void free_urlhandle(struct Curl_URL *u)
{
  free(u->scheme);
  free(u->user);
  free(u->password);
  free(u->options);
  free(u->host);
  free(u->zoneid);
  free(u->port);
  free(u->path);
  free(u->query);
  free(u->fragment);
}

/*
 * Find the separator at the end of the host name, or the '?' in cases like
 * http://www.example.com?id=2380
 */
static const char *find_host_sep(const char *url)
{
  const char *sep;
  const char *query;








>



















|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  char *port;
  char *path;
  char *query;
  char *fragment;
  unsigned short portnum; /* the numerical version (if 'port' is set) */
  BIT(query_present);    /* to support blank */
  BIT(fragment_present); /* to support blank */
  BIT(guessed_scheme);   /* when a URL without scheme is parsed */
};

#define DEFAULT_SCHEME "https"

static void free_urlhandle(struct Curl_URL *u)
{
  free(u->scheme);
  free(u->user);
  free(u->password);
  free(u->options);
  free(u->host);
  free(u->zoneid);
  free(u->port);
  free(u->path);
  free(u->query);
  free(u->fragment);
}

/*
 * Find the separator at the end of the hostname, or the '?' in cases like
 * http://www.example.com?id=2380
 */
static const char *find_host_sep(const char *url)
{
  const char *sep;
  const char *query;

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
 */
#define urlchar_needs_escaping(c) (!(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c)))

static const char hexdigits[] = "0123456789abcdef";
/* urlencode_str() writes data into an output dynbuf and URL-encodes the
 * spaces in the source URL accordingly.
 *
 * URL encoding should be skipped for host names, otherwise IDN resolution
 * will fail.
 */
static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
                               size_t len, bool relative,
                               bool query)
{
  /* we must add this with whitespace-replacing */







|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
 */
#define urlchar_needs_escaping(c) (!(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c)))

static const char hexdigits[] = "0123456789abcdef";
/* urlencode_str() writes data into an output dynbuf and URL-encodes the
 * spaces in the source URL accordingly.
 *
 * URL encoding should be skipped for hostnames, otherwise IDN resolution
 * will fail.
 */
static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
                               size_t len, bool relative,
                               bool query)
{
  /* we must add this with whitespace-replacing */
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
 *
 * If 'guess_scheme' is TRUE, it means the URL might be provided without
 * scheme.
 */
size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
                            bool guess_scheme)
{
  int i = 0;
  DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN));
  (void)buflen; /* only used in debug-builds */
  if(buf)
    buf[0] = 0; /* always leave a defined value in buf */
#ifdef _WIN32
  if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url))
    return 0;







|







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
 *
 * If 'guess_scheme' is TRUE, it means the URL might be provided without
 * scheme.
 */
size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
                            bool guess_scheme)
{
  size_t i = 0;
  DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN));
  (void)buflen; /* only used in debug-builds */
  if(buf)
    buf[0] = 0; /* always leave a defined value in buf */
#ifdef _WIN32
  if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url))
    return 0;
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
      else {
        break;
      }
    }
  if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) {
    /* If this does not guess scheme, the scheme always ends with the colon so
       that this also detects data: URLs etc. In guessing mode, data: could
       be the host name "data" with a specified port number. */

    /* the length of the scheme is the name part only */
    size_t len = i;
    if(buf) {
      Curl_strntolower(buf, url, i);
      buf[i] = 0;
    }







|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
      else {
        break;
      }
    }
  if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) {
    /* If this does not guess scheme, the scheme always ends with the colon so
       that this also detects data: URLs etc. In guessing mode, data: could
       be the hostname "data" with a specified port number. */

    /* the length of the scheme is the name part only */
    size_t len = i;
    if(buf) {
      Curl_strntolower(buf, url, i);
      buf[i] = 0;
    }
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  bool host_changed = FALSE;
  const char *useurl = relurl;
  CURLcode result = CURLE_OK;
  CURLUcode uc;
  bool skip_slash = FALSE;
  *newurl = NULL;

  /* protsep points to the start of the host name */
  protsep = strstr(base, "//");
  if(!protsep)
    protsep = base;
  else
    protsep += 2; /* pass the slashes */

  if('/' != relurl[0]) {
    int level = 0;

    /* First we need to find out if there's a ?-letter in the URL,
       and cut it and the right-side of that off */
    pathsep = strchr(protsep, '?');
    if(pathsep)
      *pathsep = 0;

    /* we have a relative path to append to the last slash if there's one
       available, or the new URL is just a query string (starts with a '?') or
       a fragment (starts with '#') we append the new one at the end of the
       current URL */
    if((useurl[0] != '?') && (useurl[0] != '#')) {
      pathsep = strrchr(protsep, '/');
      if(pathsep)
        *pathsep = 0;

      /* Check if there's any slash after the host name, and if so, remember
         that position instead */
      pathsep = strchr(protsep, '/');
      if(pathsep)
        protsep = pathsep + 1;
      else
        protsep = NULL;








|









|





|








|







264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  bool host_changed = FALSE;
  const char *useurl = relurl;
  CURLcode result = CURLE_OK;
  CURLUcode uc;
  bool skip_slash = FALSE;
  *newurl = NULL;

  /* protsep points to the start of the hostname */
  protsep = strstr(base, "//");
  if(!protsep)
    protsep = base;
  else
    protsep += 2; /* pass the slashes */

  if('/' != relurl[0]) {
    int level = 0;

    /* First we need to find out if there is a ?-letter in the URL,
       and cut it and the right-side of that off */
    pathsep = strchr(protsep, '?');
    if(pathsep)
      *pathsep = 0;

    /* we have a relative path to append to the last slash if there is one
       available, or the new URL is just a query string (starts with a '?') or
       a fragment (starts with '#') we append the new one at the end of the
       current URL */
    if((useurl[0] != '?') && (useurl[0] != '#')) {
      pathsep = strrchr(protsep, '/');
      if(pathsep)
        *pathsep = 0;

      /* Check if there is any slash after the hostname, and if so, remember
         that position instead */
      pathsep = strchr(protsep, '/');
      if(pathsep)
        protsep = pathsep + 1;
      else
        protsep = NULL;

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
    else {
      /* cut off the original URL from the first slash, or deal with URLs
         without slash */
      pathsep = strchr(protsep, '/');
      if(pathsep) {
        /* When people use badly formatted URLs, such as
           "http://www.example.com?dir=/home/daniel" we must not use the first
           slash, if there's a ?-letter before it! */
        char *sep = strchr(protsep, '?');
        if(sep && (sep < pathsep))
          pathsep = sep;
        *pathsep = 0;
      }
      else {
        /* There was no slash. Now, since we might be operating on a badly
           formatted URL, such as "http://www.example.com?id=2380" which
           doesn't use a slash separator as it is supposed to, we need to check
           for a ?-letter as well! */
        pathsep = strchr(protsep, '?');
        if(pathsep)
          *pathsep = 0;
      }
    }
  }

  Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH);

  /* copy over the root url part */
  result = Curl_dyn_add(&newest, base);
  if(result)
    return result;

  /* check if we need to append a slash */
  if(('/' == useurl[0]) || (protsep && !*protsep) || skip_slash)
    ;







|







|
|










|







344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
    else {
      /* cut off the original URL from the first slash, or deal with URLs
         without slash */
      pathsep = strchr(protsep, '/');
      if(pathsep) {
        /* When people use badly formatted URLs, such as
           "http://www.example.com?dir=/home/daniel" we must not use the first
           slash, if there is a ?-letter before it! */
        char *sep = strchr(protsep, '?');
        if(sep && (sep < pathsep))
          pathsep = sep;
        *pathsep = 0;
      }
      else {
        /* There was no slash. Now, since we might be operating on a badly
           formatted URL, such as "http://www.example.com?id=2380" which does
           not use a slash separator as it is supposed to, we need to check
           for a ?-letter as well! */
        pathsep = strchr(protsep, '?');
        if(pathsep)
          *pathsep = 0;
      }
    }
  }

  Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH);

  /* copy over the root URL part */
  result = Curl_dyn_add(&newest, base);
  if(result)
    return result;

  /* check if we need to append a slash */
  if(('/' == useurl[0]) || (protsep && !*protsep) || skip_slash)
    ;
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  *urllen = n;
  return CURLUE_OK;
}

/*
 * parse_hostname_login()
 *
 * Parse the login details (user name, password and options) from the URL and
 * strip them out of the host name
 *
 */
static CURLUcode parse_hostname_login(struct Curl_URL *u,
                                      const char *login,
                                      size_t len,
                                      unsigned int flags,
                                      size_t *offset) /* to the host name */
{
  CURLUcode result = CURLUE_OK;
  CURLcode ccode;
  char *userp = NULL;
  char *passwdp = NULL;
  char *optionsp = NULL;
  const struct Curl_handler *h = NULL;







|
|






|







417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  *urllen = n;
  return CURLUE_OK;
}

/*
 * parse_hostname_login()
 *
 * Parse the login details (username, password and options) from the URL and
 * strip them out of the hostname
 *
 */
static CURLUcode parse_hostname_login(struct Curl_URL *u,
                                      const char *login,
                                      size_t len,
                                      unsigned int flags,
                                      size_t *offset) /* to the hostname */
{
  CURLUcode result = CURLUE_OK;
  CURLcode ccode;
  char *userp = NULL;
  char *passwdp = NULL;
  char *optionsp = NULL;
  const struct Curl_handler *h = NULL;
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  if(ccode) {
    result = CURLUE_BAD_LOGIN;
    goto out;
  }

  if(userp) {
    if(flags & CURLU_DISALLOW_USER) {
      /* Option DISALLOW_USER is set and url contains username. */
      result = CURLUE_USER_NOT_ALLOWED;
      goto out;
    }
    free(u->user);
    u->user = userp;
  }

  if(passwdp) {
    free(u->password);
    u->password = passwdp;
  }

  if(optionsp) {
    free(u->options);
    u->options = optionsp;
  }

  /* the host name starts at this offset */
  *offset = ptr - login;
  return CURLUE_OK;

out:

  free(userp);
  free(passwdp);







|

















|







472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
  if(ccode) {
    result = CURLUE_BAD_LOGIN;
    goto out;
  }

  if(userp) {
    if(flags & CURLU_DISALLOW_USER) {
      /* Option DISALLOW_USER is set and URL contains username. */
      result = CURLUE_USER_NOT_ALLOWED;
      goto out;
    }
    free(u->user);
    u->user = userp;
  }

  if(passwdp) {
    free(u->password);
    u->password = passwdp;
  }

  if(optionsp) {
    free(u->options);
    u->options = optionsp;
  }

  /* the hostname starts at this offset */
  *offset = ptr - login;
  return CURLUE_OK;

out:

  free(userp);
  free(passwdp);
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
    portptr = strchr(hostname, ':');

  if(portptr) {
    char *rest = NULL;
    unsigned long port;
    size_t keep = portptr - hostname;

    /* Browser behavior adaptation. If there's a colon with no digits after,
       just cut off the name there which makes us ignore the colon and just
       use the default port. Firefox, Chrome and Safari all do that.

       Don't do it if the URL has no scheme, to make something that looks like
       a scheme not work!
    */
    Curl_dyn_setlen(host, keep);
    portptr++;
    if(!*portptr)
      return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER;








|



|







535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
    portptr = strchr(hostname, ':');

  if(portptr) {
    char *rest = NULL;
    unsigned long port;
    size_t keep = portptr - hostname;

    /* Browser behavior adaptation. If there is a colon with no digits after,
       just cut off the name there which makes us ignore the colon and just
       use the default port. Firefox, Chrome and Safari all do that.

       Do not do it if the URL has no scheme, to make something that looks like
       a scheme not work!
    */
    Curl_dyn_setlen(host, keep);
    portptr++;
    if(!*portptr)
      return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER;

587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  if(hlen != len) {
    hlen = len;
    if(hostname[len] == '%') {
      /* this could now be '%[zone id]' */
      char zoneid[16];
      int i = 0;
      char *h = &hostname[len + 1];
      /* pass '25' if present and is a url encoded percent sign */
      if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']'))
        h += 2;
      while(*h && (*h != ']') && (i < 15))
        zoneid[i++] = *h++;
      if(!i || (']' != *h))
        return CURLUE_BAD_IPV6;
      zoneid[i] = 0;







|







588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  if(hlen != len) {
    hlen = len;
    if(hostname[len] == '%') {
      /* this could now be '%[zone id]' */
      char zoneid[16];
      int i = 0;
      char *h = &hostname[len + 1];
      /* pass '25' if present and is a URL encoded percent sign */
      if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']'))
        h += 2;
      while(*h && (*h != ']') && (i < 15))
        zoneid[i++] = *h++;
      if(!i || (']' != *h))
        return CURLUE_BAD_IPV6;
      zoneid[i] = 0;
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
 * Output the "normalized" version of that input string in plain quad decimal
 * integers.
 *
 * Returns the host type.
 */

#define HOST_ERROR   -1 /* out of memory */
#define HOST_BAD     -2 /* bad IPv4 address */

#define HOST_NAME    1
#define HOST_IPV4    2
#define HOST_IPV6    3

static int ipv4_normalize(struct dynbuf *host)
{







<







661
662
663
664
665
666
667

668
669
670
671
672
673
674
 * Output the "normalized" version of that input string in plain quad decimal
 * integers.
 *
 * Returns the host type.
 */

#define HOST_ERROR   -1 /* out of memory */


#define HOST_NAME    1
#define HOST_IPV4    2
#define HOST_IPV6    3

static int ipv4_normalize(struct dynbuf *host)
{
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
    return HOST_IPV6;

  errno = 0; /* for strtoul */
  while(!done) {
    char *endp = NULL;
    unsigned long l;
    if(!ISDIGIT(*c))
      /* most importantly this doesn't allow a leading plus or minus */
      return HOST_NAME;
    l = strtoul(c, &endp, 0);
    if(errno)
      return HOST_NAME;
#if SIZEOF_LONG > 4
    /* a value larger than 32 bits */
    if(l > UINT_MAX)







|







682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
    return HOST_IPV6;

  errno = 0; /* for strtoul */
  while(!done) {
    char *endp = NULL;
    unsigned long l;
    if(!ISDIGIT(*c))
      /* most importantly this does not allow a leading plus or minus */
      return HOST_NAME;
    l = strtoul(c, &endp, 0);
    if(errno)
      return HOST_NAME;
#if SIZEOF_LONG > 4
    /* a value larger than 32 bits */
    if(l > UINT_MAX)
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
                                 bool has_scheme)
{
  size_t offset;
  CURLUcode uc;
  CURLcode result;

  /*
   * Parse the login details and strip them out of the host name.
   */
  uc = parse_hostname_login(u, auth, authlen, flags, &offset);
  if(uc)
    goto out;

  result = Curl_dyn_addn(host, auth + offset, authlen - offset);
  if(result) {







|







798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
                                 bool has_scheme)
{
  size_t offset;
  CURLUcode uc;
  CURLcode result;

  /*
   * Parse the login details and strip them out of the hostname.
   */
  uc = parse_hostname_login(u, auth, authlen, flags, &offset);
  if(uc)
    goto out;

  result = Curl_dyn_addn(host, auth + offset, authlen - offset);
  if(result) {
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
    uc = urldecode_host(host);
    if(!uc)
      uc = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
    break;
  case HOST_ERROR:
    uc = CURLUE_OUT_OF_MEMORY;
    break;
  case HOST_BAD:
  default:
    uc = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */
    break;
  }

out:
  return uc;







<







831
832
833
834
835
836
837

838
839
840
841
842
843
844
    uc = urldecode_host(host);
    if(!uc)
      uc = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
    break;
  case HOST_ERROR:
    uc = CURLUE_OUT_OF_MEMORY;
    break;

  default:
    uc = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */
    break;
  }

out:
  return uc;
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953

  *out = 0; /* null-terminates, for inputs like "./" */
  outptr = out;

  do {
    bool dotdot = TRUE;
    if(*input == '.') {
      /*  A.  If the input buffer begins with a prefix of "../" or "./", then
          remove that prefix from the input buffer; otherwise, */

      if(!strncmp("./", input, 2)) {
        input += 2;
        clen -= 2;
      }
      else if(!strncmp("../", input, 3)) {
        input += 3;
        clen -= 3;
      }
      /*  D.  if the input buffer consists only of "." or "..", then remove
          that from the input buffer; otherwise, */

      else if(!strcmp(".", input) || !strcmp("..", input) ||
              !strncmp(".?", input, 2) || !strncmp("..?", input, 3)) {
        *out = 0;
        break;
      }
      else
        dotdot = FALSE;
    }
    else if(*input == '/') {
      /*  B.  if the input buffer begins with a prefix of "/./" or "/.", where
          "."  is a complete path segment, then replace that prefix with "/" in
          the input buffer; otherwise, */
      if(!strncmp("/./", input, 3)) {
        input += 2;
        clen -= 2;
      }
      else if(!strcmp("/.", input) || !strncmp("/.?", input, 3)) {
        *outptr++ = '/';
        *outptr = 0;
        break;
      }

      /*  C.  if the input buffer begins with a prefix of "/../" or "/..",
          where ".." is a complete path segment, then replace that prefix with
          "/" in the input buffer and remove the last segment and its
          preceding "/" (if any) from the output buffer; otherwise, */

      else if(!strncmp("/../", input, 4)) {
        input += 3;
        clen -= 3;







|










|











|












|







902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952

  *out = 0; /* null-terminates, for inputs like "./" */
  outptr = out;

  do {
    bool dotdot = TRUE;
    if(*input == '.') {
      /*  A. If the input buffer begins with a prefix of "../" or "./", then
          remove that prefix from the input buffer; otherwise, */

      if(!strncmp("./", input, 2)) {
        input += 2;
        clen -= 2;
      }
      else if(!strncmp("../", input, 3)) {
        input += 3;
        clen -= 3;
      }
      /*  D. if the input buffer consists only of "." or "..", then remove
          that from the input buffer; otherwise, */

      else if(!strcmp(".", input) || !strcmp("..", input) ||
              !strncmp(".?", input, 2) || !strncmp("..?", input, 3)) {
        *out = 0;
        break;
      }
      else
        dotdot = FALSE;
    }
    else if(*input == '/') {
      /*  B. if the input buffer begins with a prefix of "/./" or "/.", where
          "."  is a complete path segment, then replace that prefix with "/" in
          the input buffer; otherwise, */
      if(!strncmp("/./", input, 3)) {
        input += 2;
        clen -= 2;
      }
      else if(!strcmp("/.", input) || !strncmp("/.?", input, 3)) {
        *outptr++ = '/';
        *outptr = 0;
        break;
      }

      /*  C. if the input buffer begins with a prefix of "/../" or "/..",
          where ".." is a complete path segment, then replace that prefix with
          "/" in the input buffer and remove the last segment and its
          preceding "/" (if any) from the output buffer; otherwise, */

      else if(!strncmp("/../", input, 4)) {
        input += 3;
        clen -= 3;
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
      else
        dotdot = FALSE;
    }
    else
      dotdot = FALSE;

    if(!dotdot) {
      /*  E.  move the first path segment in the input buffer to the end of
          the output buffer, including the initial "/" character (if any) and
          any subsequent characters up to, but not including, the next "/"
          character or the end of the input buffer. */

      do {
        *outptr++ = *input++;
        clen--;







|







972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
      else
        dotdot = FALSE;
    }
    else
      dotdot = FALSE;

    if(!dotdot) {
      /*  E. move the first path segment in the input buffer to the end of
          the output buffer, including the initial "/" character (if any) and
          any subsequent characters up to, but not including, the next "/"
          character or the end of the input buffer. */

      do {
        *outptr++ = *input++;
        clen--;
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
       * "127.0.0.1" hostnames as local, otherwise as an UNC String.
       *
       * Additionally, there is an exception for URLs with a Windows drive
       * letter in the authority (which was accidentally omitted from RFC 8089
       * Appendix E, but believe me, it was meant to be there. --MK)
       */
      if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
        /* the URL includes a host name, it must match "localhost" or
           "127.0.0.1" to be valid */
        if(checkprefix("localhost/", ptr) ||
           checkprefix("127.0.0.1/", ptr)) {
          ptr += 9; /* now points to the slash after the host */
        }
        else {
#if defined(_WIN32)
          size_t len;

          /* the host name, NetBIOS computer name, can not contain disallowed
             chars, and the delimiting slash character must be appended to the
             host name */
          path = strpbrk(ptr, "/\\:*?\"<>|");
          if(!path || *path != '/') {
            result = CURLUE_BAD_FILE_URL;
            goto fail;
          }

          len = path - ptr;







|









|

|







1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
       * "127.0.0.1" hostnames as local, otherwise as an UNC String.
       *
       * Additionally, there is an exception for URLs with a Windows drive
       * letter in the authority (which was accidentally omitted from RFC 8089
       * Appendix E, but believe me, it was meant to be there. --MK)
       */
      if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
        /* the URL includes a hostname, it must match "localhost" or
           "127.0.0.1" to be valid */
        if(checkprefix("localhost/", ptr) ||
           checkprefix("127.0.0.1/", ptr)) {
          ptr += 9; /* now points to the slash after the host */
        }
        else {
#if defined(_WIN32)
          size_t len;

          /* the hostname, NetBIOS computer name, can not contain disallowed
             chars, and the delimiting slash character must be appended to the
             hostname */
          path = strpbrk(ptr, "/\\:*?\"<>|");
          if(!path || *path != '/') {
            result = CURLUE_BAD_FILE_URL;
            goto fail;
          }

          len = path - ptr;
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
    }

    if(!uncpath)
      /* no host for file: URLs by default */
      Curl_dyn_reset(&host);

#if !defined(_WIN32) && !defined(MSDOS) && !defined(__CYGWIN__)
    /* Don't allow Windows drive letters when not in Windows.
     * This catches both "file:/c:" and "file:c:" */
    if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
       STARTS_WITH_URL_DRIVE_PREFIX(path)) {
      /* File drive letters are only accepted in MSDOS/Windows */
      result = CURLUE_BAD_FILE_URL;
      goto fail;
    }







|







1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
    }

    if(!uncpath)
      /* no host for file: URLs by default */
      Curl_dyn_reset(&host);

#if !defined(_WIN32) && !defined(MSDOS) && !defined(__CYGWIN__)
    /* Do not allow Windows drive letters when not in Windows.
     * This catches both "file:/c:" and "file:c:" */
    if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
       STARTS_WITH_URL_DRIVE_PREFIX(path)) {
      /* File drive letters are only accepted in MSDOS/Windows */
      result = CURLUE_BAD_FILE_URL;
      goto fail;
    }
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
      }

      if((i < 1) || (i > 3)) {
        /* less than one or more than three slashes */
        result = CURLUE_BAD_SLASHES;
        goto fail;
      }
      hostp = p; /* host name starts here */
    }
    else {
      /* no scheme! */

      if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) {
        result = CURLUE_BAD_SCHEME;
        goto fail;







|







1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
      }

      if((i < 1) || (i > 3)) {
        /* less than one or more than three slashes */
        result = CURLUE_BAD_SLASHES;
        goto fail;
      }
      hostp = p; /* hostname starts here */
    }
    else {
      /* no scheme! */

      if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) {
        result = CURLUE_BAD_SCHEME;
        goto fail;
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225

1226
1227
1228
1229
1230
1231
1232
      u->scheme = strdup(schemep);
      if(!u->scheme) {
        result = CURLUE_OUT_OF_MEMORY;
        goto fail;
      }
    }

    /* find the end of the host name + port number */
    hostlen = strcspn(hostp, "/?#");
    path = &hostp[hostlen];

    /* this pathlen also contains the query and the fragment */
    pathlen = urllen - (path - url);
    if(hostlen) {

      result = parse_authority(u, hostp, hostlen, flags, &host, schemelen);
      if(result)
        goto fail;

      if((flags & CURLU_GUESS_SCHEME) && !schemep) {
        const char *hostname = Curl_dyn_ptr(&host);
        /* legacy curl-style guess based on host name */
        if(checkprefix("ftp.", hostname))
          schemep = "ftp";
        else if(checkprefix("dict.", hostname))
          schemep = "dict";
        else if(checkprefix("ldap.", hostname))
          schemep = "ldap";
        else if(checkprefix("imap.", hostname))
          schemep = "imap";
        else if(checkprefix("smtp.", hostname))
          schemep = "smtp";
        else if(checkprefix("pop3.", hostname))
          schemep = "pop3";
        else
          schemep = "http";

        u->scheme = strdup(schemep);
        if(!u->scheme) {
          result = CURLUE_OUT_OF_MEMORY;
          goto fail;
        }

      }
    }
    else if(flags & CURLU_NO_AUTHORITY) {
      /* allowed to be empty. */
      if(Curl_dyn_add(&host, "")) {
        result = CURLUE_OUT_OF_MEMORY;
        goto fail;







|













|




















>







1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
      u->scheme = strdup(schemep);
      if(!u->scheme) {
        result = CURLUE_OUT_OF_MEMORY;
        goto fail;
      }
    }

    /* find the end of the hostname + port number */
    hostlen = strcspn(hostp, "/?#");
    path = &hostp[hostlen];

    /* this pathlen also contains the query and the fragment */
    pathlen = urllen - (path - url);
    if(hostlen) {

      result = parse_authority(u, hostp, hostlen, flags, &host, schemelen);
      if(result)
        goto fail;

      if((flags & CURLU_GUESS_SCHEME) && !schemep) {
        const char *hostname = Curl_dyn_ptr(&host);
        /* legacy curl-style guess based on hostname */
        if(checkprefix("ftp.", hostname))
          schemep = "ftp";
        else if(checkprefix("dict.", hostname))
          schemep = "dict";
        else if(checkprefix("ldap.", hostname))
          schemep = "ldap";
        else if(checkprefix("imap.", hostname))
          schemep = "imap";
        else if(checkprefix("smtp.", hostname))
          schemep = "smtp";
        else if(checkprefix("pop3.", hostname))
          schemep = "pop3";
        else
          schemep = "http";

        u->scheme = strdup(schemep);
        if(!u->scheme) {
          result = CURLUE_OUT_OF_MEMORY;
          goto fail;
        }
        u->guessed_scheme = TRUE;
      }
    }
    else if(flags & CURLU_NO_AUTHORITY) {
      /* allowed to be empty. */
      if(Curl_dyn_add(&host, "")) {
        result = CURLUE_OUT_OF_MEMORY;
        goto fail;
1433
1434
1435
1436
1437
1438
1439


1440
1441
1442
1443
1444
1445
1446
  *part = NULL;

  switch(what) {
  case CURLUPART_SCHEME:
    ptr = u->scheme;
    ifmissing = CURLUE_NO_SCHEME;
    urldecode = FALSE; /* never for schemes */


    break;
  case CURLUPART_USER:
    ptr = u->user;
    ifmissing = CURLUE_NO_USER;
    break;
  case CURLUPART_PASSWORD:
    ptr = u->password;







>
>







1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
  *part = NULL;

  switch(what) {
  case CURLUPART_SCHEME:
    ptr = u->scheme;
    ifmissing = CURLUE_NO_SCHEME;
    urldecode = FALSE; /* never for schemes */
    if((flags & CURLU_NO_GUESS_SCHEME) && u->guessed_scheme)
      return CURLUE_NO_SCHEME;
    break;
  case CURLUPART_USER:
    ptr = u->user;
    ifmissing = CURLUE_NO_USER;
    break;
  case CURLUPART_PASSWORD:
    ptr = u->password;
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
    ifmissing = CURLUE_NO_ZONEID;
    break;
  case CURLUPART_PORT:
    ptr = u->port;
    ifmissing = CURLUE_NO_PORT;
    urldecode = FALSE; /* never for port */
    if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
      /* there's no stored port number, but asked to deliver
         a default one for the scheme */
      const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme);
      if(h) {
        msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
        ptr = portbuf;
      }
    }







|







1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
    ifmissing = CURLUE_NO_ZONEID;
    break;
  case CURLUPART_PORT:
    ptr = u->port;
    ifmissing = CURLUE_NO_PORT;
    urldecode = FALSE; /* never for port */
    if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
      /* there is no stored port number, but asked to deliver
         a default one for the scheme */
      const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme);
      if(h) {
        msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
        ptr = portbuf;
      }
    }
1521
1522
1523
1524
1525
1526
1527

1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
                    show_fragment ? "#": "",
                    u->fragment ? u->fragment : "");
    }
    else if(!u->host)
      return CURLUE_NO_HOST;
    else {
      const struct Curl_handler *h = NULL;

      if(u->scheme)
        scheme = u->scheme;
      else if(flags & CURLU_DEFAULT_SCHEME)
        scheme = (char *) DEFAULT_SCHEME;
      else
        return CURLUE_NO_SCHEME;

      h = Curl_get_scheme_handler(scheme);
      if(!port && (flags & CURLU_DEFAULT_PORT)) {
        /* there's no stored port number, but asked to deliver
           a default one for the scheme */
        if(h) {
          msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
          port = portbuf;
        }
      }
      else if(port) {







>









|







1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
                    show_fragment ? "#": "",
                    u->fragment ? u->fragment : "");
    }
    else if(!u->host)
      return CURLUE_NO_HOST;
    else {
      const struct Curl_handler *h = NULL;
      char schemebuf[MAX_SCHEME_LEN + 5];
      if(u->scheme)
        scheme = u->scheme;
      else if(flags & CURLU_DEFAULT_SCHEME)
        scheme = (char *) DEFAULT_SCHEME;
      else
        return CURLUE_NO_SCHEME;

      h = Curl_get_scheme_handler(scheme);
      if(!port && (flags & CURLU_DEFAULT_PORT)) {
        /* there is no stored port number, but asked to deliver
           a default one for the scheme */
        if(h) {
          msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
          port = portbuf;
        }
      }
      else if(port) {
1591
1592
1593
1594
1595
1596
1597





1598
1599
1600
1601
1602
1603
1604
1605
1606
            /* this is the most likely error */
            return (result == CURLE_OUT_OF_MEMORY) ?
              CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
#endif
        }
      }






      url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                    scheme,
                    u->user ? u->user : "",
                    u->password ? ":": "",
                    u->password ? u->password : "",
                    options ? ";" : "",
                    options ? options : "",
                    (u->user || u->password || options) ? "@": "",
                    allochost ? allochost : u->host,







>
>
>
>
>
|
|







1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
            /* this is the most likely error */
            return (result == CURLE_OUT_OF_MEMORY) ?
              CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
#endif
        }
      }

      if(!(flags & CURLU_NO_GUESS_SCHEME) || !u->guessed_scheme)
        msnprintf(schemebuf, sizeof(schemebuf), "%s://", scheme);
      else
        schemebuf[0] = 0;

      url = aprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                    schemebuf,
                    u->user ? u->user : "",
                    u->password ? ":": "",
                    u->password ? u->password : "",
                    options ? ";" : "",
                    options ? options : "",
                    (u->user || u->password || options) ? "@": "",
                    allochost ? allochost : u->host,
1714
1715
1716
1717
1718
1719
1720

1721
1722
1723
1724
1725
1726
1727
  if(!part) {
    /* setting a part to NULL clears it */
    switch(what) {
    case CURLUPART_URL:
      break;
    case CURLUPART_SCHEME:
      storep = &u->scheme;

      break;
    case CURLUPART_USER:
      storep = &u->user;
      break;
    case CURLUPART_PASSWORD:
      storep = &u->password;
      break;







>







1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
  if(!part) {
    /* setting a part to NULL clears it */
    switch(what) {
    case CURLUPART_URL:
      break;
    case CURLUPART_SCHEME:
      storep = &u->scheme;
      u->guessed_scheme = FALSE;
      break;
    case CURLUPART_USER:
      storep = &u->user;
      break;
    case CURLUPART_PASSWORD:
      storep = &u->password;
      break;
1786
1787
1788
1789
1790
1791
1792

1793
1794
1795
1796
1797
1798
1799
          s++; /* fine */
        else
          return CURLUE_BAD_SCHEME;
      }
    }
    else
      return CURLUE_BAD_SCHEME;

    break;
  }
  case CURLUPART_USER:
    storep = &u->user;
    break;
  case CURLUPART_PASSWORD:
    storep = &u->password;







>







1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
          s++; /* fine */
        else
          return CURLUE_BAD_SCHEME;
      }
    }
    else
      return CURLUE_BAD_SCHEME;
    u->guessed_scheme = FALSE;
    break;
  }
  case CURLUPART_USER:
    storep = &u->user;
    break;
  case CURLUPART_PASSWORD:
    storep = &u->password;
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
    char *redired_url;

    if(!nalloc)
      /* a blank URL is not a valid URL */
      return CURLUE_MALFORMED_INPUT;

    /* if the new thing is absolute or the old one is not
     * (we could not get an absolute url in 'oldurl'),
     * then replace the existing with the new. */
    if(Curl_is_absolute_url(part, NULL, 0,
                            flags & (CURLU_GUESS_SCHEME|
                                     CURLU_DEFAULT_SCHEME))
       || curl_url_get(u, CURLUPART_URL, &oldurl, flags)) {
      return parseurl_and_replace(part, u, flags);
    }







|







1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
    char *redired_url;

    if(!nalloc)
      /* a blank URL is not a valid URL */
      return CURLUE_MALFORMED_INPUT;

    /* if the new thing is absolute or the old one is not
     * (we could not get an absolute URL in 'oldurl'),
     * then replace the existing with the new. */
    if(Curl_is_absolute_url(part, NULL, 0,
                            flags & (CURLU_GUESS_SCHEME|
                                     CURLU_DEFAULT_SCHEME))
       || curl_url_get(u, CURLUPART_URL, &oldurl, flags)) {
      return parseurl_and_replace(part, u, flags);
    }
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
        return CURLUE_OUT_OF_MEMORY;
      }
    }

    else if(what == CURLUPART_HOST) {
      size_t n = Curl_dyn_len(&enc);
      if(!n && (flags & CURLU_NO_AUTHORITY)) {
        /* Skip hostname check, it's allowed to be empty. */
      }
      else {
        if(!n || hostname_check(u, (char *)newp, n)) {
          Curl_dyn_free(&enc);
          return CURLUE_BAD_HOSTNAME;
        }
      }







|







1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
        return CURLUE_OUT_OF_MEMORY;
      }
    }

    else if(what == CURLUPART_HOST) {
      size_t n = Curl_dyn_len(&enc);
      if(!n && (flags & CURLU_NO_AUTHORITY)) {
        /* Skip hostname check, it is allowed to be empty. */
      }
      else {
        if(!n || hostname_check(u, (char *)newp, n)) {
          Curl_dyn_free(&enc);
          return CURLUE_BAD_HOSTNAME;
        }
      }
Changes to jni/curl/lib/urldata.h.
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# define CURLECH_HARD       (1<<3)
# define CURLECH_CLA_CFG    (1<<4)
#endif

#ifdef USE_WEBSOCKETS
/* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number,
 * the rest are internal information. If we use higher bits we only do this on
 * platforms that have a >= 64 bit type and then we use such a type for the
 * protocol fields in the protocol handler.
 */
#define CURLPROTO_WS     (1<<30)
#define CURLPROTO_WSS    ((curl_prot_t)1<<31)
#else
#define CURLPROTO_WS 0
#define CURLPROTO_WSS 0







|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# define CURLECH_HARD       (1<<3)
# define CURLECH_CLA_CFG    (1<<4)
#endif

#ifdef USE_WEBSOCKETS
/* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number,
 * the rest are internal information. If we use higher bits we only do this on
 * platforms that have a >= 64-bit type and then we use such a type for the
 * protocol fields in the protocol handler.
 */
#define CURLPROTO_WS     (1<<30)
#define CURLPROTO_WSS    ((curl_prot_t)1<<31)
#else
#define CURLPROTO_WS 0
#define CURLPROTO_WSS 0
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  PROT_CONFIDENTIAL,
  PROT_PRIVATE,
  PROT_CMD,
  PROT_LAST /* last in list */
};
#endif

/* enum for the nonblocking SSL connection state machine */
typedef enum {
  ssl_connect_1,
  ssl_connect_2,
  ssl_connect_2_reading,
  ssl_connect_2_writing,
  ssl_connect_3,
  ssl_connect_done
} ssl_connect_state;

typedef enum {
  ssl_connection_none,
  ssl_connection_negotiating,
  ssl_connection_complete
} ssl_connection_state;

/* SSL backend-specific data; declared differently by each SSL backend */
struct ssl_backend_data;

typedef enum {
  CURL_SSL_PEER_DNS,
  CURL_SSL_PEER_IPV4,
  CURL_SSL_PEER_IPV6
} ssl_peer_type;

struct ssl_peer {
  char *hostname;        /* hostname for verification */
  char *dispname;        /* display version of hostname */
  char *sni;             /* SNI version of hostname or NULL if not usable */
  ssl_peer_type type;    /* type of the peer information */
  int port;              /* port we are talking to */
  int transport;         /* TCP or QUIC */
};

struct ssl_primary_config {
  char *CApath;          /* certificate dir (doesn't work on windows) */
  char *CAfile;          /* certificate to verify peer against */
  char *issuercert;      /* optional issuer certificate filename */
  char *clientcert;
  char *cipher_list;     /* list of ciphers to use */
  char *cipher_list13;   /* list of TLS 1.3 cipher suites to use */
  char *pinned_key;
  char *CRLfile;         /* CRL to check certificate revocation */







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



















|







253
254
255
256
257
258
259
















260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  PROT_CONFIDENTIAL,
  PROT_PRIVATE,
  PROT_CMD,
  PROT_LAST /* last in list */
};
#endif

















/* SSL backend-specific data; declared differently by each SSL backend */
struct ssl_backend_data;

typedef enum {
  CURL_SSL_PEER_DNS,
  CURL_SSL_PEER_IPV4,
  CURL_SSL_PEER_IPV6
} ssl_peer_type;

struct ssl_peer {
  char *hostname;        /* hostname for verification */
  char *dispname;        /* display version of hostname */
  char *sni;             /* SNI version of hostname or NULL if not usable */
  ssl_peer_type type;    /* type of the peer information */
  int port;              /* port we are talking to */
  int transport;         /* TCP or QUIC */
};

struct ssl_primary_config {
  char *CApath;          /* certificate dir (does not work on windows) */
  char *CAfile;          /* certificate to verify peer against */
  char *issuercert;      /* optional issuer certificate filename */
  char *clientcert;
  char *cipher_list;     /* list of ciphers to use */
  char *cipher_list13;   /* list of TLS 1.3 cipher suites to use */
  char *pinned_key;
  char *CRLfile;         /* CRL to check certificate revocation */
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  char *curves;          /* list of curves to use */
  unsigned char ssl_options;  /* the CURLOPT_SSL_OPTIONS bitmask */
  unsigned int version_max; /* max supported version the client wants to use */
  unsigned char version;    /* what version the client wants to use */
  BIT(verifypeer);       /* set TRUE if this is desired */
  BIT(verifyhost);       /* set TRUE if CN/SAN must match hostname */
  BIT(verifystatus);     /* set TRUE if certificate status must be checked */
  BIT(sessionid);        /* cache session IDs or not */
};

struct ssl_config_data {
  struct ssl_primary_config primary;
  long certverifyresult; /* result from the certificate verification */
  curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
  void *fsslctxp;        /* parameter for call back */
  char *cert_type; /* format for certificate (default: PEM)*/
  char *key; /* private key file name */
  struct curl_blob *key_blob;
  char *key_type; /* format for private key (default: PEM) */
  char *key_passwd; /* plain text private key password */
  BIT(certinfo);     /* gather lots of certificate info */
  BIT(falsestart);
  BIT(enable_beast); /* allow this flaw for interoperability's sake */
  BIT(no_revoke);    /* disable SSL certificate revocation checks */
  BIT(no_partialchain); /* don't accept partial certificate chains */
  BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
                              list errors */
  BIT(native_ca_store); /* use the native ca store of operating system */
  BIT(auto_client_cert);   /* automatically locate and use a client
                              certificate for authentication (Schannel) */
};

struct ssl_general_config {
  size_t max_ssl_sessions; /* SSL session id cache size */
  int ca_cache_timeout;  /* Certificate store cache timeout (seconds) */
};

typedef void Curl_ssl_sessionid_dtor(void *sessionid, size_t idsize);

/* information stored about one single SSL session */
struct Curl_ssl_session {
  char *name;       /* host name for which this ID was used */
  char *conn_to_host; /* host name for the connection (may be NULL) */
  const char *scheme; /* protocol scheme used */
  void *sessionid;  /* as returned from the SSL layer */
  size_t idsize;    /* if known, otherwise 0 */
  Curl_ssl_sessionid_dtor *sessionid_free; /* free `sessionid` callback */
  long age;         /* just a number, the higher the more recent */
  int remote_port;  /* remote port */
  int conn_to_port; /* remote port for the connection (may be -1) */







|








|







|
















|
|







294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  char *curves;          /* list of curves to use */
  unsigned char ssl_options;  /* the CURLOPT_SSL_OPTIONS bitmask */
  unsigned int version_max; /* max supported version the client wants to use */
  unsigned char version;    /* what version the client wants to use */
  BIT(verifypeer);       /* set TRUE if this is desired */
  BIT(verifyhost);       /* set TRUE if CN/SAN must match hostname */
  BIT(verifystatus);     /* set TRUE if certificate status must be checked */
  BIT(cache_session);    /* cache session or not */
};

struct ssl_config_data {
  struct ssl_primary_config primary;
  long certverifyresult; /* result from the certificate verification */
  curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
  void *fsslctxp;        /* parameter for call back */
  char *cert_type; /* format for certificate (default: PEM)*/
  char *key; /* private key filename */
  struct curl_blob *key_blob;
  char *key_type; /* format for private key (default: PEM) */
  char *key_passwd; /* plain text private key password */
  BIT(certinfo);     /* gather lots of certificate info */
  BIT(falsestart);
  BIT(enable_beast); /* allow this flaw for interoperability's sake */
  BIT(no_revoke);    /* disable SSL certificate revocation checks */
  BIT(no_partialchain); /* do not accept partial certificate chains */
  BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
                              list errors */
  BIT(native_ca_store); /* use the native ca store of operating system */
  BIT(auto_client_cert);   /* automatically locate and use a client
                              certificate for authentication (Schannel) */
};

struct ssl_general_config {
  size_t max_ssl_sessions; /* SSL session id cache size */
  int ca_cache_timeout;  /* Certificate store cache timeout (seconds) */
};

typedef void Curl_ssl_sessionid_dtor(void *sessionid, size_t idsize);

/* information stored about one single SSL session */
struct Curl_ssl_session {
  char *name;       /* hostname for which this ID was used */
  char *conn_to_host; /* hostname for the connection (may be NULL) */
  const char *scheme; /* protocol scheme used */
  void *sessionid;  /* as returned from the SSL layer */
  size_t idsize;    /* if known, otherwise 0 */
  Curl_ssl_sessionid_dtor *sessionid_free; /* free `sessionid` callback */
  long age;         /* just a number, the higher the more recent */
  int remote_port;  /* remote port */
  int conn_to_port; /* remote port for the connection (may be -1) */
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
                   supposed to be called, after ->curl_do() */
  BIT(protoconnstart);/* the protocol layer has STARTED its operation after
                         the TCP layer connect */
  BIT(retry);         /* this connection is about to get closed and then
                         re-attempted at another connection. */
#ifndef CURL_DISABLE_FTP
  BIT(ftp_use_epsv);  /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
                         EPSV doesn't work we disable it for the forthcoming
                         requests */
  BIT(ftp_use_eprt);  /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
                         EPRT doesn't work we disable it for the forthcoming
                         requests */
  BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
  BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */
#endif
#ifndef CURL_DISABLE_NETRC
  BIT(netrc);         /* name+password provided by netrc */
#endif







|


|







515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
                   supposed to be called, after ->curl_do() */
  BIT(protoconnstart);/* the protocol layer has STARTED its operation after
                         the TCP layer connect */
  BIT(retry);         /* this connection is about to get closed and then
                         re-attempted at another connection. */
#ifndef CURL_DISABLE_FTP
  BIT(ftp_use_epsv);  /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
                         EPSV does not work we disable it for the forthcoming
                         requests */
  BIT(ftp_use_eprt);  /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
                         EPRT does not work we disable it for the forthcoming
                         requests */
  BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
  BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */
#endif
#ifndef CURL_DISABLE_NETRC
  BIT(netrc);         /* name+password provided by netrc */
#endif
558
559
560
561
562
563
564



565
566
567
568
569
570
571
  BIT(abstract_unix_socket);
#endif
  BIT(tls_upgraded);
  BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with
                         accept() */
  BIT(parallel_connect); /* set TRUE when a parallel connect attempt has
                            started (happy eyeballs) */



};

struct hostname {
  char *rawalloc; /* allocated "raw" version of the name */
  char *encalloc; /* allocated IDN-encoded version of the name */
  char *name;     /* name to use internally, might be encoded, might be raw */
  const char *dispname; /* name to display, as 'name' might be encoded */







>
>
>







542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  BIT(abstract_unix_socket);
#endif
  BIT(tls_upgraded);
  BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with
                         accept() */
  BIT(parallel_connect); /* set TRUE when a parallel connect attempt has
                            started (happy eyeballs) */
  BIT(aborted); /* connection was aborted, e.g. in unclean state */
  BIT(shutdown_handler); /* connection shutdown: handler shut down */
  BIT(shutdown_filters); /* connection shutdown: filters shut down */
};

struct hostname {
  char *rawalloc; /* allocated "raw" version of the name */
  char *encalloc; /* allocated IDN-encoded version of the name */
  char *name;     /* name to use internally, might be encoded, might be raw */
  const char *dispname; /* name to display, as 'name' might be encoded */
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
   * for doing the FTP stuff after the PASV/PORT command.
   */
  CURLcode (*do_more)(struct Curl_easy *, int *);

  /* This function *MAY* be set to a protocol-dependent function that is run
   * after the connect() and everything is done, as a step in the connection.
   * The 'done' pointer points to a bool that should be set to TRUE if the
   * function completes before return. If it doesn't complete, the caller
   * should call the ->connecting() function until it is.
   */
  CURLcode (*connect_it)(struct Curl_easy *data, bool *done);

  /* See above. */
  CURLcode (*connecting)(struct Curl_easy *data, bool *done);
  CURLcode (*doing)(struct Curl_easy *data, bool *done);







|







659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
   * for doing the FTP stuff after the PASV/PORT command.
   */
  CURLcode (*do_more)(struct Curl_easy *, int *);

  /* This function *MAY* be set to a protocol-dependent function that is run
   * after the connect() and everything is done, as a step in the connection.
   * The 'done' pointer points to a bool that should be set to TRUE if the
   * function completes before return. If it does not complete, the caller
   * should call the ->connecting() function until it is.
   */
  CURLcode (*connect_it)(struct Curl_easy *data, bool *done);

  /* See above. */
  CURLcode (*connecting)(struct Curl_easy *data, bool *done);
  CURLcode (*doing)(struct Curl_easy *data, bool *done);
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
  /* Called from the multi interface during the DO_DONE, PERFORM and
     WAITPERFORM phases, and it should then return a proper fd set. Not setting
     this will make libcurl use the generic default one. */
  int (*perform_getsock)(struct Curl_easy *data,
                         struct connectdata *conn, curl_socket_t *socks);

  /* This function *MAY* be set to a protocol-dependent function that is run
   * by the curl_disconnect(), as a step in the disconnection.  If the handler
   * is called because the connection has been considered dead,
   * dead_connection is set to TRUE. The connection is (again) associated with
   * the transfer here.
   */
  CURLcode (*disconnect)(struct Curl_easy *, struct connectdata *,
                         bool dead_connection);








|







690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
  /* Called from the multi interface during the DO_DONE, PERFORM and
     WAITPERFORM phases, and it should then return a proper fd set. Not setting
     this will make libcurl use the generic default one. */
  int (*perform_getsock)(struct Curl_easy *data,
                         struct connectdata *conn, curl_socket_t *socks);

  /* This function *MAY* be set to a protocol-dependent function that is run
   * by the curl_disconnect(), as a step in the disconnection. If the handler
   * is called because the connection has been considered dead,
   * dead_connection is set to TRUE. The connection is (again) associated with
   * the transfer here.
   */
  CURLcode (*disconnect)(struct Curl_easy *, struct connectdata *,
                         bool dead_connection);

751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
#define PROTOPT_DUAL (1<<1)        /* this protocol uses two connections */
#define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */
/* some protocols will have to call the underlying functions without regard to
   what exact state the socket signals. IE even if the socket says "readable",
   the send function might need to be called while uploading, or vice versa.
*/
#define PROTOPT_DIRLOCK (1<<3)
#define PROTOPT_NONETWORK (1<<4)   /* protocol doesn't use the network! */
#define PROTOPT_NEEDSPWD (1<<5)    /* needs a password, and if none is set it
                                      gets a default */
#define PROTOPT_NOURLQUERY (1<<6)   /* protocol can't handle
                                        url query strings (?foo=bar) ! */
#define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per
                                          request instead of per connection */
#define PROTOPT_ALPN (1<<8) /* set ALPN for this */
/* (1<<9) was PROTOPT_STREAM, now free */
#define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field
                                      of the URL */
#define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a
                                         HTTP proxy as HTTP proxies may know
                                         this protocol and act as a gateway */
#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
#define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in
                                       user name and password */
#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol can't proxy over TCP */

#define CONNCHECK_NONE 0                 /* No checks */
#define CONNCHECK_ISDEAD (1<<0)          /* Check if the connection is dead. */
#define CONNCHECK_KEEPALIVE (1<<1)       /* Perform any keepalive function. */

#define CONNRESULT_NONE 0                /* No extra information. */
#define CONNRESULT_DEAD (1<<0)           /* The connection is dead. */

struct ip_quadruple {
  char remote_ip[MAX_IPADR_LEN];
  char local_ip[MAX_IPADR_LEN];
  int remote_port;
  int local_port;
};

struct proxy_info {
  struct hostname host;
  int port;
  unsigned char proxytype; /* curl_proxytype: what kind of proxy that is in
                              use */
  char *user;    /* proxy user name string, allocated */
  char *passwd;  /* proxy password string, allocated */
};

struct ldapconninfo;

#define TRNSPRT_TCP 3
#define TRNSPRT_UDP 4







|


|
|











|
|




















|







738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
#define PROTOPT_DUAL (1<<1)        /* this protocol uses two connections */
#define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */
/* some protocols will have to call the underlying functions without regard to
   what exact state the socket signals. IE even if the socket says "readable",
   the send function might need to be called while uploading, or vice versa.
*/
#define PROTOPT_DIRLOCK (1<<3)
#define PROTOPT_NONETWORK (1<<4)   /* protocol does not use the network! */
#define PROTOPT_NEEDSPWD (1<<5)    /* needs a password, and if none is set it
                                      gets a default */
#define PROTOPT_NOURLQUERY (1<<6)   /* protocol cannot handle
                                       URL query strings (?foo=bar) ! */
#define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per
                                          request instead of per connection */
#define PROTOPT_ALPN (1<<8) /* set ALPN for this */
/* (1<<9) was PROTOPT_STREAM, now free */
#define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field
                                      of the URL */
#define PROTOPT_PROXY_AS_HTTP (1<<11) /* allow this non-HTTP scheme over a
                                         HTTP proxy as HTTP proxies may know
                                         this protocol and act as a gateway */
#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
#define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in
                                       username and password */
#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol cannot proxy over TCP */

#define CONNCHECK_NONE 0                 /* No checks */
#define CONNCHECK_ISDEAD (1<<0)          /* Check if the connection is dead. */
#define CONNCHECK_KEEPALIVE (1<<1)       /* Perform any keepalive function. */

#define CONNRESULT_NONE 0                /* No extra information. */
#define CONNRESULT_DEAD (1<<0)           /* The connection is dead. */

struct ip_quadruple {
  char remote_ip[MAX_IPADR_LEN];
  char local_ip[MAX_IPADR_LEN];
  int remote_port;
  int local_port;
};

struct proxy_info {
  struct hostname host;
  int port;
  unsigned char proxytype; /* curl_proxytype: what kind of proxy that is in
                              use */
  char *user;    /* proxy username string, allocated */
  char *passwd;  /* proxy password string, allocated */
};

struct ldapconninfo;

#define TRNSPRT_TCP 3
#define TRNSPRT_UDP 4
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865







866
867
868
869
870
871
872
  struct Curl_dns_entry *dns_entry;

  /* 'remote_addr' is the particular IP we connected to. it is owned, set
   * and NULLed by the connected socket filter (if there is one). */
  const struct Curl_sockaddr_ex *remote_addr;

  struct hostname host;
  char *hostname_resolve; /* host name to resolve to address, allocated */
  char *secondaryhostname; /* secondary socket host name (ftp) */
  struct hostname conn_to_host; /* the host to connect to. valid only if
                                   bits.conn_to_host is set */
#ifndef CURL_DISABLE_PROXY
  struct proxy_info socks_proxy;
  struct proxy_info http_proxy;
#endif
  /* 'primary' and 'secondary' get filled with IP quadruple
     (local/remote numerical ip address and port) whenever a is *attempted*.
     When more than one address is tried for a connection these will hold data
     for the last attempt. When the connection is actually established
     these are updated with data which comes directly from the socket. */
  struct ip_quadruple primary;
  struct ip_quadruple secondary;
  char *user;    /* user name string, allocated */
  char *passwd;  /* password string, allocated */
  char *options; /* options string, allocated */
  char *sasl_authzid;     /* authorization identity string, allocated */
  char *oauth_bearer; /* OAUTH2 bearer, allocated */
  struct curltime now;     /* "current" time */
  struct curltime created; /* creation time */
  struct curltime lastused; /* when returned to the connection cache */
  curl_socket_t sock[2]; /* two sockets, the second is used for the data
                            transfer when doing FTP */
  Curl_recv *recv[2];
  Curl_send *send[2];
  struct Curl_cfilter *cfilter[2]; /* connection filters */








  struct ssl_primary_config ssl_config;
#ifndef CURL_DISABLE_PROXY
  struct ssl_primary_config proxy_ssl_config;
#endif
  struct ConnectBits bits;    /* various state-flags for this connection */








|
|













|












>
>
>
>
>
>
>







818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
  struct Curl_dns_entry *dns_entry;

  /* 'remote_addr' is the particular IP we connected to. it is owned, set
   * and NULLed by the connected socket filter (if there is one). */
  const struct Curl_sockaddr_ex *remote_addr;

  struct hostname host;
  char *hostname_resolve; /* hostname to resolve to address, allocated */
  char *secondaryhostname; /* secondary socket hostname (ftp) */
  struct hostname conn_to_host; /* the host to connect to. valid only if
                                   bits.conn_to_host is set */
#ifndef CURL_DISABLE_PROXY
  struct proxy_info socks_proxy;
  struct proxy_info http_proxy;
#endif
  /* 'primary' and 'secondary' get filled with IP quadruple
     (local/remote numerical ip address and port) whenever a is *attempted*.
     When more than one address is tried for a connection these will hold data
     for the last attempt. When the connection is actually established
     these are updated with data which comes directly from the socket. */
  struct ip_quadruple primary;
  struct ip_quadruple secondary;
  char *user;    /* username string, allocated */
  char *passwd;  /* password string, allocated */
  char *options; /* options string, allocated */
  char *sasl_authzid;     /* authorization identity string, allocated */
  char *oauth_bearer; /* OAUTH2 bearer, allocated */
  struct curltime now;     /* "current" time */
  struct curltime created; /* creation time */
  struct curltime lastused; /* when returned to the connection cache */
  curl_socket_t sock[2]; /* two sockets, the second is used for the data
                            transfer when doing FTP */
  Curl_recv *recv[2];
  Curl_send *send[2];
  struct Curl_cfilter *cfilter[2]; /* connection filters */
  struct {
    struct curltime start[2]; /* when filter shutdown started */
    unsigned int timeout_ms; /* 0 means no timeout */
  } shutdown;
  /* Last pollset used in connection shutdown. Used to detect changes
   * for multi_socket API. */
  struct easy_pollset shutdown_poll;

  struct ssl_primary_config ssl_config;
#ifndef CURL_DISABLE_PROXY
  struct ssl_primary_config proxy_ssl_config;
#endif
  struct ConnectBits bits;    /* various state-flags for this connection */

904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
  struct Curl_llist easyq;    /* List of easy handles using this connection */

  /*************** Request - specific items ************/
#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
  CtxtHandle *sslContext;
#endif

#if defined(_WIN32) && defined(USE_WINSOCK)
  struct curltime last_sndbuf_update;  /* last time readwrite_upload called
                                          win_update_buffer_size */
#endif

#ifdef USE_GSASL
  struct gsasldata gsasl;
#endif

#if defined(USE_NTLM)
  curlntlm http_ntlm_state;
  curlntlm proxy_ntlm_state;







<
<
<
<
<







898
899
900
901
902
903
904





905
906
907
908
909
910
911
  struct Curl_llist easyq;    /* List of easy handles using this connection */

  /*************** Request - specific items ************/
#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
  CtxtHandle *sslContext;
#endif






#ifdef USE_GSASL
  struct gsasldata gsasl;
#endif

#if defined(USE_NTLM)
  curlntlm http_ntlm_state;
  curlntlm proxy_ntlm_state;
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
#ifdef USE_HYPER
  /* if set, an alternative data transfer function */
  Curl_datastream datastream;
#endif
  /* When this connection is created, store the conditions for the local end
     bind. This is stored before the actual bind and before any connection is
     made and will serve the purpose of being used for comparison reasons so
     that subsequent bound-requested connections aren't accidentally reusing
     wrong connections. */
  char *localdev;
  unsigned short localportrange;
  int waitfor;      /* current READ/WRITE bits to wait for */
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  int socks5_gssapi_enctype;
#endif







|







971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
#ifdef USE_HYPER
  /* if set, an alternative data transfer function */
  Curl_datastream datastream;
#endif
  /* When this connection is created, store the conditions for the local end
     bind. This is stored before the actual bind and before any connection is
     made and will serve the purpose of being used for comparison reasons so
     that subsequent bound-requested connections are not accidentally reusing
     wrong connections. */
  char *localdev;
  unsigned short localportrange;
  int waitfor;      /* current READ/WRITE bits to wait for */
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
  int socks5_gssapi_enctype;
#endif
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
  time_t filetime; /* If requested, this is might get set. Set to -1 if the
                      time was unretrievable. */
  curl_off_t request_size; /* the amount of bytes sent in the request(s) */
  unsigned long proxyauthavail; /* what proxy auth types were announced */
  unsigned long httpauthavail;  /* what host auth types were announced */
  long numconnects; /* how many new connection did libcurl created */
  char *contenttype; /* the content type of the object */
  char *wouldredirect; /* URL this would've been redirected to if asked to */
  curl_off_t retry_after; /* info from Retry-After: header */
  unsigned int header_size;  /* size of read header(s) in bytes */

  /* PureInfo primary ip_quadruple is copied over from the connectdata
     struct in order to allow curl_easy_getinfo() to return this information
     even when the session handle is no longer associated with a connection,
     and also allow curl_easy_reset() to clear this information from the
     session handle without disturbing information which is still alive, and
     that might be reused, in the connection cache. */
  struct ip_quadruple primary;
  int conn_remote_port;  /* this is the "remote port", which is the port
                            number of the used URL, independent of proxy or
                            not */
  const char *conn_scheme;
  unsigned int conn_protocol;
  struct curl_certinfo certs; /* info about the certs. Asked for with
                                 CURLOPT_CERTINFO / CURLINFO_CERTINFO */
  CURLproxycode pxcode;
  BIT(timecond);  /* set to TRUE if the time condition didn't match, which
                     thus made the document NOT get fetched */
  BIT(used_proxy); /* the transfer used a proxy */
};


struct Progress {
  time_t lastshow; /* time() of the last displayed progress meter or NULL to







|


















|







1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  time_t filetime; /* If requested, this is might get set. Set to -1 if the
                      time was unretrievable. */
  curl_off_t request_size; /* the amount of bytes sent in the request(s) */
  unsigned long proxyauthavail; /* what proxy auth types were announced */
  unsigned long httpauthavail;  /* what host auth types were announced */
  long numconnects; /* how many new connection did libcurl created */
  char *contenttype; /* the content type of the object */
  char *wouldredirect; /* URL this would have been redirected to if asked to */
  curl_off_t retry_after; /* info from Retry-After: header */
  unsigned int header_size;  /* size of read header(s) in bytes */

  /* PureInfo primary ip_quadruple is copied over from the connectdata
     struct in order to allow curl_easy_getinfo() to return this information
     even when the session handle is no longer associated with a connection,
     and also allow curl_easy_reset() to clear this information from the
     session handle without disturbing information which is still alive, and
     that might be reused, in the connection cache. */
  struct ip_quadruple primary;
  int conn_remote_port;  /* this is the "remote port", which is the port
                            number of the used URL, independent of proxy or
                            not */
  const char *conn_scheme;
  unsigned int conn_protocol;
  struct curl_certinfo certs; /* info about the certs. Asked for with
                                 CURLOPT_CERTINFO / CURLINFO_CERTINFO */
  CURLproxycode pxcode;
  BIT(timecond);  /* set to TRUE if the time condition did not match, which
                     thus made the document NOT get fetched */
  BIT(used_proxy); /* the transfer used a proxy */
};


struct Progress {
  time_t lastshow; /* time() of the last displayed progress meter or NULL to
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
                              * longer exist */
  struct dynbuf headerb; /* buffer to store headers in */
  struct curl_slist *hstslist; /* list of HSTS files set by
                                  curl_easy_setopt(HSTS) calls */
  curl_off_t current_speed;  /* the ProgressShow() function sets this,
                                bytes / second */

  /* host name, port number and protocol of the first (not followed) request.
     if set, this should be the host name that we will sent authorization to,
     no else. Used to make Location: following not keep sending user+password.
     This is strdup()ed data. */
  char *first_host;
  int first_remote_port;
  curl_prot_t first_remote_protocol;

  int retrycount; /* number of retries on a new connection */







|
|







1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
                              * longer exist */
  struct dynbuf headerb; /* buffer to store headers in */
  struct curl_slist *hstslist; /* list of HSTS files set by
                                  curl_easy_setopt(HSTS) calls */
  curl_off_t current_speed;  /* the ProgressShow() function sets this,
                                bytes / second */

  /* hostname, port number and protocol of the first (not followed) request.
     if set, this should be the hostname that we will sent authorization to,
     no else. Used to make Location: following not keep sending user+password.
     This is strdup()ed data. */
  char *first_host;
  int first_remote_port;
  curl_prot_t first_remote_protocol;

  int retrycount; /* number of retries on a new connection */
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
  unsigned char httpversion; /* the lowest HTTP version*10 reported by any
                                server involved in this request */
  unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any)
                            is this */
  unsigned char select_bits; /* != 0 -> bitmask of socket events for this
                                 transfer overriding anything the socket may
                                 report */
#ifdef CURLDEBUG
  BIT(conncache_lock);
#endif
  /* when curl_easy_perform() is called, the multi handle is "owned" by
     the easy handle so curl_easy_cleanup() on such an easy handle will
     also close the multi handle! */
  BIT(multi_owned_by_easy);

  BIT(this_is_a_follow); /* this is a followed Location: request */
  BIT(refused_stream); /* this was refused, try again */
  BIT(errorbuf); /* Set to TRUE if the error buffer is already filled in.
                    This must be set to FALSE every time _easy_perform() is
                    called. */
  BIT(allow_port); /* Is set.use_port allowed to take effect or not. This
                      is always set TRUE when curl_easy_perform() is called. */
  BIT(authproblem); /* TRUE if there's some problem authenticating */
  /* set after initial USER failure, to prevent an authentication loop */
  BIT(wildcardmatch); /* enable wildcard matching */
  BIT(disableexpect);    /* TRUE if Expect: is disabled due to a previous
                            417 response */
  BIT(use_range);
  BIT(rangestringalloc); /* the range string is malloc()'ed */
  BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE







|














|







1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
  unsigned char httpversion; /* the lowest HTTP version*10 reported by any
                                server involved in this request */
  unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any)
                            is this */
  unsigned char select_bits; /* != 0 -> bitmask of socket events for this
                                 transfer overriding anything the socket may
                                 report */
#ifdef DEBUGBUILD
  BIT(conncache_lock);
#endif
  /* when curl_easy_perform() is called, the multi handle is "owned" by
     the easy handle so curl_easy_cleanup() on such an easy handle will
     also close the multi handle! */
  BIT(multi_owned_by_easy);

  BIT(this_is_a_follow); /* this is a followed Location: request */
  BIT(refused_stream); /* this was refused, try again */
  BIT(errorbuf); /* Set to TRUE if the error buffer is already filled in.
                    This must be set to FALSE every time _easy_perform() is
                    called. */
  BIT(allow_port); /* Is set.use_port allowed to take effect or not. This
                      is always set TRUE when curl_easy_perform() is called. */
  BIT(authproblem); /* TRUE if there is some problem authenticating */
  /* set after initial USER failure, to prevent an authentication loop */
  BIT(wildcardmatch); /* enable wildcard matching */
  BIT(disableexpect);    /* TRUE if Expect: is disabled due to a previous
                            417 response */
  BIT(use_range);
  BIT(rangestringalloc); /* the range string is malloc()'ed */
  BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465


1466
1467
1468
1469
1470
1471
1472
 * the 'DynamicStatic' struct.
 * Character pointer fields point to dynamic storage, unless otherwise stated.
 */

struct Curl_multi;    /* declared in multihandle.c */

enum dupstring {
  STRING_CERT,            /* client certificate file name */
  STRING_CERT_TYPE,       /* format for certificate (default: PEM)*/
  STRING_KEY,             /* private key file name */
  STRING_KEY_PASSWD,      /* plain text private key password */
  STRING_KEY_TYPE,        /* format for private key (default: PEM) */
  STRING_SSL_CAPATH,      /* CA directory name (doesn't work on windows) */
  STRING_SSL_CAFILE,      /* certificate file to verify peer against */
  STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */
  STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
  STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */
  STRING_SSL_CRLFILE,     /* crl file to check certificate */
  STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
  STRING_SERVICE_NAME,    /* Service name */
#ifndef CURL_DISABLE_PROXY
  STRING_CERT_PROXY,      /* client certificate file name */
  STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/
  STRING_KEY_PROXY,       /* private key file name */
  STRING_KEY_PASSWD_PROXY, /* plain text private key password */
  STRING_KEY_TYPE_PROXY,  /* format for private key (default: PEM) */
  STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
  STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
  STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
  STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
  STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */
  STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
  STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
  STRING_PROXY_SERVICE_NAME, /* Proxy service name */
#endif
#ifndef CURL_DISABLE_COOKIES
  STRING_COOKIE,          /* HTTP cookie string to send */
  STRING_COOKIEJAR,       /* dump all cookies to this file */
#endif
  STRING_CUSTOMREQUEST,   /* HTTP/FTP/RTSP request/method to use */
  STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */
  STRING_DEVICE,          /* local network interface/address to use */


  STRING_ENCODING,        /* Accept-Encoding string */
#ifndef CURL_DISABLE_FTP
  STRING_FTP_ACCOUNT,     /* ftp account data */
  STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
  STRING_FTPPORT,         /* port to send with the FTP PORT command */
#endif
#if defined(HAVE_GSSAPI)







|

|


|








|

|


|













|

>
>







1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
 * the 'DynamicStatic' struct.
 * Character pointer fields point to dynamic storage, unless otherwise stated.
 */

struct Curl_multi;    /* declared in multihandle.c */

enum dupstring {
  STRING_CERT,            /* client certificate filename */
  STRING_CERT_TYPE,       /* format for certificate (default: PEM)*/
  STRING_KEY,             /* private key filename */
  STRING_KEY_PASSWD,      /* plain text private key password */
  STRING_KEY_TYPE,        /* format for private key (default: PEM) */
  STRING_SSL_CAPATH,      /* CA directory name (does not work on windows) */
  STRING_SSL_CAFILE,      /* certificate file to verify peer against */
  STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */
  STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
  STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */
  STRING_SSL_CRLFILE,     /* crl file to check certificate */
  STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
  STRING_SERVICE_NAME,    /* Service name */
#ifndef CURL_DISABLE_PROXY
  STRING_CERT_PROXY,      /* client certificate filename */
  STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/
  STRING_KEY_PROXY,       /* private key filename */
  STRING_KEY_PASSWD_PROXY, /* plain text private key password */
  STRING_KEY_TYPE_PROXY,  /* format for private key (default: PEM) */
  STRING_SSL_CAPATH_PROXY, /* CA directory name (does not work on windows) */
  STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
  STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
  STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
  STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */
  STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
  STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
  STRING_PROXY_SERVICE_NAME, /* Proxy service name */
#endif
#ifndef CURL_DISABLE_COOKIES
  STRING_COOKIE,          /* HTTP cookie string to send */
  STRING_COOKIEJAR,       /* dump all cookies to this file */
#endif
  STRING_CUSTOMREQUEST,   /* HTTP/FTP/RTSP request/method to use */
  STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL does not specify */
  STRING_DEVICE,          /* local network interface/address to use */
  STRING_INTERFACE,       /* local network interface to use */
  STRING_BINDHOST,        /* local address to use */
  STRING_ENCODING,        /* Accept-Encoding string */
#ifndef CURL_DISABLE_FTP
  STRING_FTP_ACCOUNT,     /* ftp account data */
  STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
  STRING_FTPPORT,         /* port to send with the FTP PORT command */
#endif
#if defined(HAVE_GSSAPI)
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  STRING_RTSP_TRANSPORT,  /* Transport for this session */
#endif
#ifdef USE_SSH
  STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
  STRING_SSH_PUBLIC_KEY,  /* path to the public key file for auth */
  STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
  STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */
  STRING_SSH_KNOWNHOSTS,  /* file name of knownhosts file */
#endif
#ifndef CURL_DISABLE_SMTP
  STRING_MAIL_FROM,
  STRING_MAIL_AUTH,
#endif
#ifdef USE_TLS_SRP
  STRING_TLSAUTH_USERNAME,  /* TLS auth <username> */







|







1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
  STRING_RTSP_TRANSPORT,  /* Transport for this session */
#endif
#ifdef USE_SSH
  STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
  STRING_SSH_PUBLIC_KEY,  /* path to the public key file for auth */
  STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
  STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */
  STRING_SSH_KNOWNHOSTS,  /* filename of knownhosts file */
#endif
#ifndef CURL_DISABLE_SMTP
  STRING_MAIL_FROM,
  STRING_MAIL_AUTH,
#endif
#ifdef USE_TLS_SRP
  STRING_TLSAUTH_USERNAME,  /* TLS auth <username> */
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
  BLOB_SSL_ISSUERCERT_PROXY,
  BLOB_CAINFO_PROXY,
#endif
  BLOB_LAST
};

/* callback that gets called when this easy handle is completed within a multi
   handle.  Only used for internally created transfers, like for example
   DoH. */
typedef int (*multidone_func)(struct Curl_easy *easy, CURLcode result);

struct UserDefined {
  FILE *err;         /* the stderr user data goes here */
  void *debugdata;   /* the data that will be passed to fdebug */
  char *errorbuffer; /* (Static) store failure messages in here */







|







1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
  BLOB_SSL_ISSUERCERT_PROXY,
  BLOB_CAINFO_PROXY,
#endif
  BLOB_LAST
};

/* callback that gets called when this easy handle is completed within a multi
   handle. Only used for internally created transfers, like for example
   DoH. */
typedef int (*multidone_func)(struct Curl_easy *easy, CURLcode result);

struct UserDefined {
  FILE *err;         /* the stderr user data goes here */
  void *debugdata;   /* the data that will be passed to fdebug */
  char *errorbuffer; /* (Static) store failure messages in here */
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
  curl_seek_callback seek_func;      /* function that seeks the input */
  curl_off_t postfieldsize; /* if POST, this might have a size to use instead
                               of strlen(), and then the data *may* be binary
                               (contain zero bytes) */
#ifndef CURL_DISABLE_BINDLOCAL
  unsigned short localport; /* local port number to bind to */
  unsigned short localportrange; /* number of additional port numbers to test
                                    in case the 'localport' one can't be
                                    bind()ed */
#endif
  curl_write_callback fwrite_func;   /* function that stores the output */
  curl_write_callback fwrite_header; /* function that stores headers */
  curl_write_callback fwrite_rtp;    /* function that stores interleaved RTP */
  curl_read_callback fread_func_set; /* function that reads the input */
  curl_progress_callback fprogress; /* OLD and deprecated progress callback  */







|







1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
  curl_seek_callback seek_func;      /* function that seeks the input */
  curl_off_t postfieldsize; /* if POST, this might have a size to use instead
                               of strlen(), and then the data *may* be binary
                               (contain zero bytes) */
#ifndef CURL_DISABLE_BINDLOCAL
  unsigned short localport; /* local port number to bind to */
  unsigned short localportrange; /* number of additional port numbers to test
                                    in case the 'localport' one cannot be
                                    bind()ed */
#endif
  curl_write_callback fwrite_func;   /* function that stores the output */
  curl_write_callback fwrite_header; /* function that stores headers */
  curl_write_callback fwrite_rtp;    /* function that stores interleaved RTP */
  curl_read_callback fread_func_set; /* function that reads the input */
  curl_progress_callback fprogress; /* OLD and deprecated progress callback  */
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638

1639
1640
1641
1642
1643
1644
1645
  void *hsts_read_userp;
  curl_hstswrite_callback hsts_write;
  void *hsts_write_userp;
#endif
  void *progress_client; /* pointer to pass to the progress callback */
  void *ioctl_client;   /* pointer to pass to the ioctl callback */
  unsigned int timeout;        /* ms, 0 means no timeout */
  unsigned int connecttimeout; /* ms, 0 means no timeout */
  unsigned int happy_eyeballs_timeout; /* ms, 0 is a valid value */
  unsigned int server_response_timeout; /* ms, 0 means no timeout */

  long maxage_conn;     /* in seconds, max idle time to allow a connection that
                           is to be reused */
  long maxlifetime_conn; /* in seconds, max time since creation to allow a
                            connection that is to be reused */
#ifndef CURL_DISABLE_TFTP
  long tftp_blksize;    /* in bytes, 0 means use default */
#endif







|


>







1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
  void *hsts_read_userp;
  curl_hstswrite_callback hsts_write;
  void *hsts_write_userp;
#endif
  void *progress_client; /* pointer to pass to the progress callback */
  void *ioctl_client;   /* pointer to pass to the ioctl callback */
  unsigned int timeout;        /* ms, 0 means no timeout */
  unsigned int connecttimeout; /* ms, 0 means default timeout */
  unsigned int happy_eyeballs_timeout; /* ms, 0 is a valid value */
  unsigned int server_response_timeout; /* ms, 0 means no timeout */
  unsigned int shutdowntimeout; /* ms, 0 means default timeout */
  long maxage_conn;     /* in seconds, max idle time to allow a connection that
                           is to be reused */
  long maxlifetime_conn; /* in seconds, max time since creation to allow a
                            connection that is to be reused */
#ifndef CURL_DISABLE_TFTP
  long tftp_blksize;    /* in bytes, 0 means use default */
#endif
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
  unsigned int accepttimeout;   /* in milliseconds, 0 means no timeout */
#endif
#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
  struct curl_slist *quote;     /* after connection is established */
  struct curl_slist *postquote; /* after the transfer */
  struct curl_slist *prequote; /* before the transfer, after type */
  /* Despite the name, ftp_create_missing_dirs is for FTP(S) and SFTP
     1 - create directories that don't exist
     2 - the same but also allow MKD to fail once
  */
  unsigned char ftp_create_missing_dirs;
#endif
#ifdef USE_LIBSSH2
  curl_sshhostkeycallback ssh_hostkeyfunc; /* hostkey check callback */
  void *ssh_hostkeyfunc_userp;         /* custom pointer to callback */







|







1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
  unsigned int accepttimeout;   /* in milliseconds, 0 means no timeout */
#endif
#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
  struct curl_slist *quote;     /* after connection is established */
  struct curl_slist *postquote; /* after the transfer */
  struct curl_slist *prequote; /* before the transfer, after type */
  /* Despite the name, ftp_create_missing_dirs is for FTP(S) and SFTP
     1 - create directories that do not exist
     2 - the same but also allow MKD to fail once
  */
  unsigned char ftp_create_missing_dirs;
#endif
#ifdef USE_LIBSSH2
  curl_sshhostkeycallback ssh_hostkeyfunc; /* hostkey check callback */
  void *ssh_hostkeyfunc_userp;         /* custom pointer to callback */
1743
1744
1745
1746
1747
1748
1749

1750
1751
1752
1753
1754
1755
1756
#endif
 /* GSS-API credential delegation, see the documentation of
    CURLOPT_GSSAPI_DELEGATION */
  unsigned char gssapi_delegation;

  int tcp_keepidle;     /* seconds in idle before sending keepalive probe */
  int tcp_keepintvl;    /* seconds between TCP keepalive probes */


  long expect_100_timeout; /* in milliseconds */
#if defined(USE_HTTP2) || defined(USE_HTTP3)
  struct Curl_data_priority priority;
#endif
  curl_resolver_start_callback resolver_start; /* optional callback called
                                                  before resolver start */







>







1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
#endif
 /* GSS-API credential delegation, see the documentation of
    CURLOPT_GSSAPI_DELEGATION */
  unsigned char gssapi_delegation;

  int tcp_keepidle;     /* seconds in idle before sending keepalive probe */
  int tcp_keepintvl;    /* seconds between TCP keepalive probes */
  int tcp_keepcnt;      /* maximum number of keepalive probes */

  long expect_100_timeout; /* in milliseconds */
#if defined(USE_HTTP2) || defined(USE_HTTP3)
  struct Curl_data_priority priority;
#endif
  curl_resolver_start_callback resolver_start; /* optional callback called
                                                  before resolver start */
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
  BIT(crlf);            /* convert crlf on ftp upload(?) */
#ifdef USE_SSH
  BIT(ssh_compression);            /* enable SSH compression */
#endif

/* Here follows boolean settings that define how to behave during
   this session. They are STATIC, set by libcurl users or at least initially
   and they don't change during operations. */
  BIT(quick_exit);       /* set 1L when it is okay to leak things (like
                            threads), as we're about to exit() anyway and
                            don't want lengthy cleanups to delay termination,
                            e.g. after a DNS timeout */
  BIT(get_filetime);     /* get the time and get of the remote file */
#ifndef CURL_DISABLE_PROXY
  BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
#endif
  BIT(prefer_ascii);     /* ASCII rather than binary */
  BIT(remote_append);    /* append, not overwrite, on upload */
#ifdef CURL_LIST_ONLY_PROTOCOL
  BIT(list_only);        /* list directory */
#endif
#ifndef CURL_DISABLE_FTP
  BIT(ftp_use_port);     /* use the FTP PORT command */
  BIT(ftp_use_epsv);     /* if EPSV is to be attempted or not */
  BIT(ftp_use_eprt);     /* if EPRT is to be attempted or not */
  BIT(ftp_use_pret);     /* if PRET is to be used before PASV or not */
  BIT(ftp_skip_ip);      /* skip the IP address the FTP server passes on to
                            us */
  BIT(wildcard_enabled); /* enable wildcard matching */
#endif
  BIT(hide_progress);    /* don't use the progress meter */
  BIT(http_fail_on_error);  /* fail on HTTP error codes >= 400 */
  BIT(http_keep_sending_on_error); /* for HTTP status codes >= 300 */
  BIT(http_follow_location); /* follow HTTP redirects */
  BIT(http_transfer_encoding); /* request compressed HTTP transfer-encoding */
  BIT(allow_auth_to_other_hosts);
  BIT(include_header); /* include received protocol headers in data output */
  BIT(http_set_referer); /* is a custom referer used */







|

|
|



















|







1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
  BIT(crlf);            /* convert crlf on ftp upload(?) */
#ifdef USE_SSH
  BIT(ssh_compression);            /* enable SSH compression */
#endif

/* Here follows boolean settings that define how to behave during
   this session. They are STATIC, set by libcurl users or at least initially
   and they do not change during operations. */
  BIT(quick_exit);       /* set 1L when it is okay to leak things (like
                            threads), as we are about to exit() anyway and
                            do not want lengthy cleanups to delay termination,
                            e.g. after a DNS timeout */
  BIT(get_filetime);     /* get the time and get of the remote file */
#ifndef CURL_DISABLE_PROXY
  BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
#endif
  BIT(prefer_ascii);     /* ASCII rather than binary */
  BIT(remote_append);    /* append, not overwrite, on upload */
#ifdef CURL_LIST_ONLY_PROTOCOL
  BIT(list_only);        /* list directory */
#endif
#ifndef CURL_DISABLE_FTP
  BIT(ftp_use_port);     /* use the FTP PORT command */
  BIT(ftp_use_epsv);     /* if EPSV is to be attempted or not */
  BIT(ftp_use_eprt);     /* if EPRT is to be attempted or not */
  BIT(ftp_use_pret);     /* if PRET is to be used before PASV or not */
  BIT(ftp_skip_ip);      /* skip the IP address the FTP server passes on to
                            us */
  BIT(wildcard_enabled); /* enable wildcard matching */
#endif
  BIT(hide_progress);    /* do not use the progress meter */
  BIT(http_fail_on_error);  /* fail on HTTP error codes >= 400 */
  BIT(http_keep_sending_on_error); /* for HTTP status codes >= 300 */
  BIT(http_follow_location); /* follow HTTP redirects */
  BIT(http_transfer_encoding); /* request compressed HTTP transfer-encoding */
  BIT(allow_auth_to_other_hosts);
  BIT(include_header); /* include received protocol headers in data output */
  BIT(http_set_referer); /* is a custom referer used */
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
#ifndef CURL_DISABLE_PROXY
  BIT(haproxyprotocol); /* whether to send HAProxy PROXY protocol v1
                           header */
#endif
#ifdef USE_UNIX_SOCKETS
  BIT(abstract_unix_socket);
#endif
  BIT(disallow_username_in_url); /* disallow username in url */
#ifndef CURL_DISABLE_DOH
  BIT(doh); /* DNS-over-HTTPS enabled */
  BIT(doh_verifypeer);     /* DoH certificate peer verification */
  BIT(doh_verifyhost);     /* DoH certificate hostname verification */
  BIT(doh_verifystatus);   /* DoH certificate status verification */
#endif
  BIT(http09_allowed); /* allow HTTP/0.9 responses */







|







1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
#ifndef CURL_DISABLE_PROXY
  BIT(haproxyprotocol); /* whether to send HAProxy PROXY protocol v1
                           header */
#endif
#ifdef USE_UNIX_SOCKETS
  BIT(abstract_unix_socket);
#endif
  BIT(disallow_username_in_url); /* disallow username in URL */
#ifndef CURL_DISABLE_DOH
  BIT(doh); /* DNS-over-HTTPS enabled */
  BIT(doh_verifypeer);     /* DoH certificate peer verification */
  BIT(doh_verifyhost);     /* DoH certificate hostname verification */
  BIT(doh_verifystatus);   /* DoH certificate status verification */
#endif
  BIT(http09_allowed); /* allow HTTP/0.9 responses */
Changes to jni/curl/lib/vauth/cleartext.c.
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  return CURLE_OK;
}

/*
 * Curl_auth_create_login_message()
 *
 * This is used to generate an already encoded LOGIN message containing the
 * user name or password ready for sending to the recipient.
 *
 * Parameters:
 *
 * valuep  [in]     - The user name or user's password.
 * out     [out]    - The result storage.
 *
 * Returns void.
 */
void Curl_auth_create_login_message(const char *valuep, struct bufref *out)
{
  Curl_bufref_set(out, valuep, strlen(valuep), NULL);
}

/*
 * Curl_auth_create_external_message()
 *
 * This is used to generate an already encoded EXTERNAL message containing
 * the user name ready for sending to the recipient.
 *
 * Parameters:
 *
 * user    [in]     - The user name.
 * out     [out]    - The result storage.
 *
 * Returns void.
 */
void Curl_auth_create_external_message(const char *user,
                                           struct bufref *out)
{







|



|













|



|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  return CURLE_OK;
}

/*
 * Curl_auth_create_login_message()
 *
 * This is used to generate an already encoded LOGIN message containing the
 * username or password ready for sending to the recipient.
 *
 * Parameters:
 *
 * valuep  [in]     - The username or user's password.
 * out     [out]    - The result storage.
 *
 * Returns void.
 */
void Curl_auth_create_login_message(const char *valuep, struct bufref *out)
{
  Curl_bufref_set(out, valuep, strlen(valuep), NULL);
}

/*
 * Curl_auth_create_external_message()
 *
 * This is used to generate an already encoded EXTERNAL message containing
 * the username ready for sending to the recipient.
 *
 * Parameters:
 *
 * user    [in]     - The username.
 * out     [out]    - The result storage.
 *
 * Returns void.
 */
void Curl_auth_create_external_message(const char *user,
                                           struct bufref *out)
{
Changes to jni/curl/lib/vauth/cram.c.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 *
 * This is used to generate a CRAM-MD5 response message ready for sending to
 * the recipient.
 *
 * Parameters:
 *
 * chlg    [in]     - The challenge.
 * userp   [in]     - The user name.
 * passwdp [in]     - The user's password.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
                                           const char *userp,







|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 *
 * This is used to generate a CRAM-MD5 response message ready for sending to
 * the recipient.
 *
 * Parameters:
 *
 * chlg    [in]     - The challenge.
 * userp   [in]     - The username.
 * passwdp [in]     - The user's password.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
                                           const char *userp,
Changes to jni/curl/lib/vauth/digest.c.
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
          escape = TRUE;
          continue;
        }
        break;

      case ',':
        if(!starts_with_quote) {
          /* This signals the end of the content if we didn't get a starting
             quote and then we do "sloppy" parsing */
          c = 0; /* the end */
          continue;
        }
        break;

      case '\r':







|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
          escape = TRUE;
          continue;
        }
        break;

      case ',':
        if(!starts_with_quote) {
          /* This signals the end of the content if we did not get a starting
             quote and then we do "sloppy" parsing */
          c = 0; /* the end */
          continue;
        }
        break;

      case '\r':
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
 * This is used to generate an already encoded DIGEST-MD5 response message
 * ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg    [in]     - The challenge message.
 * userp   [in]     - The user name.
 * passwdp [in]     - The user's password.
 * service [in]     - The service type such as http, smtp, pop or imap.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,







|







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
 * This is used to generate an already encoded DIGEST-MD5 response message
 * ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg    [in]     - The challenge message.
 * userp   [in]     - The username.
 * passwdp [in]     - The user's password.
 * service [in]     - The service type such as http, smtp, pop or imap.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
        }
      }
      else {
        /* Unknown specifier, ignore it! */
      }
    }
    else
      break; /* We're done here */

    /* Pass all additional spaces here */
    while(*chlg && ISBLANK(*chlg))
      chlg++;

    /* Allow the list to be comma-separated */
    if(',' == *chlg)
      chlg++;
  }

  /* We had a nonce since before, and we got another one now without
     'stale=true'. This means we provided bad credentials in the previous
     request */
  if(before && !digest->stale)
    return CURLE_BAD_CONTENT_ENCODING;

  /* We got this header without a nonce, that's a bad Digest line! */
  if(!digest->nonce)
    return CURLE_BAD_CONTENT_ENCODING;

  /* "<algo>-sess" protocol versions require "auth" or "auth-int" qop */
  if(!digest->qop && (digest->algo & SESSION_ALGO))
    return CURLE_BAD_CONTENT_ENCODING;

  return CURLE_OK;
}

/*
 * auth_create_digest_http_message()
 *
 * This is used to generate an HTTP DIGEST response message ready for sending
 * to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The user name.
 * passwdp [in]     - The user's password.
 * request [in]     - The HTTP request.
 * uripath [in]     - The path of the HTTP uri.
 * digest  [in/out] - The digest data struct being used and modified.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.







|
















|



















|







625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
        }
      }
      else {
        /* Unknown specifier, ignore it! */
      }
    }
    else
      break; /* We are done here */

    /* Pass all additional spaces here */
    while(*chlg && ISBLANK(*chlg))
      chlg++;

    /* Allow the list to be comma-separated */
    if(',' == *chlg)
      chlg++;
  }

  /* We had a nonce since before, and we got another one now without
     'stale=true'. This means we provided bad credentials in the previous
     request */
  if(before && !digest->stale)
    return CURLE_BAD_CONTENT_ENCODING;

  /* We got this header without a nonce, that is a bad Digest line! */
  if(!digest->nonce)
    return CURLE_BAD_CONTENT_ENCODING;

  /* "<algo>-sess" protocol versions require "auth" or "auth-int" qop */
  if(!digest->qop && (digest->algo & SESSION_ALGO))
    return CURLE_BAD_CONTENT_ENCODING;

  return CURLE_OK;
}

/*
 * auth_create_digest_http_message()
 *
 * This is used to generate an HTTP DIGEST response message ready for sending
 * to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The username.
 * passwdp [in]     - The user's password.
 * request [in]     - The HTTP request.
 * uripath [in]     - The path of the HTTP uri.
 * digest  [in/out] - The digest data struct being used and modified.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
  */

  hashthis = aprintf("%s:%s", request, uripath);
  if(!hashthis)
    return CURLE_OUT_OF_MEMORY;

  if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
    /* We don't support auth-int for PUT or POST */
    char hashed[65];
    char *hashthis2;

    result = hash(hashbuf, (const unsigned char *)"", 0);
    if(result) {
      free(hashthis);
      return result;







|







784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
  */

  hashthis = aprintf("%s:%s", request, uripath);
  if(!hashthis)
    return CURLE_OUT_OF_MEMORY;

  if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
    /* We do not support auth-int for PUT or POST */
    char hashed[65];
    char *hashthis2;

    result = hash(hashbuf, (const unsigned char *)"", 0);
    if(result) {
      free(hashthis);
      return result;
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
  convert_to_ascii(hashbuf, request_digest);

  /* For test case 64 (snooped from a Mozilla 1.3a request)

     Authorization: Digest username="testuser", realm="testrealm", \
     nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"

     Digest parameters are all quoted strings.  Username which is provided by
     the user will need double quotes and backslashes within it escaped.
     realm, nonce, and opaque will need backslashes as well as they were
     de-escaped when copied from request header.  cnonce is generated with
     web-safe characters.  uri is already percent encoded.  nc is 8 hex
     characters.  algorithm and qop with standard values only contain web-safe
     characters.
  */
  userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
  if(!userp_quoted)
    return CURLE_OUT_OF_MEMORY;
  if(digest->realm)
    realm_quoted = auth_digest_string_quoted(digest->realm);







|


|
|
|







831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
  convert_to_ascii(hashbuf, request_digest);

  /* For test case 64 (snooped from a Mozilla 1.3a request)

     Authorization: Digest username="testuser", realm="testrealm", \
     nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"

     Digest parameters are all quoted strings. Username which is provided by
     the user will need double quotes and backslashes within it escaped.
     realm, nonce, and opaque will need backslashes as well as they were
     de-escaped when copied from request header. cnonce is generated with
     web-safe characters. uri is already percent encoded. nc is 8 hex
     characters. algorithm and qop with standard values only contain web-safe
     characters.
  */
  userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
  if(!userp_quoted)
    return CURLE_OUT_OF_MEMORY;
  if(digest->realm)
    realm_quoted = auth_digest_string_quoted(digest->realm);
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
 *
 * This is used to generate an HTTP DIGEST response message ready for sending
 * to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The user name.
 * passwdp [in]     - The user's password.
 * request [in]     - The HTTP request.
 * uripath [in]     - The path of the HTTP uri.
 * digest  [in/out] - The digest data struct being used and modified.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.







|







953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
 *
 * This is used to generate an HTTP DIGEST response message ready for sending
 * to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The username.
 * passwdp [in]     - The user's password.
 * request [in]     - The HTTP request.
 * uripath [in]     - The path of the HTTP uri.
 * digest  [in/out] - The digest data struct being used and modified.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
Changes to jni/curl/lib/vauth/digest_sspi.c.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
 * This is used to generate an already encoded DIGEST-MD5 response message
 * ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg    [in]     - The challenge message.
 * userp   [in]     - The user name in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * service [in]     - The service type such as http, smtp, pop or imap.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,







|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
 * This is used to generate an already encoded DIGEST-MD5 response message
 * ready for sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * chlg    [in]     - The challenge message.
 * userp   [in]     - The username in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * service [in]     - The service type such as http, smtp, pop or imap.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Query the security package for DigestSSP */
  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
                                              &SecurityPackage);
  if(status != SEC_E_OK) {
    failf(data, "SSPI: couldn't get auth info");
    return CURLE_AUTH_ERROR;
  }

  token_max = SecurityPackage->cbMaxToken;

  /* Release the package buffer as it is not required anymore */
  s_pSecFn->FreeContextBuffer(SecurityPackage);







|







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    return CURLE_BAD_CONTENT_ENCODING;
  }

  /* Query the security package for DigestSSP */
  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
                                              &SecurityPackage);
  if(status != SEC_E_OK) {
    failf(data, "SSPI: could not get auth info");
    return CURLE_AUTH_ERROR;
  }

  token_max = SecurityPackage->cbMaxToken;

  /* Release the package buffer as it is not required anymore */
  s_pSecFn->FreeContextBuffer(SecurityPackage);
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
          curlx_unicodefree(domain.tchar_ptr);
        }
        else {
          /* Unknown specifier, ignore it! */
        }
      }
      else
        break; /* We're done here */

      /* Pass all additional spaces here */
      while(*chlg && ISBLANK(*chlg))
        chlg++;

      /* Allow the list to be comma-separated */
      if(',' == *chlg)







|







287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
          curlx_unicodefree(domain.tchar_ptr);
        }
        else {
          /* Unknown specifier, ignore it! */
        }
      }
      else
        break; /* We are done here */

      /* Pass all additional spaces here */
      while(*chlg && ISBLANK(*chlg))
        chlg++;

      /* Allow the list to be comma-separated */
      if(',' == *chlg)
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
                                              struct digestdata *digest)
{
  size_t chlglen = strlen(chlg);

  /* We had an input token before so if there's another one now that means we
     provided bad credentials in the previous request or it's stale. */
  if(digest->input_token) {
    bool stale = false;
    const char *p = chlg;

    /* Check for the 'stale' directive */
    for(;;) {
      char value[DIGEST_MAX_VALUE_LENGTH];







|
|







320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
                                              struct digestdata *digest)
{
  size_t chlglen = strlen(chlg);

  /* We had an input token before so if there is another one now that means we
     provided bad credentials in the previous request or it is stale. */
  if(digest->input_token) {
    bool stale = false;
    const char *p = chlg;

    /* Check for the 'stale' directive */
    for(;;) {
      char value[DIGEST_MAX_VALUE_LENGTH];
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
 *
 * This is used to generate an HTTP DIGEST response message ready for sending
 * to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The user name in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * request [in]     - The HTTP request.
 * uripath [in]     - The path of the HTTP uri.
 * digest  [in/out] - The digest data struct being used and modified.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.







|







375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
 *
 * This is used to generate an HTTP DIGEST response message ready for sending
 * to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The username in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * request [in]     - The HTTP request.
 * uripath [in]     - The path of the HTTP uri.
 * digest  [in/out] - The digest data struct being used and modified.
 * outptr  [in/out] - The address where a pointer to newly allocated memory
 *                    holding the result will be stored upon completion.
 * outlen  [out]    - The length of the output message.
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423

  (void) data;

  /* Query the security package for DigestSSP */
  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
                                              &SecurityPackage);
  if(status != SEC_E_OK) {
    failf(data, "SSPI: couldn't get auth info");
    return CURLE_AUTH_ERROR;
  }

  token_max = SecurityPackage->cbMaxToken;

  /* Release the package buffer as it is not required anymore */
  s_pSecFn->FreeContextBuffer(SecurityPackage);







|







409
410
411
412
413
414
415
416
417
418
419
420
421
422
423

  (void) data;

  /* Query the security package for DigestSSP */
  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
                                              &SecurityPackage);
  if(status != SEC_E_OK) {
    failf(data, "SSPI: could not get auth info");
    return CURLE_AUTH_ERROR;
  }

  token_max = SecurityPackage->cbMaxToken;

  /* Release the package buffer as it is not required anymore */
  s_pSecFn->FreeContextBuffer(SecurityPackage);
Changes to jni/curl/lib/vauth/krb5_gssapi.c.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
 * message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * userp       [in]     - The user name.
 * passwdp     [in]     - The user's password.
 * service     [in]     - The service type such as http, smtp, pop or imap.
 * host        [in[     - The host name.
 * mutual_auth [in]     - Flag specifying whether or not mutual authentication
 *                        is enabled.
 * chlg        [in]     - Optional challenge message.
 * krb5        [in/out] - The Kerberos 5 data struct being used and modified.
 * out         [out]    - The result storage.
 *
 * Returns CURLE_OK on success.







|


|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
 * message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * userp       [in]     - The username.
 * passwdp     [in]     - The user's password.
 * service     [in]     - The service type such as http, smtp, pop or imap.
 * host        [in[     - The hostname.
 * mutual_auth [in]     - Flag specifying whether or not mutual authentication
 *                        is enabled.
 * chlg        [in]     - Optional challenge message.
 * krb5        [in/out] - The Kerberos 5 data struct being used and modified.
 * out         [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
    return CURLE_BAD_CONTENT_ENCODING;
  }
  sec_layer &= GSSAUTH_P_NONE;  /* We do not support a security layer */

  /* Process the maximum message size the server can receive */
  if(max_size > 0) {
    /* The server has told us it supports a maximum receive buffer, however, as
       we don't require one unless we are encrypting data, we tell the server
       our receive buffer is zero. */
    max_size = 0;
  }

  /* Allocate our message */
  messagelen = 4;
  if(authzid)







|







239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
    return CURLE_BAD_CONTENT_ENCODING;
  }
  sec_layer &= GSSAUTH_P_NONE;  /* We do not support a security layer */

  /* Process the maximum message size the server can receive */
  if(max_size > 0) {
    /* The server has told us it supports a maximum receive buffer, however, as
       we do not require one unless we are encrypting data, we tell the server
       our receive buffer is zero. */
    max_size = 0;
  }

  /* Allocate our message */
  messagelen = 4;
  if(authzid)
Changes to jni/curl/lib/vauth/krb5_sspi.c.
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
 * message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * userp       [in]     - The user name in the format User or Domain\User.
 * passwdp     [in]     - The user's password.
 * service     [in]     - The service type such as http, smtp, pop or imap.
 * host        [in]     - The host name.
 * mutual_auth [in]     - Flag specifying whether or not mutual authentication
 *                        is enabled.
 * chlg        [in]     - Optional challenge message.
 * krb5        [in/out] - The Kerberos 5 data struct being used and modified.
 * out         [out]    - The result storage.
 *
 * Returns CURLE_OK on success.







|


|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
 *
 * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
 * message ready for sending to the recipient.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * userp       [in]     - The username in the format User or Domain\User.
 * passwdp     [in]     - The user's password.
 * service     [in]     - The service type such as http, smtp, pop or imap.
 * host        [in]     - The hostname.
 * mutual_auth [in]     - Flag specifying whether or not mutual authentication
 *                        is enabled.
 * chlg        [in]     - Optional challenge message.
 * krb5        [in/out] - The Kerberos 5 data struct being used and modified.
 * out         [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

  if(!krb5->output_token) {
    /* Query the security package for Kerberos */
    status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
                                                TEXT(SP_NAME_KERBEROS),
                                                &SecurityPackage);
    if(status != SEC_E_OK) {
      failf(data, "SSPI: couldn't get auth info");
      return CURLE_AUTH_ERROR;
    }

    krb5->token_max = SecurityPackage->cbMaxToken;

    /* Release the package buffer as it is not required anymore */
    s_pSecFn->FreeContextBuffer(SecurityPackage);







|







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

  if(!krb5->output_token) {
    /* Query the security package for Kerberos */
    status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
                                                TEXT(SP_NAME_KERBEROS),
                                                &SecurityPackage);
    if(status != SEC_E_OK) {
      failf(data, "SSPI: could not get auth info");
      return CURLE_AUTH_ERROR;
    }

    krb5->token_max = SecurityPackage->cbMaxToken;

    /* Release the package buffer as it is not required anymore */
    s_pSecFn->FreeContextBuffer(SecurityPackage);
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
    return CURLE_BAD_CONTENT_ENCODING;
  }
  sec_layer &= KERB_WRAP_NO_ENCRYPT;  /* We do not support a security layer */

  /* Process the maximum message size the server can receive */
  if(max_size > 0) {
    /* The server has told us it supports a maximum receive buffer, however, as
       we don't require one unless we are encrypting data, we tell the server
       our receive buffer is zero. */
    max_size = 0;
  }

  /* Allocate the trailer */
  trailer = malloc(sizes.cbSecurityTrailer);
  if(!trailer)







|







331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
    return CURLE_BAD_CONTENT_ENCODING;
  }
  sec_layer &= KERB_WRAP_NO_ENCRYPT;  /* We do not support a security layer */

  /* Process the maximum message size the server can receive */
  if(max_size > 0) {
    /* The server has told us it supports a maximum receive buffer, however, as
       we do not require one unless we are encrypting data, we tell the server
       our receive buffer is zero. */
    max_size = 0;
  }

  /* Allocate the trailer */
  trailer = malloc(sizes.cbSecurityTrailer);
  if(!trailer)
Changes to jni/curl/lib/vauth/ntlm.c.
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* The last #include files should be: */
#include "curl_memory.h"
#include "memdebug.h"

/* "NTLMSSP" signature is always in ASCII regardless of the platform */
#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"

/* The fixed host name we provide, in order to not leak our real local host
   name. Copy the name used by Firefox. */
#define NTLM_HOSTNAME "WORKSTATION"

#if DEBUG_ME
# define DEBUG_OUT(x) x
static void ntlm_print_flags(FILE *handle, unsigned long flags)
{







|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* The last #include files should be: */
#include "curl_memory.h"
#include "memdebug.h"

/* "NTLMSSP" signature is always in ASCII regardless of the platform */
#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"

/* The fixed hostname we provide, in order to not leak our real local host
   name. Copy the name used by Firefox. */
#define NTLM_HOSTNAME "WORKSTATION"

#if DEBUG_ME
# define DEBUG_OUT(x) x
static void ntlm_print_flags(FILE *handle, unsigned long flags)
{
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
 *
 * This is used to generate an NTLM type-1 message ready for sending to the
 * recipient using the appropriate compile time crypto API.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The user name in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * service [in]     - The service type such as http, smtp, pop or imap.
 * host    [in]     - The host name.
 * ntlm    [in/out] - The NTLM data struct being used and modified.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
                                             const char *userp,







|


|







321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
 *
 * This is used to generate an NTLM type-1 message ready for sending to the
 * recipient using the appropriate compile time crypto API.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The username in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * service [in]     - The service type such as http, smtp, pop or imap.
 * host    [in]     - The hostname.
 * ntlm    [in/out] - The NTLM data struct being used and modified.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
                                             const char *userp,
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
                    "%c%c%c%c"   /* 32-bit NTLM flag field */
                    "%c%c"       /* domain length */
                    "%c%c"       /* domain allocated space */
                    "%c%c"       /* domain name offset */
                    "%c%c"       /* 2 zeroes */
                    "%c%c"       /* host length */
                    "%c%c"       /* host allocated space */
                    "%c%c"       /* host name offset */
                    "%c%c"       /* 2 zeroes */
                    "%s"         /* host name */
                    "%s",        /* domain string */
                    0,           /* trailing zero */
                    0, 0, 0,     /* part of type-1 long */

                    LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
                                NTLMFLAG_REQUEST_TARGET |
                                NTLMFLAG_NEGOTIATE_NTLM_KEY |







|

|







380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
                    "%c%c%c%c"   /* 32-bit NTLM flag field */
                    "%c%c"       /* domain length */
                    "%c%c"       /* domain allocated space */
                    "%c%c"       /* domain name offset */
                    "%c%c"       /* 2 zeroes */
                    "%c%c"       /* host length */
                    "%c%c"       /* host allocated space */
                    "%c%c"       /* hostname offset */
                    "%c%c"       /* 2 zeroes */
                    "%s"         /* hostname */
                    "%s",        /* domain string */
                    0,           /* trailing zero */
                    0, 0, 0,     /* part of type-1 long */

                    LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
                                NTLMFLAG_REQUEST_TARGET |
                                NTLMFLAG_NEGOTIATE_NTLM_KEY |
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
 *
 * This is used to generate an already encoded NTLM type-3 message ready for
 * sending to the recipient using the appropriate compile time crypto API.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The user name in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * ntlm    [in/out] - The NTLM data struct being used and modified.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,







|







444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
 *
 * This is used to generate an already encoded NTLM type-3 message ready for
 * sending to the recipient using the appropriate compile time crypto API.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The username in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * ntlm    [in/out] - The NTLM data struct being used and modified.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
          Index  Description            Content
            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
                                        (0x4e544c4d53535000)
            8    NTLM Message Type      long (0x03000000)
           12    LM/LMv2 Response       security buffer
           20    NTLM/NTLMv2 Response   security buffer
           28    Target Name            security buffer
           36    User Name              security buffer
           44    Workstation Name       security buffer
          (52)   Session Key            security buffer (*)
          (60)   Flags                  long (*)
          (64)   OS Version Structure   8 bytes (*)
  52 (64) (72)   Start of data block
                                          (*) -> Optional
  */

  CURLcode result = CURLE_OK;
  size_t size;
  unsigned char ntlmbuf[NTLM_BUFSIZE];
  int lmrespoff;
  unsigned char lmresp[24]; /* fixed-size */
  int ntrespoff;
  unsigned int ntresplen = 24;
  unsigned char ntresp[24]; /* fixed-size */
  unsigned char *ptr_ntresp = &ntresp[0];
  unsigned char *ntlmv2resp = NULL;
  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
  char host[HOSTNAME_MAX + 1] = "";
  const char *user;







|











|

|







466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
          Index  Description            Content
            0    NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
                                        (0x4e544c4d53535000)
            8    NTLM Message Type      long (0x03000000)
           12    LM/LMv2 Response       security buffer
           20    NTLM/NTLMv2 Response   security buffer
           28    Target Name            security buffer
           36    username              security buffer
           44    Workstation Name       security buffer
          (52)   Session Key            security buffer (*)
          (60)   Flags                  long (*)
          (64)   OS Version Structure   8 bytes (*)
  52 (64) (72)   Start of data block
                                          (*) -> Optional
  */

  CURLcode result = CURLE_OK;
  size_t size;
  unsigned char ntlmbuf[NTLM_BUFSIZE];
  unsigned int lmrespoff;
  unsigned char lmresp[24]; /* fixed-size */
  unsigned int ntrespoff;
  unsigned int ntresplen = 24;
  unsigned char ntresp[24]; /* fixed-size */
  unsigned char *ptr_ntresp = &ntresp[0];
  unsigned char *ntlmv2resp = NULL;
  bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
  char host[HOSTNAME_MAX + 1] = "";
  const char *user;
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
  }
  else
    user = userp;

  userlen = strlen(user);

#ifndef NTLM_HOSTNAME
  /* Get the machine's un-qualified host name as NTLM doesn't like the fully
     qualified domain name */
  if(Curl_gethostname(host, sizeof(host))) {
    infof(data, "gethostname() failed, continuing without");
    hostlen = 0;
  }
  else {
    hostlen = strlen(host);







|







513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
  }
  else
    user = userp;

  userlen = strlen(user);

#ifndef NTLM_HOSTNAME
  /* Get the machine's un-qualified hostname as NTLM does not like the fully
     qualified domain name */
  if(Curl_gethostname(host, sizeof(host))) {
    infof(data, "gethostname() failed, continuing without");
    hostlen = 0;
  }
  else {
    hostlen = strlen(host);
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);

    result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer);
    if(result)
      return result;

    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
    ntlm->flags &= ~NTLMFLAG_NEGOTIATE_NTLM2_KEY;

    /* A safer but less compatible alternative is:
     *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
     * See https://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
  }

  if(unicode) {







|







581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
    Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);

    result = Curl_ntlm_core_mk_lm_hash(passwdp, lmbuffer);
    if(result)
      return result;

    Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
    ntlm->flags &= ~(unsigned int)NTLMFLAG_NEGOTIATE_NTLM2_KEY;

    /* A safer but less compatible alternative is:
     *   Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
     * See https://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
  }

  if(unicode) {
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
    ntlm_print_flags(stderr, ntlm->flags);
    fprintf(stderr, "\n****\n");
  });

  /* Make sure that the domain, user and host strings fit in the
     buffer before we copy them there. */
  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
    failf(data, "user + domain + host name too big");
    return CURLE_OUT_OF_MEMORY;
  }

  DEBUGASSERT(size == domoff);
  if(unicode)
    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
  else







|







718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
    ntlm_print_flags(stderr, ntlm->flags);
    fprintf(stderr, "\n****\n");
  });

  /* Make sure that the domain, user and host strings fit in the
     buffer before we copy them there. */
  if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
    failf(data, "user + domain + hostname too big");
    return CURLE_OUT_OF_MEMORY;
  }

  DEBUGASSERT(size == domoff);
  if(unicode)
    unicodecpy(&ntlmbuf[size], domain, domlen / 2);
  else
Changes to jni/curl/lib/vauth/ntlm_sspi.c.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
 *
 * This is used to generate an already encoded NTLM type-1 message ready for
 * sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The user name in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * service [in]     - The service type such as http, smtp, pop or imap.
 * host    [in]     - The host name.
 * ntlm    [in/out] - The NTLM data struct being used and modified.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
                                             const char *userp,







|


|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
 *
 * This is used to generate an already encoded NTLM type-1 message ready for
 * sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The username in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * service [in]     - The service type such as http, smtp, pop or imap.
 * host    [in]     - The hostname.
 * ntlm    [in/out] - The NTLM data struct being used and modified.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
                                             const char *userp,
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  /* Clean up any former leftovers and initialise to defaults */
  Curl_auth_cleanup_ntlm(ntlm);

  /* Query the security package for NTLM */
  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
                                              &SecurityPackage);
  if(status != SEC_E_OK) {
    failf(data, "SSPI: couldn't get auth info");
    return CURLE_AUTH_ERROR;
  }

  ntlm->token_max = SecurityPackage->cbMaxToken;

  /* Release the package buffer as it is not required anymore */
  s_pSecFn->FreeContextBuffer(SecurityPackage);







|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  /* Clean up any former leftovers and initialise to defaults */
  Curl_auth_cleanup_ntlm(ntlm);

  /* Query the security package for NTLM */
  status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
                                              &SecurityPackage);
  if(status != SEC_E_OK) {
    failf(data, "SSPI: could not get auth info");
    return CURLE_AUTH_ERROR;
  }

  ntlm->token_max = SecurityPackage->cbMaxToken;

  /* Release the package buffer as it is not required anymore */
  s_pSecFn->FreeContextBuffer(SecurityPackage);
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
 *
 * This is used to generate an already encoded NTLM type-3 message ready for
 * sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The user name in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * ntlm    [in/out] - The NTLM data struct being used and modified.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,







|







229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
 *
 * This is used to generate an already encoded NTLM type-3 message ready for
 * sending to the recipient.
 *
 * Parameters:
 *
 * data    [in]     - The session handle.
 * userp   [in]     - The username in the format User or Domain\User.
 * passwdp [in]     - The user's password.
 * ntlm    [in/out] - The NTLM data struct being used and modified.
 * out     [out]    - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
Changes to jni/curl/lib/vauth/oauth2.c.
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 * Curl_auth_create_oauth_bearer_message()
 *
 * This is used to generate an OAuth 2.0 message ready for sending to the
 * recipient.
 *
 * Parameters:
 *
 * user[in]         - The user name.
 * host[in]         - The host name.
 * port[in]         - The port(when not Port 80).
 * bearer[in]       - The bearer token.
 * out[out]         - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_oauth_bearer_message(const char *user,







|
|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 * Curl_auth_create_oauth_bearer_message()
 *
 * This is used to generate an OAuth 2.0 message ready for sending to the
 * recipient.
 *
 * Parameters:
 *
 * user[in]         - The username.
 * host[in]         - The hostname.
 * port[in]         - The port(when not Port 80).
 * bearer[in]       - The bearer token.
 * out[out]         - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_oauth_bearer_message(const char *user,
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
 * Curl_auth_create_xoauth_bearer_message()
 *
 * This is used to generate a XOAuth 2.0 message ready for * sending to the
 * recipient.
 *
 * Parameters:
 *
 * user[in]         - The user name.
 * bearer[in]       - The bearer token.
 * out[out]         - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
                                               const char *bearer,







|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
 * Curl_auth_create_xoauth_bearer_message()
 *
 * This is used to generate a XOAuth 2.0 message ready for * sending to the
 * recipient.
 *
 * Parameters:
 *
 * user[in]         - The username.
 * bearer[in]       - The bearer token.
 * out[out]         - The result storage.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
                                               const char *bearer,
Changes to jni/curl/lib/vauth/spnego_gssapi.c.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 *
 * This is used to decode an already encoded SPNEGO (Negotiate) challenge
 * message.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * userp       [in]     - The user name in the format User or Domain\User.
 * passwdp     [in]     - The user's password.
 * service     [in]     - The service type such as http, smtp, pop or imap.
 * host        [in]     - The host name.
 * chlg64      [in]     - The optional base64 encoded challenge message.
 * nego        [in/out] - The Negotiate data struct being used and modified.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
                                         const char *user,







|


|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 *
 * This is used to decode an already encoded SPNEGO (Negotiate) challenge
 * message.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * userp       [in]     - The username in the format User or Domain\User.
 * passwdp     [in]     - The user's password.
 * service     [in]     - The service type such as http, smtp, pop or imap.
 * host        [in]     - The hostname.
 * chlg64      [in]     - The optional base64 encoded challenge message.
 * nego        [in/out] - The Negotiate data struct being used and modified.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
                                         const char *user,
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;

  (void) user;
  (void) password;

  if(nego->context && nego->status == GSS_S_COMPLETE) {
    /* We finished successfully our part of authentication, but server
     * rejected it (since we're again here). Exit with an error since we
     * can't invent anything better */
    Curl_auth_cleanup_spnego(nego);
    return CURLE_LOGIN_DENIED;
  }

  if(!nego->spn) {
    /* Generate our SPN */
    char *spn = Curl_auth_build_spn(service, NULL, host);







|
|







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;

  (void) user;
  (void) password;

  if(nego->context && nego->status == GSS_S_COMPLETE) {
    /* We finished successfully our part of authentication, but server
     * rejected it (since we are again here). Exit with an error since we
     * cannot invent anything better */
    Curl_auth_cleanup_spnego(nego);
    return CURLE_LOGIN_DENIED;
  }

  if(!nego->spn) {
    /* Generate our SPN */
    char *spn = Curl_auth_build_spn(service, NULL, host);
Changes to jni/curl/lib/vauth/spnego_sspi.c.
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 *
 * This is used to decode an already encoded SPNEGO (Negotiate) challenge
 * message.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * user        [in]     - The user name in the format User or Domain\User.
 * password    [in]     - The user's password.
 * service     [in]     - The service type such as http, smtp, pop or imap.
 * host        [in]     - The host name.
 * chlg64      [in]     - The optional base64 encoded challenge message.
 * nego        [in/out] - The Negotiate data struct being used and modified.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
                                         const char *user,







|


|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 *
 * This is used to decode an already encoded SPNEGO (Negotiate) challenge
 * message.
 *
 * Parameters:
 *
 * data        [in]     - The session handle.
 * user        [in]     - The username in the format User or Domain\User.
 * password    [in]     - The user's password.
 * service     [in]     - The service type such as http, smtp, pop or imap.
 * host        [in]     - The hostname.
 * chlg64      [in]     - The optional base64 encoded challenge message.
 * nego        [in/out] - The Negotiate data struct being used and modified.
 *
 * Returns CURLE_OK on success.
 */
CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
                                         const char *user,
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

#if defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void) data;
#endif

  if(nego->context && nego->status == SEC_E_OK) {
    /* We finished successfully our part of authentication, but server
     * rejected it (since we're again here). Exit with an error since we
     * can't invent anything better */
    Curl_auth_cleanup_spnego(nego);
    return CURLE_LOGIN_DENIED;
  }

  if(!nego->spn) {
    /* Generate our SPN */
    nego->spn = Curl_auth_build_spn(service, host, NULL);
    if(!nego->spn)
      return CURLE_OUT_OF_MEMORY;
  }

  if(!nego->output_token) {
    /* Query the security package for Negotiate */
    nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
                                                      TEXT(SP_NAME_NEGOTIATE),
                                                      &SecurityPackage);
    if(nego->status != SEC_E_OK) {
      failf(data, "SSPI: couldn't get auth info");
      return CURLE_AUTH_ERROR;
    }

    nego->token_max = SecurityPackage->cbMaxToken;

    /* Release the package buffer as it is not required anymore */
    s_pSecFn->FreeContextBuffer(SecurityPackage);







|
|













|
|
|

|







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

#if defined(CURL_DISABLE_VERBOSE_STRINGS)
  (void) data;
#endif

  if(nego->context && nego->status == SEC_E_OK) {
    /* We finished successfully our part of authentication, but server
     * rejected it (since we are again here). Exit with an error since we
     * cannot invent anything better */
    Curl_auth_cleanup_spnego(nego);
    return CURLE_LOGIN_DENIED;
  }

  if(!nego->spn) {
    /* Generate our SPN */
    nego->spn = Curl_auth_build_spn(service, host, NULL);
    if(!nego->spn)
      return CURLE_OUT_OF_MEMORY;
  }

  if(!nego->output_token) {
    /* Query the security package for Negotiate */
    nego->status = (DWORD)s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
                                                       TEXT(SP_NAME_NEGOTIATE),
                                                       &SecurityPackage);
    if(nego->status != SEC_E_OK) {
      failf(data, "SSPI: could not get auth info");
      return CURLE_AUTH_ERROR;
    }

    nego->token_max = SecurityPackage->cbMaxToken;

    /* Release the package buffer as it is not required anymore */
    s_pSecFn->FreeContextBuffer(SecurityPackage);
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

    /* Allocate our credentials handle */
    nego->credentials = calloc(1, sizeof(CredHandle));
    if(!nego->credentials)
      return CURLE_OUT_OF_MEMORY;

    /* Acquire our credentials handle */
    nego->status =
      s_pSecFn->AcquireCredentialsHandle(NULL,
                                         (TCHAR *)TEXT(SP_NAME_NEGOTIATE),
                                         SECPKG_CRED_OUTBOUND, NULL,
                                         nego->p_identity, NULL, NULL,
                                         nego->credentials, &expiry);
    if(nego->status != SEC_E_OK)
      return CURLE_AUTH_ERROR;







|







164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

    /* Allocate our credentials handle */
    nego->credentials = calloc(1, sizeof(CredHandle));
    if(!nego->credentials)
      return CURLE_OUT_OF_MEMORY;

    /* Acquire our credentials handle */
    nego->status = (DWORD)
      s_pSecFn->AcquireCredentialsHandle(NULL,
                                         (TCHAR *)TEXT(SP_NAME_NEGOTIATE),
                                         SECPKG_CRED_OUTBOUND, NULL,
                                         nego->p_identity, NULL, NULL,
                                         nego->credentials, &expiry);
    if(nego->status != SEC_E_OK)
      return CURLE_AUTH_ERROR;
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    * https://docs.microsoft.com/en-us/security-updates
    * /SecurityAdvisories/2009/973811
    */
    if(nego->sslContext) {
      SEC_CHANNEL_BINDINGS channelBindings;
      SecPkgContext_Bindings pkgBindings;
      pkgBindings.Bindings = &channelBindings;
      nego->status = s_pSecFn->QueryContextAttributes(
          nego->sslContext,
          SECPKG_ATTR_ENDPOINT_BINDINGS,
          &pkgBindings
      );
      if(nego->status == SEC_E_OK) {
        chlg_desc.cBuffers++;
        chlg_buf[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;







|







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    * https://docs.microsoft.com/en-us/security-updates
    * /SecurityAdvisories/2009/973811
    */
    if(nego->sslContext) {
      SEC_CHANNEL_BINDINGS channelBindings;
      SecPkgContext_Bindings pkgBindings;
      pkgBindings.Bindings = &channelBindings;
      nego->status = (DWORD)s_pSecFn->QueryContextAttributes(
          nego->sslContext,
          SECPKG_ATTR_ENDPOINT_BINDINGS,
          &pkgBindings
      );
      if(nego->status == SEC_E_OK) {
        chlg_desc.cBuffers++;
        chlg_buf[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

273
274
275
276
277
278
279
280
281
282
283
  resp_desc.cBuffers  = 1;
  resp_desc.pBuffers  = &resp_buf;
  resp_buf.BufferType = SECBUFFER_TOKEN;
  resp_buf.pvBuffer   = nego->output_token;
  resp_buf.cbBuffer   = curlx_uztoul(nego->token_max);

  /* Generate our challenge-response message */
  nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials,
                                                     chlg ? nego->context :
                                                            NULL,
                                                     nego->spn,
                                                     ISC_REQ_CONFIDENTIALITY,
                                                     0, SECURITY_NATIVE_DREP,
                                                     chlg ? &chlg_desc : NULL,
                                                     0, nego->context,
                                                     &resp_desc, &attrs,
                                                     &expiry);

  /* Free the decoded challenge as it is not required anymore */
  free(chlg);

  if(GSS_ERROR(nego->status)) {
    char buffer[STRERROR_LEN];
    failf(data, "InitializeSecurityContext failed: %s",
          Curl_sspi_strerror(nego->status, buffer, sizeof(buffer)));

    if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY)
      return CURLE_OUT_OF_MEMORY;

    return CURLE_AUTH_ERROR;
  }

  if(nego->status == SEC_I_COMPLETE_NEEDED ||
     nego->status == SEC_I_COMPLETE_AND_CONTINUE) {
    nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc);

    if(GSS_ERROR(nego->status)) {
      char buffer[STRERROR_LEN];
      failf(data, "CompleteAuthToken failed: %s",
            Curl_sspi_strerror(nego->status, buffer, sizeof(buffer)));

      if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY)
        return CURLE_OUT_OF_MEMORY;

      return CURLE_AUTH_ERROR;
    }
  }







|
















|









|
>



|







238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  resp_desc.cBuffers  = 1;
  resp_desc.pBuffers  = &resp_buf;
  resp_buf.BufferType = SECBUFFER_TOKEN;
  resp_buf.pvBuffer   = nego->output_token;
  resp_buf.cbBuffer   = curlx_uztoul(nego->token_max);

  /* Generate our challenge-response message */
  nego->status = (DWORD)s_pSecFn->InitializeSecurityContext(nego->credentials,
                                                     chlg ? nego->context :
                                                            NULL,
                                                     nego->spn,
                                                     ISC_REQ_CONFIDENTIALITY,
                                                     0, SECURITY_NATIVE_DREP,
                                                     chlg ? &chlg_desc : NULL,
                                                     0, nego->context,
                                                     &resp_desc, &attrs,
                                                     &expiry);

  /* Free the decoded challenge as it is not required anymore */
  free(chlg);

  if(GSS_ERROR(nego->status)) {
    char buffer[STRERROR_LEN];
    failf(data, "InitializeSecurityContext failed: %s",
          Curl_sspi_strerror((int)nego->status, buffer, sizeof(buffer)));

    if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY)
      return CURLE_OUT_OF_MEMORY;

    return CURLE_AUTH_ERROR;
  }

  if(nego->status == SEC_I_COMPLETE_NEEDED ||
     nego->status == SEC_I_COMPLETE_AND_CONTINUE) {
    nego->status = (DWORD)s_pSecFn->CompleteAuthToken(nego->context,
                                                      &resp_desc);
    if(GSS_ERROR(nego->status)) {
      char buffer[STRERROR_LEN];
      failf(data, "CompleteAuthToken failed: %s",
            Curl_sspi_strerror((int)nego->status, buffer, sizeof(buffer)));

      if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY)
        return CURLE_OUT_OF_MEMORY;

      return CURLE_AUTH_ERROR;
    }
  }
Changes to jni/curl/lib/vauth/vauth.c.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 * service/host@realm (Not currently used)
 * service/host       (Not used by GSS-API)
 * service@realm      (Not used by Windows SSPI)
 *
 * Parameters:
 *
 * service  [in] - The service type such as http, smtp, pop or imap.
 * host     [in] - The host name.
 * realm    [in] - The realm.
 *
 * Returns a pointer to the newly allocated SPN.
 */
#if !defined(USE_WINDOWS_SSPI)
char *Curl_auth_build_spn(const char *service, const char *host,
                          const char *realm)







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 * service/host@realm (Not currently used)
 * service/host       (Not used by GSS-API)
 * service@realm      (Not used by Windows SSPI)
 *
 * Parameters:
 *
 * service  [in] - The service type such as http, smtp, pop or imap.
 * host     [in] - The hostname.
 * realm    [in] - The realm.
 *
 * Returns a pointer to the newly allocated SPN.
 */
#if !defined(USE_WINDOWS_SSPI)
char *Curl_auth_build_spn(const char *service, const char *host,
                          const char *realm)
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

  /* Generate our UTF8 based SPN */
  utf8_spn = aprintf("%s/%s", service, host);
  if(!utf8_spn)
    return NULL;

  /* Allocate and return a TCHAR based SPN. Since curlx_convert_UTF8_to_tchar
     must be freed by curlx_unicodefree we'll dupe the result so that the
     pointer this function returns can be normally free'd. */
  tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn);
  free(utf8_spn);
  if(!tchar_spn)
    return NULL;
  dupe_tchar_spn = _tcsdup(tchar_spn);
  curlx_unicodefree(tchar_spn);







|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

  /* Generate our UTF8 based SPN */
  utf8_spn = aprintf("%s/%s", service, host);
  if(!utf8_spn)
    return NULL;

  /* Allocate and return a TCHAR based SPN. Since curlx_convert_UTF8_to_tchar
     must be freed by curlx_unicodefree we will dupe the result so that the
     pointer this function returns can be normally free'd. */
  tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn);
  free(utf8_spn);
  if(!tchar_spn)
    return NULL;
  dupe_tchar_spn = _tcsdup(tchar_spn);
  curlx_unicodefree(tchar_spn);
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
 * This is used to test if the specified user contains a Windows domain name as
 * follows:
 *
 * Domain\User (Down-level Logon Name)
 * Domain/User (curl Down-level format - for compatibility with existing code)
 * User@Domain (User Principal Name)
 *
 * Note: The user name may be empty when using a GSS-API library or Windows
 * SSPI as the user and domain are either obtained from the credentials cache
 * when using GSS-API or via the currently logged in user's credentials when
 * using Windows SSPI.
 *
 * Parameters:
 *
 * user  [in] - The user name.
 *
 * Returns TRUE on success; otherwise FALSE.
 */
bool Curl_auth_user_contains_domain(const char *user)
{
  bool valid = FALSE;








|






|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
 * This is used to test if the specified user contains a Windows domain name as
 * follows:
 *
 * Domain\User (Down-level Logon Name)
 * Domain/User (curl Down-level format - for compatibility with existing code)
 * User@Domain (User Principal Name)
 *
 * Note: The username may be empty when using a GSS-API library or Windows
 * SSPI as the user and domain are either obtained from the credentials cache
 * when using GSS-API or via the currently logged in user's credentials when
 * using Windows SSPI.
 *
 * Parameters:
 *
 * user  [in] - The username.
 *
 * Returns TRUE on success; otherwise FALSE.
 */
bool Curl_auth_user_contains_domain(const char *user)
{
  bool valid = FALSE;

Changes to jni/curl/lib/version.c.
254
255
256
257
258
259
260
261
262
263
264

265
266
267
268
269
270
271
#endif
#ifdef USE_OPENLDAP
  {
    LDAPAPIInfo api;
    api.ldapai_info_version = LDAP_API_INFO_VERSION;

    if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
      unsigned int patch = api.ldapai_vendor_version % 100;
      unsigned int major = api.ldapai_vendor_version / 10000;
      unsigned int minor =
        ((api.ldapai_vendor_version - major * 10000) - patch) / 100;

      msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u",
                api.ldapai_vendor_name, major, minor, patch);
      src[i++] = ldap_buf;
      ldap_memfree(api.ldapai_vendor_name);
      ber_memvfree((void **)api.ldapai_extensions);
    }
  }







|
|

|
>







254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#endif
#ifdef USE_OPENLDAP
  {
    LDAPAPIInfo api;
    api.ldapai_info_version = LDAP_API_INFO_VERSION;

    if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
      unsigned int patch = (unsigned int)(api.ldapai_vendor_version % 100);
      unsigned int major = (unsigned int)(api.ldapai_vendor_version / 10000);
      unsigned int minor =
        (((unsigned int)api.ldapai_vendor_version - major * 10000)
          - patch) / 100;
      msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u",
                api.ldapai_vendor_name, major, minor, patch);
      src[i++] = ldap_buf;
      ldap_memfree(api.ldapai_vendor_name);
      ber_memvfree((void **)api.ldapai_extensions);
    }
  }
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  "wss",
#endif

  NULL
};

/*
 * Feature presence run-time check functions.
 *
 * Warning: the value returned by these should not change between
 * curl_global_init() and curl_global_cleanup() calls.
 */

#if defined(USE_LIBIDN2)
static int idn_present(curl_version_info_data *info)







|







391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  "wss",
#endif

  NULL
};

/*
 * Feature presence runtime check functions.
 *
 * Warning: the value returned by these should not change between
 * curl_global_init() and curl_global_cleanup() calls.
 */

#if defined(USE_LIBIDN2)
static int idn_present(curl_version_info_data *info)
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550


static curl_version_info_data version_info = {
  CURLVERSION_NOW,
  LIBCURL_VERSION,
  LIBCURL_VERSION_NUM,
  OS,   /* as found by configure or set by hand at build-time */
  0,    /* features bitmask is built at run-time */
  NULL, /* ssl_version */
  0,    /* ssl_version_num, this is kept at zero */
  NULL, /* zlib_version */
  supported_protocols,
  NULL, /* c-ares version */
  0,    /* c-ares version numerical */
  NULL, /* libidn version */







|







537
538
539
540
541
542
543
544
545
546
547
548
549
550
551


static curl_version_info_data version_info = {
  CURLVERSION_NOW,
  LIBCURL_VERSION,
  LIBCURL_VERSION_NUM,
  OS,   /* as found by configure or set by hand at build-time */
  0,    /* features bitmask is built at runtime */
  NULL, /* ssl_version */
  0,    /* ssl_version_num, this is kept at zero */
  NULL, /* zlib_version */
  supported_protocols,
  NULL, /* c-ares version */
  0,    /* c-ares version numerical */
  NULL, /* libidn version */
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
#ifdef HAVE_BROTLI
  static char brotli_buffer[80];
#endif
#ifdef HAVE_ZSTD
  static char zstd_buffer[80];
#endif

  (void)stamp; /* avoid compiler warnings, we don't use this */

#ifdef USE_SSL
  Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
  version_info.ssl_version = ssl_buffer;
#endif

#ifdef HAVE_LIBZ







|







593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
#ifdef HAVE_BROTLI
  static char brotli_buffer[80];
#endif
#ifdef HAVE_ZSTD
  static char zstd_buffer[80];
#endif

  (void)stamp; /* avoid compiler warnings, we do not use this */

#ifdef USE_SSL
  Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
  version_info.ssl_version = ssl_buffer;
#endif

#ifdef HAVE_LIBZ
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  zstd_version(zstd_buffer, sizeof(zstd_buffer));
  version_info.zstd_version = zstd_buffer;
#endif

#ifdef USE_NGHTTP2
  {
    nghttp2_info *h2 = nghttp2_version(0);
    version_info.nghttp2_ver_num = h2->version_num;
    version_info.nghttp2_version = h2->version_str;
  }
#endif

#ifdef USE_HTTP3
  {
    static char quicbuffer[80];







|







637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
  zstd_version(zstd_buffer, sizeof(zstd_buffer));
  version_info.zstd_version = zstd_buffer;
#endif

#ifdef USE_NGHTTP2
  {
    nghttp2_info *h2 = nghttp2_version(0);
    version_info.nghttp2_ver_num = (unsigned int)h2->version_num;
    version_info.nghttp2_version = h2->version_str;
  }
#endif

#ifdef USE_HTTP3
  {
    static char quicbuffer[80];
Changes to jni/curl/lib/version_win32.c.
26
27
28
29
30
31
32
33

34

35
36
37
38
39
40
41

#if defined(_WIN32)

#include <curl/curl.h>
#include "version_win32.h"
#include "warnless.h"

/* The last #include files should be: */

#include "curl_memory.h"

#include "memdebug.h"

/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
   and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
struct OUR_OSVERSIONINFOEXW {
  ULONG  dwOSVersionInfoSize;
  ULONG  dwMajorVersion;







|
>

>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

#if defined(_WIN32)

#include <curl/curl.h>
#include "version_win32.h"
#include "warnless.h"

/* The last 2 #include files should be in this order */
#ifdef BUILDING_LIBCURL
#include "curl_memory.h"
#endif
#include "memdebug.h"

/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
   and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */
struct OUR_OSVERSIONINFOEXW {
  ULONG  dwOSVersionInfoSize;
  ULONG  dwMajorVersion;
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86


87
88
89
90
91
92
93
 *
 * majorVersion [in] - The major version number.
 * minorVersion [in] - The minor version number.
 * buildVersion [in] - The build version number. If 0, this parameter is
 *                     ignored.
 * platform     [in] - The optional platform identifier.
 * condition    [in] - The test condition used to specifier whether we are
 *                     checking a version less then, equal to or greater than
 *                     what is specified in the major and minor version
 *                     numbers.
 *
 * Returns TRUE if matched; otherwise FALSE.
 */
bool curlx_verify_windows_version(const unsigned int majorVersion,
                                  const unsigned int minorVersion,
                                  const unsigned int buildVersion,
                                  const PlatformIdentifier platform,
                                  const VersionCondition condition)
{
  bool matched = FALSE;

#if defined(CURL_WINDOWS_APP)
  (void)buildVersion;

  /* We have no way to determine the Windows version from Windows apps,
     so let's assume we're running on the target Windows version. */
  const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
  const WORD targetVersion = (WORD)_WIN32_WINNT;



  switch(condition) {
  case VERSION_LESS_THAN:
    matched = targetVersion < fullVersion;
    break;

  case VERSION_LESS_THAN_EQUAL:







|














<
<

|


>
>







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82


83
84
85
86
87
88
89
90
91
92
93
94
95
 *
 * majorVersion [in] - The major version number.
 * minorVersion [in] - The minor version number.
 * buildVersion [in] - The build version number. If 0, this parameter is
 *                     ignored.
 * platform     [in] - The optional platform identifier.
 * condition    [in] - The test condition used to specifier whether we are
 *                     checking a version less than, equal to or greater than
 *                     what is specified in the major and minor version
 *                     numbers.
 *
 * Returns TRUE if matched; otherwise FALSE.
 */
bool curlx_verify_windows_version(const unsigned int majorVersion,
                                  const unsigned int minorVersion,
                                  const unsigned int buildVersion,
                                  const PlatformIdentifier platform,
                                  const VersionCondition condition)
{
  bool matched = FALSE;

#if defined(CURL_WINDOWS_APP)


  /* We have no way to determine the Windows version from Windows apps,
     so let's assume we are running on the target Windows version. */
  const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
  const WORD targetVersion = (WORD)_WIN32_WINNT;

  (void)buildVersion;

  switch(condition) {
  case VERSION_LESS_THAN:
    matched = targetVersion < fullVersion;
    break;

  case VERSION_LESS_THAN_EQUAL:
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

  case VERSION_GREATER_THAN:
    matched = targetVersion > fullVersion;
    break;
  }

  if(matched && (platform == PLATFORM_WINDOWS)) {
    /* we're always running on PLATFORM_WINNT */
    matched = FALSE;
  }
#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
  OSVERSIONINFO osver;

  memset(&osver, 0, sizeof(osver));







|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

  case VERSION_GREATER_THAN:
    matched = targetVersion > fullVersion;
    break;
  }

  if(matched && (platform == PLATFORM_WINDOWS)) {
    /* we are always running on PLATFORM_WINNT */
    matched = FALSE;
  }
#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
  OSVERSIONINFO osver;

  memset(&osver, 0, sizeof(osver));
Changes to jni/curl/lib/vquic/curl_msh3.c.
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  msh3_header_received,
  msh3_data_received,
  msh3_complete,
  msh3_shutdown_complete,
  msh3_data_sent
};

/* Decode HTTP status code.  Returns -1 if no valid status code was
   decoded. (duplicate from http2.c) */
static int decode_status_code(const char *value, size_t len)
{
  int i;
  int res;

  if(len != 3) {







|







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  msh3_header_received,
  msh3_data_received,
  msh3_complete,
  msh3_shutdown_complete,
  msh3_data_sent
};

/* Decode HTTP status code. Returns -1 if no valid status code was
   decoded. (duplicate from http2.c) */
static int decode_status_code(const char *value, size_t len)
{
  int i;
  int res;

  if(len != 3) {
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
    if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_NONE, buf,
                        (uint32_t)len, stream)) {
      *err = CURLE_SEND_ERROR;
      goto out;
    }

    /* TODO - msh3/msquic will hold onto this memory until the send complete
       event. How do we make sure curl doesn't free it until then? */
    *err = CURLE_OK;
    nwritten = len;
  }

out:
  set_quic_expire(cf, data);
  free(nva);







|







685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
    if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_NONE, buf,
                        (uint32_t)len, stream)) {
      *err = CURLE_SEND_ERROR;
      goto out;
    }

    /* TODO - msh3/msquic will hold onto this memory until the send complete
       event. How do we make sure curl does not free it until then? */
    *err = CURLE_OK;
    nwritten = len;
  }

out:
  set_quic_expire(cf, data);
  free(nva);
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
  }

  CURL_TRC_CF(data, cf, "connecting to %s:%d (verify=%d)",
              cf->conn->host.name, (int)cf->conn->remote_port, verify);

  ctx->api = MsH3ApiOpen();
  if(!ctx->api) {
    failf(data, "can't create msh3 api");
    return CURLE_FAILED_INIT;
  }

  ctx->qconn = MsH3ConnectionOpen(ctx->api,
                                  &msh3_conn_if,
                                  cf,
                                  cf->conn->host.name,
                                  &addr,
                                  !verify);
  if(!ctx->qconn) {
    failf(data, "can't create msh3 connection");
    if(ctx->api) {
      MsH3ApiClose(ctx->api);
      ctx->api = NULL;
    }
    return CURLE_FAILED_INIT;
  }








|










|







836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
  }

  CURL_TRC_CF(data, cf, "connecting to %s:%d (verify=%d)",
              cf->conn->host.name, (int)cf->conn->remote_port, verify);

  ctx->api = MsH3ApiOpen();
  if(!ctx->api) {
    failf(data, "cannot create msh3 api");
    return CURLE_FAILED_INIT;
  }

  ctx->qconn = MsH3ConnectionOpen(ctx->api,
                                  &msh3_conn_if,
                                  cf,
                                  cf->conn->host.name,
                                  &addr,
                                  !verify);
  if(!ctx->qconn) {
    failf(data, "cannot create msh3 connection");
    if(ctx->api) {
      MsH3ApiClose(ctx->api);
      ctx->api = NULL;
    }
    return CURLE_FAILED_INIT;
  }

879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
    *done = TRUE;
    return CURLE_OK;
  }

  CF_DATA_SAVE(save, cf, data);

  if(ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD) {
    if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0]) < 0) {
      ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
      ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
      return CURLE_COULDNT_CONNECT;
    }
  }

  *done = FALSE;







|







879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
    *done = TRUE;
    return CURLE_OK;
  }

  CF_DATA_SAVE(save, cf, data);

  if(ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD) {
    if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0], FALSE) < 0) {
      ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
      ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
      return CURLE_COULDNT_CONNECT;
    }
  }

  *done = FALSE;
1034
1035
1036
1037
1038
1039
1040

1041
1042
1043
1044
1045
1046
1047
struct Curl_cftype Curl_cft_http3 = {
  "HTTP/3",
  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  0,
  cf_msh3_destroy,
  cf_msh3_connect,
  cf_msh3_close,

  Curl_cf_def_get_host,
  cf_msh3_adjust_pollset,
  cf_msh3_data_pending,
  cf_msh3_send,
  cf_msh3_recv,
  cf_msh3_data_event,
  cf_msh3_conn_is_alive,







>







1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
struct Curl_cftype Curl_cft_http3 = {
  "HTTP/3",
  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  0,
  cf_msh3_destroy,
  cf_msh3_connect,
  cf_msh3_close,
  Curl_cf_def_shutdown,
  Curl_cf_def_get_host,
  cf_msh3_adjust_pollset,
  cf_msh3_data_pending,
  cf_msh3_send,
  cf_msh3_recv,
  cf_msh3_data_event,
  cf_msh3_conn_is_alive,
Changes to jni/curl/lib/vquic/curl_ngtcp2.c.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
 * when we take things out of the buffer.
 * Chunk size is large enough to take a full DATA frame */
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE   (16 * 1024)
/* The pool keeps spares around and half of a full stream windows
 * seems good. More does not seem to improve performance.
 * The benefit of the pool is that stream buffer to not keep
 * spares. So memory consumption goes down when streams run empty,
 * have a large upload done, etc. */
#define H3_STREAM_POOL_SPARES \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
/* Receive and Send max number of chunks just follows from the
 * chunk size and window size */
#define H3_STREAM_RECV_CHUNKS \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)







|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
 * when we take things out of the buffer.
 * Chunk size is large enough to take a full DATA frame */
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE   (16 * 1024)
/* The pool keeps spares around and half of a full stream windows
 * seems good. More does not seem to improve performance.
 * The benefit of the pool is that stream buffer to not keep
 * spares. Memory consumption goes down when streams run empty,
 * have a large upload done, etc. */
#define H3_STREAM_POOL_SPARES \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
/* Receive and Send max number of chunks just follows from the
 * chunk size and window size */
#define H3_STREAM_RECV_CHUNKS \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  struct dynbuf scratch;             /* temp buffer for header construction */
  struct Curl_hash streams;          /* hash `data->id` to `h3_stream_ctx` */
  size_t max_stream_window;          /* max flow window for one stream */
  uint64_t max_idle_ms;              /* max idle time for QUIC connection */
  uint64_t used_bidi_streams;        /* bidi streams we have opened */
  uint64_t max_bidi_streams;         /* max bidi streams we can open */
  int qlogfd;
  BIT(conn_closed);                  /* connection is closed */
};

/* How to access `call_data` from a cf_ngtcp2 filter */
#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf)  \
  ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data








|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
  struct dynbuf scratch;             /* temp buffer for header construction */
  struct Curl_hash streams;          /* hash `data->id` to `h3_stream_ctx` */
  size_t max_stream_window;          /* max flow window for one stream */
  uint64_t max_idle_ms;              /* max idle time for QUIC connection */
  uint64_t used_bidi_streams;        /* bidi streams we have opened */
  uint64_t max_bidi_streams;         /* max bidi streams we can open */
  int qlogfd;
  BIT(shutdown_started);             /* queued shutdown packets */
};

/* How to access `call_data` from a cf_ngtcp2 filter */
#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf)  \
  ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
 * All about the H3 internals of a stream
 */
struct h3_stream_ctx {
  curl_int64_t id; /* HTTP/3 protocol identifier */
  struct bufq sendbuf;   /* h3 request body */
  struct h1_req_parser h1; /* h1 request parsing */
  size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
  size_t upload_blocked_len; /* the amount written last and EGAINed */
  curl_uint64_t error3; /* HTTP/3 stream error code */
  curl_off_t upload_left; /* number of request bytes left to upload */
  int status_code; /* HTTP status code */
  CURLcode xfer_result; /* result from xfer_resp_write(_hd) */
  bool resp_hds_complete; /* we have a complete, final response */
  bool closed; /* TRUE on stream close */
  bool reset;  /* TRUE on stream reset */







<







158
159
160
161
162
163
164

165
166
167
168
169
170
171
 * All about the H3 internals of a stream
 */
struct h3_stream_ctx {
  curl_int64_t id; /* HTTP/3 protocol identifier */
  struct bufq sendbuf;   /* h3 request body */
  struct h1_req_parser h1; /* h1 request parsing */
  size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */

  curl_uint64_t error3; /* HTTP/3 stream error code */
  curl_off_t upload_left; /* number of request bytes left to upload */
  int status_code; /* HTTP status code */
  CURLcode xfer_result; /* result from xfer_resp_write(_hd) */
  bool resp_hds_complete; /* we have a complete, final response */
  bool closed; /* TRUE on stream close */
  bool reset;  /* TRUE on stream reset */
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208

static CURLcode h3_data_setup(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);

  if(!data || !data->req.p.http) {
    failf(data, "initialization failure, transfer not http initialized");
    return CURLE_FAILED_INIT;
  }

  if(stream)
    return CURLE_OK;








|







193
194
195
196
197
198
199
200
201
202
203
204
205
206
207

static CURLcode h3_data_setup(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);

  if(!data) {
    failf(data, "initialization failure, transfer not http initialized");
    return CURLE_FAILED_INIT;
  }

  if(stream)
    return CURLE_OK;

322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

static void pktx_update_time(struct pkt_io_ctx *pktx,
                             struct Curl_cfilter *cf)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;

  vquic_ctx_update_time(&ctx->q);
  pktx->ts = ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
             ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
}

static void pktx_init(struct pkt_io_ctx *pktx,
                      struct Curl_cfilter *cf,
                      struct Curl_easy *data)
{
  pktx->cf = cf;







|
|







321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

static void pktx_update_time(struct pkt_io_ctx *pktx,
                             struct Curl_cfilter *cf)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;

  vquic_ctx_update_time(&ctx->q);
  pktx->ts = (ngtcp2_tstamp)ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
             (ngtcp2_tstamp)ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
}

static void pktx_init(struct pkt_io_ctx *pktx,
                      struct Curl_cfilter *cf,
                      struct Curl_easy *data)
{
  pktx->cf = cf;
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  t->initial_max_streams_uni = QUIC_MAX_STREAMS;
  t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS);
  if(ctx->qlogfd != -1) {
    s->qlog_write = qlog_callback;
  }
}

static int init_ngh3_conn(struct Curl_cfilter *cf);

static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
{
  (void)user_data;
  (void)tconn;
  return 0;
}







|







412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  t->initial_max_streams_uni = QUIC_MAX_STREAMS;
  t->max_idle_timeout = (ctx->max_idle_ms * NGTCP2_MILLISECONDS);
  if(ctx->qlogfd != -1) {
    s->qlog_write = qlog_callback;
  }
}

static CURLcode init_ngh3_conn(struct Curl_cfilter *cf);

static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
{
  (void)user_data;
  (void)tconn;
  return 0;
}
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
    }
    return NGTCP2_ERR_CALLBACK_FAILURE;
  }

  /* number of bytes inside buflen which consists of framing overhead
   * including QPACK HEADERS. In other words, it does not consume payload of
   * DATA frame. */
  ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
  ngtcp2_conn_extend_max_offset(tconn, nconsumed);

  return 0;
}

static int
cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
                            uint64_t offset, uint64_t datalen, void *user_data,







|
|







501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
    }
    return NGTCP2_ERR_CALLBACK_FAILURE;
  }

  /* number of bytes inside buflen which consists of framing overhead
   * including QPACK HEADERS. In other words, it does not consume payload of
   * DATA frame. */
  ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, (uint64_t)nconsumed);
  ngtcp2_conn_extend_max_offset(tconn, (uint64_t)nconsumed);

  return 0;
}

static int
cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
                            uint64_t offset, uint64_t datalen, void *user_data,
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
                    const ngtcp2_rand_ctx *rand_ctx)
{
  CURLcode result;
  (void)rand_ctx;

  result = Curl_rand(NULL, dest, destlen);
  if(result) {
    /* cb_rand is only used for non-cryptographic context.  If Curl_rand
       failed, just fill 0 and call it *random*. */
    memset(dest, 0, destlen);
  }
}

static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
                                    uint8_t *token, size_t cidlen,







|







658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
                    const ngtcp2_rand_ctx *rand_ctx)
{
  CURLcode result;
  (void)rand_ctx;

  result = Curl_rand(NULL, dest, destlen);
  if(result) {
    /* cb_rand is only used for non-cryptographic context. If Curl_rand
       failed, just fill 0 and call it *random*. */
    memset(dest, 0, destlen);
  }
}

static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
                                    uint8_t *token, size_t cidlen,
794
795
796
797
798
799
800
801

802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817



818
819
820
821
822
823
824
    }

    if(expiry > pktx->ts) {
      ngtcp2_duration timeout = expiry - pktx->ts;
      if(timeout % NGTCP2_MILLISECONDS) {
        timeout += NGTCP2_MILLISECONDS;
      }
      Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);

    }
  }
  return CURLE_OK;
}

static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
                                      struct Curl_easy *data,
                                      struct easy_pollset *ps)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  bool want_recv, want_send;

  if(!ctx->qconn)
    return;

  Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);



  if(want_recv || want_send) {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    struct cf_call_data save;
    bool c_exhaust, s_exhaust;

    CF_DATA_SAVE(save, cf, data);
    c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) ||







|
>
















>
>
>







793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
    }

    if(expiry > pktx->ts) {
      ngtcp2_duration timeout = expiry - pktx->ts;
      if(timeout % NGTCP2_MILLISECONDS) {
        timeout += NGTCP2_MILLISECONDS;
      }
      Curl_expire(data, (timediff_t)(timeout / NGTCP2_MILLISECONDS),
                  EXPIRE_QUIC);
    }
  }
  return CURLE_OK;
}

static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
                                      struct Curl_easy *data,
                                      struct easy_pollset *ps)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  bool want_recv, want_send;

  if(!ctx->qconn)
    return;

  Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
  if(!want_send && !Curl_bufq_is_empty(&ctx->q.sendbuf))
    want_send = TRUE;

  if(want_recv || want_send) {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    struct cf_call_data save;
    bool c_exhaust, s_exhaust;

    CF_DATA_SAVE(save, cf, data);
    c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) ||
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
  (void)conn;
  (void)stream_id;
  (void)fin;
  (void)cf;

  if(!stream)
    return 0;
  /* add a CRLF only if we've received some headers */
  h3_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);

  CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] end_headers, status=%d",
              stream_id, stream->status_code);
  if(stream->status_code / 100 != 1) {
    stream->resp_hds_complete = TRUE;
  }







|







953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
  (void)conn;
  (void)stream_id;
  (void)fin;
  (void)cf;

  if(!stream)
    return 0;
  /* add a CRLF only if we have received some headers */
  h3_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);

  CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] end_headers, status=%d",
              stream_id, stream->status_code);
  if(stream->status_code / 100 != 1) {
    stream->resp_hds_complete = TRUE;
  }
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
  cb_h3_stop_sending,
  NULL, /* end_stream */
  cb_h3_reset_stream,
  NULL, /* shutdown */
  NULL /* recv_settings */
};

static int init_ngh3_conn(struct Curl_cfilter *cf)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  CURLcode result;
  int rc;
  int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;

  if(ngtcp2_conn_get_streams_uni_left(ctx->qconn) < 3) {







|







1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
  cb_h3_stop_sending,
  NULL, /* end_stream */
  cb_h3_reset_stream,
  NULL, /* shutdown */
  NULL /* recv_settings */
};

static CURLcode init_ngh3_conn(struct Curl_cfilter *cf)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  CURLcode result;
  int rc;
  int64_t ctrl_stream_id, qpack_enc_stream_id, qpack_dec_stream_id;

  if(ngtcp2_conn_get_streams_uni_left(ctx->qconn) < 3) {
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
  DEBUGASSERT(ctx);
  DEBUGASSERT(ctx->qconn);
  DEBUGASSERT(ctx->h3conn);
  *err = CURLE_OK;

  pktx_init(&pktx, cf, data);

  if(!stream || ctx->conn_closed) {
    *err = CURLE_RECV_ERROR;
    goto out;
  }

  if(cf_progress_ingress(cf, data, &pktx)) {
    *err = CURLE_RECV_ERROR;
    nread = -1;







|







1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
  DEBUGASSERT(ctx);
  DEBUGASSERT(ctx->qconn);
  DEBUGASSERT(ctx->h3conn);
  *err = CURLE_OK;

  pktx_init(&pktx, cf, data);

  if(!stream || ctx->shutdown_started) {
    *err = CURLE_RECV_ERROR;
    goto out;
  }

  if(cf_progress_ingress(cf, data, &pktx)) {
    *err = CURLE_RECV_ERROR;
    nread = -1;
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
  if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
    skiplen = stream->sendbuf_len_in_flight;
  else
    skiplen = (size_t)datalen;
  Curl_bufq_skip(&stream->sendbuf, skiplen);
  stream->sendbuf_len_in_flight -= skiplen;

  /* Everything ACKed, we resume upload processing */
  if(!stream->sendbuf_len_in_flight) {
    int rv = nghttp3_conn_resume_stream(conn, stream_id);
    if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
      return NGTCP2_ERR_CALLBACK_FAILURE;
    }
  }
  return 0;
}







|
|







1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
    skiplen = stream->sendbuf_len_in_flight;
  else
    skiplen = (size_t)datalen;
  Curl_bufq_skip(&stream->sendbuf, skiplen);
  stream->sendbuf_len_in_flight -= skiplen;

  /* Resume upload processing if we have more data to send */
  if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
    int rv = nghttp3_conn_resume_stream(conn, stream_id);
    if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
      return NGTCP2_ERR_CALLBACK_FAILURE;
    }
  }
  return 0;
}
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
  result = cf_progress_ingress(cf, data, &pktx);
  if(result) {
    *err = result;
    sent = -1;
  }

  if(!stream || stream->id < 0) {
    if(ctx->conn_closed) {
      CURL_TRC_CF(data, cf, "cannot open stream on closed connection");
      *err = CURLE_SEND_ERROR;
      sent = -1;
      goto out;
    }
    sent = h3_stream_open(cf, data, buf, len, err);
    if(sent < 0) {
      CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
      goto out;
    }
    stream = H3_STREAM_CTX(ctx, data);
  }
  else if(stream->xfer_result) {
    CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] xfer write failed", stream->id);
    cf_ngtcp2_stream_close(cf, data, stream);
    *err = stream->xfer_result;
    sent = -1;
    goto out;
  }
  else if(stream->upload_blocked_len) {
    /* the data in `buf` has already been submitted or added to the
     * buffers, but have been EAGAINed on the last invocation. */
    DEBUGASSERT(len >= stream->upload_blocked_len);
    if(len < stream->upload_blocked_len) {
      /* Did we get called again with a smaller `len`? This should not
       * happen. We are not prepared to handle that. */
      failf(data, "HTTP/3 send again with decreased length");
      *err = CURLE_HTTP3;
      sent = -1;
      goto out;
    }
    sent = (ssize_t)stream->upload_blocked_len;
    stream->upload_blocked_len = 0;
  }
  else if(stream->closed) {
    if(stream->resp_hds_complete) {
      /* Server decided to close the stream after having sent us a final
       * response. This is valid if it is not interested in the request
       * body. This happens on 30x or 40x responses.
       * We silently discard the data sent, since this is not a transport
       * error situation. */
      CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] discarding data"
                  "on closed stream with response", stream->id);
      *err = CURLE_OK;
      sent = (ssize_t)len;
      goto out;
    }
    CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send_body(len=%zu) "
                "-> stream closed", stream->id, len);
    *err = CURLE_HTTP3;
    sent = -1;
    goto out;
  }
  else if(ctx->conn_closed) {
    CURL_TRC_CF(data, cf, "cannot send on closed connection");
    *err = CURLE_SEND_ERROR;
    sent = -1;
    goto out;
  }
  else {
    sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);







|



















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



















|







1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529















1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
  result = cf_progress_ingress(cf, data, &pktx);
  if(result) {
    *err = result;
    sent = -1;
  }

  if(!stream || stream->id < 0) {
    if(ctx->shutdown_started) {
      CURL_TRC_CF(data, cf, "cannot open stream on closed connection");
      *err = CURLE_SEND_ERROR;
      sent = -1;
      goto out;
    }
    sent = h3_stream_open(cf, data, buf, len, err);
    if(sent < 0) {
      CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
      goto out;
    }
    stream = H3_STREAM_CTX(ctx, data);
  }
  else if(stream->xfer_result) {
    CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] xfer write failed", stream->id);
    cf_ngtcp2_stream_close(cf, data, stream);
    *err = stream->xfer_result;
    sent = -1;
    goto out;
  }















  else if(stream->closed) {
    if(stream->resp_hds_complete) {
      /* Server decided to close the stream after having sent us a final
       * response. This is valid if it is not interested in the request
       * body. This happens on 30x or 40x responses.
       * We silently discard the data sent, since this is not a transport
       * error situation. */
      CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] discarding data"
                  "on closed stream with response", stream->id);
      *err = CURLE_OK;
      sent = (ssize_t)len;
      goto out;
    }
    CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send_body(len=%zu) "
                "-> stream closed", stream->id, len);
    *err = CURLE_HTTP3;
    sent = -1;
    goto out;
  }
  else if(ctx->shutdown_started) {
    CURL_TRC_CF(data, cf, "cannot send on closed connection");
    *err = CURLE_SEND_ERROR;
    sent = -1;
    goto out;
  }
  else {
    sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603

  result = cf_progress_egress(cf, data, &pktx);
  if(result) {
    *err = result;
    sent = -1;
  }

  if(stream && sent > 0 && stream->sendbuf_len_in_flight) {
    /* We have unacknowledged DATA and cannot report success to our
     * caller. Instead we EAGAIN and remember how much we have already
     * "written" into our various internal connection buffers. */
    stream->upload_blocked_len = sent;
    CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu), "
                "%zu bytes in flight -> EGAIN", stream->id, len,
                stream->sendbuf_len_in_flight);
    *err = CURLE_AGAIN;
    sent = -1;
  }

out:
  result = check_and_set_expiry(cf, data, &pktx);
  if(result) {
    *err = result;
    sent = -1;
  }
  CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d",







<
<
<
<
<
<
<
<
<
<
<
<







1566
1567
1568
1569
1570
1571
1572












1573
1574
1575
1576
1577
1578
1579

  result = cf_progress_egress(cf, data, &pktx);
  if(result) {
    *err = result;
    sent = -1;
  }













out:
  result = check_and_set_expiry(cf, data, &pktx);
  if(result) {
    *err = result;
    sent = -1;
  }
  CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d",
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
  struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx;
  ngtcp2_pkt_info pi;
  ngtcp2_path path;
  int rv;

  ++pktx->pkt_count;
  ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
                   ctx->q.local_addrlen);
  ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
                   remote_addrlen);
  pi.ecn = (uint8_t)ecn;

  rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts);
  if(rv) {
    CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",







|







1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
  struct cf_ngtcp2_ctx *ctx = pktx->cf->ctx;
  ngtcp2_pkt_info pi;
  ngtcp2_path path;
  int rv;

  ++pktx->pkt_count;
  ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
                   (socklen_t)ctx->q.local_addrlen);
  ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
                   remote_addrlen);
  pi.ecn = (uint8_t)ecn;

  rv = ngtcp2_conn_read_pkt(ctx->qconn, &path, &pi, pkt, pktlen, pktx->ts);
  if(rv) {
    CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
      }
      goto out;
    }

    DEBUGASSERT(nread > 0);
    if(pktcnt == 0) {
      /* first packet in buffer. This is either of a known, "good"
       * payload size or it is a PMTUD. We'll see. */
      gsolen = (size_t)nread;
    }
    else if((size_t)nread > gsolen ||
            (gsolen > path_max_payload_size && (size_t)nread != gsolen)) {
      /* The just added packet is a PMTUD *or* the one(s) before the
       * just added were PMTUD and the last one is smaller.
       * Flush the buffer before the last add. */







|







1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
      }
      goto out;
    }

    DEBUGASSERT(nread > 0);
    if(pktcnt == 0) {
      /* first packet in buffer. This is either of a known, "good"
       * payload size or it is a PMTUD. We will see. */
      gsolen = (size_t)nread;
    }
    else if((size_t)nread > gsolen ||
            (gsolen > path_max_payload_size && (size_t)nread != gsolen)) {
      /* The just added packet is a PMTUD *or* the one(s) before the
       * just added were PMTUD and the last one is smaller.
       * Flush the buffer before the last add. */
1957
1958
1959
1960
1961
1962
1963
1964

1965
1966
1967
1968
1969
1970
1971
  case CF_CTRL_DATA_DONE:
    h3_data_done(cf, data);
    break;
  case CF_CTRL_DATA_DONE_SEND: {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    if(stream && !stream->send_closed) {
      stream->send_closed = TRUE;
      stream->upload_left = Curl_bufq_len(&stream->sendbuf);

      (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
    }
    break;
  }
  case CF_CTRL_DATA_IDLE: {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    CURL_TRC_CF(data, cf, "data idle");







|
>







1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
  case CF_CTRL_DATA_DONE:
    h3_data_done(cf, data);
    break;
  case CF_CTRL_DATA_DONE_SEND: {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    if(stream && !stream->send_closed) {
      stream->send_closed = TRUE;
      stream->upload_left = Curl_bufq_len(&stream->sendbuf) -
        stream->sendbuf_len_in_flight;
      (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
    }
    break;
  }
  case CF_CTRL_DATA_IDLE: {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    CURL_TRC_CF(data, cf, "data idle");
2002
2003
2004
2005
2006
2007
2008






















































































2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
  Curl_hash_destroy(&ctx->streams);
  Curl_ssl_peer_cleanup(&ctx->peer);

  memset(ctx, 0, sizeof(*ctx));
  ctx->qlogfd = -1;
  ctx->call_data = save;
}























































































static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf,
                                 struct Curl_easy *data)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  if(ctx && ctx->qconn && !ctx->conn_closed) {
    char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
    struct pkt_io_ctx pktx;
    ngtcp2_ssize rc;

    ctx->conn_closed = TRUE;
    pktx_init(&pktx, cf, data);
    rc = ngtcp2_conn_write_connection_close(ctx->qconn, NULL, /* path */
                                            NULL, /* pkt_info */
                                            (uint8_t *)buffer, sizeof(buffer),
                                            &ctx->last_error, pktx.ts);
    CURL_TRC_CF(data, cf, "closing connection(err_type=%d, err_code=%"
                CURL_PRIu64 ") -> %d", ctx->last_error.type,
                (curl_uint64_t)ctx->last_error.error_code, (int)rc);
    if(rc > 0) {
      while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) &&
            SOCKERRNO == EINTR);
    }
  }
}

static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  struct cf_call_data save;








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




<
<
<
<
<
|
<
|
<
<
<
<
<
<
<
<
<
<
<
<







1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075





2076

2077












2078
2079
2080
2081
2082
2083
2084
  Curl_hash_destroy(&ctx->streams);
  Curl_ssl_peer_cleanup(&ctx->peer);

  memset(ctx, 0, sizeof(*ctx));
  ctx->qlogfd = -1;
  ctx->call_data = save;
}

static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf,
                                   struct Curl_easy *data, bool *done)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  struct cf_call_data save;
  struct pkt_io_ctx pktx;
  CURLcode result = CURLE_OK;

  if(cf->shutdown || !ctx->qconn) {
    *done = TRUE;
    return CURLE_OK;
  }

  CF_DATA_SAVE(save, cf, data);
  *done = FALSE;
  pktx_init(&pktx, cf, data);

  if(!ctx->shutdown_started) {
    char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
    ngtcp2_ssize nwritten;

    if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
      CURL_TRC_CF(data, cf, "shutdown, flushing sendbuf");
      result = cf_progress_egress(cf, data, &pktx);
      if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
        CURL_TRC_CF(data, cf, "sending shutdown packets blocked");
        result = CURLE_OK;
        goto out;
      }
      else if(result) {
        CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf", result);
        *done = TRUE;
        goto out;
      }
    }

    ctx->shutdown_started = TRUE;
    nwritten = ngtcp2_conn_write_connection_close(
      ctx->qconn, NULL, /* path */
      NULL, /* pkt_info */
      (uint8_t *)buffer, sizeof(buffer),
      &ctx->last_error, pktx.ts);
    CURL_TRC_CF(data, cf, "start shutdown(err_type=%d, err_code=%"
                CURL_PRIu64 ") -> %d", ctx->last_error.type,
                (curl_uint64_t)ctx->last_error.error_code, (int)nwritten);
    if(nwritten > 0) {
      Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
                      (size_t)nwritten, &result);
      if(result) {
        CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, "
                    "aborting shutdown", result);
        goto out;
      }
      ctx->q.no_gso = TRUE;
      ctx->q.gsolen = (size_t)nwritten;
      ctx->q.split_len = 0;
    }
  }

  if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
    CURL_TRC_CF(data, cf, "shutdown, flushing egress");
    result = vquic_flush(cf, data, &ctx->q);
    if(result == CURLE_AGAIN) {
      CURL_TRC_CF(data, cf, "sending shutdown packets blocked");
      result = CURLE_OK;
      goto out;
    }
    else if(result) {
      CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf", result);
      *done = TRUE;
      goto out;
    }
  }

  if(Curl_bufq_is_empty(&ctx->q.sendbuf)) {
    /* Sent everything off. ngtcp2 seems to have no support for graceful
     * shutdowns. So, we are done. */
    CURL_TRC_CF(data, cf, "shutdown completely sent off, done");
    *done = TRUE;
    result = CURLE_OK;
  }
out:
  CF_DATA_RESTORE(cf, save);
  return result;
}

static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf,
                                 struct Curl_easy *data)
{





  bool done;

  cf_ngtcp2_shutdown(cf, data, &done);












}

static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  struct cf_call_data save;

2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
  }
#else
  if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) {
    failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
    return CURLE_FAILED_INIT;
  }
#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
  /* Enable the session cache because it's a prerequisite for the
   * "new session" callback. Use the "external storage" mode to prevent
   * OpenSSL from creating an internal session cache.
   */
  SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
                                 SSL_SESS_CACHE_CLIENT |
                                 SSL_SESS_CACHE_NO_INTERNAL);
  SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);

#elif defined(USE_GNUTLS)
  if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
    failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
    return CURLE_FAILED_INIT;
  }
#elif defined(USE_WOLFSSL)
  if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->ssl_ctx) != 0) {
    failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
    return CURLE_FAILED_INIT;
  }
#endif
  return CURLE_OK;
}








|














|







2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
  }
#else
  if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) {
    failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
    return CURLE_FAILED_INIT;
  }
#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
  /* Enable the session cache because it is a prerequisite for the
   * "new session" callback. Use the "external storage" mode to prevent
   * OpenSSL from creating an internal session cache.
   */
  SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
                                 SSL_SESS_CACHE_CLIENT |
                                 SSL_SESS_CACHE_NO_INTERNAL);
  SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);

#elif defined(USE_GNUTLS)
  if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
    failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
    return CURLE_FAILED_INIT;
  }
#elif defined(USE_WOLFSSL)
  if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
    failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
    return CURLE_FAILED_INIT;
  }
#endif
  return CURLE_OK;
}

2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
  if(rv == -1)
    return CURLE_QUIC_CONNECT_ERROR;

  ngtcp2_addr_init(&ctx->connected_path.local,
                   (struct sockaddr *)&ctx->q.local_addr,
                   ctx->q.local_addrlen);
  ngtcp2_addr_init(&ctx->connected_path.remote,
                   &sockaddr->sa_addr, sockaddr->addrlen);

  rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
                              &ctx->connected_path,
                              NGTCP2_PROTO_VER_V1, &ng_callbacks,
                              &ctx->settings, &ctx->transport_params,
                              NULL, cf);
  if(rc)
    return CURLE_QUIC_CONNECT_ERROR;

#ifdef USE_OPENSSL
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
#elif defined(USE_GNUTLS)
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
#else
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ssl);
#endif

  ngtcp2_ccerr_default(&ctx->last_error);

  ctx->conn_ref.get_conn = get_conn;
  ctx->conn_ref.user_data = cf;








|














|







2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
  if(rv == -1)
    return CURLE_QUIC_CONNECT_ERROR;

  ngtcp2_addr_init(&ctx->connected_path.local,
                   (struct sockaddr *)&ctx->q.local_addr,
                   ctx->q.local_addrlen);
  ngtcp2_addr_init(&ctx->connected_path.remote,
                   &sockaddr->sa_addr, (socklen_t)sockaddr->addrlen);

  rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
                              &ctx->connected_path,
                              NGTCP2_PROTO_VER_V1, &ng_callbacks,
                              &ctx->settings, &ctx->transport_params,
                              NULL, cf);
  if(rc)
    return CURLE_QUIC_CONNECT_ERROR;

#ifdef USE_OPENSSL
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
#elif defined(USE_GNUTLS)
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
#else
  ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
#endif

  ngtcp2_ccerr_default(&ctx->last_error);

  ctx->conn_ref.get_conn = get_conn;
  ctx->conn_ref.user_data = cf;

2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
  case CF_QUERY_MAX_CONCURRENT: {
    DEBUGASSERT(pres1);
    CF_DATA_SAVE(save, cf, data);
    /* Set after transport params arrived and continually updated
     * by callback. QUIC counts the number over the lifetime of the
     * connection, ever increasing.
     * We count the *open* transfers plus the budget for new ones. */
    if(!ctx->qconn || ctx->conn_closed) {
      *pres1 = 0;
    }
    else if(ctx->max_bidi_streams) {
      uint64_t avail_bidi_streams = 0;
      uint64_t max_streams = CONN_INUSE(cf->conn);
      if(ctx->max_bidi_streams > ctx->used_bidi_streams)
        avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
      max_streams += avail_bidi_streams;
      *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
    }
    else  /* transport params not arrived yet? take our default. */
      *pres1 = Curl_multi_max_concurrent_streams(data->multi);
    CURL_TRC_CF(data, cf, "query conn[%" CURL_FORMAT_CURL_OFF_T "]: "
                "MAX_CONCURRENT -> %d (%zu in use)",
                cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
    CF_DATA_RESTORE(cf, save);
    return CURLE_OK;
  }
  case CF_QUERY_CONNECT_REPLY_MS:







|











|







2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
  case CF_QUERY_MAX_CONCURRENT: {
    DEBUGASSERT(pres1);
    CF_DATA_SAVE(save, cf, data);
    /* Set after transport params arrived and continually updated
     * by callback. QUIC counts the number over the lifetime of the
     * connection, ever increasing.
     * We count the *open* transfers plus the budget for new ones. */
    if(!ctx->qconn || ctx->shutdown_started) {
      *pres1 = 0;
    }
    else if(ctx->max_bidi_streams) {
      uint64_t avail_bidi_streams = 0;
      uint64_t max_streams = CONN_INUSE(cf->conn);
      if(ctx->max_bidi_streams > ctx->used_bidi_streams)
        avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
      max_streams += avail_bidi_streams;
      *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
    }
    else  /* transport params not arrived yet? take our default. */
      *pres1 = (int)Curl_multi_max_concurrent_streams(data->multi);
    CURL_TRC_CF(data, cf, "query conn[%" CURL_FORMAT_CURL_OFF_T "]: "
                "MAX_CONCURRENT -> %d (%zu in use)",
                cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
    CF_DATA_RESTORE(cf, save);
    return CURLE_OK;
  }
  case CF_QUERY_CONNECT_REPLY_MS:
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  bool alive = FALSE;
  const ngtcp2_transport_params *rp;
  struct cf_call_data save;

  CF_DATA_SAVE(save, cf, data);
  *input_pending = FALSE;
  if(!ctx->qconn || ctx->conn_closed)
    goto out;

  /* Both sides of the QUIC connection announce they max idle times in
   * the transport parameters. Look at the minimum of both and if
   * we exceed this, regard the connection as dead. The other side
   * may have completely purged it and will no longer respond
   * to any packets from us. */







|







2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
  struct cf_ngtcp2_ctx *ctx = cf->ctx;
  bool alive = FALSE;
  const ngtcp2_transport_params *rp;
  struct cf_call_data save;

  CF_DATA_SAVE(save, cf, data);
  *input_pending = FALSE;
  if(!ctx->qconn || ctx->shutdown_started)
    goto out;

  /* Both sides of the QUIC connection announce they max idle times in
   * the transport parameters. Look at the minimum of both and if
   * we exceed this, regard the connection as dead. The other side
   * may have completely purged it and will no longer respond
   * to any packets from us. */
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439

2440
2441
2442
2443
2444
2445
2446

  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    goto out;

  alive = TRUE;
  if(*input_pending) {
    CURLcode result;
    /* This happens before we've sent off a request and the connection is
       not in use by any other transfer, there shouldn't be any data here,
       only "protocol frames" */
    *input_pending = FALSE;
    result = cf_progress_ingress(cf, data, NULL);
    CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
    alive = result? FALSE : TRUE;
  }

out:
  CF_DATA_RESTORE(cf, save);
  return alive;
}

struct Curl_cftype Curl_cft_http3 = {
  "HTTP/3",
  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  0,
  cf_ngtcp2_destroy,
  cf_ngtcp2_connect,
  cf_ngtcp2_close,

  Curl_cf_def_get_host,
  cf_ngtcp2_adjust_pollset,
  cf_ngtcp2_data_pending,
  cf_ngtcp2_send,
  cf_ngtcp2_recv,
  cf_ngtcp2_data_event,
  cf_ngtcp2_conn_is_alive,







|
|



















>







2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492

  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    goto out;

  alive = TRUE;
  if(*input_pending) {
    CURLcode result;
    /* This happens before we have sent off a request and the connection is
       not in use by any other transfer, there should not be any data here,
       only "protocol frames" */
    *input_pending = FALSE;
    result = cf_progress_ingress(cf, data, NULL);
    CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
    alive = result? FALSE : TRUE;
  }

out:
  CF_DATA_RESTORE(cf, save);
  return alive;
}

struct Curl_cftype Curl_cft_http3 = {
  "HTTP/3",
  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  0,
  cf_ngtcp2_destroy,
  cf_ngtcp2_connect,
  cf_ngtcp2_close,
  cf_ngtcp2_shutdown,
  Curl_cf_def_get_host,
  cf_ngtcp2_adjust_pollset,
  cf_ngtcp2_data_pending,
  cf_ngtcp2_send,
  cf_ngtcp2_recv,
  cf_ngtcp2_data_event,
  cf_ngtcp2_conn_is_alive,
Changes to jni/curl/lib/vquic/curl_osslq.c.
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 * when we take things out of the buffer.
 * Chunk size is large enough to take a full DATA frame */
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE   (16 * 1024)
/* The pool keeps spares around and half of a full stream window
 * seems good. More does not seem to improve performance.
 * The benefit of the pool is that stream buffer to not keep
 * spares. So memory consumption goes down when streams run empty,
 * have a large upload done, etc. */
#define H3_STREAM_POOL_SPARES \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
/* Receive and Send max number of chunks just follows from the
 * chunk size and window size */
#define H3_STREAM_RECV_CHUNKS \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)







|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 * when we take things out of the buffer.
 * Chunk size is large enough to take a full DATA frame */
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE   (16 * 1024)
/* The pool keeps spares around and half of a full stream window
 * seems good. More does not seem to improve performance.
 * The benefit of the pool is that stream buffer to not keep
 * spares. Memory consumption goes down when streams run empty,
 * have a large upload done, etc. */
#define H3_STREAM_POOL_SPARES \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
/* Receive and Send max number of chunks just follows from the
 * chunk size and window size */
#define H3_STREAM_RECV_CHUNKS \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
{
  DEBUGASSERT(!s->ssl);
  Curl_bufq_initp(&s->recvbuf, bufcp, 1, BUFQ_OPT_NONE);
  s->ssl = SSL_new_stream(conn, flags);
  if(!s->ssl) {
    return CURLE_FAILED_INIT;
  }
  s->id = SSL_get_stream_id(s->ssl);
  SSL_set_app_data(s->ssl, user_data);
  return CURLE_OK;
}

static void cf_osslq_stream_cleanup(struct cf_osslq_stream *s)
{
  if(s->ssl) {







|







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
{
  DEBUGASSERT(!s->ssl);
  Curl_bufq_initp(&s->recvbuf, bufcp, 1, BUFQ_OPT_NONE);
  s->ssl = SSL_new_stream(conn, flags);
  if(!s->ssl) {
    return CURLE_FAILED_INIT;
  }
  s->id = (curl_int64_t)SSL_get_stream_id(s->ssl);
  SSL_set_app_data(s->ssl, user_data);
  return CURLE_OK;
}

static void cf_osslq_stream_cleanup(struct cf_osslq_stream *s)
{
  if(s->ssl) {
290
291
292
293
294
295
296
297
298
299

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318







































































319
320
321
322
323
324
325
326
327






328
329
330
331
332
333
334
  struct curltime first_byte_at;     /* when first byte was recvd */
  struct curltime reconnect_at;      /* time the next attempt should start */
  struct bufc_pool stream_bufcp;     /* chunk pool for streams */
  struct Curl_hash streams;          /* hash `data->id` to `h3_stream_ctx` */
  size_t max_stream_window;          /* max flow window for one stream */
  uint64_t max_idle_ms;              /* max idle time for QUIC connection */
  BIT(got_first_byte);               /* if first byte was received */
#ifdef USE_OPENSSL
  BIT(x509_store_setup);             /* if x509 store has been set up */
  BIT(protocol_shutdown);            /* QUIC connection is shut down */

#endif
};

static void cf_osslq_ctx_clear(struct cf_osslq_ctx *ctx)
{
  struct cf_call_data save = ctx->call_data;

  cf_osslq_h3conn_cleanup(&ctx->h3);
  Curl_vquic_tls_cleanup(&ctx->tls);
  vquic_ctx_free(&ctx->q);
  Curl_bufcp_free(&ctx->stream_bufcp);
  Curl_hash_clean(&ctx->streams);
  Curl_hash_destroy(&ctx->streams);
  Curl_ssl_peer_cleanup(&ctx->peer);

  memset(ctx, 0, sizeof(*ctx));
  ctx->call_data = save;
}








































































static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_osslq_ctx *ctx = cf->ctx;
  struct cf_call_data save;

  CF_DATA_SAVE(save, cf, data);
  if(ctx && ctx->tls.ossl.ssl) {
    /* TODO: send connection close */
    CURL_TRC_CF(data, cf, "cf_osslq_close()");






    cf_osslq_ctx_clear(ctx);
  }

  cf->connected = FALSE;
  CF_DATA_RESTORE(cf, save);
}








<


>
|


















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







<

>
>
>
>
>
>







290
291
292
293
294
295
296

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396

397
398
399
400
401
402
403
404
405
406
407
408
409
410
  struct curltime first_byte_at;     /* when first byte was recvd */
  struct curltime reconnect_at;      /* time the next attempt should start */
  struct bufc_pool stream_bufcp;     /* chunk pool for streams */
  struct Curl_hash streams;          /* hash `data->id` to `h3_stream_ctx` */
  size_t max_stream_window;          /* max flow window for one stream */
  uint64_t max_idle_ms;              /* max idle time for QUIC connection */
  BIT(got_first_byte);               /* if first byte was received */

  BIT(x509_store_setup);             /* if x509 store has been set up */
  BIT(protocol_shutdown);            /* QUIC connection is shut down */
  BIT(need_recv);                    /* QUIC connection needs to receive */
  BIT(need_send);                    /* QUIC connection needs to send */
};

static void cf_osslq_ctx_clear(struct cf_osslq_ctx *ctx)
{
  struct cf_call_data save = ctx->call_data;

  cf_osslq_h3conn_cleanup(&ctx->h3);
  Curl_vquic_tls_cleanup(&ctx->tls);
  vquic_ctx_free(&ctx->q);
  Curl_bufcp_free(&ctx->stream_bufcp);
  Curl_hash_clean(&ctx->streams);
  Curl_hash_destroy(&ctx->streams);
  Curl_ssl_peer_cleanup(&ctx->peer);

  memset(ctx, 0, sizeof(*ctx));
  ctx->call_data = save;
}

static CURLcode cf_osslq_shutdown(struct Curl_cfilter *cf,
                                  struct Curl_easy *data, bool *done)
{
  struct cf_osslq_ctx *ctx = cf->ctx;
  struct cf_call_data save;
  CURLcode result = CURLE_OK;
  int rc;

  CF_DATA_SAVE(save, cf, data);

  if(cf->shutdown || ctx->protocol_shutdown) {
    *done = TRUE;
    return CURLE_OK;
  }

  CF_DATA_SAVE(save, cf, data);
  *done = FALSE;
  ctx->need_send = FALSE;
  ctx->need_recv = FALSE;

  rc = SSL_shutdown_ex(ctx->tls.ossl.ssl,
                       SSL_SHUTDOWN_FLAG_NO_BLOCK, NULL, 0);
  if(rc == 0) {  /* ongoing */
    CURL_TRC_CF(data, cf, "shutdown ongoing");
    ctx->need_recv = TRUE;
    goto out;
  }
  else if(rc == 1) {  /* done */
    CURL_TRC_CF(data, cf, "shutdown finished");
    *done = TRUE;
    goto out;
  }
  else {
    long sslerr;
    char err_buffer[256];
    int err = SSL_get_error(ctx->tls.ossl.ssl, rc);

    switch(err) {
    case SSL_ERROR_NONE:
    case SSL_ERROR_ZERO_RETURN:
      CURL_TRC_CF(data, cf, "shutdown not received, but closed");
      *done = TRUE;
      goto out;
    case SSL_ERROR_WANT_READ:
      /* SSL has send its notify and now wants to read the reply
       * from the server. We are not really interested in that. */
      CURL_TRC_CF(data, cf, "shutdown sent, want receive");
      ctx->need_recv = TRUE;
      goto out;
    case SSL_ERROR_WANT_WRITE:
      CURL_TRC_CF(data, cf, "shutdown send blocked");
      ctx->need_send = TRUE;
      goto out;
    default:
      /* We give up on this. */
      sslerr = ERR_get_error();
      CURL_TRC_CF(data, cf, "shutdown, ignore recv error: '%s', errno %d",
                  (sslerr ?
                   osslq_strerror(sslerr, err_buffer, sizeof(err_buffer)) :
                   osslq_SSL_ERROR_to_str(err)),
                  SOCKERRNO);
      *done = TRUE;
      result = CURLE_OK;
      goto out;
    }
  }
out:
  CF_DATA_RESTORE(cf, save);
  return result;
}

static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_osslq_ctx *ctx = cf->ctx;
  struct cf_call_data save;

  CF_DATA_SAVE(save, cf, data);
  if(ctx && ctx->tls.ossl.ssl) {

    CURL_TRC_CF(data, cf, "cf_osslq_close()");
    if(!cf->shutdown && !ctx->protocol_shutdown) {
      /* last best effort, which OpenSSL calls a "rapid" shutdown. */
      SSL_shutdown_ex(ctx->tls.ossl.ssl,
                      (SSL_SHUTDOWN_FLAG_NO_BLOCK | SSL_SHUTDOWN_FLAG_RAPID),
                      NULL, 0);
    }
    cf_osslq_ctx_clear(ctx);
  }

  cf->connected = FALSE;
  CF_DATA_RESTORE(cf, save);
}

351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386

static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
                                           SSL *stream_ssl,
                                           struct Curl_cfilter *cf,
                                           struct Curl_easy *data)
{
  struct cf_osslq_ctx *ctx = cf->ctx;
  int64_t stream_id = SSL_get_stream_id(stream_ssl);

  if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) {
    /* rejected, we are full */
    CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] rejecting remote stream",
                (curl_int64_t)stream_id);
    SSL_free(stream_ssl);
    return CURLE_FAILED_INIT;
  }
  switch(SSL_get_stream_type(stream_ssl)) {
    case SSL_STREAM_TYPE_READ: {
      struct cf_osslq_stream *nstream = &h3->remote_ctrl[h3->remote_ctrl_n++];
      nstream->id = stream_id;
      nstream->ssl = stream_ssl;
      Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE);
      CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] accepted remote uni stream",
                  (curl_int64_t)stream_id);
      break;
    }
    default:
      CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reject remote non-uni-read"
                  " stream", (curl_int64_t)stream_id);
      SSL_free(stream_ssl);
      return CURLE_FAILED_INIT;
  }
  return CURLE_OK;

}








|




|










|




|







427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462

static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
                                           SSL *stream_ssl,
                                           struct Curl_cfilter *cf,
                                           struct Curl_easy *data)
{
  struct cf_osslq_ctx *ctx = cf->ctx;
  curl_int64_t stream_id = (curl_int64_t)SSL_get_stream_id(stream_ssl);

  if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) {
    /* rejected, we are full */
    CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] rejecting remote stream",
                stream_id);
    SSL_free(stream_ssl);
    return CURLE_FAILED_INIT;
  }
  switch(SSL_get_stream_type(stream_ssl)) {
    case SSL_STREAM_TYPE_READ: {
      struct cf_osslq_stream *nstream = &h3->remote_ctrl[h3->remote_ctrl_n++];
      nstream->id = stream_id;
      nstream->ssl = stream_ssl;
      Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE);
      CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] accepted remote uni stream",
                  stream_id);
      break;
    }
    default:
      CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] reject remote non-uni-read"
                  " stream", stream_id);
      SSL_free(stream_ssl);
      return CURLE_FAILED_INIT;
  }
  return CURLE_OK;

}

436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  else {
    result = def_result;
    osslq_strerror(errdetail, ebuf, sizeof(ebuf));
  }

  /* detail is already set to the SSL error above */

  /* If we e.g. use SSLv2 request-method and the server doesn't like us
   * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
   * the SO_ERROR is also lost.
   */
  if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
    char extramsg[80]="";
    int sockerr = SOCKERRNO;
    struct ip_quadruple ip;







|







512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
  else {
    result = def_result;
    osslq_strerror(errdetail, ebuf, sizeof(ebuf));
  }

  /* detail is already set to the SSL error above */

  /* If we e.g. use SSLv2 request-method and the server does not like us
   * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
   * the SO_ERROR is also lost.
   */
  if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
    char extramsg[80]="";
    int sockerr = SOCKERRNO;
    struct ip_quadruple ip;
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
 */
struct h3_stream_ctx {
  struct cf_osslq_stream s;
  struct bufq sendbuf;   /* h3 request body */
  struct bufq recvbuf;   /* h3 response body */
  struct h1_req_parser h1; /* h1 request parsing */
  size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
  size_t upload_blocked_len; /* the amount written last and EGAINed */
  size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */
  curl_uint64_t error3; /* HTTP/3 stream error code */
  curl_off_t upload_left; /* number of request bytes left to upload */
  curl_off_t download_recvd; /* number of response DATA bytes received */
  int status_code; /* HTTP status code */
  bool resp_hds_complete; /* we have a complete, final response */
  bool closed; /* TRUE on stream close */







<







556
557
558
559
560
561
562

563
564
565
566
567
568
569
 */
struct h3_stream_ctx {
  struct cf_osslq_stream s;
  struct bufq sendbuf;   /* h3 request body */
  struct bufq recvbuf;   /* h3 response body */
  struct h1_req_parser h1; /* h1 request parsing */
  size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */

  size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */
  curl_uint64_t error3; /* HTTP/3 stream error code */
  curl_off_t upload_left; /* number of request bytes left to upload */
  curl_off_t download_recvd; /* number of response DATA bytes received */
  int status_code; /* HTTP status code */
  bool resp_hds_complete; /* we have a complete, final response */
  bool closed; /* TRUE on stream close */
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531

static CURLcode h3_data_setup(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
{
  struct cf_osslq_ctx *ctx = cf->ctx;
  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);

  if(!data || !data->req.p.http) {
    failf(data, "initialization failure, transfer not http initialized");
    return CURLE_FAILED_INIT;
  }

  if(stream)
    return CURLE_OK;








|







592
593
594
595
596
597
598
599
600
601
602
603
604
605
606

static CURLcode h3_data_setup(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
{
  struct cf_osslq_ctx *ctx = cf->ctx;
  struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);

  if(!data) {
    failf(data, "initialization failure, transfer not http initialized");
    return CURLE_FAILED_INIT;
  }

  if(stream)
    return CURLE_OK;

825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
  (void)conn;
  (void)stream_id;
  (void)fin;
  (void)cf;

  if(!stream)
    return 0;
  /* add a CRLF only if we've received some headers */
  result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
  if(result) {
    return -1;
  }

  CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] end_headers, status=%d",
              stream_id, stream->status_code);







|







900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
  (void)conn;
  (void)stream_id;
  (void)fin;
  (void)cf;

  if(!stream)
    return 0;
  /* add a CRLF only if we have received some headers */
  result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
  if(result) {
    return -1;
  }

  CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] end_headers, status=%d",
              stream_id, stream->status_code);
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
  if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
    skiplen = stream->sendbuf_len_in_flight;
  else
    skiplen = (size_t)datalen;
  Curl_bufq_skip(&stream->sendbuf, skiplen);
  stream->sendbuf_len_in_flight -= skiplen;

  /* Everything ACKed, we resume upload processing */
  if(!stream->sendbuf_len_in_flight) {
    int rv = nghttp3_conn_resume_stream(conn, stream_id);
    if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
      return NGHTTP3_ERR_CALLBACK_FAILURE;
    }
  }
  return 0;
}







|
|







1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
    skiplen = stream->sendbuf_len_in_flight;
  else
    skiplen = (size_t)datalen;
  Curl_bufq_skip(&stream->sendbuf, skiplen);
  stream->sendbuf_len_in_flight -= skiplen;

  /* Resume upload processing if we have more data to send */
  if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
    int rv = nghttp3_conn_resume_stream(conn, stream_id);
    if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
      return NGHTTP3_ERR_CALLBACK_FAILURE;
    }
  }
  return 0;
}
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
    DEBUGASSERT(s->id == stream_id);
    for(i = 0, total_len = 0; i < n; ++i) {
      total_len += vec[i].len;
    }
    for(i = 0; (i < n) && !blocked; ++i) {
      /* Without stream->s.ssl, we closed that already, so
       * pretend the write did succeed. */
#ifdef SSL_WRITE_FLAG_CONCLUDE
      /* Since OpenSSL v3.3.x, on last chunk set EOS if needed  */
      uint64_t flags = (eos && ((i + 1) == n))? SSL_WRITE_FLAG_CONCLUDE : 0;
      written = vec[i].len;
      ok = !s->ssl || SSL_write_ex2(s->ssl, vec[i].base, vec[i].len, flags,
                                   &written);
      if(ok && flags & SSL_WRITE_FLAG_CONCLUDE)
        eos_written = TRUE;
#else
      written = vec[i].len;
      ok = !s->ssl || SSL_write_ex(s->ssl, vec[i].base, vec[i].len,
                                   &written);
#endif
      if(ok) {
        /* As OpenSSL buffers the data, we count this as acknowledged
         * from nghttp3's point of view */
        CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send %zu bytes to QUIC ok",
                    s->id, vec[i].len);
        acked_len += vec[i].len;
      }







<
<






<
<
<
<
<







1513
1514
1515
1516
1517
1518
1519


1520
1521
1522
1523
1524
1525





1526
1527
1528
1529
1530
1531
1532
    DEBUGASSERT(s->id == stream_id);
    for(i = 0, total_len = 0; i < n; ++i) {
      total_len += vec[i].len;
    }
    for(i = 0; (i < n) && !blocked; ++i) {
      /* Without stream->s.ssl, we closed that already, so
       * pretend the write did succeed. */


      uint64_t flags = (eos && ((i + 1) == n))? SSL_WRITE_FLAG_CONCLUDE : 0;
      written = vec[i].len;
      ok = !s->ssl || SSL_write_ex2(s->ssl, vec[i].base, vec[i].len, flags,
                                   &written);
      if(ok && flags & SSL_WRITE_FLAG_CONCLUDE)
        eos_written = TRUE;





      if(ok) {
        /* As OpenSSL buffers the data, we count this as acknowledged
         * from nghttp3's point of view */
        CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] send %zu bytes to QUIC ok",
                    s->id, vec[i].len);
        acked_len += vec[i].len;
      }
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
    nva[i].flags = NGHTTP3_NV_FLAG_NONE;
  }

  DEBUGASSERT(stream->s.id == -1);
  *err = cf_osslq_stream_open(&stream->s, ctx->tls.ossl.ssl, 0,
                              &ctx->stream_bufcp, data);
  if(*err) {
    failf(data, "can't get bidi streams");
    *err = CURLE_SEND_ERROR;
    goto out;
  }

  switch(data->state.httpreq) {
  case HTTPREQ_POST:
  case HTTPREQ_POST_FORM:







|







1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
    nva[i].flags = NGHTTP3_NV_FLAG_NONE;
  }

  DEBUGASSERT(stream->s.id == -1);
  *err = cf_osslq_stream_open(&stream->s, ctx->tls.ossl.ssl, 0,
                              &ctx->stream_bufcp, data);
  if(*err) {
    failf(data, "cannot get bidi streams");
    *err = CURLE_SEND_ERROR;
    goto out;
  }

  switch(data->state.httpreq) {
  case HTTPREQ_POST:
  case HTTPREQ_POST_FORM:
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
    nwritten = h3_stream_open(cf, data, buf, len, err);
    if(nwritten < 0) {
      CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
      goto out;
    }
    stream = H3_STREAM_CTX(ctx, data);
  }
  else if(stream->upload_blocked_len) {
    /* the data in `buf` has already been submitted or added to the
     * buffers, but have been EAGAINed on the last invocation. */
    DEBUGASSERT(len >= stream->upload_blocked_len);
    if(len < stream->upload_blocked_len) {
      /* Did we get called again with a smaller `len`? This should not
       * happen. We are not prepared to handle that. */
      failf(data, "HTTP/3 send again with decreased length");
      *err = CURLE_HTTP3;
      nwritten = -1;
      goto out;
    }
    nwritten = (ssize_t)stream->upload_blocked_len;
    stream->upload_blocked_len = 0;
  }
  else if(stream->closed) {
    if(stream->resp_hds_complete) {
      /* Server decided to close the stream after having sent us a final
       * response. This is valid if it is not interested in the request
       * body. This happens on 30x or 40x responses.
       * We silently discard the data sent, since this is not a transport
       * error situation. */







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1931
1932
1933
1934
1935
1936
1937















1938
1939
1940
1941
1942
1943
1944
    nwritten = h3_stream_open(cf, data, buf, len, err);
    if(nwritten < 0) {
      CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
      goto out;
    }
    stream = H3_STREAM_CTX(ctx, data);
  }















  else if(stream->closed) {
    if(stream->resp_hds_complete) {
      /* Server decided to close the stream after having sent us a final
       * response. This is valid if it is not interested in the request
       * body. This happens on 30x or 40x responses.
       * We silently discard the data sent, since this is not a transport
       * error situation. */
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940

  result = cf_progress_egress(cf, data);
  if(result) {
    *err = result;
    nwritten = -1;
  }

  if(stream && nwritten > 0 && stream->sendbuf_len_in_flight) {
    /* We have unacknowledged DATA and cannot report success to our
     * caller. Instead we EAGAIN and remember how much we have already
     * "written" into our various internal connection buffers. */
    stream->upload_blocked_len = nwritten;
    CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu), "
                "%zu bytes in flight -> EGAIN", stream->s.id, len,
                stream->sendbuf_len_in_flight);
    *err = CURLE_AGAIN;
    nwritten = -1;
  }

out:
  result = check_and_set_expiry(cf, data);
  CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d",
              stream? stream->s.id : -1, len, nwritten, *err);
  CF_DATA_RESTORE(cf, save);
  return nwritten;
}







<
<
<
<
<
<
<
<
<
<
<
<







1968
1969
1970
1971
1972
1973
1974












1975
1976
1977
1978
1979
1980
1981

  result = cf_progress_egress(cf, data);
  if(result) {
    *err = result;
    nwritten = -1;
  }













out:
  result = check_and_set_expiry(cf, data);
  CURL_TRC_CF(data, cf, "[%" CURL_PRId64 "] cf_send(len=%zu) -> %zd, %d",
              stream? stream->s.id : -1, len, nwritten, *err);
  CF_DATA_RESTORE(cf, save);
  return nwritten;
}
2086
2087
2088
2089
2090
2091
2092
2093

2094
2095
2096
2097
2098
2099
2100
  case CF_CTRL_DATA_DONE:
    h3_data_done(cf, data);
    break;
  case CF_CTRL_DATA_DONE_SEND: {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    if(stream && !stream->send_closed) {
      stream->send_closed = TRUE;
      stream->upload_left = Curl_bufq_len(&stream->sendbuf);

      (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
    }
    break;
  }
  case CF_CTRL_DATA_IDLE: {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    CURL_TRC_CF(data, cf, "data idle");







|
>







2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
  case CF_CTRL_DATA_DONE:
    h3_data_done(cf, data);
    break;
  case CF_CTRL_DATA_DONE_SEND: {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    if(stream && !stream->send_closed) {
      stream->send_closed = TRUE;
      stream->upload_left = Curl_bufq_len(&stream->sendbuf) -
        stream->sendbuf_len_in_flight;
      (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
    }
    break;
  }
  case CF_CTRL_DATA_IDLE: {
    struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
    CURL_TRC_CF(data, cf, "data idle");
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160

  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    goto out;

  alive = TRUE;
  if(*input_pending) {
    CURLcode result;
    /* This happens before we've sent off a request and the connection is
       not in use by any other transfer, there shouldn't be any data here,
       only "protocol frames" */
    *input_pending = FALSE;
    result = cf_progress_ingress(cf, data);
    CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
    alive = result? FALSE : TRUE;
  }








|
|







2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202

  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    goto out;

  alive = TRUE;
  if(*input_pending) {
    CURLcode result;
    /* This happens before we have sent off a request and the connection is
       not in use by any other transfer, there should not be any data here,
       only "protocol frames" */
    *input_pending = FALSE;
    result = cf_progress_ingress(cf, data);
    CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
    alive = result? FALSE : TRUE;
  }

2185
2186
2187
2188
2189
2190
2191




2192
2193
2194
2195
2196
2197
2198
    bool want_recv, want_send;
    Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
    if(want_recv || want_send) {
      Curl_pollset_set(data, ps, ctx->q.sockfd,
                       SSL_net_read_desired(ctx->tls.ossl.ssl),
                       SSL_net_write_desired(ctx->tls.ossl.ssl));
    }




  }
}

static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               int query, int *pres1, void *pres2)
{







>
>
>
>







2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
    bool want_recv, want_send;
    Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
    if(want_recv || want_send) {
      Curl_pollset_set(data, ps, ctx->q.sockfd,
                       SSL_net_read_desired(ctx->tls.ossl.ssl),
                       SSL_net_write_desired(ctx->tls.ossl.ssl));
    }
    else if(ctx->need_recv || ctx->need_send) {
      Curl_pollset_set(data, ps, ctx->q.sockfd,
                       ctx->need_recv, ctx->need_send);
    }
  }
}

static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               int query, int *pres1, void *pres2)
{
2248
2249
2250
2251
2252
2253
2254

2255
2256
2257
2258
2259
2260
2261
struct Curl_cftype Curl_cft_http3 = {
  "HTTP/3",
  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  0,
  cf_osslq_destroy,
  cf_osslq_connect,
  cf_osslq_close,

  Curl_cf_def_get_host,
  cf_osslq_adjust_pollset,
  cf_osslq_data_pending,
  cf_osslq_send,
  cf_osslq_recv,
  cf_osslq_data_event,
  cf_osslq_conn_is_alive,







>







2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
struct Curl_cftype Curl_cft_http3 = {
  "HTTP/3",
  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  0,
  cf_osslq_destroy,
  cf_osslq_connect,
  cf_osslq_close,
  cf_osslq_shutdown,
  Curl_cf_def_get_host,
  cf_osslq_adjust_pollset,
  cf_osslq_data_pending,
  cf_osslq_send,
  cf_osslq_recv,
  cf_osslq_data_event,
  cf_osslq_conn_is_alive,
Changes to jni/curl/lib/vquic/curl_quiche.c.
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/* HTTP/3 error values defined in RFC 9114, ch. 8.1 */
#define CURL_H3_NO_ERROR  (0x0100)

#define QUIC_MAX_STREAMS              (100)

#define H3_STREAM_WINDOW_SIZE  (128 * 1024)
#define H3_STREAM_CHUNK_SIZE    (16 * 1024)
/* The pool keeps spares around and half of a full stream windows
 * seems good. More does not seem to improve performance.
 * The benefit of the pool is that stream buffer to not keep
 * spares. So memory consumption goes down when streams run empty,
 * have a large upload done, etc. */
#define H3_STREAM_POOL_SPARES \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
/* Receive and Send max number of chunks just follows from the
 * chunk size and window size */
#define H3_STREAM_RECV_CHUNKS \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
#define H3_STREAM_SEND_CHUNKS \







|
|
<
|
|







60
61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76
77
/* HTTP/3 error values defined in RFC 9114, ch. 8.1 */
#define CURL_H3_NO_ERROR  (0x0100)

#define QUIC_MAX_STREAMS              (100)

#define H3_STREAM_WINDOW_SIZE  (128 * 1024)
#define H3_STREAM_CHUNK_SIZE    (16 * 1024)
/* The pool keeps spares around and half of a full stream windows seems good.
 * More does not seem to improve performance. The benefit of the pool is that

 * stream buffer to not keep spares. Memory consumption goes down when streams
 * run empty, have a large upload done, etc. */
#define H3_STREAM_POOL_SPARES \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
/* Receive and Send max number of chunks just follows from the
 * chunk size and window size */
#define H3_STREAM_RECV_CHUNKS \
          (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
#define H3_STREAM_SEND_CHUNKS \
99
100
101
102
103
104
105

106
107
108
109
110
111
112
  struct curltime handshake_at;      /* time connect handshake finished */
  struct curltime reconnect_at;      /* time the next attempt should start */
  struct bufc_pool stream_bufcp;     /* chunk pool for streams */
  struct Curl_hash streams;          /* hash `data->id` to `stream_ctx` */
  curl_off_t data_recvd;
  BIT(goaway);                       /* got GOAWAY from server */
  BIT(x509_store_setup);             /* if x509 store has been set up */

};

#ifdef DEBUG_QUICHE
static void quiche_debug_log(const char *line, void *argp)
{
  (void)argp;
  fprintf(stderr, "%s\n", line);







>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  struct curltime handshake_at;      /* time connect handshake finished */
  struct curltime reconnect_at;      /* time the next attempt should start */
  struct bufc_pool stream_bufcp;     /* chunk pool for streams */
  struct Curl_hash streams;          /* hash `data->id` to `stream_ctx` */
  curl_off_t data_recvd;
  BIT(goaway);                       /* got GOAWAY from server */
  BIT(x509_store_setup);             /* if x509 store has been set up */
  BIT(shutdown_started);             /* queued shutdown packets */
};

#ifdef DEBUG_QUICHE
static void quiche_debug_log(const char *line, void *argp)
{
  (void)argp;
  fprintf(stderr, "%s\n", line);
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
out:
  result = cf_flush_egress(cf, data);
  if(result) {
    *err = result;
    nwritten = -1;
  }
  CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
              stream? stream->id : -1, len, nwritten, *err);
  return nwritten;
}

static bool stream_is_writeable(struct Curl_cfilter *cf,
                                struct Curl_easy *data)
{
  struct cf_quiche_ctx *ctx = cf->ctx;







|







1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
out:
  result = cf_flush_egress(cf, data);
  if(result) {
    *err = result;
    nwritten = -1;
  }
  CURL_TRC_CF(data, cf, "[%" CURL_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
              stream? stream->id : (uint64_t)~0, len, nwritten, *err);
  return nwritten;
}

static bool stream_is_writeable(struct Curl_cfilter *cf,
                                struct Curl_easy *data)
{
  struct cf_quiche_ctx *ctx = cf->ctx;
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281

  result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
  if(result)
    return result;

  ctx->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION);
  if(!ctx->cfg) {
    failf(data, "can't create quiche config");
    return CURLE_FAILED_INIT;
  }
  quiche_config_enable_pacing(ctx->cfg, false);
  quiche_config_set_max_idle_timeout(ctx->cfg, CURL_QUIC_MAX_IDLE_MS);
  quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
    /* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
  quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS);







|







1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281

  result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
  if(result)
    return result;

  ctx->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION);
  if(!ctx->cfg) {
    failf(data, "cannot create quiche config");
    return CURLE_FAILED_INIT;
  }
  quiche_config_enable_pacing(ctx->cfg, false);
  quiche_config_set_max_idle_timeout(ctx->cfg, CURL_QUIC_MAX_IDLE_MS);
  quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
    /* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
  quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS);
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
  ctx->qconn = quiche_conn_new_with_tls((const uint8_t *)ctx->scid,
                                      sizeof(ctx->scid), NULL, 0,
                                      (struct sockaddr *)&ctx->q.local_addr,
                                      ctx->q.local_addrlen,
                                      &sockaddr->sa_addr, sockaddr->addrlen,
                                      ctx->cfg, ctx->tls.ossl.ssl, false);
  if(!ctx->qconn) {
    failf(data, "can't create quiche connection");
    return CURLE_OUT_OF_MEMORY;
  }

  /* Known to not work on Windows */
#if !defined(_WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD)
  {
    int qfd;







|







1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
  ctx->qconn = quiche_conn_new_with_tls((const uint8_t *)ctx->scid,
                                      sizeof(ctx->scid), NULL, 0,
                                      (struct sockaddr *)&ctx->q.local_addr,
                                      ctx->q.local_addrlen,
                                      &sockaddr->sa_addr, sockaddr->addrlen,
                                      ctx->cfg, ctx->tls.ossl.ssl, false);
  if(!ctx->qconn) {
    failf(data, "cannot create quiche connection");
    return CURLE_OUT_OF_MEMORY;
  }

  /* Known to not work on Windows */
#if !defined(_WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD)
  {
    int qfd;
1459
1460
1461
1462
1463
1464
1465
1466

1467
1468
1469

1470




1471



1472

1473
1474







1475
1476


1477


1478






















1479
1480
1481
1482
1483
1484
1485
    Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
    infof(data, "connect to %s port %u failed: %s",
          ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
  }
#endif
  return result;
}


static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_quiche_ctx *ctx = cf->ctx;






  if(ctx) {



    if(ctx->qconn) {

      vquic_ctx_update_time(&ctx->q);
      (void)quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0);







      /* flushing the egress is not a failsafe way to deliver all the
         outstanding packets, but we also don't want to get stuck here... */


      (void)cf_flush_egress(cf, data);


    }






















    cf_quiche_ctx_clear(ctx);
  }
}

static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_quiche_ctx *ctx = cf->ctx;








>
|


>

>
>
>
>
|
>
>
>
|
>
|
|
>
>
>
>
>
>
>
|
<
>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492

1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
    Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
    infof(data, "connect to %s port %u failed: %s",
          ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
  }
#endif
  return result;
}

static CURLcode cf_quiche_shutdown(struct Curl_cfilter *cf,
                                   struct Curl_easy *data, bool *done)
{
  struct cf_quiche_ctx *ctx = cf->ctx;
  CURLcode result = CURLE_OK;

  if(cf->shutdown || !ctx || !ctx->qconn) {
    *done = TRUE;
    return CURLE_OK;
  }

  *done = FALSE;
  if(!ctx->shutdown_started) {
    int err;

    ctx->shutdown_started = TRUE;
    vquic_ctx_update_time(&ctx->q);
    err = quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0);
    if(err) {
      CURL_TRC_CF(data, cf, "error %d adding shutdown packet, "
                  "aborting shutdown", err);
      result = CURLE_SEND_ERROR;
      goto out;
    }
  }


  if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
    CURL_TRC_CF(data, cf, "shutdown, flushing sendbuf");
    result = cf_flush_egress(cf, data);
    if(result)
      goto out;
  }

  if(Curl_bufq_is_empty(&ctx->q.sendbuf)) {
    /* sent everything, quiche does not seem to support a graceful
     * shutdown waiting for a reply, so ware done. */
    CURL_TRC_CF(data, cf, "shutdown completely sent off, done");
    *done = TRUE;
  }
  else {
    CURL_TRC_CF(data, cf, "shutdown sending blocked");
  }

out:
  return result;
}

static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_quiche_ctx *ctx = cf->ctx;

  if(ctx) {
    bool done;
    (void)cf_quiche_shutdown(cf, data, &done);
    cf_quiche_ctx_clear(ctx);
  }
}

static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct cf_quiche_ctx *ctx = cf->ctx;
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582

1583
1584
1585
1586
1587
1588
1589
    return FALSE;
  }

  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    return FALSE;

  if(*input_pending) {
    /* This happens before we've sent off a request and the connection is
       not in use by any other transfer, there shouldn't be any data here,
       only "protocol frames" */
    *input_pending = FALSE;
    if(cf_process_ingress(cf, data))
      alive = FALSE;
    else {
      alive = TRUE;
    }
  }

  return alive;
}

struct Curl_cftype Curl_cft_http3 = {
  "HTTP/3",
  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  0,
  cf_quiche_destroy,
  cf_quiche_connect,
  cf_quiche_close,

  Curl_cf_def_get_host,
  cf_quiche_adjust_pollset,
  cf_quiche_data_pending,
  cf_quiche_send,
  cf_quiche_recv,
  cf_quiche_data_event,
  cf_quiche_conn_is_alive,







|
|



















>







1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
    return FALSE;
  }

  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
    return FALSE;

  if(*input_pending) {
    /* This happens before we have sent off a request and the connection is
       not in use by any other transfer, there should not be any data here,
       only "protocol frames" */
    *input_pending = FALSE;
    if(cf_process_ingress(cf, data))
      alive = FALSE;
    else {
      alive = TRUE;
    }
  }

  return alive;
}

struct Curl_cftype Curl_cft_http3 = {
  "HTTP/3",
  CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
  0,
  cf_quiche_destroy,
  cf_quiche_connect,
  cf_quiche_close,
  cf_quiche_shutdown,
  Curl_cf_def_get_host,
  cf_quiche_adjust_pollset,
  cf_quiche_data_pending,
  cf_quiche_send,
  cf_quiche_recv,
  cf_quiche_data_event,
  cf_quiche_conn_is_alive,
Changes to jni/curl/lib/vquic/vquic-tls.c.
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
static void keylog_callback(const WOLFSSL *ssl, const char *line)
{
  (void)ssl;
  Curl_tls_keylog_write_line(line);
}
#endif

static CURLcode curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
                                   struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   Curl_vquic_tls_ctx_setup *cb_setup,
                                   void *cb_user_data)
{
  struct ssl_primary_config *conn_config;
  CURLcode result = CURLE_FAILED_INIT;

  conn_config = Curl_ssl_cf_get_primary_config(cf);
  if(!conn_config) {
    result = CURLE_FAILED_INIT;
    goto out;
  }

  ctx->ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
  if(!ctx->ssl_ctx) {
    result = CURLE_OUT_OF_MEMORY;
    goto out;
  }

  if(cb_setup) {
    result = cb_setup(cf, data, cb_user_data);
    if(result)
      goto out;
  }

  wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx);

  if(wolfSSL_CTX_set_cipher_list(ctx->ssl_ctx, conn_config->cipher_list13 ?
                                 conn_config->cipher_list13 :
                                 QUIC_CIPHERS) != 1) {
    char error_buffer[256];
    ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
    failf(data, "wolfSSL failed to set ciphers: %s", error_buffer);
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    goto out;
  }

  if(wolfSSL_CTX_set1_groups_list(ctx->ssl_ctx, conn_config->curves ?
                                  conn_config->curves :
                                  (char *)QUIC_GROUPS) != 1) {
    failf(data, "wolfSSL failed to set curves");
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    goto out;
  }

  /* Open the file if a TLS or QUIC backend has not done this before. */
  Curl_tls_keylog_open();
  if(Curl_tls_keylog_enabled()) {
#if defined(HAVE_SECRET_CALLBACK)
    wolfSSL_CTX_set_keylog_callback(ctx->ssl_ctx, keylog_callback);
#else
    failf(data, "wolfSSL was built without keylog callback");
    result = CURLE_NOT_BUILT_IN;
    goto out;
#endif
  }

  if(conn_config->verifypeer) {
    const char * const ssl_cafile = conn_config->CAfile;
    const char * const ssl_capath = conn_config->CApath;

    wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
    if(ssl_cafile || ssl_capath) {
      /* tell wolfSSL where to find CA certificates that are used to verify
         the server's certificate. */
      int rc =
        wolfSSL_CTX_load_verify_locations_ex(ctx->ssl_ctx, ssl_cafile,
                                             ssl_capath,
                                             WOLFSSL_LOAD_FLAG_IGNORE_ERR);
      if(SSL_SUCCESS != rc) {
        /* Fail if we insist on successfully verifying the server. */
        failf(data, "error setting certificate verify locations:"
              "  CAfile: %s CApath: %s",
              ssl_cafile ? ssl_cafile : "none",
              ssl_capath ? ssl_capath : "none");
        result = CURLE_SSL_CACERT_BADFILE;
        goto out;
      }
      infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
      infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
    }
#ifdef CURL_CA_FALLBACK
    else {
      /* verifying the peer without any CA certificates won't work so
         use wolfssl's built-in default as fallback */
      wolfSSL_CTX_set_default_verify_paths(ctx->ssl_ctx);
    }
#endif
  }
  else {
    wolfSSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_NONE, NULL);
  }

  /* give application a chance to interfere with SSL set up. */
  if(data->set.ssl.fsslctx) {
    Curl_set_in_callback(data, true);
    result = (*data->set.ssl.fsslctx)(data, ctx->ssl_ctx,
                                      data->set.ssl.fsslctxp);
    Curl_set_in_callback(data, false);
    if(result) {
      failf(data, "error signaled by ssl ctx callback");
      goto out;
    }
  }
  result = CURLE_OK;

out:
  if(result && ctx->ssl_ctx) {
    SSL_CTX_free(ctx->ssl_ctx);
    ctx->ssl_ctx = NULL;
  }
  return result;
}

/** SSL callbacks ***/

static CURLcode curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
                                   struct Curl_easy *data,
                                   struct ssl_peer *peer,
                                   const char *alpn, size_t alpn_len,
                                   void *user_data)
{
  (void)data;
  DEBUGASSERT(!ctx->ssl);
  DEBUGASSERT(ctx->ssl_ctx);
  ctx->ssl = wolfSSL_new(ctx->ssl_ctx);

  wolfSSL_set_app_data(ctx->ssl, user_data);
  wolfSSL_set_connect_state(ctx->ssl);
  wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);

  if(alpn)
    wolfSSL_set_alpn_protos(ctx->ssl, (const unsigned char *)alpn,
                            (int)alpn_len);

  if(peer->sni) {
    wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME,
                   peer->sni, (unsigned short)strlen(peer->sni));
  }

  return CURLE_OK;
}
#endif /* defined(USE_WOLFSSL) */








|














|
|










|

|









|











|











|




|
















|

|




|





|










|
|
|






|






|
|
|

|
|
|


|
|


|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
static void keylog_callback(const WOLFSSL *ssl, const char *line)
{
  (void)ssl;
  Curl_tls_keylog_write_line(line);
}
#endif

static CURLcode Curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
                                   struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   Curl_vquic_tls_ctx_setup *cb_setup,
                                   void *cb_user_data)
{
  struct ssl_primary_config *conn_config;
  CURLcode result = CURLE_FAILED_INIT;

  conn_config = Curl_ssl_cf_get_primary_config(cf);
  if(!conn_config) {
    result = CURLE_FAILED_INIT;
    goto out;
  }

  ctx->wssl.ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
  if(!ctx->wssl.ctx) {
    result = CURLE_OUT_OF_MEMORY;
    goto out;
  }

  if(cb_setup) {
    result = cb_setup(cf, data, cb_user_data);
    if(result)
      goto out;
  }

  wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);

  if(wolfSSL_CTX_set_cipher_list(ctx->wssl.ctx, conn_config->cipher_list13 ?
                                 conn_config->cipher_list13 :
                                 QUIC_CIPHERS) != 1) {
    char error_buffer[256];
    ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
    failf(data, "wolfSSL failed to set ciphers: %s", error_buffer);
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    goto out;
  }

  if(wolfSSL_CTX_set1_groups_list(ctx->wssl.ctx, conn_config->curves ?
                                  conn_config->curves :
                                  (char *)QUIC_GROUPS) != 1) {
    failf(data, "wolfSSL failed to set curves");
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    goto out;
  }

  /* Open the file if a TLS or QUIC backend has not done this before. */
  Curl_tls_keylog_open();
  if(Curl_tls_keylog_enabled()) {
#if defined(HAVE_SECRET_CALLBACK)
    wolfSSL_CTX_set_keylog_callback(ctx->wssl.ctx, keylog_callback);
#else
    failf(data, "wolfSSL was built without keylog callback");
    result = CURLE_NOT_BUILT_IN;
    goto out;
#endif
  }

  if(conn_config->verifypeer) {
    const char * const ssl_cafile = conn_config->CAfile;
    const char * const ssl_capath = conn_config->CApath;

    wolfSSL_CTX_set_verify(ctx->wssl.ctx, SSL_VERIFY_PEER, NULL);
    if(ssl_cafile || ssl_capath) {
      /* tell wolfSSL where to find CA certificates that are used to verify
         the server's certificate. */
      int rc =
        wolfSSL_CTX_load_verify_locations_ex(ctx->wssl.ctx, ssl_cafile,
                                             ssl_capath,
                                             WOLFSSL_LOAD_FLAG_IGNORE_ERR);
      if(SSL_SUCCESS != rc) {
        /* Fail if we insist on successfully verifying the server. */
        failf(data, "error setting certificate verify locations:"
              "  CAfile: %s CApath: %s",
              ssl_cafile ? ssl_cafile : "none",
              ssl_capath ? ssl_capath : "none");
        result = CURLE_SSL_CACERT_BADFILE;
        goto out;
      }
      infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
      infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
    }
#ifdef CURL_CA_FALLBACK
    else {
      /* verifying the peer without any CA certificates will not work so
         use wolfssl's built-in default as fallback */
      wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);
    }
#endif
  }
  else {
    wolfSSL_CTX_set_verify(ctx->wssl.ctx, SSL_VERIFY_NONE, NULL);
  }

  /* give application a chance to interfere with SSL set up. */
  if(data->set.ssl.fsslctx) {
    Curl_set_in_callback(data, true);
    result = (*data->set.ssl.fsslctx)(data, ctx->wssl.ctx,
                                      data->set.ssl.fsslctxp);
    Curl_set_in_callback(data, false);
    if(result) {
      failf(data, "error signaled by ssl ctx callback");
      goto out;
    }
  }
  result = CURLE_OK;

out:
  if(result && ctx->wssl.ctx) {
    SSL_CTX_free(ctx->wssl.ctx);
    ctx->wssl.ctx = NULL;
  }
  return result;
}

/** SSL callbacks ***/

static CURLcode Curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
                                   struct Curl_easy *data,
                                   struct ssl_peer *peer,
                                   const char *alpn, size_t alpn_len,
                                   void *user_data)
{
  (void)data;
  DEBUGASSERT(!ctx->wssl.handle);
  DEBUGASSERT(ctx->wssl.ctx);
  ctx->wssl.handle = wolfSSL_new(ctx->wssl.ctx);

  wolfSSL_set_app_data(ctx->wssl.handle, user_data);
  wolfSSL_set_connect_state(ctx->wssl.handle);
  wolfSSL_set_quic_use_legacy_codepoint(ctx->wssl.handle, 0);

  if(alpn)
    wolfSSL_set_alpn_protos(ctx->wssl.handle, (const unsigned char *)alpn,
                            (unsigned int)alpn_len);

  if(peer->sni) {
    wolfSSL_UseSNI(ctx->wssl.handle, WOLFSSL_SNI_HOST_NAME,
                   peer->sni, (unsigned short)strlen(peer->sni));
  }

  return CURLE_OK;
}
#endif /* defined(USE_WOLFSSL) */

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288






289
290
291
292
293
294
295
296
297
                            cb_setup, cb_user_data, NULL, ssl_user_data);
#elif defined(USE_GNUTLS)
  (void)result;
  return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
                            (const unsigned char *)alpn, alpn_len,
                            cb_setup, cb_user_data, ssl_user_data);
#elif defined(USE_WOLFSSL)
  result = curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
  if(result)
    return result;

  return curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
#else
#error "no TLS lib in used, should not happen"
  return CURLE_FAILED_INIT;
#endif
}

void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx)
{
#ifdef USE_OPENSSL
  if(ctx->ossl.ssl)
    SSL_free(ctx->ossl.ssl);
  if(ctx->ossl.ssl_ctx)
    SSL_CTX_free(ctx->ossl.ssl_ctx);
#elif defined(USE_GNUTLS)
  if(ctx->gtls.cred)
    gnutls_certificate_free_credentials(ctx->gtls.cred);
  if(ctx->gtls.session)
    gnutls_deinit(ctx->gtls.session);

#elif defined(USE_WOLFSSL)
  if(ctx->ssl)
    wolfSSL_free(ctx->ssl);
  if(ctx->ssl_ctx)
    wolfSSL_CTX_free(ctx->ssl_ctx);
#endif
  memset(ctx, 0, sizeof(*ctx));
}

CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx,
                                    struct Curl_cfilter *cf,
                                    struct Curl_easy *data)
{
#ifdef USE_OPENSSL
  if(!ctx->ossl.x509_store_setup) {
    CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ossl.ssl_ctx);
    if(result)
      return result;
    ctx->ossl.x509_store_setup = TRUE;
  }






#elif defined(USE_GNUTLS)
  if(!ctx->gtls.trust_setup) {
    CURLcode result = Curl_gtls_client_trust_setup(cf, data, &ctx->gtls);
    if(result)
      return result;
  }
#else
  (void)ctx; (void)cf; (void)data;
#endif







|



|














<
<


>

|
|
|
|















>
>
>
>
>
>

|







239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264


265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
                            cb_setup, cb_user_data, NULL, ssl_user_data);
#elif defined(USE_GNUTLS)
  (void)result;
  return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
                            (const unsigned char *)alpn, alpn_len,
                            cb_setup, cb_user_data, ssl_user_data);
#elif defined(USE_WOLFSSL)
  result = Curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
  if(result)
    return result;

  return Curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
#else
#error "no TLS lib in used, should not happen"
  return CURLE_FAILED_INIT;
#endif
}

void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx)
{
#ifdef USE_OPENSSL
  if(ctx->ossl.ssl)
    SSL_free(ctx->ossl.ssl);
  if(ctx->ossl.ssl_ctx)
    SSL_CTX_free(ctx->ossl.ssl_ctx);
#elif defined(USE_GNUTLS)


  if(ctx->gtls.session)
    gnutls_deinit(ctx->gtls.session);
  Curl_gtls_shared_creds_free(&ctx->gtls.shared_creds);
#elif defined(USE_WOLFSSL)
  if(ctx->wssl.handle)
    wolfSSL_free(ctx->wssl.handle);
  if(ctx->wssl.ctx)
    wolfSSL_CTX_free(ctx->wssl.ctx);
#endif
  memset(ctx, 0, sizeof(*ctx));
}

CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx,
                                    struct Curl_cfilter *cf,
                                    struct Curl_easy *data)
{
#ifdef USE_OPENSSL
  if(!ctx->ossl.x509_store_setup) {
    CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ossl.ssl_ctx);
    if(result)
      return result;
    ctx->ossl.x509_store_setup = TRUE;
  }
#elif defined(USE_WOLFSSL)
  if(!ctx->wssl.x509_store_setup) {
    CURLcode result = Curl_wssl_setup_x509_store(cf, data, &ctx->wssl);
    if(result)
      return result;
  }
#elif defined(USE_GNUTLS)
  if(!ctx->gtls.shared_creds->trust_setup) {
    CURLcode result = Curl_gtls_client_trust_setup(cf, data, &ctx->gtls);
    if(result)
      return result;
  }
#else
  (void)ctx; (void)cf; (void)data;
#endif
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
    if(result)
      return result;
  }
#elif defined(USE_WOLFSSL)
  (void)data;
  if(conn_config->verifyhost) {
    if(peer->sni) {
      WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->ssl);
      if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
            == WOLFSSL_FAILURE) {
        result = CURLE_PEER_FAILED_VERIFICATION;
      }
      wolfSSL_X509_free(cert);
    }








|







326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
    if(result)
      return result;
  }
#elif defined(USE_WOLFSSL)
  (void)data;
  if(conn_config->verifyhost) {
    if(peer->sni) {
      WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.handle);
      if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
            == WOLFSSL_FAILURE) {
        result = CURLE_PEER_FAILED_VERIFICATION;
      }
      wolfSSL_X509_free(cert);
    }

Changes to jni/curl/lib/vquic/vquic-tls.h.
27
28
29
30
31
32
33


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "curl_setup.h"
#include "bufq.h"
#include "vtls/openssl.h"

#if defined(USE_HTTP3) && \
  (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))



struct curl_tls_ctx {
#ifdef USE_OPENSSL
  struct ossl_ctx ossl;
#elif defined(USE_GNUTLS)
  struct gtls_ctx gtls;
#elif defined(USE_WOLFSSL)
  WOLFSSL_CTX *ssl_ctx;
  WOLFSSL *ssl;
#endif
};

/**
 * Callback passed to `Curl_vquic_tls_init()` that can
 * do early initializations on the not otherwise configured TLS
 * instances created. This varies by TLS backend:







>
>






|
<







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
#include "curl_setup.h"
#include "bufq.h"
#include "vtls/openssl.h"

#if defined(USE_HTTP3) && \
  (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))

#include "vtls/wolfssl.h"

struct curl_tls_ctx {
#ifdef USE_OPENSSL
  struct ossl_ctx ossl;
#elif defined(USE_GNUTLS)
  struct gtls_ctx gtls;
#elif defined(USE_WOLFSSL)
  struct wolfssl_ctx wssl;

#endif
};

/**
 * Callback passed to `Curl_vquic_tls_init()` that can
 * do early initializations on the not otherwise configured TLS
 * instances created. This varies by TLS backend:
Changes to jni/curl/lib/vquic/vquic.c.
32
33
34
35
36
37
38



39
40
41
42
43
44
45
#define _GNU_SOURCE
#include <sys/socket.h>
#undef _GNU_SOURCE
#endif

#include "curl_setup.h"




#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "urldata.h"
#include "bufq.h"
#include "dynbuf.h"
#include "cfilters.h"







>
>
>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#define _GNU_SOURCE
#include <sys/socket.h>
#undef _GNU_SOURCE
#endif

#include "curl_setup.h"

#ifdef HAVE_NETINET_UDP_H
#include <netinet/udp.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "urldata.h"
#include "bufq.h"
#include "dynbuf.h"
#include "cfilters.h"
324
325
326
327
328
329
330






























331
332
333
334
335
336
337
338
339
340
341

342
343
344
345
346
347



348
349
350
351
352
353
354
355
356
357
358
359
360
361


362
363
364
365
366
367
368
  qctx->split_gsolen = gsolen;
  qctx->gsolen = tail_gsolen;
  CURL_TRC_CF(data, cf, "vquic_send_tail_split: [%zu gso=%zu][%zu gso=%zu]",
              qctx->split_len, qctx->split_gsolen,
              tail_len, qctx->gsolen);
  return vquic_flush(cf, data, qctx);
}































#ifdef HAVE_SENDMMSG
static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 struct cf_quic_ctx *qctx,
                                 size_t max_pkts,
                                 vquic_recv_pkt_cb *recv_cb, void *userp)
{
#define MMSG_NUM  64
  struct iovec msg_iov[MMSG_NUM];
  struct mmsghdr mmsg[MMSG_NUM];

  uint8_t bufs[MMSG_NUM][2*1024];
  struct sockaddr_storage remote_addr[MMSG_NUM];
  size_t total_nread, pkts;
  int mcount, i, n;
  char errstr[STRERROR_LEN];
  CURLcode result = CURLE_OK;




  DEBUGASSERT(max_pkts > 0);
  pkts = 0;
  total_nread = 0;
  while(pkts < max_pkts) {
    n = (int)CURLMIN(MMSG_NUM, max_pkts);
    memset(&mmsg, 0, sizeof(mmsg));
    for(i = 0; i < n; ++i) {
      msg_iov[i].iov_base = bufs[i];
      msg_iov[i].iov_len = (int)sizeof(bufs[i]);
      mmsg[i].msg_hdr.msg_iov = &msg_iov[i];
      mmsg[i].msg_hdr.msg_iovlen = 1;
      mmsg[i].msg_hdr.msg_name = &remote_addr[i];
      mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]);


    }

    while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
          SOCKERRNO == EINTR)
      ;
    if(mcount == -1) {
      if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>











>






>
>
>














>
>







327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
  qctx->split_gsolen = gsolen;
  qctx->gsolen = tail_gsolen;
  CURL_TRC_CF(data, cf, "vquic_send_tail_split: [%zu gso=%zu][%zu gso=%zu]",
              qctx->split_len, qctx->split_gsolen,
              tail_len, qctx->gsolen);
  return vquic_flush(cf, data, qctx);
}

#if defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)
static size_t msghdr_get_udp_gro(struct msghdr *msg)
{
  int gso_size = 0;
#if defined(__linux__) && defined(UDP_GRO)
  struct cmsghdr *cmsg;

  /* Workaround musl CMSG_NXTHDR issue */
#ifndef __GLIBC__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-compare"
#pragma clang diagnostic ignored "-Wcast-align"
#endif
  for(cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
#ifndef __GLIBC__
#pragma clang diagnostic pop
#endif
    if(cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
      memcpy(&gso_size, CMSG_DATA(cmsg), sizeof(gso_size));

      break;
    }
  }
#endif
  (void)msg;

  return (size_t)gso_size;
}
#endif

#ifdef HAVE_SENDMMSG
static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 struct cf_quic_ctx *qctx,
                                 size_t max_pkts,
                                 vquic_recv_pkt_cb *recv_cb, void *userp)
{
#define MMSG_NUM  64
  struct iovec msg_iov[MMSG_NUM];
  struct mmsghdr mmsg[MMSG_NUM];
  uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(uint16_t))];
  uint8_t bufs[MMSG_NUM][2*1024];
  struct sockaddr_storage remote_addr[MMSG_NUM];
  size_t total_nread, pkts;
  int mcount, i, n;
  char errstr[STRERROR_LEN];
  CURLcode result = CURLE_OK;
  size_t gso_size;
  size_t pktlen;
  size_t offset, to;

  DEBUGASSERT(max_pkts > 0);
  pkts = 0;
  total_nread = 0;
  while(pkts < max_pkts) {
    n = (int)CURLMIN(MMSG_NUM, max_pkts);
    memset(&mmsg, 0, sizeof(mmsg));
    for(i = 0; i < n; ++i) {
      msg_iov[i].iov_base = bufs[i];
      msg_iov[i].iov_len = (int)sizeof(bufs[i]);
      mmsg[i].msg_hdr.msg_iov = &msg_iov[i];
      mmsg[i].msg_hdr.msg_iovlen = 1;
      mmsg[i].msg_hdr.msg_name = &remote_addr[i];
      mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]);
      mmsg[i].msg_hdr.msg_control = &msg_ctrl[i];
      mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
    }

    while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
          SOCKERRNO == EINTR)
      ;
    if(mcount == -1) {
      if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
381
382
383
384
385
386
387
388
389
390

















391
392
393
394
395

396
397
398
399
400
401
402
      failf(data, "QUIC: recvmsg() unexpectedly returned %d (errno=%d; %s)",
                  mcount, SOCKERRNO, errstr);
      result = CURLE_RECV_ERROR;
      goto out;
    }

    CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount);
    pkts += mcount;
    for(i = 0; i < mcount; ++i) {
      total_nread += mmsg[i].msg_len;

















      result = recv_cb(bufs[i], mmsg[i].msg_len,
                       mmsg[i].msg_hdr.msg_name, mmsg[i].msg_hdr.msg_namelen,
                       0, userp);
      if(result)
        goto out;

    }
  }

out:
  if(total_nread || result)
    CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
                pkts, total_nread, result);







<


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
|
|
>







420
421
422
423
424
425
426

427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

448
449
450
451
452
453
454
455
456
457
      failf(data, "QUIC: recvmsg() unexpectedly returned %d (errno=%d; %s)",
                  mcount, SOCKERRNO, errstr);
      result = CURLE_RECV_ERROR;
      goto out;
    }

    CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount);

    for(i = 0; i < mcount; ++i) {
      total_nread += mmsg[i].msg_len;

      gso_size = msghdr_get_udp_gro(&mmsg[i].msg_hdr);
      if(gso_size == 0) {
        gso_size = mmsg[i].msg_len;
      }

      for(offset = 0; offset < mmsg[i].msg_len; offset = to) {
        ++pkts;

        to = offset + gso_size;
        if(to > mmsg[i].msg_len) {
          pktlen = mmsg[i].msg_len - offset;
        }
        else {
          pktlen = gso_size;
        }

        result = recv_cb(bufs[i] + offset, pktlen, mmsg[i].msg_hdr.msg_name,
                         mmsg[i].msg_hdr.msg_namelen, 0, userp);

        if(result)
          goto out;
      }
    }
  }

out:
  if(total_nread || result)
    CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
                pkts, total_nread, result);
414
415
416
417
418
419
420




421
422
423
424
425
426
427

428
429
430
431
432

433
434
435
436
437
438
439
  struct msghdr msg;
  uint8_t buf[64*1024];
  struct sockaddr_storage remote_addr;
  size_t total_nread, pkts;
  ssize_t nread;
  char errstr[STRERROR_LEN];
  CURLcode result = CURLE_OK;





  msg_iov.iov_base = buf;
  msg_iov.iov_len = (int)sizeof(buf);

  memset(&msg, 0, sizeof(msg));
  msg.msg_iov = &msg_iov;
  msg.msg_iovlen = 1;


  DEBUGASSERT(max_pkts > 0);
  for(pkts = 0, total_nread = 0; pkts < max_pkts;) {
    msg.msg_name = &remote_addr;
    msg.msg_namelen = sizeof(remote_addr);

    while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
          SOCKERRNO == EINTR)
      ;
    if(nread == -1) {
      if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
        goto out;
      }







>
>
>
>







>





>







469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
  struct msghdr msg;
  uint8_t buf[64*1024];
  struct sockaddr_storage remote_addr;
  size_t total_nread, pkts;
  ssize_t nread;
  char errstr[STRERROR_LEN];
  CURLcode result = CURLE_OK;
  uint8_t msg_ctrl[CMSG_SPACE(sizeof(uint16_t))];
  size_t gso_size;
  size_t pktlen;
  size_t offset, to;

  msg_iov.iov_base = buf;
  msg_iov.iov_len = (int)sizeof(buf);

  memset(&msg, 0, sizeof(msg));
  msg.msg_iov = &msg_iov;
  msg.msg_iovlen = 1;
  msg.msg_control = msg_ctrl;

  DEBUGASSERT(max_pkts > 0);
  for(pkts = 0, total_nread = 0; pkts < max_pkts;) {
    msg.msg_name = &remote_addr;
    msg.msg_namelen = sizeof(remote_addr);
    msg.msg_controllen = sizeof(msg_ctrl);
    while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
          SOCKERRNO == EINTR)
      ;
    if(nread == -1) {
      if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
        goto out;
      }
448
449
450
451
452
453
454








455



456




457

458
459
460

461
462
463
464
465
466
467
      Curl_strerror(SOCKERRNO, errstr, sizeof(errstr));
      failf(data, "QUIC: recvmsg() unexpectedly returned %zd (errno=%d; %s)",
                  nread, SOCKERRNO, errstr);
      result = CURLE_RECV_ERROR;
      goto out;
    }









    ++pkts;



    total_nread += (size_t)nread;




    result = recv_cb(buf, (size_t)nread, msg.msg_name, msg.msg_namelen,

                     0, userp);
    if(result)
      goto out;

  }

out:
  if(total_nread || result)
    CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
                pkts, total_nread, result);
  return result;







>
>
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
|
>
|
|
|
>







509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
      Curl_strerror(SOCKERRNO, errstr, sizeof(errstr));
      failf(data, "QUIC: recvmsg() unexpectedly returned %zd (errno=%d; %s)",
                  nread, SOCKERRNO, errstr);
      result = CURLE_RECV_ERROR;
      goto out;
    }

    total_nread += (size_t)nread;

    gso_size = msghdr_get_udp_gro(&msg);
    if(gso_size == 0) {
      gso_size = (size_t)nread;
    }

    for(offset = 0; offset < (size_t)nread; offset = to) {
      ++pkts;

      to = offset + gso_size;
      if(to > (size_t)nread) {
        pktlen = (size_t)nread - offset;
      }
      else {
        pktlen = gso_size;
      }

      result =
        recv_cb(buf + offset, pktlen, msg.msg_name, msg.msg_namelen, 0, userp);
      if(result)
        goto out;
    }
  }

out:
  if(total_nread || result)
    CURL_TRC_CF(data, cf, "recvd %zu packets with %zu bytes -> %d",
                pkts, total_nread, result);
  return result;
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
  }
#ifndef CURL_DISABLE_PROXY
  if(conn->bits.socksproxy) {
    failf(data, "HTTP/3 is not supported over a SOCKS proxy");
    return CURLE_URL_MALFORMAT;
  }
  if(conn->bits.httpproxy && conn->bits.tunnel_proxy) {
    failf(data, "HTTP/3 is not supported over a HTTP proxy");
    return CURLE_URL_MALFORMAT;
  }
#endif

  return CURLE_OK;
}








|







729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  }
#ifndef CURL_DISABLE_PROXY
  if(conn->bits.socksproxy) {
    failf(data, "HTTP/3 is not supported over a SOCKS proxy");
    return CURLE_URL_MALFORMAT;
  }
  if(conn->bits.httpproxy && conn->bits.tunnel_proxy) {
    failf(data, "HTTP/3 is not supported over an HTTP proxy");
    return CURLE_URL_MALFORMAT;
  }
#endif

  return CURLE_OK;
}

Changes to jni/curl/lib/vssh/libssh.c.
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
      goto cleanup;
    }

    rc = SSH_OK;
    goto cleanup;
  }

  if(data->set.ssl.primary.verifyhost != TRUE) {
    rc = SSH_OK;
    goto cleanup;
  }

#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
  /* Get the known_key from the known hosts file */
  vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
                                             &knownhostsentry);

  /* Case an entry was found in a known hosts file */
  if(knownhostsentry) {
    if(knownhostsentry->publickey) {
      rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
                                        &known_base64);
      if(rc != SSH_OK) {
        goto cleanup;
      }
      knownkey.key = known_base64;
      knownkey.len = strlen(known_base64);

      switch(ssh_key_type(knownhostsentry->publickey)) {
        case SSH_KEYTYPE_RSA:
          knownkey.keytype = CURLKHTYPE_RSA;
          break;
        case SSH_KEYTYPE_RSA1:
          knownkey.keytype = CURLKHTYPE_RSA1;
          break;
        case SSH_KEYTYPE_ECDSA:







|
<
<
|
<

|
|
|

|
|
|
|
|
|
|
|
|
|

|







384
385
386
387
388
389
390
391


392

393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
      goto cleanup;
    }

    rc = SSH_OK;
    goto cleanup;
  }

  if(data->set.str[STRING_SSH_KNOWNHOSTS]) {




#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
    /* Get the known_key from the known hosts file */
    vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
                                               &knownhostsentry);

    /* Case an entry was found in a known hosts file */
    if(knownhostsentry) {
      if(knownhostsentry->publickey) {
        rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
                                          &known_base64);
        if(rc != SSH_OK) {
          goto cleanup;
        }
        knownkey.key = known_base64;
        knownkey.len = strlen(known_base64);

        switch(ssh_key_type(knownhostsentry->publickey)) {
        case SSH_KEYTYPE_RSA:
          knownkey.keytype = CURLKHTYPE_RSA;
          break;
        case SSH_KEYTYPE_RSA1:
          knownkey.keytype = CURLKHTYPE_RSA1;
          break;
        case SSH_KEYTYPE_ECDSA:
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
          break;
        case SSH_KEYTYPE_DSS:
          knownkey.keytype = CURLKHTYPE_DSS;
          break;
        default:
          rc = SSH_ERROR;
          goto cleanup;
      }
      knownkeyp = &knownkey;
    }
  }

  switch(vstate) {
    case SSH_KNOWN_HOSTS_OK:
      keymatch = CURLKHMATCH_OK;
      break;
    case SSH_KNOWN_HOSTS_OTHER:
    case SSH_KNOWN_HOSTS_NOT_FOUND:
    case SSH_KNOWN_HOSTS_UNKNOWN:
    case SSH_KNOWN_HOSTS_ERROR:
      keymatch = CURLKHMATCH_MISSING;
      break;
  default:
      keymatch = CURLKHMATCH_MISMATCH;
      break;
  }

#else
  vstate = ssh_is_server_known(sshc->ssh_session);
  switch(vstate) {
    case SSH_SERVER_KNOWN_OK:
      keymatch = CURLKHMATCH_OK;
      break;
    case SSH_SERVER_FILE_NOT_FOUND:
    case SSH_SERVER_NOT_KNOWN:
      keymatch = CURLKHMATCH_MISSING;
      break;
  default:
      keymatch = CURLKHMATCH_MISMATCH;
      break;
  }
#endif

  if(func) { /* use callback to determine action */
    rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
    if(rc != SSH_OK)
      goto cleanup;

    foundkey.key = found_base64;
    foundkey.len = strlen(found_base64);

    switch(ssh_key_type(pubkey)) {
      case SSH_KEYTYPE_RSA:
        foundkey.keytype = CURLKHTYPE_RSA;
        break;
      case SSH_KEYTYPE_RSA1:
        foundkey.keytype = CURLKHTYPE_RSA1;
        break;
      case SSH_KEYTYPE_ECDSA:







|
|
|
|

|









|


|


|
|







|


|


|
|
|
|

|
|

|







424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
          break;
        case SSH_KEYTYPE_DSS:
          knownkey.keytype = CURLKHTYPE_DSS;
          break;
        default:
          rc = SSH_ERROR;
          goto cleanup;
        }
        knownkeyp = &knownkey;
      }
    }

    switch(vstate) {
    case SSH_KNOWN_HOSTS_OK:
      keymatch = CURLKHMATCH_OK;
      break;
    case SSH_KNOWN_HOSTS_OTHER:
    case SSH_KNOWN_HOSTS_NOT_FOUND:
    case SSH_KNOWN_HOSTS_UNKNOWN:
    case SSH_KNOWN_HOSTS_ERROR:
      keymatch = CURLKHMATCH_MISSING;
      break;
    default:
      keymatch = CURLKHMATCH_MISMATCH;
      break;
    }

#else
    vstate = ssh_is_server_known(sshc->ssh_session);
    switch(vstate) {
    case SSH_SERVER_KNOWN_OK:
      keymatch = CURLKHMATCH_OK;
      break;
    case SSH_SERVER_FILE_NOT_FOUND:
    case SSH_SERVER_NOT_KNOWN:
      keymatch = CURLKHMATCH_MISSING;
      break;
    default:
      keymatch = CURLKHMATCH_MISMATCH;
      break;
    }
#endif

    if(func) { /* use callback to determine action */
      rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
      if(rc != SSH_OK)
        goto cleanup;

      foundkey.key = found_base64;
      foundkey.len = strlen(found_base64);

      switch(ssh_key_type(pubkey)) {
      case SSH_KEYTYPE_RSA:
        foundkey.keytype = CURLKHTYPE_RSA;
        break;
      case SSH_KEYTYPE_RSA1:
        foundkey.keytype = CURLKHTYPE_RSA1;
        break;
      case SSH_KEYTYPE_ECDSA:
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533

534
535
536
537
538
539
540
#endif
      case SSH_KEYTYPE_DSS:
        foundkey.keytype = CURLKHTYPE_DSS;
        break;
      default:
        rc = SSH_ERROR;
        goto cleanup;
    }

    Curl_set_in_callback(data, true);
    rc = func(data, knownkeyp, /* from the knownhosts file */
              &foundkey, /* from the remote host */
              keymatch, data->set.ssh_keyfunc_userp);
    Curl_set_in_callback(data, false);

    switch(rc) {
      case CURLKHSTAT_FINE_ADD_TO_FILE:
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
        rc = ssh_session_update_known_hosts(sshc->ssh_session);
#else
        rc = ssh_write_knownhost(sshc->ssh_session);
#endif
        if(rc != SSH_OK) {
          goto cleanup;
        }
        break;
      case CURLKHSTAT_FINE:
        break;
      default: /* REJECT/DEFER */
        rc = SSH_ERROR;
        goto cleanup;
    }
  }
  else {
    if(keymatch != CURLKHMATCH_OK) {
      rc = SSH_ERROR;
      goto cleanup;

    }
  }
  rc = SSH_OK;

cleanup:
  if(found_base64) {
    (free)(found_base64);







|

|
|
|
|
|

|















|
|
|
|
|
|
>







494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
#endif
      case SSH_KEYTYPE_DSS:
        foundkey.keytype = CURLKHTYPE_DSS;
        break;
      default:
        rc = SSH_ERROR;
        goto cleanup;
      }

      Curl_set_in_callback(data, true);
      rc = func(data, knownkeyp, /* from the knownhosts file */
                &foundkey, /* from the remote host */
                keymatch, data->set.ssh_keyfunc_userp);
      Curl_set_in_callback(data, false);

      switch(rc) {
      case CURLKHSTAT_FINE_ADD_TO_FILE:
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
        rc = ssh_session_update_known_hosts(sshc->ssh_session);
#else
        rc = ssh_write_knownhost(sshc->ssh_session);
#endif
        if(rc != SSH_OK) {
          goto cleanup;
        }
        break;
      case CURLKHSTAT_FINE:
        break;
      default: /* REJECT/DEFER */
        rc = SSH_ERROR;
        goto cleanup;
      }
    }
    else {
      if(keymatch != CURLKHMATCH_OK) {
        rc = SSH_ERROR;
        goto cleanup;
      }
    }
  }
  rc = SSH_OK;

cleanup:
  if(found_base64) {
    (free)(found_base64);
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687

  sshc->kbd_state = 0;
  return rc;
}

/*
 * ssh_statemach_act() runs the SSH state machine as far as it can without
 * blocking and without reaching the end.  The data the pointer 'block' points
 * to will be set to TRUE if the libssh function returns SSH_AGAIN
 * meaning it wants to be called again when the socket is ready
 */
static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct SSHPROTO *protop = data->req.p.ssh;
  struct ssh_conn *sshc = &conn->proto.sshc;
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
  int rc = SSH_NO_ERROR, err;
  int seekerr = CURL_SEEKFUNC_OK;
  const char *err_msg;
  *block = 0;                   /* we're not blocking by default */

  do {

    switch(sshc->state) {
    case SSH_INIT:
      sshc->secondCreateDirs = 0;
      sshc->nextstate = SSH_NO_STATE;







|













|







657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685

  sshc->kbd_state = 0;
  return rc;
}

/*
 * ssh_statemach_act() runs the SSH state machine as far as it can without
 * blocking and without reaching the end. The data the pointer 'block' points
 * to will be set to TRUE if the libssh function returns SSH_AGAIN
 * meaning it wants to be called again when the socket is ready
 */
static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct SSHPROTO *protop = data->req.p.ssh;
  struct ssh_conn *sshc = &conn->proto.sshc;
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
  int rc = SSH_NO_ERROR, err;
  int seekerr = CURL_SEEKFUNC_OK;
  const char *err_msg;
  *block = 0;                   /* we are not blocking by default */

  do {

    switch(sshc->state) {
    case SSH_INIT:
      sshc->secondCreateDirs = 0;
      sshc->nextstate = SSH_NO_STATE;
738
739
740
741
742
743
744
745

746
747
748
749
750
751
752
          break;
        }
        else if(rc == SSH_AUTH_ERROR) {
          MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
          break;
        }

        sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);

        if(sshc->auth_methods)
          infof(data, "SSH authentication methods available: %s%s%s%s",
                sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
                "public key, ": "",
                sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
                "GSSAPI, " : "",
                sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?







|
>







736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
          break;
        }
        else if(rc == SSH_AUTH_ERROR) {
          MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
          break;
        }

        sshc->auth_methods =
          (unsigned int)ssh_userauth_list(sshc->ssh_session, NULL);
        if(sshc->auth_methods)
          infof(data, "SSH authentication methods available: %s%s%s%s",
                sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
                "public key, ": "",
                sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC ?
                "GSSAPI, " : "",
                sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE ?
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
        if(seekerr != CURL_SEEKFUNC_OK) {
          curl_off_t passed = 0;

          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
            failf(data, "Could not seek stream");
            return CURLE_FTP_COULDNT_USE_REST;
          }
          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
          do {
            char scratch[4*1024];
            size_t readthisamountnow =
              (data->state.resume_from - passed >
                (curl_off_t)sizeof(scratch)) ?
              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);








|







1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
        if(seekerr != CURL_SEEKFUNC_OK) {
          curl_off_t passed = 0;

          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
            failf(data, "Could not seek stream");
            return CURLE_FTP_COULDNT_USE_REST;
          }
          /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
          do {
            char scratch[4*1024];
            size_t readthisamountnow =
              (data->state.resume_from - passed >
                (curl_off_t)sizeof(scratch)) ?
              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);

1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
        }
      }
      if(data->state.infilesize > 0) {
        data->req.size = data->state.infilesize;
        Curl_pgrsSetUploadSize(data, data->state.infilesize);
      }
      /* upload data */
      Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      /* store this original bitmask setup to use later on if we can't
         figure out a "real" bitmask */
      sshc->orig_waitfor = data->req.keepon;

      /* we want to use the _sending_ function even when the socket turns
         out readable as the underlying libssh sftp send function will deal
         with both accordingly */
      data->state.select_bits = CURL_CSELECT_OUT;

      /* since we don't really wait for anything at this point, we want the
         state machine to move on as soon as possible so we set a very short
         timeout here */
      Curl_expire(data, 0, EXPIRE_RUN_NOW);

      state(data, SSH_STOP);
      break;
    }







|




|








|







1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
        }
      }
      if(data->state.infilesize > 0) {
        data->req.size = data->state.infilesize;
        Curl_pgrsSetUploadSize(data, data->state.infilesize);
      }
      /* upload data */
      Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      /* store this original bitmask setup to use later on if we cannot
         figure out a "real" bitmask */
      sshc->orig_waitfor = data->req.keepon;

      /* we want to use the _sending_ function even when the socket turns
         out readable as the underlying libssh sftp send function will deal
         with both accordingly */
      data->state.select_bits = CURL_CSELECT_OUT;

      /* since we do not really wait for anything at this point, we want the
         state machine to move on as soon as possible so we set a very short
         timeout here */
      Curl_expire(data, 0, EXPIRE_RUN_NOW);

      state(data, SSH_STOP);
      break;
    }
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
      /* 'mode' - parameter is preliminary - default to 0644 */
      rc = sftp_mkdir(sshc->sftp_session, protop->path,
                      (mode_t)data->set.new_directory_perms);
      *sshc->slash_pos = '/';
      ++sshc->slash_pos;
      if(rc < 0) {
        /*
         * Abort if failure wasn't that the dir already exists or the
         * permission was denied (creation might succeed further down the
         * path) - retry on unspecific FAILURE also
         */
        err = sftp_get_error(sshc->sftp_session);
        if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
           (err != SSH_FX_FAILURE) &&
           (err != SSH_FX_PERMISSION_DENIED)) {







|







1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
      /* 'mode' - parameter is preliminary - default to 0644 */
      rc = sftp_mkdir(sshc->sftp_session, protop->path,
                      (mode_t)data->set.new_directory_perms);
      *sshc->slash_pos = '/';
      ++sshc->slash_pos;
      if(rc < 0) {
        /*
         * Abort if failure was not that the dir already exists or the
         * permission was denied (creation might succeed further down the
         * path) - retry on unspecific FAILURE also
         */
        err = sftp_get_error(sshc->sftp_session);
        if((err != SSH_FX_FILE_ALREADY_EXISTS) &&
           (err != SSH_FX_FAILURE) &&
           (err != SSH_FX_PERMISSION_DENIED)) {
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
      break;

    case SSH_SFTP_READDIR_DONE:
      sftp_closedir(sshc->sftp_dir);
      sshc->sftp_dir = NULL;

      /* no data to transfer */
      Curl_xfer_setup(data, -1, -1, FALSE, -1);
      state(data, SSH_STOP);
      break;

    case SSH_SFTP_DOWNLOAD_INIT:
      /*
       * Work on getting the specified file
       */







|







1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
      break;

    case SSH_SFTP_READDIR_DONE:
      sftp_closedir(sshc->sftp_dir);
      sshc->sftp_dir = NULL;

      /* no data to transfer */
      Curl_xfer_setup_nop(data);
      state(data, SSH_STOP);
      break;

    case SSH_SFTP_DOWNLOAD_INIT:
      /*
       * Work on getting the specified file
       */
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
      curl_off_t size;

      attrs = sftp_fstat(sshc->sftp_file);
      if(!attrs ||
              !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
              (attrs->size == 0)) {
        /*
         * sftp_fstat didn't return an error, so maybe the server
         * just doesn't support stat()
         * OR the server doesn't return a file size with a stat()
         * OR file size is 0
         */
        data->req.size = -1;
        data->req.maxdownload = -1;
        Curl_pgrsSetDownloadSize(data, -1);
        size = 0;
      }







|
|
|







1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
      curl_off_t size;

      attrs = sftp_fstat(sshc->sftp_file);
      if(!attrs ||
              !(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
              (attrs->size == 0)) {
        /*
         * sftp_fstat did not return an error, so maybe the server
         * just does not support stat()
         * OR the server does not return a file size with a stat()
         * OR file size is 0
         */
        data->req.size = -1;
        data->req.maxdownload = -1;
        Curl_pgrsSetDownloadSize(data, -1);
        size = 0;
      }
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
        data->req.maxdownload = size;
        Curl_pgrsSetDownloadSize(data, size);
      }

      /* We can resume if we can seek to the resume position */
      if(data->state.resume_from) {
        if(data->state.resume_from < 0) {
          /* We're supposed to download the last abs(from) bytes */
          if((curl_off_t)size < -data->state.resume_from) {
            failf(data, "Offset (%"
                  CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
                  CURL_FORMAT_CURL_OFF_T ")",
                  data->state.resume_from, size);
            return CURLE_BAD_DOWNLOAD_RESUME;
          }







|







1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
        data->req.maxdownload = size;
        Curl_pgrsSetDownloadSize(data, size);
      }

      /* We can resume if we can seek to the resume position */
      if(data->state.resume_from) {
        if(data->state.resume_from < 0) {
          /* We are supposed to download the last abs(from) bytes */
          if((curl_off_t)size < -data->state.resume_from) {
            failf(data, "Offset (%"
                  CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
                  CURL_FORMAT_CURL_OFF_T ")",
                  data->state.resume_from, size);
            return CURLE_BAD_DOWNLOAD_RESUME;
          }
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
        }
      }
    }

    /* Setup the actual download */
    if(data->req.size == 0) {
      /* no data to transfer */
      Curl_xfer_setup(data, -1, -1, FALSE, -1);
      infof(data, "File already completely downloaded");
      state(data, SSH_STOP);
      break;
    }
    Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);

    /* not set by Curl_xfer_setup to preserve keepon bits */
    conn->writesockfd = conn->sockfd;

    /* we want to use the _receiving_ function even when the socket turns
       out writableable as the underlying libssh recv function will deal
       with both accordingly */







|




|







1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
        }
      }
    }

    /* Setup the actual download */
    if(data->req.size == 0) {
      /* no data to transfer */
      Curl_xfer_setup_nop(data);
      infof(data, "File already completely downloaded");
      state(data, SSH_STOP);
      break;
    }
    Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);

    /* not set by Curl_xfer_setup to preserve keepon bits */
    conn->writesockfd = conn->sockfd;

    /* we want to use the _receiving_ function even when the socket turns
       out writableable as the underlying libssh recv function will deal
       with both accordingly */
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
        err_msg = ssh_get_error(sshc->ssh_session);
        failf(data, "%s", err_msg);
        MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
        break;
      }

      /* upload data */
      Curl_xfer_setup(data, -1, data->req.size, FALSE, FIRSTSOCKET);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      /* store this original bitmask setup to use later on if we can't
         figure out a "real" bitmask */
      sshc->orig_waitfor = data->req.keepon;

      /* we want to use the _sending_ function even when the socket turns
         out readable as the underlying libssh scp send function will deal
         with both accordingly */
      data->state.select_bits = CURL_CSELECT_OUT;







|




|







1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
        err_msg = ssh_get_error(sshc->ssh_session);
        failf(data, "%s", err_msg);
        MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
        break;
      }

      /* upload data */
      Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      /* store this original bitmask setup to use later on if we cannot
         figure out a "real" bitmask */
      sshc->orig_waitfor = data->req.keepon;

      /* we want to use the _sending_ function even when the socket turns
         out readable as the underlying libssh scp send function will deal
         with both accordingly */
      data->state.select_bits = CURL_CSELECT_OUT;
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
          MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
          break;
        }

        /* download data */
        bytecount = ssh_scp_request_get_size(sshc->scp_session);
        data->req.maxdownload = (curl_off_t) bytecount;
        Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);

        /* not set by Curl_xfer_setup to preserve keepon bits */
        conn->writesockfd = conn->sockfd;

        /* we want to use the _receiving_ function even when the socket turns
           out writableable as the underlying libssh recv function will deal
           with both accordingly */







|







1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
          MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND);
          break;
        }

        /* download data */
        bytecount = ssh_scp_request_get_size(sshc->scp_session);
        data->req.maxdownload = (curl_off_t) bytecount;
        Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);

        /* not set by Curl_xfer_setup to preserve keepon bits */
        conn->writesockfd = conn->sockfd;

        /* we want to use the _receiving_ function even when the socket turns
           out writableable as the underlying libssh recv function will deal
           with both accordingly */
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956

      ssh_set_blocking(sshc->ssh_session, 0);

      state(data, SSH_SESSION_DISCONNECT);
      FALLTHROUGH();

    case SSH_SESSION_DISCONNECT:
      /* during weird times when we've been prematurely aborted, the channel
         is still alive when we reach this state and we MUST kill the channel
         properly first */
      if(sshc->scp_session) {
        ssh_scp_free(sshc->scp_session);
        sshc->scp_session = NULL;
      }








|







1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955

      ssh_set_blocking(sshc->ssh_session, 0);

      state(data, SSH_SESSION_DISCONNECT);
      FALLTHROUGH();

    case SSH_SESSION_DISCONNECT:
      /* during weird times when we have been prematurely aborted, the channel
         is still alive when we reach this state and we MUST kill the channel
         properly first */
      if(sshc->scp_session) {
        ssh_scp_free(sshc->scp_session);
        sshc->scp_session = NULL;
      }

2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
  return bitmap;
}

static void myssh_block2waitfor(struct connectdata *conn, bool block)
{
  struct ssh_conn *sshc = &conn->proto.sshc;

  /* If it didn't block, or nothing was returned by ssh_get_poll_flags
   * have the original set */
  conn->waitfor = sshc->orig_waitfor;

  if(block) {
    int dir = ssh_get_poll_flags(sshc->ssh_session);
    if(dir & SSH_READ_PENDING) {
      /* translate the libssh define bits into our own bit defines */







|







2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
  return bitmap;
}

static void myssh_block2waitfor(struct connectdata *conn, bool block)
{
  struct ssh_conn *sshc = &conn->proto.sshc;

  /* If it did not block, or nothing was returned by ssh_get_poll_flags
   * have the original set */
  conn->waitfor = sshc->orig_waitfor;

  if(block) {
    int dir = ssh_get_poll_flags(sshc->ssh_session);
    if(dir & SSH_READ_PENDING) {
      /* translate the libssh define bits into our own bit defines */
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
                               bool dead_connection)
{
  CURLcode result = CURLE_OK;
  struct ssh_conn *ssh = &conn->proto.sshc;
  (void) dead_connection;

  if(ssh->ssh_session) {
    /* only if there's a session still around to use! */

    state(data, SSH_SESSION_DISCONNECT);

    result = myssh_block_statemach(data, TRUE);
  }

  return result;







|







2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
                               bool dead_connection)
{
  CURLcode result = CURLE_OK;
  struct ssh_conn *ssh = &conn->proto.sshc;
  (void) dead_connection;

  if(ssh->ssh_session) {
    /* only if there is a session still around to use! */

    state(data, SSH_SESSION_DISCONNECT);

    result = myssh_block_statemach(data, TRUE);
  }

  return result;
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
{
  CURLcode result = CURLE_OK;
  (void) dead_connection;

  DEBUGF(infof(data, "SSH DISCONNECT starts now"));

  if(conn->proto.sshc.ssh_session) {
    /* only if there's a session still around to use! */
    state(data, SSH_SFTP_SHUTDOWN);
    result = myssh_block_statemach(data, TRUE);
  }

  DEBUGF(infof(data, "SSH DISCONNECT is done"));

  return result;







|







2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
{
  CURLcode result = CURLE_OK;
  (void) dead_connection;

  DEBUGF(infof(data, "SSH DISCONNECT starts now"));

  if(conn->proto.sshc.ssh_session) {
    /* only if there is a session still around to use! */
    state(data, SSH_SFTP_SHUTDOWN);
    result = myssh_block_statemach(data, TRUE);
  }

  DEBUGF(infof(data, "SSH DISCONNECT is done"));

  return result;
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623

      FALLTHROUGH();
    case 1:
      conn->proto.sshc.sftp_recv_state = 1;

      nread = sftp_async_read(conn->proto.sshc.sftp_file,
                              mem, (uint32_t)len,
                              conn->proto.sshc.sftp_file_index);

      myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);

      if(nread == SSH_AGAIN) {
        *err = CURLE_AGAIN;
        return -1;
      }







|







2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622

      FALLTHROUGH();
    case 1:
      conn->proto.sshc.sftp_recv_state = 1;

      nread = sftp_async_read(conn->proto.sshc.sftp_file,
                              mem, (uint32_t)len,
                              (uint32_t)conn->proto.sshc.sftp_file_index);

      myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);

      if(nread == SSH_AGAIN) {
        *err = CURLE_AGAIN;
        return -1;
      }
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
    state(data, SSH_SFTP_CLOSE);
    sshc->nextstate = SSH_NO_STATE;
    sshc->actualcode = result;
    return;
  }

  /*
   * SFTP is a binary protocol, so we don't send text commands
   * to the server. Instead, we scan for commands used by
   * OpenSSH's sftp program and call the appropriate libssh
   * functions.
   */
  if(strncasecompare(cmd, "chgrp ", 6) ||
     strncasecompare(cmd, "chmod ", 6) ||
     strncasecompare(cmd, "chown ", 6) ||







|







2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
    state(data, SSH_SFTP_CLOSE);
    sshc->nextstate = SSH_NO_STATE;
    sshc->actualcode = result;
    return;
  }

  /*
   * SFTP is a binary protocol, so we do not send text commands
   * to the server. Instead, we scan for commands used by
   * OpenSSH's sftp program and call the appropriate libssh
   * functions.
   */
  if(strncasecompare(cmd, "chgrp ", 6) ||
     strncasecompare(cmd, "chmod ", 6) ||
     strncasecompare(cmd, "chown ", 6) ||
Changes to jni/curl/lib/vssh/libssh2.c.
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

  /* we only allow perfect matches, and we reject everything else */
  return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
}
#endif

/*
 * Earlier libssh2 versions didn't have the ability to seek to 64bit positions
 * with 32bit size_t.
 */
#ifdef HAVE_LIBSSH2_SFTP_SEEK64
#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
#else
#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y)
#endif

/*
 * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit
 * architectures so we check of the necessary function is present.
 */
#ifndef HAVE_LIBSSH2_SCP_SEND64
#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
#else
#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c),            \
                                             (libssh2_uint64_t)d, 0, 0)
#endif

/*
 * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64.
 */
#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
#define session_startup(x,y) libssh2_session_handshake(x, y)
#else
#define session_startup(x,y) libssh2_session_startup(x, (int)y)
#endif
static int convert_ssh2_keytype(int sshkeytype)
{
  int keytype = CURLKHTYPE_UNKNOWN;
  switch(sshkeytype) {
  case LIBSSH2_HOSTKEY_TYPE_RSA:
    keytype = CURLKHTYPE_RSA;
    break;
  case LIBSSH2_HOSTKEY_TYPE_DSS:
    keytype = CURLKHTYPE_DSS;
    break;







|
|








|
|





|



|






|

|







401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

  /* we only allow perfect matches, and we reject everything else */
  return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
}
#endif

/*
 * Earlier libssh2 versions did not have the ability to seek to 64-bit
 * positions with 32-bit size_t.
 */
#ifdef HAVE_LIBSSH2_SFTP_SEEK64
#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
#else
#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y)
#endif

/*
 * Earlier libssh2 versions did not do SCP properly beyond 32-bit sizes on
 * 32-bit architectures so we check of the necessary function is present.
 */
#ifndef HAVE_LIBSSH2_SCP_SEND64
#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
#else
#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c),            \
                                             (libssh2_int64_t)d, 0, 0)
#endif

/*
 * libssh2 1.2.8 fixed the problem with 32-bit ints used for sockets on win64.
 */
#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
#define session_startup(x,y) libssh2_session_handshake(x, y)
#else
#define session_startup(x,y) libssh2_session_startup(x, (int)y)
#endif
static enum curl_khtype convert_ssh2_keytype(int sshkeytype)
{
  enum curl_khtype keytype = CURLKHTYPE_UNKNOWN;
  switch(sshkeytype) {
  case LIBSSH2_HOSTKEY_TYPE_RSA:
    keytype = CURLKHTYPE_RSA;
    break;
  case LIBSSH2_HOSTKEY_TYPE_DSS:
    keytype = CURLKHTYPE_DSS;
    break;
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  int sshkeytype = 0;
  size_t keylen = 0;
  int rc = 0;
  CURLcode result = CURLE_OK;

#ifdef HAVE_LIBSSH2_KNOWNHOST_API
  if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
    /* we're asked to verify the host against a file */
    struct connectdata *conn = data->conn;
    struct ssh_conn *sshc = &conn->proto.sshc;
    struct libssh2_knownhost *host = NULL;
    const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
                                                    &keylen, &sshkeytype);
    int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
    int keybit = 0;

    if(remotekey) {
      /*
       * A subject to figure out is what host name we need to pass in here.
       * What host name does OpenSSH store in its file if an IDN name is
       * used?
       */
      enum curl_khmatch keymatch;
      curl_sshkeycallback func =
        data->set.ssh_keyfunc ? data->set.ssh_keyfunc : sshkeycallback;
      struct curl_khkey knownkey;
      struct curl_khkey *knownkeyp = NULL;







|










|
|







472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  int sshkeytype = 0;
  size_t keylen = 0;
  int rc = 0;
  CURLcode result = CURLE_OK;

#ifdef HAVE_LIBSSH2_KNOWNHOST_API
  if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
    /* we are asked to verify the host against a file */
    struct connectdata *conn = data->conn;
    struct ssh_conn *sshc = &conn->proto.sshc;
    struct libssh2_knownhost *host = NULL;
    const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
                                                    &keylen, &sshkeytype);
    int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
    int keybit = 0;

    if(remotekey) {
      /*
       * A subject to figure out is what hostname we need to pass in here.
       * What hostname does OpenSSH store in its file if an IDN name is
       * used?
       */
      enum curl_khmatch keymatch;
      curl_sshkeycallback func =
        data->set.ssh_keyfunc ? data->set.ssh_keyfunc : sshkeycallback;
      struct curl_khkey knownkey;
      struct curl_khkey *knownkeyp = NULL;
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
#endif
#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
      case LIBSSH2_HOSTKEY_TYPE_ED25519:
        keybit = LIBSSH2_KNOWNHOST_KEY_ED25519;
        break;
#endif
      default:
        infof(data, "unsupported key type, can't check knownhosts");
        keybit = 0;
        break;
      }
      if(!keybit)
        /* no check means failure! */
        rc = CURLKHSTAT_REJECT;
      else {







|







522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
#endif
#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
      case LIBSSH2_HOSTKEY_TYPE_ED25519:
        keybit = LIBSSH2_KNOWNHOST_KEY_ED25519;
        break;
#endif
      default:
        infof(data, "unsupported key type, cannot check knownhosts");
        keybit = 0;
        break;
      }
      if(!keybit)
        /* no check means failure! */
        rc = CURLKHSTAT_REJECT;
      else {
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
      state(data, SSH_SESSION_FREE);
      FALLTHROUGH();
    case CURLKHSTAT_DEFER:
      /* DEFER means bail out but keep the SSH_HOSTKEY state */
      result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
      break;
    case CURLKHSTAT_FINE_REPLACE:
      /* remove old host+key that doesn't match */
      if(host)
        libssh2_knownhost_del(sshc->kh, host);
      FALLTHROUGH();
    case CURLKHSTAT_FINE:
    case CURLKHSTAT_FINE_ADD_TO_FILE:
      /* proceed */
      if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
        /* the found host+key didn't match but has been told to be fine
           anyway so we add it in memory */
        int addrc = libssh2_knownhost_add(sshc->kh,
                                          conn->host.name, NULL,
                                          remotekey, keylen,
                                          LIBSSH2_KNOWNHOST_TYPE_PLAIN|
                                          LIBSSH2_KNOWNHOST_KEYENC_RAW|
                                          keybit, NULL);







|







|







596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
      state(data, SSH_SESSION_FREE);
      FALLTHROUGH();
    case CURLKHSTAT_DEFER:
      /* DEFER means bail out but keep the SSH_HOSTKEY state */
      result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
      break;
    case CURLKHSTAT_FINE_REPLACE:
      /* remove old host+key that does not match */
      if(host)
        libssh2_knownhost_del(sshc->kh, host);
      FALLTHROUGH();
    case CURLKHSTAT_FINE:
    case CURLKHSTAT_FINE_ADD_TO_FILE:
      /* proceed */
      if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
        /* the found host+key did not match but has been told to be fine
           anyway so we add it in memory */
        int addrc = libssh2_knownhost_add(sshc->kh,
                                          conn->host.name, NULL,
                                          remotekey, keylen,
                                          LIBSSH2_KNOWNHOST_TYPE_PLAIN|
                                          LIBSSH2_KNOWNHOST_KEYENC_RAW|
                                          keybit, NULL);
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
    const char *fingerprint = NULL;
    char *fingerprint_b64 = NULL;
    size_t fingerprint_b64_len;
    size_t pub_pos = 0;
    size_t b64_pos = 0;

#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
    /* The fingerprint points to static storage (!), don't free() it. */
    fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
                                       LIBSSH2_HOSTKEY_HASH_SHA256);
#else
    const char *hostkey;
    size_t len = 0;
    unsigned char hash[32];








|







658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
    const char *fingerprint = NULL;
    char *fingerprint_b64 = NULL;
    size_t fingerprint_b64_len;
    size_t pub_pos = 0;
    size_t b64_pos = 0;

#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
    /* The fingerprint points to static storage (!), do not free() it. */
    fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
                                       LIBSSH2_HOSTKEY_HASH_SHA256);
#else
    const char *hostkey;
    size_t len = 0;
    unsigned char hash[32];

738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
    char md5buffer[33];
    const char *fingerprint = NULL;

    fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
                                       LIBSSH2_HOSTKEY_HASH_MD5);

    if(fingerprint) {
      /* The fingerprint points to static storage (!), don't free() it. */
      int i;
      for(i = 0; i < 16; i++) {
        msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
      }

      infof(data, "SSH MD5 fingerprint: %s", md5buffer);
    }







|







738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
    char md5buffer[33];
    const char *fingerprint = NULL;

    fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
                                       LIBSSH2_HOSTKEY_HASH_MD5);

    if(fingerprint) {
      /* The fingerprint points to static storage (!), do not free() it. */
      int i;
      for(i = 0; i < 16; i++) {
        msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
      }

      infof(data, "SSH MD5 fingerprint: %s", md5buffer);
    }
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
      size_t keylen = 0;
      int sshkeytype = 0;
      int rc = 0;
      /* we handle the process to the callback */
      const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
                                                      &keylen, &sshkeytype);
      if(remotekey) {
        int keytype = convert_ssh2_keytype(sshkeytype);
        Curl_set_in_callback(data, true);
        rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp,
                                       keytype, remotekey, keylen);
        Curl_set_in_callback(data, false);
        if(rc!= CURLKHMATCH_OK) {
          state(data, SSH_SESSION_FREE);
          sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
          return sshc->actualcode;
        }
      }







|


|







776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
      size_t keylen = 0;
      int sshkeytype = 0;
      int rc = 0;
      /* we handle the process to the callback */
      const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
                                                      &keylen, &sshkeytype);
      if(remotekey) {
        enum curl_khtype keytype = convert_ssh2_keytype(sshkeytype);
        Curl_set_in_callback(data, true);
        rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp,
                                       (int)keytype, remotekey, keylen);
        Curl_set_in_callback(data, false);
        if(rc!= CURLKHMATCH_OK) {
          state(data, SSH_SESSION_FREE);
          sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
          return sshc->actualcode;
        }
      }
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
#endif /* HAVE_LIBSSH2_KNOWNHOST_API */

  return result;
}

/*
 * ssh_statemach_act() runs the SSH state machine as far as it can without
 * blocking and without reaching the end.  The data the pointer 'block' points
 * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
 * meaning it wants to be called again when the socket is ready
 */

static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct SSHPROTO *sshp = data->req.p.ssh;
  struct ssh_conn *sshc = &conn->proto.sshc;
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
  int rc = LIBSSH2_ERROR_NONE;
  int ssherr;
  unsigned long sftperr;
  int seekerr = CURL_SEEKFUNC_OK;
  size_t readdir_len;
  *block = 0; /* we're not blocking by default */

  do {
    switch(sshc->state) {
    case SSH_INIT:
      sshc->secondCreateDirs = 0;
      sshc->nextstate = SSH_NO_STATE;
      sshc->actualcode = CURLE_OK;







|
















|







956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
#endif /* HAVE_LIBSSH2_KNOWNHOST_API */

  return result;
}

/*
 * ssh_statemach_act() runs the SSH state machine as far as it can without
 * blocking and without reaching the end. The data the pointer 'block' points
 * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
 * meaning it wants to be called again when the socket is ready
 */

static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct SSHPROTO *sshp = data->req.p.ssh;
  struct ssh_conn *sshc = &conn->proto.sshc;
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
  int rc = LIBSSH2_ERROR_NONE;
  int ssherr;
  unsigned long sftperr;
  int seekerr = CURL_SEEKFUNC_OK;
  size_t readdir_len;
  *block = 0; /* we are not blocking by default */

  do {
    switch(sshc->state) {
    case SSH_INIT:
      sshc->secondCreateDirs = 0;
      sshc->nextstate = SSH_NO_STATE;
      sshc->actualcode = CURLE_OK;
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
    case SSH_AUTHLIST:
      /*
       * Figure out authentication methods
       * NB: As soon as we have provided a username to an openssh server we
       * must never change it later. Thus, always specify the correct username
       * here, even though the libssh2 docs kind of indicate that it should be
       * possible to get a 'generic' list (not user-specific) of authentication
       * methods, presumably with a blank username. That won't work in my
       * experience.
       * So always specify it here.
       */
      sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
                                             conn->user,
                                             curlx_uztoui(strlen(conn->user)));








|







1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
    case SSH_AUTHLIST:
      /*
       * Figure out authentication methods
       * NB: As soon as we have provided a username to an openssh server we
       * must never change it later. Thus, always specify the correct username
       * here, even though the libssh2 docs kind of indicate that it should be
       * possible to get a 'generic' list (not user-specific) of authentication
       * methods, presumably with a blank username. That will not work in my
       * experience.
       * So always specify it here.
       */
      sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
                                             conn->user,
                                             curlx_uztoui(strlen(conn->user)));

1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
      }
      else {
        /* Return the error type */
        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
        if(sftperr)
          result = sftp_libssh2_error_to_CURLE(sftperr);
        else
          /* in this case, the error wasn't in the SFTP level but for example
             a time-out or similar */
          result = CURLE_SSH;
        sshc->actualcode = result;
        DEBUGF(infof(data, "error = %lu makes libcurl = %d",
                     sftperr, (int)result));
        state(data, SSH_STOP);
        break;







|







1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
      }
      else {
        /* Return the error type */
        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
        if(sftperr)
          result = sftp_libssh2_error_to_CURLE(sftperr);
        else
          /* in this case, the error was not in the SFTP level but for example
             a time-out or similar */
          result = CURLE_SSH;
        sshc->actualcode = result;
        DEBUGF(infof(data, "error = %lu makes libcurl = %d",
                     sftperr, (int)result));
        state(data, SSH_STOP);
        break;
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
        state(data, SSH_SFTP_CLOSE);
        sshc->nextstate = SSH_NO_STATE;
        sshc->actualcode = result;
        break;
      }

      /*
       * SFTP is a binary protocol, so we don't send text commands
       * to the server. Instead, we scan for commands used by
       * OpenSSH's sftp program and call the appropriate libssh2
       * functions.
       */
      if(strncasecompare(cmd, "chgrp ", 6) ||
         strncasecompare(cmd, "chmod ", 6) ||
         strncasecompare(cmd, "chown ", 6) ||







|







1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
        state(data, SSH_SFTP_CLOSE);
        sshc->nextstate = SSH_NO_STATE;
        sshc->actualcode = result;
        break;
      }

      /*
       * SFTP is a binary protocol, so we do not send text commands
       * to the server. Instead, we scan for commands used by
       * OpenSSH's sftp program and call the appropriate libssh2
       * functions.
       */
      if(strncasecompare(cmd, "chgrp ", 6) ||
         strncasecompare(cmd, "chmod ", 6) ||
         strncasecompare(cmd, "chown ", 6) ||
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
        cmd++;
        sshc->acceptfail = TRUE;
      }

      if(!strncasecompare(cmd, "chmod", 5)) {
        /* Since chown and chgrp only set owner OR group but libssh2 wants to
         * set them both at once, we need to obtain the current ownership
         * first.  This takes an extra protocol round trip.
         */
        rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
                                  curlx_uztoui(strlen(sshc->quote_path2)),
                                  LIBSSH2_SFTP_STAT,
                                  &sshp->quote_attrs);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
          break;







|







1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
        cmd++;
        sshc->acceptfail = TRUE;
      }

      if(!strncasecompare(cmd, "chmod", 5)) {
        /* Since chown and chgrp only set owner OR group but libssh2 wants to
         * set them both at once, we need to obtain the current ownership
         * first. This takes an extra protocol round trip.
         */
        rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
                                  curlx_uztoui(strlen(sshc->quote_path2)),
                                  LIBSSH2_SFTP_STAT,
                                  &sshp->quote_attrs);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
          break;
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796

        if(date == -1) {
          failf(data, "incorrect date format for %.*s", 5, cmd);
          fail = TRUE;
        }
#if SIZEOF_TIME_T > SIZEOF_LONG
        if(date > 0xffffffff) {
          /* if 'long' can't old >32bit, this date cannot be sent */
          failf(data, "date overflow");
          fail = TRUE;
        }
#endif
        if(fail) {
          Curl_safefree(sshc->quote_path1);
          Curl_safefree(sshc->quote_path2);







|







1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796

        if(date == -1) {
          failf(data, "incorrect date format for %.*s", 5, cmd);
          fail = TRUE;
        }
#if SIZEOF_TIME_T > SIZEOF_LONG
        if(date > 0xffffffff) {
          /* if 'long' cannot old >32bit, this date cannot be sent */
          failf(data, "date overflow");
          fail = TRUE;
        }
#endif
        if(fail) {
          Curl_safefree(sshc->quote_path1);
          Curl_safefree(sshc->quote_path2);
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
      }
      state(data, SSH_SFTP_NEXT_QUOTE);
      break;

    case SSH_SFTP_QUOTE_MKDIR:
      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
                                 curlx_uztoui(strlen(sshc->quote_path1)),
                                 data->set.new_directory_perms);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      if(rc && !sshc->acceptfail) {
        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
        Curl_safefree(sshc->quote_path1);
        failf(data, "mkdir command failed: %s",







|







1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
      }
      state(data, SSH_SFTP_NEXT_QUOTE);
      break;

    case SSH_SFTP_QUOTE_MKDIR:
      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
                                 curlx_uztoui(strlen(sshc->quote_path1)),
                                 (long)data->set.new_directory_perms);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      if(rc && !sshc->acceptfail) {
        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
        Curl_safefree(sshc->quote_path1);
        failf(data, "mkdir command failed: %s",
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
                                curlx_uztoui(strlen(sshp->path)),
                                LIBSSH2_SFTP_STAT, &attrs);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      if(rc == 0) {
        data->info.filetime = attrs.mtime;
      }

      state(data, SSH_SFTP_TRANS_INIT);
      break;
    }

    case SSH_SFTP_TRANS_INIT:







|







2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
                                curlx_uztoui(strlen(sshp->path)),
                                LIBSSH2_SFTP_STAT, &attrs);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      if(rc == 0) {
        data->info.filetime = (time_t)attrs.mtime;
      }

      state(data, SSH_SFTP_TRANS_INIT);
      break;
    }

    case SSH_SFTP_TRANS_INIT:
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
      else
        /* Clear file before writing (normal behavior) */
        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;

      sshc->sftp_handle =
        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
                             curlx_uztoui(strlen(sshp->path)),
                             flags, data->set.new_file_perms,
                             LIBSSH2_SFTP_OPENFILE);

      if(!sshc->sftp_handle) {
        rc = libssh2_session_last_errno(sshc->ssh_session);

        if(LIBSSH2_ERROR_EAGAIN == rc)
          break;







|







2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
      else
        /* Clear file before writing (normal behavior) */
        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;

      sshc->sftp_handle =
        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
                             curlx_uztoui(strlen(sshp->path)),
                             flags, (long)data->set.new_file_perms,
                             LIBSSH2_SFTP_OPENFILE);

      if(!sshc->sftp_handle) {
        rc = libssh2_session_last_errno(sshc->ssh_session);

        if(LIBSSH2_ERROR_EAGAIN == rc)
          break;
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
        if(seekerr != CURL_SEEKFUNC_OK) {
          curl_off_t passed = 0;

          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
            failf(data, "Could not seek stream");
            return CURLE_FTP_COULDNT_USE_REST;
          }
          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
          do {
            char scratch[4*1024];
            size_t readthisamountnow =
              (data->state.resume_from - passed >
                (curl_off_t)sizeof(scratch)) ?
              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);








|







2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
        if(seekerr != CURL_SEEKFUNC_OK) {
          curl_off_t passed = 0;

          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
            failf(data, "Could not seek stream");
            return CURLE_FTP_COULDNT_USE_REST;
          }
          /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
          do {
            char scratch[4*1024];
            size_t readthisamountnow =
              (data->state.resume_from - passed >
                (curl_off_t)sizeof(scratch)) ?
              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);

2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
      }
      if(data->state.infilesize > 0) {
        data->req.size = data->state.infilesize;
        Curl_pgrsSetUploadSize(data, data->state.infilesize);
      }
      /* upload data */
      Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      if(result) {
        state(data, SSH_SFTP_CLOSE);
        sshc->actualcode = result;
      }
      else {
        /* store this original bitmask setup to use later on if we can't
           figure out a "real" bitmask */
        sshc->orig_waitfor = data->req.keepon;

        /* we want to use the _sending_ function even when the socket turns
           out readable as the underlying libssh2 sftp send function will deal
           with both accordingly */
        data->state.select_bits = CURL_CSELECT_OUT;

        /* since we don't really wait for anything at this point, we want the
           state machine to move on as soon as possible so we set a very short
           timeout here */
        Curl_expire(data, 0, EXPIRE_RUN_NOW);

        state(data, SSH_STOP);
      }
      break;







|









|








|







2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
      }
      if(data->state.infilesize > 0) {
        data->req.size = data->state.infilesize;
        Curl_pgrsSetUploadSize(data, data->state.infilesize);
      }
      /* upload data */
      Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      if(result) {
        state(data, SSH_SFTP_CLOSE);
        sshc->actualcode = result;
      }
      else {
        /* store this original bitmask setup to use later on if we cannot
           figure out a "real" bitmask */
        sshc->orig_waitfor = data->req.keepon;

        /* we want to use the _sending_ function even when the socket turns
           out readable as the underlying libssh2 sftp send function will deal
           with both accordingly */
        data->state.select_bits = CURL_CSELECT_OUT;

        /* since we do not really wait for anything at this point, we want the
           state machine to move on as soon as possible so we set a very short
           timeout here */
        Curl_expire(data, 0, EXPIRE_RUN_NOW);

        state(data, SSH_STOP);
      }
      break;
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
      state(data, SSH_SFTP_UPLOAD_INIT);
      break;

    case SSH_SFTP_CREATE_DIRS_MKDIR:
      /* 'mode' - parameter is preliminary - default to 0644 */
      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path,
                                 curlx_uztoui(strlen(sshp->path)),
                                 data->set.new_directory_perms);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      *sshc->slash_pos = '/';
      ++sshc->slash_pos;
      if(rc < 0) {
        /*
         * Abort if failure wasn't that the dir already exists or the
         * permission was denied (creation might succeed further down the
         * path) - retry on unspecific FAILURE also
         */
        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
        if((sftperr != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
           (sftperr != LIBSSH2_FX_FAILURE) &&
           (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) {







|







|







2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
      state(data, SSH_SFTP_UPLOAD_INIT);
      break;

    case SSH_SFTP_CREATE_DIRS_MKDIR:
      /* 'mode' - parameter is preliminary - default to 0644 */
      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path,
                                 curlx_uztoui(strlen(sshp->path)),
                                 (long)data->set.new_directory_perms);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      *sshc->slash_pos = '/';
      ++sshc->slash_pos;
      if(rc < 0) {
        /*
         * Abort if failure was not that the dir already exists or the
         * permission was denied (creation might succeed further down the
         * path) - retry on unspecific FAILURE also
         */
        sftperr = libssh2_sftp_last_error(sshc->sftp_session);
        if((sftperr != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
           (sftperr != LIBSSH2_FX_FAILURE) &&
           (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) {
2398
2399
2400
2401
2402
2403
2404

2405
2406
2407
2408
2409
2410
2411
2412
      }
      break;

    case SSH_SFTP_READDIR_LINK:
      rc =
        libssh2_sftp_symlink_ex(sshc->sftp_session,
                                Curl_dyn_ptr(&sshp->readdir_link),

                                (int)Curl_dyn_len(&sshp->readdir_link),
                                sshp->readdir_filename,
                                PATH_MAX, LIBSSH2_SFTP_READLINK);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      Curl_dyn_free(&sshp->readdir_link);








>
|







2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
      }
      break;

    case SSH_SFTP_READDIR_LINK:
      rc =
        libssh2_sftp_symlink_ex(sshc->sftp_session,
                                Curl_dyn_ptr(&sshp->readdir_link),
                                (unsigned int)
                                  Curl_dyn_len(&sshp->readdir_link),
                                sshp->readdir_filename,
                                PATH_MAX, LIBSSH2_SFTP_READLINK);
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      Curl_dyn_free(&sshp->readdir_link);

2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
        break;
      }
      sshc->sftp_handle = NULL;
      Curl_safefree(sshp->readdir_filename);
      Curl_safefree(sshp->readdir_longentry);

      /* no data to transfer */
      Curl_xfer_setup(data, -1, -1, FALSE, -1);
      state(data, SSH_STOP);
      break;

    case SSH_SFTP_DOWNLOAD_INIT:
      /*
       * Work on getting the specified file
       */
      sshc->sftp_handle =
        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
                             curlx_uztoui(strlen(sshp->path)),
                             LIBSSH2_FXF_READ, data->set.new_file_perms,
                             LIBSSH2_SFTP_OPENFILE);
      if(!sshc->sftp_handle) {
        if(libssh2_session_last_errno(sshc->ssh_session) ==
           LIBSSH2_ERROR_EAGAIN) {
          rc = LIBSSH2_ERROR_EAGAIN;
          break;
        }







|










|







2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
        break;
      }
      sshc->sftp_handle = NULL;
      Curl_safefree(sshp->readdir_filename);
      Curl_safefree(sshp->readdir_longentry);

      /* no data to transfer */
      Curl_xfer_setup_nop(data);
      state(data, SSH_STOP);
      break;

    case SSH_SFTP_DOWNLOAD_INIT:
      /*
       * Work on getting the specified file
       */
      sshc->sftp_handle =
        libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
                             curlx_uztoui(strlen(sshp->path)),
                             LIBSSH2_FXF_READ, (long)data->set.new_file_perms,
                             LIBSSH2_SFTP_OPENFILE);
      if(!sshc->sftp_handle) {
        if(libssh2_session_last_errno(sshc->ssh_session) ==
           LIBSSH2_ERROR_EAGAIN) {
          rc = LIBSSH2_ERROR_EAGAIN;
          break;
        }
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      if(rc ||
         !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
         (attrs.filesize == 0)) {
        /*
         * libssh2_sftp_open() didn't return an error, so maybe the server
         * just doesn't support stat()
         * OR the server doesn't return a file size with a stat()
         * OR file size is 0
         */
        data->req.size = -1;
        data->req.maxdownload = -1;
        Curl_pgrsSetDownloadSize(data, -1);
      }
      else {







|
|
|







2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
      if(rc == LIBSSH2_ERROR_EAGAIN) {
        break;
      }
      if(rc ||
         !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
         (attrs.filesize == 0)) {
        /*
         * libssh2_sftp_open() did not return an error, so maybe the server
         * just does not support stat()
         * OR the server does not return a file size with a stat()
         * OR file size is 0
         */
        data->req.size = -1;
        data->req.maxdownload = -1;
        Curl_pgrsSetDownloadSize(data, -1);
      }
      else {
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
        data->req.maxdownload = size;
        Curl_pgrsSetDownloadSize(data, size);
      }

      /* We can resume if we can seek to the resume position */
      if(data->state.resume_from) {
        if(data->state.resume_from < 0) {
          /* We're supposed to download the last abs(from) bytes */
          if((curl_off_t)attrs.filesize < -data->state.resume_from) {
            failf(data, "Offset (%"
                  CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
                  CURL_FORMAT_CURL_OFF_T ")",
                  data->state.resume_from, (curl_off_t)attrs.filesize);
            return CURLE_BAD_DOWNLOAD_RESUME;
          }







|







2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
        data->req.maxdownload = size;
        Curl_pgrsSetDownloadSize(data, size);
      }

      /* We can resume if we can seek to the resume position */
      if(data->state.resume_from) {
        if(data->state.resume_from < 0) {
          /* We are supposed to download the last abs(from) bytes */
          if((curl_off_t)attrs.filesize < -data->state.resume_from) {
            failf(data, "Offset (%"
                  CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
                  CURL_FORMAT_CURL_OFF_T ")",
                  data->state.resume_from, (curl_off_t)attrs.filesize);
            return CURLE_BAD_DOWNLOAD_RESUME;
          }
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
      }
    }

    /* Setup the actual download */
    if(data->req.size == 0) {
      /* no data to transfer */
      Curl_xfer_setup(data, -1, -1, FALSE, -1);
      infof(data, "File already completely downloaded");
      state(data, SSH_STOP);
      break;
    }
    Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);

    /* not set by Curl_xfer_setup to preserve keepon bits */
    conn->writesockfd = conn->sockfd;

    /* we want to use the _receiving_ function even when the socket turns
       out writableable as the underlying libssh2 recv function will deal
       with both accordingly */







|




|







2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
      }
    }

    /* Setup the actual download */
    if(data->req.size == 0) {
      /* no data to transfer */
      Curl_xfer_setup_nop(data);
      infof(data, "File already completely downloaded");
      state(data, SSH_STOP);
      break;
    }
    Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);

    /* not set by Curl_xfer_setup to preserve keepon bits */
    conn->writesockfd = conn->sockfd;

    /* we want to use the _receiving_ function even when the socket turns
       out writableable as the underlying libssh2 recv function will deal
       with both accordingly */
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
        state(data, SSH_SCP_DOWNLOAD_INIT);
      }
      break;

    case SSH_SCP_UPLOAD_INIT:
      /*
       * libssh2 requires that the destination path is a full path that
       * includes the destination file and name OR ends in a "/" .  If this is
       * not done the destination file will be named the same name as the last
       * directory in the path.
       */
      sshc->ssh_channel =
        SCP_SEND(sshc->ssh_session, sshp->path, data->set.new_file_perms,
                 data->state.infilesize);
      if(!sshc->ssh_channel) {







|







2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
        state(data, SSH_SCP_DOWNLOAD_INIT);
      }
      break;

    case SSH_SCP_UPLOAD_INIT:
      /*
       * libssh2 requires that the destination path is a full path that
       * includes the destination file and name OR ends in a "/" . If this is
       * not done the destination file will be named the same name as the last
       * directory in the path.
       */
      sshc->ssh_channel =
        SCP_SEND(sshc->ssh_session, sshp->path, data->set.new_file_perms,
                 data->state.infilesize);
      if(!sshc->ssh_channel) {
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
          sshc->actualcode = CURLE_UPLOAD_FAILED;
        break;
      }

      /* upload data */
      data->req.size = data->state.infilesize;
      Curl_pgrsSetUploadSize(data, data->state.infilesize);
      Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      if(result) {
        state(data, SSH_SCP_CHANNEL_FREE);
        sshc->actualcode = result;
      }
      else {
        /* store this original bitmask setup to use later on if we can't
           figure out a "real" bitmask */
        sshc->orig_waitfor = data->req.keepon;

        /* we want to use the _sending_ function even when the socket turns
           out readable as the underlying libssh2 scp send function will deal
           with both accordingly */
        data->state.select_bits = CURL_CSELECT_OUT;







|









|







2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
          sshc->actualcode = CURLE_UPLOAD_FAILED;
        break;
      }

      /* upload data */
      data->req.size = data->state.infilesize;
      Curl_pgrsSetUploadSize(data, data->state.infilesize);
      Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      if(result) {
        state(data, SSH_SCP_CHANNEL_FREE);
        sshc->actualcode = result;
      }
      else {
        /* store this original bitmask setup to use later on if we cannot
           figure out a "real" bitmask */
        sshc->orig_waitfor = data->req.keepon;

        /* we want to use the _sending_ function even when the socket turns
           out readable as the underlying libssh2 scp send function will deal
           with both accordingly */
        data->state.select_bits = CURL_CSELECT_OUT;
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
        sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
        break;
      }

      /* download data */
      bytecount = (curl_off_t)sb.st_size;
      data->req.maxdownload = (curl_off_t)sb.st_size;
      Curl_xfer_setup(data, FIRSTSOCKET, bytecount, FALSE, -1);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->writesockfd = conn->sockfd;

      /* we want to use the _receiving_ function even when the socket turns
         out writableable as the underlying libssh2 recv function will deal
         with both accordingly */







|







2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
        sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
        break;
      }

      /* download data */
      bytecount = (curl_off_t)sb.st_size;
      data->req.maxdownload = (curl_off_t)sb.st_size;
      Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->writesockfd = conn->sockfd;

      /* we want to use the _receiving_ function even when the socket turns
         out writableable as the underlying libssh2 recv function will deal
         with both accordingly */
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
      state(data, SSH_SESSION_DISCONNECT);
#endif
      state(data, SSH_STOP);
      result = sshc->actualcode;
      break;

    case SSH_SESSION_DISCONNECT:
      /* during weird times when we've been prematurely aborted, the channel
         is still alive when we reach this state and we MUST kill the channel
         properly first */
      if(sshc->ssh_channel) {
        rc = libssh2_channel_free(sshc->ssh_channel);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
          break;
        }







|







2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
      state(data, SSH_SESSION_DISCONNECT);
#endif
      state(data, SSH_STOP);
      result = sshc->actualcode;
      break;

    case SSH_SESSION_DISCONNECT:
      /* during weird times when we have been prematurely aborted, the channel
         is still alive when we reach this state and we MUST kill the channel
         properly first */
      if(sshc->ssh_channel) {
        rc = libssh2_channel_free(sshc->ssh_channel);
        if(rc == LIBSSH2_ERROR_EAGAIN) {
          break;
        }
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
  return bitmap;
}

/*
 * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
 * function is used to figure out in what direction and stores this info so
 * that the multi interface can take advantage of it. Make sure to call this
 * function in all cases so that when it _doesn't_ return EAGAIN we can
 * restore the default wait bits.
 */
static void ssh_block2waitfor(struct Curl_easy *data, bool block)
{
  struct connectdata *conn = data->conn;
  struct ssh_conn *sshc = &conn->proto.sshc;
  int dir = 0;
  if(block) {
    dir = libssh2_session_block_directions(sshc->ssh_session);
    if(dir) {
      /* translate the libssh2 define bits into our own bit defines */
      conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
        ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
    }
  }
  if(!dir)
    /* It didn't block or libssh2 didn't reveal in which direction, put back
       the original set */
    conn->waitfor = sshc->orig_waitfor;
}

/* called repeatedly until done from multi.c */
static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
{
  struct connectdata *conn = data->conn;
  struct ssh_conn *sshc = &conn->proto.sshc;
  CURLcode result = CURLE_OK;
  bool block; /* we store the status and use that to provide a ssh_getsock()
                 implementation */
  do {
    result = ssh_statemach_act(data, &block);
    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
    /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
       try again */
  } while(!result && !*done && !block);
  ssh_block2waitfor(data, block);

  return result;
}








|
















|















|







3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
  return bitmap;
}

/*
 * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
 * function is used to figure out in what direction and stores this info so
 * that the multi interface can take advantage of it. Make sure to call this
 * function in all cases so that when it _does not_ return EAGAIN we can
 * restore the default wait bits.
 */
static void ssh_block2waitfor(struct Curl_easy *data, bool block)
{
  struct connectdata *conn = data->conn;
  struct ssh_conn *sshc = &conn->proto.sshc;
  int dir = 0;
  if(block) {
    dir = libssh2_session_block_directions(sshc->ssh_session);
    if(dir) {
      /* translate the libssh2 define bits into our own bit defines */
      conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
        ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
    }
  }
  if(!dir)
    /* It did not block or libssh2 did not reveal in which direction, put back
       the original set */
    conn->waitfor = sshc->orig_waitfor;
}

/* called repeatedly until done from multi.c */
static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
{
  struct connectdata *conn = data->conn;
  struct ssh_conn *sshc = &conn->proto.sshc;
  CURLcode result = CURLE_OK;
  bool block; /* we store the status and use that to provide a ssh_getsock()
                 implementation */
  do {
    result = ssh_statemach_act(data, &block);
    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
    /* if there is no error, it is not done and it did not EWOULDBLOCK, then
       try again */
  } while(!result && !*done && !block);
  ssh_block2waitfor(data, block);

  return result;
}

3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
    return CURLE_FAILED_INIT;
  }

  /* Set the packet read timeout if the libssh2 version supports it */
#if LIBSSH2_VERSION_NUM >= 0x010B00
  if(data->set.server_response_timeout > 0) {
    libssh2_session_set_read_timeout(sshc->ssh_session,
                                     data->set.server_response_timeout / 1000);
  }
#endif

#ifndef CURL_DISABLE_PROXY
  if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
    /*
      Setup libssh2 callbacks to make it read/write TLS from the socket.







|







3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
    return CURLE_FAILED_INIT;
  }

  /* Set the packet read timeout if the libssh2 version supports it */
#if LIBSSH2_VERSION_NUM >= 0x010B00
  if(data->set.server_response_timeout > 0) {
    libssh2_session_set_read_timeout(sshc->ssh_session,
                             (long)(data->set.server_response_timeout / 1000));
  }
#endif

#ifndef CURL_DISABLE_PROXY
  if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
    /*
      Setup libssh2 callbacks to make it read/write TLS from the socket.
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
                               bool dead_connection)
{
  CURLcode result = CURLE_OK;
  struct ssh_conn *sshc = &conn->proto.sshc;
  (void) dead_connection;

  if(sshc->ssh_session) {
    /* only if there's a session still around to use! */
    state(data, SSH_SESSION_DISCONNECT);
    result = ssh_block_statemach(data, conn, TRUE);
  }

  return result;
}








|







3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
                               bool dead_connection)
{
  CURLcode result = CURLE_OK;
  struct ssh_conn *sshc = &conn->proto.sshc;
  (void) dead_connection;

  if(sshc->ssh_session) {
    /* only if there is a session still around to use! */
    state(data, SSH_SESSION_DISCONNECT);
    result = ssh_block_statemach(data, conn, TRUE);
  }

  return result;
}

3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
  CURLcode result = CURLE_OK;
  struct ssh_conn *sshc = &conn->proto.sshc;
  (void) dead_connection;

  DEBUGF(infof(data, "SSH DISCONNECT starts now"));

  if(sshc->ssh_session) {
    /* only if there's a session still around to use! */
    state(data, SSH_SFTP_SHUTDOWN);
    result = ssh_block_statemach(data, conn, TRUE);
  }

  DEBUGF(infof(data, "SSH DISCONNECT is done"));

  return result;







|







3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
  CURLcode result = CURLE_OK;
  struct ssh_conn *sshc = &conn->proto.sshc;
  (void) dead_connection;

  DEBUGF(infof(data, "SSH DISCONNECT starts now"));

  if(sshc->ssh_session) {
    /* only if there is a session still around to use! */
    state(data, SSH_SFTP_SHUTDOWN);
    result = ssh_block_statemach(data, conn, TRUE);
  }

  DEBUGF(infof(data, "SSH DISCONNECT is done"));

  return result;
Changes to jni/curl/lib/vssh/ssh.h.
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  char *readdir_linkPath;
  size_t readdir_len;
  struct dynbuf readdir_buf;
/* our variables */
  unsigned kbd_state; /* 0 or 1 */
  ssh_key privkey;
  ssh_key pubkey;
  int auth_methods;
  ssh_session ssh_session;
  ssh_scp scp_session;
  sftp_session sftp_session;
  sftp_file sftp_file;
  sftp_dir sftp_dir;

  unsigned sftp_recv_state; /* 0 or 1 */







|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  char *readdir_linkPath;
  size_t readdir_len;
  struct dynbuf readdir_buf;
/* our variables */
  unsigned kbd_state; /* 0 or 1 */
  ssh_key privkey;
  ssh_key pubkey;
  unsigned int auth_methods;
  ssh_session ssh_session;
  ssh_scp scp_session;
  sftp_session sftp_session;
  sftp_file sftp_file;
  sftp_dir sftp_dir;

  unsigned sftp_recv_state; /* 0 or 1 */
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#endif

#if LIBSSH2_VERSION_NUM >= 0x010208
#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1
#endif

#ifdef HAVE_LIBSSH2_VERSION
/* get it run-time if possible */
#define CURL_LIBSSH2_VERSION libssh2_version(0)
#else
/* use build-time if run-time not possible */
#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
#endif

#endif /* USE_LIBSSH2 */

#ifdef USE_SSH








|


|







239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
#endif

#if LIBSSH2_VERSION_NUM >= 0x010208
#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1
#endif

#ifdef HAVE_LIBSSH2_VERSION
/* get it runtime if possible */
#define CURL_LIBSSH2_VERSION libssh2_version(0)
#else
/* use build-time if runtime not possible */
#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
#endif

#endif /* USE_LIBSSH2 */

#ifdef USE_SSH

Changes to jni/curl/lib/vssh/wolfssh.c.
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  if(!sshc->ssh_session) {
    failf(data, "No wolfSSH session");
    goto error;
  }

  rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user);
  if(rc != WS_SUCCESS) {
    failf(data, "wolfSSH failed to set user name");
    goto error;
  }

  /* set callback for authentication */
  wolfSSH_SetUserAuth(sshc->ctx, userauth);
  wolfSSH_SetUserAuthCtx(sshc->ssh_session, data);








|







396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  if(!sshc->ssh_session) {
    failf(data, "No wolfSSH session");
    goto error;
  }

  rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user);
  if(rc != WS_SUCCESS) {
    failf(data, "wolfSSH failed to set username");
    goto error;
  }

  /* set callback for authentication */
  wolfSSH_SetUserAuth(sshc->ctx, userauth);
  wolfSSH_SetUserAuthCtx(sshc->ssh_session, data);

429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  wolfSSH_free(sshc->ssh_session);
  wolfSSH_CTX_free(sshc->ctx);
  return CURLE_FAILED_INIT;
}

/*
 * wssh_statemach_act() runs the SSH state machine as far as it can without
 * blocking and without reaching the end.  The data the pointer 'block' points
 * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it
 * wants to be called again when the socket is ready
 */

static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct ssh_conn *sshc = &conn->proto.sshc;
  struct SSHPROTO *sftp_scp = data->req.p.ssh;
  WS_SFTPNAME *name;
  int rc = 0;
  *block = FALSE; /* we're not blocking by default */

  do {
    switch(sshc->state) {
    case SSH_INIT:
      state(data, SSH_S_STARTUP);
      break;








|












|







429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  wolfSSH_free(sshc->ssh_session);
  wolfSSH_CTX_free(sshc->ctx);
  return CURLE_FAILED_INIT;
}

/*
 * wssh_statemach_act() runs the SSH state machine as far as it can without
 * blocking and without reaching the end. The data the pointer 'block' points
 * to will be set to TRUE if the wolfssh function returns EAGAIN meaning it
 * wants to be called again when the socket is ready
 */

static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
{
  CURLcode result = CURLE_OK;
  struct connectdata *conn = data->conn;
  struct ssh_conn *sshc = &conn->proto.sshc;
  struct SSHPROTO *sftp_scp = data->req.p.ssh;
  WS_SFTPNAME *name;
  int rc = 0;
  *block = FALSE; /* we are not blocking by default */

  do {
    switch(sshc->state) {
    case SSH_INIT:
      state(data, SSH_S_STARTUP);
      break;

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
        if(seekerr != CURL_SEEKFUNC_OK) {
          curl_off_t passed = 0;

          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
            failf(data, "Could not seek stream");
            return CURLE_FTP_COULDNT_USE_REST;
          }
          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
          do {
            char scratch[4*1024];
            size_t readthisamountnow =
              (data->state.resume_from - passed >
                (curl_off_t)sizeof(scratch)) ?
              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);








|







637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
        if(seekerr != CURL_SEEKFUNC_OK) {
          curl_off_t passed = 0;

          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
            failf(data, "Could not seek stream");
            return CURLE_FTP_COULDNT_USE_REST;
          }
          /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
          do {
            char scratch[4*1024];
            size_t readthisamountnow =
              (data->state.resume_from - passed >
                (curl_off_t)sizeof(scratch)) ?
              sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);

676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
        sshc->offset += data->state.resume_from;
      }
      if(data->state.infilesize > 0) {
        data->req.size = data->state.infilesize;
        Curl_pgrsSetUploadSize(data, data->state.infilesize);
      }
      /* upload data */
      Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      if(result) {
        state(data, SSH_SFTP_CLOSE);
        sshc->actualcode = result;
      }
      else {
        /* store this original bitmask setup to use later on if we can't
           figure out a "real" bitmask */
        sshc->orig_waitfor = data->req.keepon;

        /* we want to use the _sending_ function even when the socket turns
           out readable as the underlying libssh2 sftp send function will deal
           with both accordingly */
        data->state.select_bits = CURL_CSELECT_OUT;

        /* since we don't really wait for anything at this point, we want the
           state machine to move on as soon as possible so we set a very short
           timeout here */
        Curl_expire(data, 0, EXPIRE_RUN_NOW);

        state(data, SSH_STOP);
      }
      break;







|









|








|







676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
        sshc->offset += data->state.resume_from;
      }
      if(data->state.infilesize > 0) {
        data->req.size = data->state.infilesize;
        Curl_pgrsSetUploadSize(data, data->state.infilesize);
      }
      /* upload data */
      Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->sockfd = conn->writesockfd;

      if(result) {
        state(data, SSH_SFTP_CLOSE);
        sshc->actualcode = result;
      }
      else {
        /* store this original bitmask setup to use later on if we cannot
           figure out a "real" bitmask */
        sshc->orig_waitfor = data->req.keepon;

        /* we want to use the _sending_ function even when the socket turns
           out readable as the underlying libssh2 sftp send function will deal
           with both accordingly */
        data->state.select_bits = CURL_CSELECT_OUT;

        /* since we do not really wait for anything at this point, we want the
           state machine to move on as soon as possible so we set a very short
           timeout here */
        Curl_expire(data, 0, EXPIRE_RUN_NOW);

        state(data, SSH_STOP);
      }
      break;
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
        infof(data, "wolfSSH cannot do range/seek on SFTP");
        return CURLE_BAD_DOWNLOAD_RESUME;
      }

      /* Setup the actual download */
      if(data->req.size == 0) {
        /* no data to transfer */
        Curl_xfer_setup(data, -1, -1, FALSE, -1);
        infof(data, "File already completely downloaded");
        state(data, SSH_STOP);
        break;
      }
      Curl_xfer_setup(data, FIRSTSOCKET, data->req.size, FALSE, -1);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->writesockfd = conn->sockfd;

      /* we want to use the _receiving_ function even when the socket turns
         out writableable as the underlying libssh2 recv function will deal
         with both accordingly */







|




|







776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
        infof(data, "wolfSSH cannot do range/seek on SFTP");
        return CURLE_BAD_DOWNLOAD_RESUME;
      }

      /* Setup the actual download */
      if(data->req.size == 0) {
        /* no data to transfer */
        Curl_xfer_setup_nop(data);
        infof(data, "File already completely downloaded");
        state(data, SSH_STOP);
        break;
      }
      Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);

      /* not set by Curl_xfer_setup to preserve keepon bits */
      conn->writesockfd = conn->sockfd;

      /* we want to use the _receiving_ function even when the socket turns
         out writableable as the underlying libssh2 recv function will deal
         with both accordingly */
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  struct ssh_conn *sshc = &conn->proto.sshc;
  CURLcode result = CURLE_OK;
  bool block; /* we store the status and use that to provide a ssh_getsock()
                 implementation */
  do {
    result = wssh_statemach_act(data, &block);
    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
    /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
       try again */
    if(*done) {
      DEBUGF(infof(data, "wssh_statemach_act says DONE"));
    }
  } while(!result && !*done && !block);

  return result;







|







904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  struct ssh_conn *sshc = &conn->proto.sshc;
  CURLcode result = CURLE_OK;
  bool block; /* we store the status and use that to provide a ssh_getsock()
                 implementation */
  do {
    result = wssh_statemach_act(data, &block);
    *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
    /* if there is no error, it is not done and it did not EWOULDBLOCK, then
       try again */
    if(*done) {
      DEBUGF(infof(data, "wssh_statemach_act says DONE"));
    }
  } while(!result && !*done && !block);

  return result;
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
{
  CURLcode result = CURLE_OK;
  (void)dead;

  DEBUGF(infof(data, "SSH DISCONNECT starts now"));

  if(conn->proto.sshc.ssh_session) {
    /* only if there's a session still around to use! */
    state(data, SSH_SFTP_SHUTDOWN);
    result = wssh_block_statemach(data, TRUE);
  }

  DEBUGF(infof(data, "SSH DISCONNECT is done"));
  return result;
}







|







1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
{
  CURLcode result = CURLE_OK;
  (void)dead;

  DEBUGF(infof(data, "SSH DISCONNECT starts now"));

  if(conn->proto.sshc.ssh_session) {
    /* only if there is a session still around to use! */
    state(data, SSH_SFTP_SHUTDOWN);
    result = wssh_block_statemach(data, TRUE);
  }

  DEBUGF(infof(data, "SSH DISCONNECT is done"));
  return result;
}
Changes to jni/curl/lib/vtls/bearssl.c.
59
60
61
62
63
64
65

66
67
68
69
70
71
72
  br_x509_trust_anchor *anchors;
  size_t anchors_len;
  const char *protocols[ALPN_ENTRIES_MAX];
  /* SSL client context is active */
  bool active;
  /* size of pending write, yet to be flushed */
  size_t pending_write;

};

struct cafile_parser {
  CURLcode err;
  bool in_cert;
  br_x509_decoder_context xc;
  /* array of trust anchors loaded from CAfile */







>







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  br_x509_trust_anchor *anchors;
  size_t anchors_len;
  const char *protocols[ALPN_ENTRIES_MAX];
  /* SSL client context is active */
  bool active;
  /* size of pending write, yet to be flushed */
  size_t pending_write;
  BIT(sent_shutdown);
};

struct cafile_parser {
  CURLcode err;
  bool in_cert;
  br_x509_decoder_context xc;
  /* array of trust anchors loaded from CAfile */
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
}

static unsigned x509_end_chain(const br_x509_class **ctx)
{
  struct x509_context *x509 = (struct x509_context *)ctx;

  if(!x509->verifypeer) {
    return br_x509_decoder_last_error(&x509->decoder);
  }

  return x509->minimal.vtable->end_chain(&x509->minimal.vtable);
}

static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx,
                                         unsigned *usages)







|







324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
}

static unsigned x509_end_chain(const br_x509_class **ctx)
{
  struct x509_context *x509 = (struct x509_context *)ctx;

  if(!x509->verifypeer) {
    return (unsigned)br_x509_decoder_last_error(&x509->decoder);
  }

  return x509->minimal.vtable->end_chain(&x509->minimal.vtable);
}

static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx,
                                         unsigned *usages)
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

  /* initialize X.509 context */
  backend->x509.vtable = &x509_vtable;
  backend->x509.verifypeer = verifypeer;
  backend->x509.verifyhost = verifyhost;
  br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);

  if(ssl_config->primary.sessionid) {
    void *session;

    CURL_TRC_CF(data, cf, "connect_step1, check session cache");
    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &session, NULL)) {
      br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
      session_set = 1;







|







580
581
582
583
584
585
586
587
588
589
590
591
592
593
594

  /* initialize X.509 context */
  backend->x509.vtable = &x509_vtable;
  backend->x509.verifypeer = verifypeer;
  backend->x509.verifyhost = verifyhost;
  br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);

  if(ssl_config->primary.cache_session) {
    void *session;

    CURL_TRC_CF(data, cf, "connect_step1, check session cache");
    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &session, NULL)) {
      br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
      session_set = 1;
718
719
720
721
722
723
724


725
726
727
728
729
730
731
732
733
734
735
736
737


738
739
740
741
742
743
744
    if(state & target)
      return CURLE_OK;
    if(state & BR_SSL_SENDREC) {
      buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
      ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
      CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
      if(ret <= 0) {


        return result;
      }
      br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
    }
    else if(state & BR_SSL_RECVREC) {
      buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
      ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
      CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
      if(ret == 0) {
        failf(data, "SSL: EOF without close notify");
        return CURLE_RECV_ERROR;
      }
      if(ret <= 0) {


        return result;
      }
      br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
    }
  }
}








>
>













>
>







719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
    if(state & target)
      return CURLE_OK;
    if(state & BR_SSL_SENDREC) {
      buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
      ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
      CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
      if(ret <= 0) {
        if(result == CURLE_AGAIN)
          connssl->io_need |= CURL_SSL_IO_NEED_SEND;
        return result;
      }
      br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
    }
    else if(state & BR_SSL_RECVREC) {
      buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len);
      ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result);
      CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
      if(ret == 0) {
        failf(data, "SSL: EOF without close notify");
        return CURLE_RECV_ERROR;
      }
      if(ret <= 0) {
        if(result == CURLE_AGAIN)
          connssl->io_need |= CURL_SSL_IO_NEED_RECV;
        return result;
      }
      br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
    }
  }
}

809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
    const char *proto;

    proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
    Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
                             proto? strlen(proto) : 0);
  }

  if(ssl_config->primary.sessionid) {
    bool incache;
    void *oldsession;
    br_ssl_session_parameters *session;

    session = malloc(sizeof(*session));
    if(!session)
      return CURLE_OUT_OF_MEMORY;
    br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
    Curl_ssl_sessionid_lock(data);
    incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
                                      &oldsession, NULL));
    if(incache)
      Curl_ssl_delsessionid(data, oldsession);

    ret = Curl_ssl_addsessionid(cf, data, &connssl->peer, session, 0,
                                bearssl_session_free);
    Curl_ssl_sessionid_unlock(data);
    if(ret)
      return ret;
  }

  connssl->connecting_state = ssl_connect_done;








|
<
<







<
<
<
<
<
|
|







814
815
816
817
818
819
820
821


822
823
824
825
826
827
828





829
830
831
832
833
834
835
836
837
    const char *proto;

    proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
    Curl_alpn_set_negotiated(cf, data, (const unsigned char *)proto,
                             proto? strlen(proto) : 0);
  }

  if(ssl_config->primary.cache_session) {


    br_ssl_session_parameters *session;

    session = malloc(sizeof(*session));
    if(!session)
      return CURLE_OUT_OF_MEMORY;
    br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
    Curl_ssl_sessionid_lock(data);





    ret = Curl_ssl_set_sessionid(cf, data, &connssl->peer, session, 0,
                                 bearssl_session_free);
    Curl_ssl_sessionid_unlock(data);
    if(ret)
      return ret;
  }

  connssl->connecting_state = ssl_connect_done;

921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954

  if(ssl_connect_1 == connssl->connecting_state) {
    ret = bearssl_connect_step1(cf, data);
    if(ret)
      return ret;
  }

  while(ssl_connect_2 == connssl->connecting_state ||
        ssl_connect_2_reading == connssl->connecting_state ||
        ssl_connect_2_writing == connssl->connecting_state) {
    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it's available. */
    if(ssl_connect_2_reading == connssl->connecting_state ||
       ssl_connect_2_writing == connssl->connecting_state) {

      curl_socket_t writefd = ssl_connect_2_writing ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;

      CURL_TRC_CF(data, cf, "connect_common, check socket");
      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking?0:timeout_ms);
      CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what);
      if(what < 0) {
        /* fatal error */







|
<
<









|
<
|

|
|
|
|







919
920
921
922
923
924
925
926


927
928
929
930
931
932
933
934
935
936

937
938
939
940
941
942
943
944
945
946
947
948
949

  if(ssl_connect_1 == connssl->connecting_state) {
    ret = bearssl_connect_step1(cf, data);
    if(ret)
      return ret;
  }

  while(ssl_connect_2 == connssl->connecting_state) {


    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it is available. */

    if(connssl->io_need) {

      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
                              sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
                             sockfd:CURL_SOCKET_BAD;

      CURL_TRC_CF(data, cf, "connect_common, check socket");
      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking?0:timeout_ms);
      CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what);
      if(what < 0) {
        /* fatal error */
971
972
973
974
975
976
977

978
979
980
981
982
983
984
985
986
987
988
989

    /* Run transaction, and return to the caller if it failed or if this
     * connection is done nonblocking and this loop would execute again. This
     * permits the owner of a multi handle to abort a connection attempt
     * before step2 has completed while ensuring that a client using select()
     * or epoll() will always have a valid fdset to wait on.
     */

    ret = bearssl_connect_step2(cf, data);
    if(ret || (nonblocking &&
               (ssl_connect_2 == connssl->connecting_state ||
                ssl_connect_2_reading == connssl->connecting_state ||
                ssl_connect_2_writing == connssl->connecting_state)))
      return ret;
  }

  if(ssl_connect_3 == connssl->connecting_state) {
    ret = bearssl_connect_step3(cf, data);
    if(ret)
      return ret;







>

|
<
<
<







966
967
968
969
970
971
972
973
974
975



976
977
978
979
980
981
982

    /* Run transaction, and return to the caller if it failed or if this
     * connection is done nonblocking and this loop would execute again. This
     * permits the owner of a multi handle to abort a connection attempt
     * before step2 has completed while ensuring that a client using select()
     * or epoll() will always have a valid fdset to wait on.
     */
    connssl->io_need = CURL_SSL_IO_NEED_NONE;
    ret = bearssl_connect_step2(cf, data);
    if(ret || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))



      return ret;
  }

  if(ssl_connect_3 == connssl->connecting_state) {
    ret = bearssl_connect_step3(cf, data);
    if(ret)
      return ret;
1065
1066
1067
1068
1069
1070
1071



































1072
1073
1074
1075
1076
1077
1078
1079

1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
                                   CURLINFO info UNUSED_PARAM)
{
  struct bearssl_ssl_backend_data *backend =
    (struct bearssl_ssl_backend_data *)connssl->backend;
  DEBUGASSERT(backend);
  return &backend->ctx;
}




































static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct bearssl_ssl_backend_data *backend =
    (struct bearssl_ssl_backend_data *)connssl->backend;
  size_t i;


  DEBUGASSERT(backend);

  if(backend->active) {
    backend->active = FALSE;
    br_ssl_engine_close(&backend->ctx.eng);
    (void)bearssl_run_until(cf, data, BR_SSL_CLOSED);
  }
  if(backend->anchors) {
    for(i = 0; i < backend->anchors_len; ++i)
      free(backend->anchors[i].dn.data);
    Curl_safefree(backend->anchors);
  }
}








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








>


<
|
<
<
<







1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110

1111



1112
1113
1114
1115
1116
1117
1118
                                   CURLINFO info UNUSED_PARAM)
{
  struct bearssl_ssl_backend_data *backend =
    (struct bearssl_ssl_backend_data *)connssl->backend;
  DEBUGASSERT(backend);
  return &backend->ctx;
}

static CURLcode bearssl_shutdown(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 bool send_shutdown, bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct bearssl_ssl_backend_data *backend =
    (struct bearssl_ssl_backend_data *)connssl->backend;
  CURLcode result;

  DEBUGASSERT(backend);
  if(!backend->active || cf->shutdown) {
    *done = TRUE;
    return CURLE_OK;
  }

  *done = FALSE;
  if(!backend->sent_shutdown) {
    (void)send_shutdown; /* unknown how to suppress our close notify */
    br_ssl_engine_close(&backend->ctx.eng);
    backend->sent_shutdown = TRUE;
  }

  result = bearssl_run_until(cf, data, BR_SSL_CLOSED);
  if(result == CURLE_OK) {
    *done = TRUE;
  }
  else if(result == CURLE_AGAIN)
    result = CURLE_OK;
  else
    CURL_TRC_CF(data, cf, "shutdown error: %d", result);

  cf->shutdown = (result || *done);
  return result;
}

static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct bearssl_ssl_backend_data *backend =
    (struct bearssl_ssl_backend_data *)connssl->backend;
  size_t i;

  (void)data;
  DEBUGASSERT(backend);


  backend->active = FALSE;



  if(backend->anchors) {
    for(i = 0; i < backend->anchors_len; ++i)
      free(backend->anchors[i].dn.data);
    Curl_safefree(backend->anchors);
  }
}

1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
  SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY,
  sizeof(struct bearssl_ssl_backend_data),

  Curl_none_init,                  /* init */
  Curl_none_cleanup,               /* cleanup */
  bearssl_version,                 /* version */
  Curl_none_check_cxn,             /* check_cxn */
  Curl_none_shutdown,              /* shutdown */
  bearssl_data_pending,            /* data_pending */
  bearssl_random,                  /* random */
  Curl_none_cert_status_request,   /* cert_status_request */
  bearssl_connect,                 /* connect */
  bearssl_connect_nonblocking,     /* connect_nonblocking */
  bearssl_adjust_pollset,          /* adjust_pollset */
  bearssl_get_internals,           /* get_internals */
  bearssl_close,                   /* close_one */
  Curl_none_close_all,             /* close_all */
  Curl_none_set_engine,            /* set_engine */
  Curl_none_set_engine_default,    /* set_engine_default */
  Curl_none_engines_list,          /* engines_list */
  Curl_none_false_start,           /* false_start */
  bearssl_sha256sum,               /* sha256sum */
  NULL,                            /* associate_connection */
  NULL,                            /* disassociate_connection */
  NULL,                            /* free_multi_ssl_backend_data */
  bearssl_recv,                    /* recv decrypted data */
  bearssl_send,                    /* send data to encrypt */
};

#endif /* USE_BEARSSL */







|
















<





1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157

1158
1159
1160
1161
1162
  SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY,
  sizeof(struct bearssl_ssl_backend_data),

  Curl_none_init,                  /* init */
  Curl_none_cleanup,               /* cleanup */
  bearssl_version,                 /* version */
  Curl_none_check_cxn,             /* check_cxn */
  bearssl_shutdown,                /* shutdown */
  bearssl_data_pending,            /* data_pending */
  bearssl_random,                  /* random */
  Curl_none_cert_status_request,   /* cert_status_request */
  bearssl_connect,                 /* connect */
  bearssl_connect_nonblocking,     /* connect_nonblocking */
  bearssl_adjust_pollset,          /* adjust_pollset */
  bearssl_get_internals,           /* get_internals */
  bearssl_close,                   /* close_one */
  Curl_none_close_all,             /* close_all */
  Curl_none_set_engine,            /* set_engine */
  Curl_none_set_engine_default,    /* set_engine_default */
  Curl_none_engines_list,          /* engines_list */
  Curl_none_false_start,           /* false_start */
  bearssl_sha256sum,               /* sha256sum */
  NULL,                            /* associate_connection */
  NULL,                            /* disassociate_connection */

  bearssl_recv,                    /* recv decrypted data */
  bearssl_send,                    /* send data to encrypt */
};

#endif /* USE_BEARSSL */
Changes to jni/curl/lib/vtls/cipher_suite.c.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curl_setup.h"

#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
#include "cipher_suite.h"
#include "curl_printf.h"
#include "strcase.h"
#include <string.h>

/*
 * To support the CURLOPT_SSL_CIPHER_LIST option on SSL backends
 * that do not support it natively, but do support setting a list of
 * IANA ids, we need a list of all supported cipher suite names
 * (openssl and IANA) to be able to look up the IANA ids.
 *
 * To keep the binary size of this list down we compress each entry
 * down to 2 + 6 bytes using the C preprocessor.
 */

/*
 * mbedTLS NOTE: mbedTLS has mbedtls_ssl_get_ciphersuite_id() to
 * convert a string representation to an IANA id, we do not use that
 * because it does not support "standard" openssl cipher suite
 * names, nor IANA names.
 */

/* NOTE: also see tests/unit/unit3205.c */

/* Text for cipher suite parts (max 64 entries),
   keep indexes below in sync with this! */







|









|








|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curl_setup.h"

#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_BEARSSL)
#include "cipher_suite.h"
#include "curl_printf.h"
#include "strcase.h"
#include <string.h>

/*
 * To support the CURLOPT_SSL_CIPHER_LIST option on SSL backends
 * that do not support it natively, but do support setting a list of
 * IANA ids, we need a list of all supported cipher suite names
 * (OpenSSL and IANA) to be able to look up the IANA ids.
 *
 * To keep the binary size of this list down we compress each entry
 * down to 2 + 6 bytes using the C preprocessor.
 */

/*
 * mbedTLS NOTE: mbedTLS has mbedtls_ssl_get_ciphersuite_id() to
 * convert a string representation to an IANA id, we do not use that
 * because it does not support "standard" OpenSSL cipher suite
 * names, nor IANA names.
 */

/* NOTE: also see tests/unit/unit3205.c */

/* Text for cipher suite parts (max 64 entries),
   keep indexes below in sync with this! */
85
86
87
88
89
90
91















92
93
94
95
96
97
98
  "ARIA" "\0"
  "ARIA128" "\0"
  "ARIA256" "\0"
  "CAMELLIA" "\0"
  "CAMELLIA128" "\0"
  "CAMELLIA256" "\0"
#endif















;
/* Indexes of above cs_txt */
enum {
  CS_TXT_IDX_,
  CS_TXT_IDX_TLS,
  CS_TXT_IDX_WITH,
  CS_TXT_IDX_128,







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  "ARIA" "\0"
  "ARIA128" "\0"
  "ARIA256" "\0"
  "CAMELLIA" "\0"
  "CAMELLIA128" "\0"
  "CAMELLIA256" "\0"
#endif
#if defined(USE_SECTRANSP)
  "40" "\0"
  "ADH" "\0"
  "AECDH" "\0"
  "anon" "\0"
  "DES40" "\0"
  "DH" "\0"
  "DSS" "\0"
  "EDH" "\0"
  "EXP" "\0"
  "EXPORT" "\0"
  "IDEA" "\0"
  "RC2" "\0"
  "RC4" "\0"
#endif
;
/* Indexes of above cs_txt */
enum {
  CS_TXT_IDX_,
  CS_TXT_IDX_TLS,
  CS_TXT_IDX_WITH,
  CS_TXT_IDX_128,
125
126
127
128
129
130
131















132
133
134
135
136
137
138
#if defined(USE_MBEDTLS)
  CS_TXT_IDX_ARIA,
  CS_TXT_IDX_ARIA128,
  CS_TXT_IDX_ARIA256,
  CS_TXT_IDX_CAMELLIA,
  CS_TXT_IDX_CAMELLIA128,
  CS_TXT_IDX_CAMELLIA256,















#endif
  CS_TXT_LEN,
};

#define CS_ZIP_IDX(a, b, c, d, e, f, g, h)    \
{                                             \
  (uint8_t) ((a) << 2 | ((b) & 0x3F) >> 4),   \







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#if defined(USE_MBEDTLS)
  CS_TXT_IDX_ARIA,
  CS_TXT_IDX_ARIA128,
  CS_TXT_IDX_ARIA256,
  CS_TXT_IDX_CAMELLIA,
  CS_TXT_IDX_CAMELLIA128,
  CS_TXT_IDX_CAMELLIA256,
#endif
#if defined(USE_SECTRANSP)
  CS_TXT_IDX_40,
  CS_TXT_IDX_ADH,
  CS_TXT_IDX_AECDH,
  CS_TXT_IDX_anon,
  CS_TXT_IDX_DES40,
  CS_TXT_IDX_DH,
  CS_TXT_IDX_DSS,
  CS_TXT_IDX_EDH,
  CS_TXT_IDX_EXP,
  CS_TXT_IDX_EXPORT,
  CS_TXT_IDX_IDEA,
  CS_TXT_IDX_RC2,
  CS_TXT_IDX_RC4,
#endif
  CS_TXT_LEN,
};

#define CS_ZIP_IDX(a, b, c, d, e, f, g, h)    \
{                                             \
  (uint8_t) ((a) << 2 | ((b) & 0x3F) >> 4),   \
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
  CS_ENTRY(0xC031, ECDH,RSA,AES128,GCM,SHA256,,,),
  CS_ENTRY(0xC032, TLS,ECDH,RSA,WITH,AES,256,GCM,SHA384),
  CS_ENTRY(0xC032, ECDH,RSA,AES256,GCM,SHA384,,,),
  CS_ENTRY(0xCCA8, TLS,ECDHE,RSA,WITH,CHACHA20,POLY1305,SHA256,),
  CS_ENTRY(0xCCA8, ECDHE,RSA,CHACHA20,POLY1305,,,,),
  CS_ENTRY(0xCCA9, TLS,ECDHE,ECDSA,WITH,CHACHA20,POLY1305,SHA256,),
  CS_ENTRY(0xCCA9, ECDHE,ECDSA,CHACHA20,POLY1305,,,,),
#if defined(USE_MBEDTLS)
  CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,),
  CS_ENTRY(0x0001, NULL,MD5,,,,,,),
  CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,),
  CS_ENTRY(0x0002, NULL,SHA,,,,,,),
  CS_ENTRY(0x002C, TLS,PSK,WITH,NULL,SHA,,,),
  CS_ENTRY(0x002C, PSK,NULL,SHA,,,,,),
  CS_ENTRY(0x002D, TLS,DHE,PSK,WITH,NULL,SHA,,),







|







250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  CS_ENTRY(0xC031, ECDH,RSA,AES128,GCM,SHA256,,,),
  CS_ENTRY(0xC032, TLS,ECDH,RSA,WITH,AES,256,GCM,SHA384),
  CS_ENTRY(0xC032, ECDH,RSA,AES256,GCM,SHA384,,,),
  CS_ENTRY(0xCCA8, TLS,ECDHE,RSA,WITH,CHACHA20,POLY1305,SHA256,),
  CS_ENTRY(0xCCA8, ECDHE,RSA,CHACHA20,POLY1305,,,,),
  CS_ENTRY(0xCCA9, TLS,ECDHE,ECDSA,WITH,CHACHA20,POLY1305,SHA256,),
  CS_ENTRY(0xCCA9, ECDHE,ECDSA,CHACHA20,POLY1305,,,,),
#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS)
  CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,),
  CS_ENTRY(0x0001, NULL,MD5,,,,,,),
  CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,),
  CS_ENTRY(0x0002, NULL,SHA,,,,,,),
  CS_ENTRY(0x002C, TLS,PSK,WITH,NULL,SHA,,,),
  CS_ENTRY(0x002C, PSK,NULL,SHA,,,,,),
  CS_ENTRY(0x002D, TLS,DHE,PSK,WITH,NULL,SHA,,),
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347








































































































































348
349
350
351
352
353
354
355
356
  CS_ENTRY(0xC035, TLS,ECDHE,PSK,WITH,AES,128,CBC,SHA),
  CS_ENTRY(0xC035, ECDHE,PSK,AES128,CBC,SHA,,,),
  CS_ENTRY(0xC036, TLS,ECDHE,PSK,WITH,AES,256,CBC,SHA),
  CS_ENTRY(0xC036, ECDHE,PSK,AES256,CBC,SHA,,,),
  CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,),
  CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,),
#endif
#if defined(USE_BEARSSL)
  CS_ENTRY(0x000A, TLS,RSA,WITH,3DES,EDE,CBC,SHA,),
  CS_ENTRY(0x000A, DES,CBC3,SHA,,,,,),
  CS_ENTRY(0xC003, TLS,ECDH,ECDSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC003, ECDH,ECDSA,DES,CBC3,SHA,,,),
  CS_ENTRY(0xC008, TLS,ECDHE,ECDSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC008, ECDHE,ECDSA,DES,CBC3,SHA,,,),
  CS_ENTRY(0xC00D, TLS,ECDH,RSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC00D, ECDH,RSA,DES,CBC3,SHA,,,),
  CS_ENTRY(0xC012, TLS,ECDHE,RSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC012, ECDHE,RSA,DES,CBC3,SHA,,,),
#endif

  CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,),
  CS_ENTRY(0xC09C, AES128,CCM,,,,,,),
  CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,),
  CS_ENTRY(0xC09D, AES256,CCM,,,,,,),
  CS_ENTRY(0xC0A0, TLS,RSA,WITH,AES,128,CCM,8,),
  CS_ENTRY(0xC0A0, AES128,CCM8,,,,,,),
  CS_ENTRY(0xC0A1, TLS,RSA,WITH,AES,256,CCM,8,),
  CS_ENTRY(0xC0A1, AES256,CCM8,,,,,,),
  CS_ENTRY(0xC0AC, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,),
  CS_ENTRY(0xC0AC, ECDHE,ECDSA,AES128,CCM,,,,),
  CS_ENTRY(0xC0AD, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,),
  CS_ENTRY(0xC0AD, ECDHE,ECDSA,AES256,CCM,,,,),
  CS_ENTRY(0xC0AE, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,8),
  CS_ENTRY(0xC0AE, ECDHE,ECDSA,AES128,CCM8,,,,),
  CS_ENTRY(0xC0AF, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,8),
  CS_ENTRY(0xC0AF, ECDHE,ECDSA,AES256,CCM8,,,,),








































































































































#if defined(USE_MBEDTLS)
  /* entries marked ns are "non-standard", they are not in openssl */
  CS_ENTRY(0x0041, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA,),
  CS_ENTRY(0x0041, CAMELLIA128,SHA,,,,,,),
  CS_ENTRY(0x0045, TLS,DHE,RSA,WITH,CAMELLIA,128,CBC,SHA),
  CS_ENTRY(0x0045, DHE,RSA,CAMELLIA128,SHA,,,,),
  CS_ENTRY(0x0084, TLS,RSA,WITH,CAMELLIA,256,CBC,SHA,),
  CS_ENTRY(0x0084, CAMELLIA256,SHA,,,,,,),
  CS_ENTRY(0x0088, TLS,DHE,RSA,WITH,CAMELLIA,256,CBC,SHA),







|











>
















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|







343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
  CS_ENTRY(0xC035, TLS,ECDHE,PSK,WITH,AES,128,CBC,SHA),
  CS_ENTRY(0xC035, ECDHE,PSK,AES128,CBC,SHA,,,),
  CS_ENTRY(0xC036, TLS,ECDHE,PSK,WITH,AES,256,CBC,SHA),
  CS_ENTRY(0xC036, ECDHE,PSK,AES256,CBC,SHA,,,),
  CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,),
  CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,),
#endif
#if defined(USE_SECTRANSP) || defined(USE_BEARSSL)
  CS_ENTRY(0x000A, TLS,RSA,WITH,3DES,EDE,CBC,SHA,),
  CS_ENTRY(0x000A, DES,CBC3,SHA,,,,,),
  CS_ENTRY(0xC003, TLS,ECDH,ECDSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC003, ECDH,ECDSA,DES,CBC3,SHA,,,),
  CS_ENTRY(0xC008, TLS,ECDHE,ECDSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC008, ECDHE,ECDSA,DES,CBC3,SHA,,,),
  CS_ENTRY(0xC00D, TLS,ECDH,RSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC00D, ECDH,RSA,DES,CBC3,SHA,,,),
  CS_ENTRY(0xC012, TLS,ECDHE,RSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC012, ECDHE,RSA,DES,CBC3,SHA,,,),
#endif
#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
  CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,),
  CS_ENTRY(0xC09C, AES128,CCM,,,,,,),
  CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,),
  CS_ENTRY(0xC09D, AES256,CCM,,,,,,),
  CS_ENTRY(0xC0A0, TLS,RSA,WITH,AES,128,CCM,8,),
  CS_ENTRY(0xC0A0, AES128,CCM8,,,,,,),
  CS_ENTRY(0xC0A1, TLS,RSA,WITH,AES,256,CCM,8,),
  CS_ENTRY(0xC0A1, AES256,CCM8,,,,,,),
  CS_ENTRY(0xC0AC, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,),
  CS_ENTRY(0xC0AC, ECDHE,ECDSA,AES128,CCM,,,,),
  CS_ENTRY(0xC0AD, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,),
  CS_ENTRY(0xC0AD, ECDHE,ECDSA,AES256,CCM,,,,),
  CS_ENTRY(0xC0AE, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,8),
  CS_ENTRY(0xC0AE, ECDHE,ECDSA,AES128,CCM8,,,,),
  CS_ENTRY(0xC0AF, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,8),
  CS_ENTRY(0xC0AF, ECDHE,ECDSA,AES256,CCM8,,,,),
#endif
#if defined(USE_SECTRANSP)
  /* entries marked bc are backward compatible aliases for old OpenSSL names */
  CS_ENTRY(0x0003, TLS,RSA,EXPORT,WITH,RC4,40,MD5,),
  CS_ENTRY(0x0003, EXP,RC4,MD5,,,,,),
  CS_ENTRY(0x0004, TLS,RSA,WITH,RC4,128,MD5,,),
  CS_ENTRY(0x0004, RC4,MD5,,,,,,),
  CS_ENTRY(0x0005, TLS,RSA,WITH,RC4,128,SHA,,),
  CS_ENTRY(0x0005, RC4,SHA,,,,,,),
  CS_ENTRY(0x0006, TLS,RSA,EXPORT,WITH,RC2,CBC,40,MD5),
  CS_ENTRY(0x0006, EXP,RC2,CBC,MD5,,,,),
  CS_ENTRY(0x0007, TLS,RSA,WITH,IDEA,CBC,SHA,,),
  CS_ENTRY(0x0007, IDEA,CBC,SHA,,,,,),
  CS_ENTRY(0x0008, TLS,RSA,EXPORT,WITH,DES40,CBC,SHA,),
  CS_ENTRY(0x0008, EXP,DES,CBC,SHA,,,,),
  CS_ENTRY(0x0009, TLS,RSA,WITH,DES,CBC,SHA,,),
  CS_ENTRY(0x0009, DES,CBC,SHA,,,,,),
  CS_ENTRY(0x000B, TLS,DH,DSS,EXPORT,WITH,DES40,CBC,SHA),
  CS_ENTRY(0x000B, EXP,DH,DSS,DES,CBC,SHA,,),
  CS_ENTRY(0x000C, TLS,DH,DSS,WITH,DES,CBC,SHA,),
  CS_ENTRY(0x000C, DH,DSS,DES,CBC,SHA,,,),
  CS_ENTRY(0x000D, TLS,DH,DSS,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0x000D, DH,DSS,DES,CBC3,SHA,,,),
  CS_ENTRY(0x000E, TLS,DH,RSA,EXPORT,WITH,DES40,CBC,SHA),
  CS_ENTRY(0x000E, EXP,DH,RSA,DES,CBC,SHA,,),
  CS_ENTRY(0x000F, TLS,DH,RSA,WITH,DES,CBC,SHA,),
  CS_ENTRY(0x000F, DH,RSA,DES,CBC,SHA,,,),
  CS_ENTRY(0x0010, TLS,DH,RSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0x0010, DH,RSA,DES,CBC3,SHA,,,),
  CS_ENTRY(0x0011, TLS,DHE,DSS,EXPORT,WITH,DES40,CBC,SHA),
  CS_ENTRY(0x0011, EXP,DHE,DSS,DES,CBC,SHA,,),
  CS_ENTRY(0x0011, EXP,EDH,DSS,DES,CBC,SHA,,), /* bc */
  CS_ENTRY(0x0012, TLS,DHE,DSS,WITH,DES,CBC,SHA,),
  CS_ENTRY(0x0012, DHE,DSS,DES,CBC,SHA,,,),
  CS_ENTRY(0x0012, EDH,DSS,DES,CBC,SHA,,,), /* bc */
  CS_ENTRY(0x0013, TLS,DHE,DSS,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0x0013, DHE,DSS,DES,CBC3,SHA,,,),
  CS_ENTRY(0x0013, EDH,DSS,DES,CBC3,SHA,,,), /* bc */
  CS_ENTRY(0x0014, TLS,DHE,RSA,EXPORT,WITH,DES40,CBC,SHA),
  CS_ENTRY(0x0014, EXP,DHE,RSA,DES,CBC,SHA,,),
  CS_ENTRY(0x0014, EXP,EDH,RSA,DES,CBC,SHA,,), /* bc */
  CS_ENTRY(0x0015, TLS,DHE,RSA,WITH,DES,CBC,SHA,),
  CS_ENTRY(0x0015, DHE,RSA,DES,CBC,SHA,,,),
  CS_ENTRY(0x0015, EDH,RSA,DES,CBC,SHA,,,), /* bc */
  CS_ENTRY(0x0016, TLS,DHE,RSA,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0x0016, DHE,RSA,DES,CBC3,SHA,,,),
  CS_ENTRY(0x0016, EDH,RSA,DES,CBC3,SHA,,,), /* bc */
  CS_ENTRY(0x0017, TLS,DH,anon,EXPORT,WITH,RC4,40,MD5),
  CS_ENTRY(0x0017, EXP,ADH,RC4,MD5,,,,),
  CS_ENTRY(0x0018, TLS,DH,anon,WITH,RC4,128,MD5,),
  CS_ENTRY(0x0018, ADH,RC4,MD5,,,,,),
  CS_ENTRY(0x0019, TLS,DH,anon,EXPORT,WITH,DES40,CBC,SHA),
  CS_ENTRY(0x0019, EXP,ADH,DES,CBC,SHA,,,),
  CS_ENTRY(0x001A, TLS,DH,anon,WITH,DES,CBC,SHA,),
  CS_ENTRY(0x001A, ADH,DES,CBC,SHA,,,,),
  CS_ENTRY(0x001B, TLS,DH,anon,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0x001B, ADH,DES,CBC3,SHA,,,,),
  CS_ENTRY(0x0030, TLS,DH,DSS,WITH,AES,128,CBC,SHA),
  CS_ENTRY(0x0030, DH,DSS,AES128,SHA,,,,),
  CS_ENTRY(0x0031, TLS,DH,RSA,WITH,AES,128,CBC,SHA),
  CS_ENTRY(0x0031, DH,RSA,AES128,SHA,,,,),
  CS_ENTRY(0x0032, TLS,DHE,DSS,WITH,AES,128,CBC,SHA),
  CS_ENTRY(0x0032, DHE,DSS,AES128,SHA,,,,),
  CS_ENTRY(0x0034, TLS,DH,anon,WITH,AES,128,CBC,SHA),
  CS_ENTRY(0x0034, ADH,AES128,SHA,,,,,),
  CS_ENTRY(0x0036, TLS,DH,DSS,WITH,AES,256,CBC,SHA),
  CS_ENTRY(0x0036, DH,DSS,AES256,SHA,,,,),
  CS_ENTRY(0x0037, TLS,DH,RSA,WITH,AES,256,CBC,SHA),
  CS_ENTRY(0x0037, DH,RSA,AES256,SHA,,,,),
  CS_ENTRY(0x0038, TLS,DHE,DSS,WITH,AES,256,CBC,SHA),
  CS_ENTRY(0x0038, DHE,DSS,AES256,SHA,,,,),
  CS_ENTRY(0x003A, TLS,DH,anon,WITH,AES,256,CBC,SHA),
  CS_ENTRY(0x003A, ADH,AES256,SHA,,,,,),
  CS_ENTRY(0x003E, TLS,DH,DSS,WITH,AES,128,CBC,SHA256),
  CS_ENTRY(0x003E, DH,DSS,AES128,SHA256,,,,),
  CS_ENTRY(0x003F, TLS,DH,RSA,WITH,AES,128,CBC,SHA256),
  CS_ENTRY(0x003F, DH,RSA,AES128,SHA256,,,,),
  CS_ENTRY(0x0040, TLS,DHE,DSS,WITH,AES,128,CBC,SHA256),
  CS_ENTRY(0x0040, DHE,DSS,AES128,SHA256,,,,),
  CS_ENTRY(0x0068, TLS,DH,DSS,WITH,AES,256,CBC,SHA256),
  CS_ENTRY(0x0068, DH,DSS,AES256,SHA256,,,,),
  CS_ENTRY(0x0069, TLS,DH,RSA,WITH,AES,256,CBC,SHA256),
  CS_ENTRY(0x0069, DH,RSA,AES256,SHA256,,,,),
  CS_ENTRY(0x006A, TLS,DHE,DSS,WITH,AES,256,CBC,SHA256),
  CS_ENTRY(0x006A, DHE,DSS,AES256,SHA256,,,,),
  CS_ENTRY(0x006C, TLS,DH,anon,WITH,AES,128,CBC,SHA256),
  CS_ENTRY(0x006C, ADH,AES128,SHA256,,,,,),
  CS_ENTRY(0x006D, TLS,DH,anon,WITH,AES,256,CBC,SHA256),
  CS_ENTRY(0x006D, ADH,AES256,SHA256,,,,,),
  CS_ENTRY(0x008A, TLS,PSK,WITH,RC4,128,SHA,,),
  CS_ENTRY(0x008A, PSK,RC4,SHA,,,,,),
  CS_ENTRY(0x008B, TLS,PSK,WITH,3DES,EDE,CBC,SHA,),
  CS_ENTRY(0x008B, PSK,3DES,EDE,CBC,SHA,,,),
  CS_ENTRY(0x008E, TLS,DHE,PSK,WITH,RC4,128,SHA,),
  CS_ENTRY(0x008E, DHE,PSK,RC4,SHA,,,,),
  CS_ENTRY(0x008F, TLS,DHE,PSK,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0x008F, DHE,PSK,3DES,EDE,CBC,SHA,,),
  CS_ENTRY(0x0092, TLS,RSA,PSK,WITH,RC4,128,SHA,),
  CS_ENTRY(0x0092, RSA,PSK,RC4,SHA,,,,),
  CS_ENTRY(0x0093, TLS,RSA,PSK,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0x0093, RSA,PSK,3DES,EDE,CBC,SHA,,),
  CS_ENTRY(0x00A0, TLS,DH,RSA,WITH,AES,128,GCM,SHA256),
  CS_ENTRY(0x00A0, DH,RSA,AES128,GCM,SHA256,,,),
  CS_ENTRY(0x00A1, TLS,DH,RSA,WITH,AES,256,GCM,SHA384),
  CS_ENTRY(0x00A1, DH,RSA,AES256,GCM,SHA384,,,),
  CS_ENTRY(0x00A2, TLS,DHE,DSS,WITH,AES,128,GCM,SHA256),
  CS_ENTRY(0x00A2, DHE,DSS,AES128,GCM,SHA256,,,),
  CS_ENTRY(0x00A3, TLS,DHE,DSS,WITH,AES,256,GCM,SHA384),
  CS_ENTRY(0x00A3, DHE,DSS,AES256,GCM,SHA384,,,),
  CS_ENTRY(0x00A4, TLS,DH,DSS,WITH,AES,128,GCM,SHA256),
  CS_ENTRY(0x00A4, DH,DSS,AES128,GCM,SHA256,,,),
  CS_ENTRY(0x00A5, TLS,DH,DSS,WITH,AES,256,GCM,SHA384),
  CS_ENTRY(0x00A5, DH,DSS,AES256,GCM,SHA384,,,),
  CS_ENTRY(0x00A6, TLS,DH,anon,WITH,AES,128,GCM,SHA256),
  CS_ENTRY(0x00A6, ADH,AES128,GCM,SHA256,,,,),
  CS_ENTRY(0x00A7, TLS,DH,anon,WITH,AES,256,GCM,SHA384),
  CS_ENTRY(0x00A7, ADH,AES256,GCM,SHA384,,,,),
  CS_ENTRY(0xC002, TLS,ECDH,ECDSA,WITH,RC4,128,SHA,),
  CS_ENTRY(0xC002, ECDH,ECDSA,RC4,SHA,,,,),
  CS_ENTRY(0xC007, TLS,ECDHE,ECDSA,WITH,RC4,128,SHA,),
  CS_ENTRY(0xC007, ECDHE,ECDSA,RC4,SHA,,,,),
  CS_ENTRY(0xC00C, TLS,ECDH,RSA,WITH,RC4,128,SHA,),
  CS_ENTRY(0xC00C, ECDH,RSA,RC4,SHA,,,,),
  CS_ENTRY(0xC011, TLS,ECDHE,RSA,WITH,RC4,128,SHA,),
  CS_ENTRY(0xC011, ECDHE,RSA,RC4,SHA,,,,),
  CS_ENTRY(0xC015, TLS,ECDH,anon,WITH,NULL,SHA,,),
  CS_ENTRY(0xC015, AECDH,NULL,SHA,,,,,),
  CS_ENTRY(0xC016, TLS,ECDH,anon,WITH,RC4,128,SHA,),
  CS_ENTRY(0xC016, AECDH,RC4,SHA,,,,,),
  CS_ENTRY(0xC017, TLS,ECDH,anon,WITH,3DES,EDE,CBC,SHA),
  CS_ENTRY(0xC017, AECDH,DES,CBC3,SHA,,,,),
  CS_ENTRY(0xC018, TLS,ECDH,anon,WITH,AES,128,CBC,SHA),
  CS_ENTRY(0xC018, AECDH,AES128,SHA,,,,,),
  CS_ENTRY(0xC019, TLS,ECDH,anon,WITH,AES,256,CBC,SHA),
  CS_ENTRY(0xC019, AECDH,AES256,SHA,,,,,),
#endif
#if defined(USE_MBEDTLS)
  /* entries marked ns are "non-standard", they are not in OpenSSL */
  CS_ENTRY(0x0041, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA,),
  CS_ENTRY(0x0041, CAMELLIA128,SHA,,,,,,),
  CS_ENTRY(0x0045, TLS,DHE,RSA,WITH,CAMELLIA,128,CBC,SHA),
  CS_ENTRY(0x0045, DHE,RSA,CAMELLIA128,SHA,,,,),
  CS_ENTRY(0x0084, TLS,RSA,WITH,CAMELLIA,256,CBC,SHA,),
  CS_ENTRY(0x0084, CAMELLIA256,SHA,,,,,,),
  CS_ENTRY(0x0088, TLS,DHE,RSA,WITH,CAMELLIA,256,CBC,SHA),
709
710
711
712
713
714
715

716

  if(r < 0)
    msnprintf(buf, buf_size, "TLS_UNKNOWN_0x%04x", id);

  return r;
}


#endif /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */







>
|
876
877
878
879
880
881
882
883
884

  if(r < 0)
    msnprintf(buf, buf_size, "TLS_UNKNOWN_0x%04x", id);

  return r;
}

#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
          defined(USE_BEARSSL) */
Changes to jni/curl/lib/vtls/cipher_suite.h.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

45
46
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
#include <stdint.h>

/* Lookup IANA id for cipher suite string, returns 0 if not recognized */
uint16_t Curl_cipher_suite_lookup_id(const char *cs_str, size_t cs_len);

/* Walk over cipher suite string, update str and end pointers to next
   cipher suite in string, returns IANA id of that suite if recognized */
uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end);

/* Copy openssl or RFC name for cipher suite in supplied buffer.
   Caller is responsible to supply sufficiently large buffer (size
   of 64 should suffice), excess bytes are silently truncated. */
int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
                              bool prefer_rfc);


#endif /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */
#endif /* HEADER_CURL_CIPHER_SUITE_H */







|















>
|

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_BEARSSL)
#include <stdint.h>

/* Lookup IANA id for cipher suite string, returns 0 if not recognized */
uint16_t Curl_cipher_suite_lookup_id(const char *cs_str, size_t cs_len);

/* Walk over cipher suite string, update str and end pointers to next
   cipher suite in string, returns IANA id of that suite if recognized */
uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end);

/* Copy openssl or RFC name for cipher suite in supplied buffer.
   Caller is responsible to supply sufficiently large buffer (size
   of 64 should suffice), excess bytes are silently truncated. */
int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
                              bool prefer_rfc);

#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
          defined(USE_BEARSSL) */
#endif /* HEADER_CURL_CIPHER_SUITE_H */
Changes to jni/curl/lib/vtls/gtls.c.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 ***************************************************************************/

/*
 * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
 * but vtls.c should ever call or use these functions.
 *
 * Note: don't use the GnuTLS' *_t variable type names in this source code,
 * since they were not present in 1.0.X.
 */

#include "curl_setup.h"

#ifdef USE_GNUTLS








|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 ***************************************************************************/

/*
 * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
 * but vtls.c should ever call or use these functions.
 *
 * Note: do not use the GnuTLS' *_t variable type names in this source code,
 * since they were not present in 1.0.X.
 */

#include "curl_setup.h"

#ifdef USE_GNUTLS

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  struct gtls_ssl_backend_data *backend =
    (struct gtls_ssl_backend_data *)connssl->backend;
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
  ssize_t nread;
  CURLcode result;

  DEBUGASSERT(data);
  if(!backend->gtls.trust_setup) {
    result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
    if(result) {
      gnutls_transport_set_errno(backend->gtls.session, EINVAL);
      backend->gtls.io_result = result;
      return -1;
    }
  }







|







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  struct gtls_ssl_backend_data *backend =
    (struct gtls_ssl_backend_data *)connssl->backend;
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
  ssize_t nread;
  CURLcode result;

  DEBUGASSERT(data);
  if(!backend->gtls.shared_creds->trust_setup) {
    result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
    if(result) {
      gnutls_transport_set_errno(backend->gtls.session, EINVAL);
      backend->gtls.io_result = result;
      return -1;
    }
  }
247
248
249
250
251
252
253

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  struct gtls_ssl_backend_data *backend =
    (struct gtls_ssl_backend_data *)connssl->backend;
  gnutls_session_t session;
  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);

  DEBUGASSERT(backend);
  session = backend->gtls.session;


  for(;;) {
    timediff_t timeout_ms;
    int rc;

    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, duringconnect);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it's available. */
    if(connssl->connecting_state == ssl_connect_2_reading
       || connssl->connecting_state == ssl_connect_2_writing) {
      int what;
      curl_socket_t writefd = ssl_connect_2_writing ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking?0:
                               timeout_ms?timeout_ms:1000);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);







>














|
|
<

|
|
|
|







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270

271
272
273
274
275
276
277
278
279
280
281
282
  struct gtls_ssl_backend_data *backend =
    (struct gtls_ssl_backend_data *)connssl->backend;
  gnutls_session_t session;
  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);

  DEBUGASSERT(backend);
  session = backend->gtls.session;
  connssl->connecting_state = ssl_connect_2;

  for(;;) {
    timediff_t timeout_ms;
    int rc;

    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, duringconnect);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it is available. */
    if(connssl->io_need) {

      int what;
      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
                              sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
                             sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking?0:
                               timeout_ms?timeout_ms:1000);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
290
291
292
293
294
295
296

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
          failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
          return CURLE_OPERATION_TIMEDOUT;
        }
      }
      /* socket is readable or writable */
    }


    backend->gtls.io_result = CURLE_OK;
    rc = gnutls_handshake(session);

    if(!backend->gtls.trust_setup) {
      /* After having send off the ClientHello, we prepare the trust
       * store to verify the coming certificate from the server */
      CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
      if(result)
        return result;
    }

    if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
      connssl->connecting_state =
        gnutls_record_get_direction(session)?
        ssl_connect_2_writing:ssl_connect_2_reading;
      continue;
    }
    else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
      const char *strerr = NULL;

      if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
        int alert = gnutls_alert_get(session);
        strerr = gnutls_alert_get_name(alert);
      }

      if(!strerr)
        strerr = gnutls_strerror(rc);

      infof(data, "gnutls_handshake() warning: %s", strerr);
      continue;
    }
    else if((rc < 0) && backend->gtls.io_result) {
      return backend->gtls.io_result;
    }
    else if(rc < 0) {
      const char *strerr = NULL;

      if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
        int alert = gnutls_alert_get(session);
        strerr = gnutls_alert_get_name(alert);
      }

      if(!strerr)
        strerr = gnutls_strerror(rc);

      failf(data, "gnutls_handshake() failed: %s", strerr);







>



|








|

|






|
















|







290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
          failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
          return CURLE_OPERATION_TIMEDOUT;
        }
      }
      /* socket is readable or writable */
    }

    connssl->io_need = CURL_SSL_IO_NEED_NONE;
    backend->gtls.io_result = CURLE_OK;
    rc = gnutls_handshake(session);

    if(!backend->gtls.shared_creds->trust_setup) {
      /* After having send off the ClientHello, we prepare the trust
       * store to verify the coming certificate from the server */
      CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
      if(result)
        return result;
    }

    if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
      connssl->io_need =
        gnutls_record_get_direction(session)?
        CURL_SSL_IO_NEED_SEND:CURL_SSL_IO_NEED_RECV;
      continue;
    }
    else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
      const char *strerr = NULL;

      if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
        gnutls_alert_description_t alert = gnutls_alert_get(session);
        strerr = gnutls_alert_get_name(alert);
      }

      if(!strerr)
        strerr = gnutls_strerror(rc);

      infof(data, "gnutls_handshake() warning: %s", strerr);
      continue;
    }
    else if((rc < 0) && backend->gtls.io_result) {
      return backend->gtls.io_result;
    }
    else if(rc < 0) {
      const char *strerr = NULL;

      if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
        gnutls_alert_description_t alert = gnutls_alert_get(session);
        strerr = gnutls_alert_get_name(alert);
      }

      if(!strerr)
        strerr = gnutls_strerror(rc);

      failf(data, "gnutls_handshake() failed: %s", strerr);
372
373
374
375
376
377
378






379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
                        struct ssl_primary_config *conn_config,
                        const char **prioritylist,
                        const char *tls13support)
{
  long ssl_version = conn_config->version;
  long ssl_version_max = conn_config->version_max;







  if(peer->transport == TRNSPRT_QUIC) {
    if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
       (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
      failf(data, "QUIC needs at least TLS version 1.3");
      return CURLE_SSL_CONNECT_ERROR;
     }
    *prioritylist = QUIC_PRIORITY;
    return CURLE_OK;
  }

  if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
     (ssl_version == CURL_SSLVERSION_TLSv1))
    ssl_version = CURL_SSLVERSION_TLSv1_0;
  if(ssl_version_max == CURL_SSLVERSION_MAX_NONE)
    ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
  if(!tls13support) {
    /* If the running GnuTLS doesn't support TLS 1.3, we must not specify a
       prioritylist involving that since it will make GnuTLS return an en
       error back at us */
    if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) ||
       (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) {
      ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
    }
  }







>
>
>
>
>
>

|
|







<
<
<
<
<

|







373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395





396
397
398
399
400
401
402
403
404
                        struct ssl_primary_config *conn_config,
                        const char **prioritylist,
                        const char *tls13support)
{
  long ssl_version = conn_config->version;
  long ssl_version_max = conn_config->version_max;

  if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
     (ssl_version == CURL_SSLVERSION_TLSv1))
    ssl_version = CURL_SSLVERSION_TLSv1_0;
  if(ssl_version_max == CURL_SSLVERSION_MAX_NONE)
    ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;

  if(peer->transport == TRNSPRT_QUIC) {
    if((ssl_version_max != CURL_SSLVERSION_MAX_DEFAULT) &&
       (ssl_version_max < CURL_SSLVERSION_MAX_TLSv1_3)) {
      failf(data, "QUIC needs at least TLS version 1.3");
      return CURLE_SSL_CONNECT_ERROR;
     }
    *prioritylist = QUIC_PRIORITY;
    return CURLE_OK;
  }






  if(!tls13support) {
    /* If the running GnuTLS does not support TLS 1.3, we must not specify a
       prioritylist involving that since it will make GnuTLS return an en
       error back at us */
    if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) ||
       (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) {
      ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
    }
  }
446
447
448
449
450
451
452
















































453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530



































































































































531



532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
    return CURLE_OK;
  }

  failf(data, "GnuTLS: cannot set ssl protocol");
  return CURLE_SSL_CONNECT_ERROR;
}

















































CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
                                      struct Curl_easy *data,
                                      struct gtls_ctx *gtls)
{
  struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  int rc;

  CURL_TRC_CF(data, cf, "setup trust anchors and CRLs");
  if(config->verifypeer) {
    bool imported_native_ca = false;

    if(ssl_config->native_ca_store) {
      rc = gnutls_certificate_set_x509_system_trust(gtls->cred);
      if(rc < 0)
        infof(data, "error reading native ca store (%s), continuing anyway",
              gnutls_strerror(rc));
      else {
        infof(data, "found %d certificates in native ca store", rc);
        if(rc > 0)
          imported_native_ca = true;
      }
    }

    if(config->CAfile) {
      /* set the trusted CA cert bundle file */
      gnutls_certificate_set_verify_flags(gtls->cred,
                                          GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);

      rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
                                                  config->CAfile,
                                                  GNUTLS_X509_FMT_PEM);
      if(rc < 0) {
        infof(data, "error reading ca cert file %s (%s)%s",
              config->CAfile, gnutls_strerror(rc),
              (imported_native_ca ? ", continuing anyway" : ""));
        if(!imported_native_ca) {
          ssl_config->certverifyresult = rc;
          return CURLE_SSL_CACERT_BADFILE;
        }
      }
      else
        infof(data, "found %d certificates in %s", rc, config->CAfile);
    }

    if(config->CApath) {
      /* set the trusted CA cert directory */
      rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
                                                 config->CApath,
                                                 GNUTLS_X509_FMT_PEM);
      if(rc < 0) {
        infof(data, "error reading ca cert file %s (%s)%s",
              config->CApath, gnutls_strerror(rc),
              (imported_native_ca ? ", continuing anyway" : ""));
        if(!imported_native_ca) {
          ssl_config->certverifyresult = rc;
          return CURLE_SSL_CACERT_BADFILE;
        }
      }
      else
        infof(data, "found %d certificates in %s", rc, config->CApath);
    }
  }

  if(config->CRLfile) {
    /* set the CRL list file */
    rc = gnutls_certificate_set_x509_crl_file(gtls->cred,
                                              config->CRLfile,
                                              GNUTLS_X509_FMT_PEM);
    if(rc < 0) {
      failf(data, "error reading crl file %s (%s)",
            config->CRLfile, gnutls_strerror(rc));
      return CURLE_SSL_CRL_BADFILE;
    }
    else
      infof(data, "found %d CRL in %s", rc, config->CRLfile);
  }




































































































































  gtls->trust_setup = TRUE;



  return CURLE_OK;
}

static void gtls_sessionid_free(void *sessionid, size_t idsize)
{
  (void)idsize;
  free(sessionid);
}

static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
                                       gnutls_session_t session)
{
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  struct ssl_connect_data *connssl = cf->ctx;
  CURLcode result = CURLE_OK;

  if(ssl_config->primary.sessionid) {
    /* we always unconditionally get the session id here, as even if we
       already got it from the cache and asked to use it in the connection, it
       might've been rejected and then a new one is in use now and we need to
       detect that. */
    void *connect_sessionid;
    size_t connect_idsize = 0;

    /* get the session ID data size */
    gnutls_session_get_data(session, NULL, &connect_idsize);
    connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
    if(!connect_sessionid) {
      return CURLE_OUT_OF_MEMORY;
    }
    else {
      bool incache;
      void *ssl_sessionid;

      /* extract session ID to the allocated buffer */
      gnutls_session_get_data(session, connect_sessionid, &connect_idsize);

      DEBUGF(infof(data, "get session id (len=%zu) and store in cache",
                   connect_idsize));
      Curl_ssl_sessionid_lock(data);
      incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
                                        &ssl_sessionid, NULL));
      if(incache) {
        /* there was one before in the cache, so instead of risking that the
           previous one was rejected, we just kill that and store the new */
        Curl_ssl_delsessionid(data, ssl_sessionid);
      }

      /* store this session id, takes ownership */
      result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
                                     connect_sessionid, connect_idsize,
                                     gtls_sessionid_free);
      Curl_ssl_sessionid_unlock(data);
    }
  }
  return result;
}

static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
                             unsigned when, unsigned int incoming,
                             const gnutls_datum_t *msg)
{
  struct Curl_cfilter *cf = gnutls_session_get_ptr(session);

  (void)msg;
  (void)incoming;
  if(when) { /* after message has been processed */
    struct Curl_easy *data = CF_DATA_CURRENT(cf);
    if(data) {
      DEBUGF(infof(data, "handshake: %s message type %d",
             incoming? "incoming" : "outgoing", htype));
      switch(htype) {
      case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
        gtls_update_session_id(cf, data, session);
        break;
      }
      default:
        break;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|





<




|












|


|

















|
<

















|
<










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>

















|














<
<
<



|
|

<
<
<
<
<
<
<
<

|
|
|

















|
|







448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510

511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549

550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567

568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744



745
746
747
748
749
750








751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
    return CURLE_OK;
  }

  failf(data, "GnuTLS: cannot set ssl protocol");
  return CURLE_SSL_CONNECT_ERROR;
}

CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data,
                                       struct gtls_shared_creds **pcreds)
{
  struct gtls_shared_creds *shared;
  int rc;

  *pcreds = NULL;
  shared = calloc(1, sizeof(*shared));
  if(!shared)
    return CURLE_OUT_OF_MEMORY;

  rc = gnutls_certificate_allocate_credentials(&shared->creds);
  if(rc != GNUTLS_E_SUCCESS) {
    failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
    free(shared);
    return CURLE_SSL_CONNECT_ERROR;
  }

  shared->refcount = 1;
  shared->time = Curl_now();
  *pcreds = shared;
  return CURLE_OK;
}

CURLcode Curl_gtls_shared_creds_up_ref(struct gtls_shared_creds *creds)
{
  DEBUGASSERT(creds);
  if(creds->refcount < SIZE_T_MAX) {
    ++creds->refcount;
    return CURLE_OK;
  }
  return CURLE_BAD_FUNCTION_ARGUMENT;
}

void Curl_gtls_shared_creds_free(struct gtls_shared_creds **pcreds)
{
  struct gtls_shared_creds *shared = *pcreds;
  *pcreds = NULL;
  if(shared) {
    --shared->refcount;
    if(!shared->refcount) {
      gnutls_certificate_free_credentials(shared->creds);
      free(shared->CAfile);
      free(shared);
    }
  }
}

static CURLcode gtls_populate_creds(struct Curl_cfilter *cf,
                                    struct Curl_easy *data,
                                    gnutls_certificate_credentials_t creds)
{
  struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  int rc;


  if(config->verifypeer) {
    bool imported_native_ca = false;

    if(ssl_config->native_ca_store) {
      rc = gnutls_certificate_set_x509_system_trust(creds);
      if(rc < 0)
        infof(data, "error reading native ca store (%s), continuing anyway",
              gnutls_strerror(rc));
      else {
        infof(data, "found %d certificates in native ca store", rc);
        if(rc > 0)
          imported_native_ca = true;
      }
    }

    if(config->CAfile) {
      /* set the trusted CA cert bundle file */
      gnutls_certificate_set_verify_flags(creds,
                                          GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);

      rc = gnutls_certificate_set_x509_trust_file(creds,
                                                  config->CAfile,
                                                  GNUTLS_X509_FMT_PEM);
      if(rc < 0) {
        infof(data, "error reading ca cert file %s (%s)%s",
              config->CAfile, gnutls_strerror(rc),
              (imported_native_ca ? ", continuing anyway" : ""));
        if(!imported_native_ca) {
          ssl_config->certverifyresult = rc;
          return CURLE_SSL_CACERT_BADFILE;
        }
      }
      else
        infof(data, "found %d certificates in %s", rc, config->CAfile);
    }

    if(config->CApath) {
      /* set the trusted CA cert directory */
      rc = gnutls_certificate_set_x509_trust_dir(creds, config->CApath,

                                                 GNUTLS_X509_FMT_PEM);
      if(rc < 0) {
        infof(data, "error reading ca cert file %s (%s)%s",
              config->CApath, gnutls_strerror(rc),
              (imported_native_ca ? ", continuing anyway" : ""));
        if(!imported_native_ca) {
          ssl_config->certverifyresult = rc;
          return CURLE_SSL_CACERT_BADFILE;
        }
      }
      else
        infof(data, "found %d certificates in %s", rc, config->CApath);
    }
  }

  if(config->CRLfile) {
    /* set the CRL list file */
    rc = gnutls_certificate_set_x509_crl_file(creds, config->CRLfile,

                                              GNUTLS_X509_FMT_PEM);
    if(rc < 0) {
      failf(data, "error reading crl file %s (%s)",
            config->CRLfile, gnutls_strerror(rc));
      return CURLE_SSL_CRL_BADFILE;
    }
    else
      infof(data, "found %d CRL in %s", rc, config->CRLfile);
  }

  return CURLE_OK;
}

/* key to use at `multi->proto_hash` */
#define MPROTO_GTLS_X509_KEY   "tls:gtls:x509:share"

static bool gtls_shared_creds_expired(const struct Curl_easy *data,
                                      const struct gtls_shared_creds *sc)
{
  const struct ssl_general_config *cfg = &data->set.general_ssl;
  struct curltime now = Curl_now();
  timediff_t elapsed_ms = Curl_timediff(now, sc->time);
  timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;

  if(timeout_ms < 0)
    return false;

  return elapsed_ms >= timeout_ms;
}

static bool gtls_shared_creds_different(struct Curl_cfilter *cf,
                                        const struct gtls_shared_creds *sc)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  if(!sc->CAfile || !conn_config->CAfile)
    return sc->CAfile != conn_config->CAfile;

  return strcmp(sc->CAfile, conn_config->CAfile);
}

static struct gtls_shared_creds*
gtls_get_cached_creds(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct gtls_shared_creds *shared_creds;

  if(data->multi) {
    shared_creds = Curl_hash_pick(&data->multi->proto_hash,
                                  (void *)MPROTO_GTLS_X509_KEY,
                                  sizeof(MPROTO_GTLS_X509_KEY)-1);
     if(shared_creds && shared_creds->creds &&
        !gtls_shared_creds_expired(data, shared_creds) &&
        !gtls_shared_creds_different(cf, shared_creds)) {
       return shared_creds;
     }
  }
  return NULL;
}

static void gtls_shared_creds_hash_free(void *key, size_t key_len, void *p)
{
  struct gtls_shared_creds *sc = p;
  DEBUGASSERT(key_len == (sizeof(MPROTO_GTLS_X509_KEY)-1));
  DEBUGASSERT(!memcmp(MPROTO_GTLS_X509_KEY, key, key_len));
  (void)key;
  (void)key_len;
  Curl_gtls_shared_creds_free(&sc); /* down reference */
}

static void gtls_set_cached_creds(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  struct gtls_shared_creds *sc)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);

  DEBUGASSERT(sc);
  DEBUGASSERT(sc->creds);
  DEBUGASSERT(!sc->CAfile);
  DEBUGASSERT(sc->refcount == 1);
  if(!data->multi)
    return;

  if(conn_config->CAfile) {
    sc->CAfile = strdup(conn_config->CAfile);
    if(!sc->CAfile)
      return;
  }

  if(Curl_gtls_shared_creds_up_ref(sc))
    return;

  if(!Curl_hash_add2(&data->multi->proto_hash,
                    (void *)MPROTO_GTLS_X509_KEY,
                    sizeof(MPROTO_GTLS_X509_KEY)-1,
                    sc, gtls_shared_creds_hash_free)) {
    Curl_gtls_shared_creds_free(&sc); /* down reference again */
    return;
  }
}

CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
                                      struct Curl_easy *data,
                                      struct gtls_ctx *gtls)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  struct gtls_shared_creds *cached_creds = NULL;
  bool cache_criteria_met;
  CURLcode result;
  int rc;


  /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
     or no source is provided and we are falling back to OpenSSL's built-in
     default. */
  cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
    conn_config->verifypeer &&
    !conn_config->CApath &&
    !conn_config->ca_info_blob &&
    !ssl_config->primary.CRLfile &&
    !ssl_config->native_ca_store &&
    !conn_config->clientcert; /* GnuTLS adds client cert to its credentials! */

  if(cache_criteria_met)
    cached_creds = gtls_get_cached_creds(cf, data);

  if(cached_creds && !Curl_gtls_shared_creds_up_ref(cached_creds)) {
    CURL_TRC_CF(data, cf, "using shared trust anchors and CRLs");
    Curl_gtls_shared_creds_free(&gtls->shared_creds);
    gtls->shared_creds = cached_creds;
    rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
                                gtls->shared_creds->creds);
    if(rc != GNUTLS_E_SUCCESS) {
      failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
  else {
    CURL_TRC_CF(data, cf, "loading trust anchors and CRLs");
    result = gtls_populate_creds(cf, data, gtls->shared_creds->creds);
    if(result)
      return result;
    gtls->shared_creds->trust_setup = TRUE;
    if(cache_criteria_met)
      gtls_set_cached_creds(cf, data, gtls->shared_creds);
  }
  return CURLE_OK;
}

static void gtls_sessionid_free(void *sessionid, size_t idsize)
{
  (void)idsize;
  free(sessionid);
}

static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
                                       gnutls_session_t session)
{
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  struct ssl_connect_data *connssl = cf->ctx;
  CURLcode result = CURLE_OK;

  if(ssl_config->primary.cache_session) {
    /* we always unconditionally get the session id here, as even if we
       already got it from the cache and asked to use it in the connection, it
       might've been rejected and then a new one is in use now and we need to
       detect that. */
    void *connect_sessionid;
    size_t connect_idsize = 0;

    /* get the session ID data size */
    gnutls_session_get_data(session, NULL, &connect_idsize);
    connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
    if(!connect_sessionid) {
      return CURLE_OUT_OF_MEMORY;
    }
    else {



      /* extract session ID to the allocated buffer */
      gnutls_session_get_data(session, connect_sessionid, &connect_idsize);

      CURL_TRC_CF(data, cf, "get session id (len=%zu) and store in cache",
                  connect_idsize);
      Curl_ssl_sessionid_lock(data);








      /* store this session id, takes ownership */
      result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
                                      connect_sessionid, connect_idsize,
                                      gtls_sessionid_free);
      Curl_ssl_sessionid_unlock(data);
    }
  }
  return result;
}

static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
                             unsigned when, unsigned int incoming,
                             const gnutls_datum_t *msg)
{
  struct Curl_cfilter *cf = gnutls_session_get_ptr(session);

  (void)msg;
  (void)incoming;
  if(when) { /* after message has been processed */
    struct Curl_easy *data = CF_DATA_CURRENT(cf);
    if(data) {
      CURL_TRC_CF(data, cf, "handshake: %s message type %d",
                  incoming? "incoming" : "outgoing", htype);
      switch(htype) {
      case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
        gtls_update_session_id(cf, data, session);
        break;
      }
      default:
        break;
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
  if(config->version == CURL_SSLVERSION_SSLv2) {
    failf(data, "GnuTLS does not support SSLv2");
    return CURLE_SSL_CONNECT_ERROR;
  }
  else if(config->version == CURL_SSLVERSION_SSLv3)
    sni = FALSE; /* SSLv3 has no SNI */

  /* allocate a cred struct */
  rc = gnutls_certificate_allocate_credentials(&gtls->cred);
  if(rc != GNUTLS_E_SUCCESS) {
    failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
    return CURLE_SSL_CONNECT_ERROR;
  }

#ifdef USE_GNUTLS_SRP
  if(config->username && Curl_auth_allowed_to_host(data)) {
    infof(data, "Using TLS-SRP username: %s", config->username);

    rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
    if(rc != GNUTLS_E_SUCCESS) {







|
|
|
<
|
<







805
806
807
808
809
810
811
812
813
814

815

816
817
818
819
820
821
822
  if(config->version == CURL_SSLVERSION_SSLv2) {
    failf(data, "GnuTLS does not support SSLv2");
    return CURLE_SSL_CONNECT_ERROR;
  }
  else if(config->version == CURL_SSLVERSION_SSLv3)
    sni = FALSE; /* SSLv3 has no SNI */

  /* allocate a shared creds struct */
  result = Curl_gtls_shared_creds_create(data, &gtls->shared_creds);
  if(result)

    return result;


#ifdef USE_GNUTLS_SRP
  if(config->username && Curl_auth_allowed_to_host(data)) {
    infof(data, "Using TLS-SRP username: %s", config->username);

    rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
    if(rc != GNUTLS_E_SUCCESS) {
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
  if(rc != GNUTLS_E_SUCCESS)
    return CURLE_SSL_CONNECT_ERROR;

  /* "In GnuTLS 3.6.5, TLS 1.3 is enabled by default" */
  tls13support = gnutls_check_version("3.6.5");

  /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
   * removed if a run-time error indicates that SRP is not supported by this
   * GnuTLS version */

  if(config->version == CURL_SSLVERSION_SSLv2 ||
     config->version == CURL_SSLVERSION_SSLv3) {
    failf(data, "GnuTLS does not support SSLv2 or SSLv3");
    return CURLE_SSL_CONNECT_ERROR;
  }







|







869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
  if(rc != GNUTLS_E_SUCCESS)
    return CURLE_SSL_CONNECT_ERROR;

  /* "In GnuTLS 3.6.5, TLS 1.3 is enabled by default" */
  tls13support = gnutls_check_version("3.6.5");

  /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
   * removed if a runtime error indicates that SRP is not supported by this
   * GnuTLS version */

  if(config->version == CURL_SSLVERSION_SSLv2 ||
     config->version == CURL_SSLVERSION_SSLv3) {
    failf(data, "GnuTLS does not support SSLv2 or SSLv3");
    return CURLE_SSL_CONNECT_ERROR;
  }
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  if(rc != GNUTLS_E_SUCCESS) {
    failf(data, "Error %d setting GnuTLS cipher list starting with %s",
          rc, err);
    return CURLE_SSL_CONNECT_ERROR;
  }

  if(config->clientcert) {
    if(!gtls->trust_setup) {
      result = Curl_gtls_client_trust_setup(cf, data, gtls);
      if(result)
        return result;
    }
    if(ssl_config->key_passwd) {
      const unsigned int supported_key_encryption_algorithms =
        GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
        GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
        GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
        GNUTLS_PKCS_USE_PBES2_AES_256;
      rc = gnutls_certificate_set_x509_key_file2(
           gtls->cred,
           config->clientcert,
           ssl_config->key ? ssl_config->key : config->clientcert,
           do_file_type(ssl_config->cert_type),
           ssl_config->key_passwd,
           supported_key_encryption_algorithms);
      if(rc != GNUTLS_E_SUCCESS) {
        failf(data,
              "error reading X.509 potentially-encrypted key file: %s",
              gnutls_strerror(rc));
        return CURLE_SSL_CONNECT_ERROR;
      }
    }
    else {
      if(gnutls_certificate_set_x509_key_file(
           gtls->cred,
           config->clientcert,
           ssl_config->key ? ssl_config->key : config->clientcert,
           do_file_type(ssl_config->cert_type) ) !=
         GNUTLS_E_SUCCESS) {
        failf(data, "error reading X.509 key or certificate file");
        return CURLE_SSL_CONNECT_ERROR;
      }







|











|














|







920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
  if(rc != GNUTLS_E_SUCCESS) {
    failf(data, "Error %d setting GnuTLS cipher list starting with %s",
          rc, err);
    return CURLE_SSL_CONNECT_ERROR;
  }

  if(config->clientcert) {
    if(!gtls->shared_creds->trust_setup) {
      result = Curl_gtls_client_trust_setup(cf, data, gtls);
      if(result)
        return result;
    }
    if(ssl_config->key_passwd) {
      const unsigned int supported_key_encryption_algorithms =
        GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
        GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
        GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
        GNUTLS_PKCS_USE_PBES2_AES_256;
      rc = gnutls_certificate_set_x509_key_file2(
           gtls->shared_creds->creds,
           config->clientcert,
           ssl_config->key ? ssl_config->key : config->clientcert,
           do_file_type(ssl_config->cert_type),
           ssl_config->key_passwd,
           supported_key_encryption_algorithms);
      if(rc != GNUTLS_E_SUCCESS) {
        failf(data,
              "error reading X.509 potentially-encrypted key file: %s",
              gnutls_strerror(rc));
        return CURLE_SSL_CONNECT_ERROR;
      }
    }
    else {
      if(gnutls_certificate_set_x509_key_file(
           gtls->shared_creds->creds,
           config->clientcert,
           ssl_config->key ? ssl_config->key : config->clientcert,
           do_file_type(ssl_config->cert_type) ) !=
         GNUTLS_E_SUCCESS) {
        failf(data, "error reading X.509 key or certificate file");
        return CURLE_SSL_CONNECT_ERROR;
      }
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
  else
#endif
  {
    rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
                                gtls->cred);
    if(rc != GNUTLS_E_SUCCESS) {
      failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
      return CURLE_SSL_CONNECT_ERROR;
    }
  }

  if(config->verifystatus) {







|







972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
  else
#endif
  {
    rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
                                gtls->shared_creds->creds);
    if(rc != GNUTLS_E_SUCCESS) {
      failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
      return CURLE_SSL_CONNECT_ERROR;
    }
  }

  if(config->verifystatus) {
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
      failf(data, "failed setting ALPN");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }

  /* This might be a reconnect, so we check for a session ID in the cache
     to speed up things */
  if(conn_config->sessionid) {
    void *ssl_sessionid;
    size_t ssl_idsize;

    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
      /* we got a session id, use it! */
      int rc;







|







1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
      failf(data, "failed setting ALPN");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }

  /* This might be a reconnect, so we check for a session ID in the cache
     to speed up things */
  if(conn_config->cache_session) {
    void *ssl_sessionid;
    size_t ssl_idsize;

    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
      /* we got a session id, use it! */
      int rc;
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
  unsigned char *buff1 = NULL;

  gnutls_pubkey_t key = NULL;

  /* Result is returned to caller */
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;

  /* if a path wasn't specified, don't pin */
  if(!pinnedpubkey)
    return CURLE_OK;

  if(!cert)
    return result;

  do {







|







1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  unsigned char *buff1 = NULL;

  gnutls_pubkey_t key = NULL;

  /* Result is returned to caller */
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;

  /* if a path was not specified, do not pin */
  if(!pinnedpubkey)
    return CURLE_OK;

  if(!cert)
    return result;

  do {
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
  char certname[65] = ""; /* limited to 64 chars by ASN.1 */
  size_t size;
  time_t certclock;
  int rc;
  CURLcode result = CURLE_OK;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
  const char *ptr;
  unsigned int algo;
  unsigned int bits;
  gnutls_protocol_t version = gnutls_protocol_get_version(session);
#endif
  long * const certverifyresult = &ssl_config->certverifyresult;

#ifndef CURL_DISABLE_VERBOSE_STRINGS
  /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */







|







1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
  char certname[65] = ""; /* limited to 64 chars by ASN.1 */
  size_t size;
  time_t certclock;
  int rc;
  CURLcode result = CURLE_OK;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
  const char *ptr;
  int algo;
  unsigned int bits;
  gnutls_protocol_t version = gnutls_protocol_get_version(session);
#endif
  long * const certverifyresult = &ssl_config->certverifyresult;

#ifndef CURL_DISABLE_VERBOSE_STRINGS
  /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
        failf(data, "failed to get server cert");
        *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND;
        return CURLE_PEER_FAILED_VERIFICATION;
#ifdef USE_GNUTLS_SRP
      }
#endif
    }
    infof(data, " common name: WARNING couldn't obtain");
  }

  if(data->set.ssl.certinfo && chainp) {
    unsigned int i;

    result = Curl_ssl_init_certinfo(data, cert_list_size);
    if(result)
      return result;

    for(i = 0; i < cert_list_size; i++) {
      const char *beg = (const char *) chainp[i].data;
      const char *end = beg + chainp[i].size;

      result = Curl_extract_certinfo(data, i, beg, end);
      if(result)
        return result;
    }
  }

  if(config->verifypeer) {
    /* This function will try to verify the peer's certificate and return its







|





|







|







1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
        failf(data, "failed to get server cert");
        *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND;
        return CURLE_PEER_FAILED_VERIFICATION;
#ifdef USE_GNUTLS_SRP
      }
#endif
    }
    infof(data, " common name: WARNING could not obtain");
  }

  if(data->set.ssl.certinfo && chainp) {
    unsigned int i;

    result = Curl_ssl_init_certinfo(data, (int)cert_list_size);
    if(result)
      return result;

    for(i = 0; i < cert_list_size; i++) {
      const char *beg = (const char *) chainp[i].data;
      const char *end = beg + chainp[i].size;

      result = Curl_extract_certinfo(data, (int)i, beg, end);
      if(result)
        return result;
    }
  }

  if(config->verifypeer) {
    /* This function will try to verify the peer's certificate and return its
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
       gnutls_x509_crt_t format */
    gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);

  if(config->issuercert) {
    gnutls_x509_crt_init(&x509_issuer);
    issuerp = load_file(config->issuercert);
    gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
    rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
    gnutls_x509_crt_deinit(x509_issuer);
    unload_file(issuerp);
    if(rc <= 0) {
      failf(data, "server certificate issuer check failed (IssuerCert: %s)",
            config->issuercert?config->issuercert:"none");
      gnutls_x509_crt_deinit(x509_cert);
      return CURLE_SSL_ISSUER_ERROR;







|







1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
       gnutls_x509_crt_t format */
    gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);

  if(config->issuercert) {
    gnutls_x509_crt_init(&x509_issuer);
    issuerp = load_file(config->issuercert);
    gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
    rc = (int)gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
    gnutls_x509_crt_deinit(x509_issuer);
    unload_file(issuerp);
    if(rc <= 0) {
      failf(data, "server certificate issuer check failed (IssuerCert: %s)",
            config->issuercert?config->issuercert:"none");
      gnutls_x509_crt_deinit(x509_cert);
      return CURLE_SSL_ISSUER_ERROR;
1283
1284
1285
1286
1287
1288
1289




1290


1291
1292
1293
1294
1295
1296
1297
1298
1299
  }

  /* This function will check if the given certificate's subject matches the
     given hostname. This is a basic implementation of the matching described
     in RFC2818 (HTTPS), which takes into account wildcards, and the subject
     alternative name PKIX extension. Returns non zero on success, and zero on
     failure. */




  rc = gnutls_x509_crt_check_hostname(x509_cert, peer->hostname);


#if GNUTLS_VERSION_NUMBER < 0x030306
  /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
     addresses. */
  if(!rc) {
#ifdef USE_IPV6
    #define use_addr in6_addr
#else
    #define use_addr in_addr
#endif







>
>
>
>
|
>
>

|







1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
  }

  /* This function will check if the given certificate's subject matches the
     given hostname. This is a basic implementation of the matching described
     in RFC2818 (HTTPS), which takes into account wildcards, and the subject
     alternative name PKIX extension. Returns non zero on success, and zero on
     failure. */

  /* This function does not handle trailing dots, so if we have an SNI name
     use that and fallback to the hostname only if there is no SNI (like for
     IP addresses) */
  rc = (int)gnutls_x509_crt_check_hostname(x509_cert,
                                           peer->sni ? peer->sni :
                                           peer->hostname);
#if GNUTLS_VERSION_NUMBER < 0x030306
  /* Before 3.3.6, gnutls_x509_crt_check_hostname() did not check IP
     addresses. */
  if(!rc) {
#ifdef USE_IPV6
    #define use_addr in6_addr
#else
    #define use_addr in_addr
#endif
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
      unsigned char certaddr[sizeof(struct use_addr)];
      int i;

      for(i = 0; ; i++) {
        size_t certaddrlen = sizeof(certaddr);
        int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
                                                       &certaddrlen, NULL);
        /* If this happens, it wasn't an IP address. */
        if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
          continue;
        if(ret < 0)
          break;
        if(ret != GNUTLS_SAN_IPADDRESS)
          continue;
        if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
          rc = 1;
          break;
        }
      }
    }
  }
#endif
  if(!rc) {
    if(config->verifyhost) {
      failf(data, "SSL: certificate subject name (%s) does not match "
            "target host name '%s'", certname, peer->dispname);
      gnutls_x509_crt_deinit(x509_cert);
      return CURLE_PEER_FAILED_VERIFICATION;
    }
    else
      infof(data, "  common name: %s (does not match '%s')",
            certname, peer->dispname);
  }







|

















|







1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
      unsigned char certaddr[sizeof(struct use_addr)];
      int i;

      for(i = 0; ; i++) {
        size_t certaddrlen = sizeof(certaddr);
        int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
                                                       &certaddrlen, NULL);
        /* If this happens, it was not an IP address. */
        if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
          continue;
        if(ret < 0)
          break;
        if(ret != GNUTLS_SAN_IPADDRESS)
          continue;
        if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
          rc = 1;
          break;
        }
      }
    }
  }
#endif
  if(!rc) {
    if(config->verifyhost) {
      failf(data, "SSL: certificate subject name (%s) does not match "
            "target hostname '%s'", certname, peer->dispname);
      gnutls_x509_crt_deinit(x509_cert);
      return CURLE_PEER_FAILED_VERIFICATION;
    }
    else
      infof(data, "  common name: %s (does not match '%s')",
            certname, peer->dispname);
  }
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432

  */

#ifndef CURL_DISABLE_VERBOSE_STRINGS
  /* public key algorithm's parameters */
  algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
  infof(data, "  certificate public key: %s",
        gnutls_pk_algorithm_get_name(algo));

  /* version of the X.509 certificate. */
  infof(data, "  certificate version: #%d",
        gnutls_x509_crt_get_version(x509_cert));


  rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields);







|







1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606

  */

#ifndef CURL_DISABLE_VERBOSE_STRINGS
  /* public key algorithm's parameters */
  algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
  infof(data, "  certificate public key: %s",
        gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo));

  /* version of the X.509 certificate. */
  infof(data, "  certificate version: #%d",
        gnutls_x509_crt_get_version(x509_cert));


  rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields);
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526

/*
 * This function is called after the TCP connect has completed. Setup the TLS
 * layer and do all necessary magic.
 */
/* We use connssl->connecting_state to keep track of the connection status;
   there are three states: 'ssl_connect_1' (not started yet or complete),
   'ssl_connect_2_reading' (waiting for data from server), and
   'ssl_connect_2_writing' (waiting to be able to write).
 */
static CURLcode
gtls_connect_common(struct Curl_cfilter *cf,
                    struct Curl_easy *data,
                    bool nonblocking,
                    bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  int rc;
  CURLcode result = CURLE_OK;

  /* Initiate the connection, if not already done */
  if(ssl_connect_1 == connssl->connecting_state) {
    rc = gtls_connect_step1(cf, data);
    if(rc) {
      result = rc;







|
|








|







1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700

/*
 * This function is called after the TCP connect has completed. Setup the TLS
 * layer and do all necessary magic.
 */
/* We use connssl->connecting_state to keep track of the connection status;
   there are three states: 'ssl_connect_1' (not started yet or complete),
   'ssl_connect_2' (doing handshake with the server), and
   'ssl_connect_3' (verifying and getting stats).
 */
static CURLcode
gtls_connect_common(struct Curl_cfilter *cf,
                    struct Curl_easy *data,
                    bool nonblocking,
                    bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  CURLcode rc;
  CURLcode result = CURLE_OK;

  /* Initiate the connection, if not already done */
  if(ssl_connect_1 == connssl->connecting_state) {
    rc = gtls_connect_step1(cf, data);
    if(rc) {
      result = rc;
1615
1616
1617
1618
1619
1620
1621











































































1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
      (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);

    rc = -1;
  }

  return rc;
}












































































static void gtls_close(struct Curl_cfilter *cf,
                       struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct gtls_ssl_backend_data *backend =
    (struct gtls_ssl_backend_data *)connssl->backend;

  (void) data;
  DEBUGASSERT(backend);

  if(backend->gtls.session) {
    char buf[32];
    /* Maybe the server has already sent a close notify alert.
       Read it to avoid an RST on the TCP connection. */
    (void)gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
    gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
    gnutls_deinit(backend->gtls.session);
    backend->gtls.session = NULL;
  }
  if(backend->gtls.cred) {
    gnutls_certificate_free_credentials(backend->gtls.cred);
    backend->gtls.cred = NULL;
  }
#ifdef USE_GNUTLS_SRP
  if(backend->gtls.srp_client_cred) {
    gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
    backend->gtls.srp_client_cred = NULL;
  }
#endif
}

/*
 * This function is called to shut down the SSL layer but keep the
 * socket open (CCC - Clear Command Channel)
 */
static int gtls_shutdown(struct Curl_cfilter *cf,
                         struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct gtls_ssl_backend_data *backend =
    (struct gtls_ssl_backend_data *)connssl->backend;
  int retval = 0;

  DEBUGASSERT(backend);

#ifndef CURL_DISABLE_FTP
  /* This has only been tested on the proftpd server, and the mod_tls code
     sends a close notify alert without waiting for a close notify alert in
     response. Thus we wait for a close notify alert from the server, but
     we do not send one. Let's hope other servers do the same... */

  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
    gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
#endif

  if(backend->gtls.session) {
    ssize_t result;
    bool done = FALSE;
    char buf[120];

    while(!done && !connssl->peer_closed) {
      int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
                                 SSL_SHUTDOWN_TIMEOUT);
      if(what > 0) {
        /* Something to read, let's do it and hope that it is the close
           notify alert from the server */
        result = gnutls_record_recv(backend->gtls.session,
                                    buf, sizeof(buf));
        switch(result) {
        case 0:
          /* This is the expected response. There was no data but only
             the close notify alert */
          done = TRUE;
          break;
        case GNUTLS_E_AGAIN:
        case GNUTLS_E_INTERRUPTED:
          infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED");
          break;
        default:
          retval = -1;
          done = TRUE;
          break;
        }
      }
      else if(0 == what) {
        /* timeout */
        failf(data, "SSL shutdown timeout");
        done = TRUE;
      }
      else {
        /* anything that gets here is fatally bad */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        retval = -1;
        done = TRUE;
      }
    }
    gnutls_deinit(backend->gtls.session);
  }
  gnutls_certificate_free_credentials(backend->gtls.cred);

#ifdef USE_GNUTLS_SRP
  {
    struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
    if(ssl_config->primary.username)
      gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
  }
#endif

  backend->gtls.cred = NULL;
  backend->gtls.session = NULL;

  return retval;
}

static ssize_t gtls_recv(struct Curl_cfilter *cf,
                         struct Curl_easy *data,
                         char *buf,
                         size_t buffersize,
                         CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = cf->ctx;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










|

<
<
<
<
<



|
<
|









<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882





1883
1884
1885
1886

1887
1888
1889
1890
1891
1892
1893
1894
1895
1896



















































































1897
1898
1899
1900
1901
1902
1903
      (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);

    rc = -1;
  }

  return rc;
}

/*
 * This function is called to shut down the SSL layer but keep the
 * socket open (CCC - Clear Command Channel)
 */
static CURLcode gtls_shutdown(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              bool send_shutdown, bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct gtls_ssl_backend_data *backend =
    (struct gtls_ssl_backend_data *)connssl->backend;
  char buf[1024];
  CURLcode result = CURLE_OK;
  ssize_t nread;
  size_t i;

  DEBUGASSERT(backend);
  if(!backend->gtls.session || cf->shutdown) {
    *done = TRUE;
    goto out;
  }

  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  *done = FALSE;

  if(!backend->gtls.sent_shutdown) {
    /* do this only once */
    backend->gtls.sent_shutdown = TRUE;
    if(send_shutdown) {
      int ret = gnutls_bye(backend->gtls.session, GNUTLS_SHUT_RDWR);
      if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
        CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye EAGAIN");
        connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
          CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
        result = CURLE_OK;
        goto out;
      }
      if(ret != GNUTLS_E_SUCCESS) {
        CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye error: '%s'(%d)",
                    gnutls_strerror((int)ret), (int)ret);
        result = CURLE_RECV_ERROR;
        goto out;
      }
    }
  }

  /* SSL should now have started the shutdown from our side. Since it
   * was not complete, we are lacking the close notify from the server. */
  for(i = 0; i < 10; ++i) {
    nread = gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
    if(nread <= 0)
      break;
  }
  if(nread > 0) {
    /* still data coming in? */
  }
  else if(nread == 0) {
    /* We got the close notify alert and are done. */
    *done = TRUE;
  }
  else if((nread == GNUTLS_E_AGAIN) || (nread == GNUTLS_E_INTERRUPTED)) {
    connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
      CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
  }
  else {
    CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)",
                gnutls_strerror((int)nread), (int)nread);
    result = CURLE_RECV_ERROR;
  }

out:
  cf->shutdown = (result || *done);
  return result;
}

static void gtls_close(struct Curl_cfilter *cf,
                       struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct gtls_ssl_backend_data *backend =
    (struct gtls_ssl_backend_data *)connssl->backend;

  (void) data;
  DEBUGASSERT(backend);
  CURL_TRC_CF(data, cf, "close");
  if(backend->gtls.session) {





    gnutls_deinit(backend->gtls.session);
    backend->gtls.session = NULL;
  }
  if(backend->gtls.shared_creds) {

    Curl_gtls_shared_creds_free(&backend->gtls.shared_creds);
  }
#ifdef USE_GNUTLS_SRP
  if(backend->gtls.srp_client_cred) {
    gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
    backend->gtls.srp_client_cred = NULL;
  }
#endif
}




















































































static ssize_t gtls_recv(struct Curl_cfilter *cf,
                         struct Curl_easy *data,
                         char *buf,
                         size_t buffersize,
                         CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = cf->ctx;
1827
1828
1829
1830
1831
1832
1833
1834

1835
1836
1837
1838
1839
1840
1841

const struct Curl_ssl Curl_ssl_gnutls = {
  { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */

  SSLSUPP_CA_PATH  |
  SSLSUPP_CERTINFO |
  SSLSUPP_PINNEDPUBKEY |
  SSLSUPP_HTTPS_PROXY,


  sizeof(struct gtls_ssl_backend_data),

  gtls_init,                     /* init */
  gtls_cleanup,                  /* cleanup */
  gtls_version,                  /* version */
  Curl_none_check_cxn,           /* check_cxn */







|
>







1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002

const struct Curl_ssl Curl_ssl_gnutls = {
  { CURLSSLBACKEND_GNUTLS, "gnutls" }, /* info */

  SSLSUPP_CA_PATH  |
  SSLSUPP_CERTINFO |
  SSLSUPP_PINNEDPUBKEY |
  SSLSUPP_HTTPS_PROXY |
  SSLSUPP_CA_CACHE,

  sizeof(struct gtls_ssl_backend_data),

  gtls_init,                     /* init */
  gtls_cleanup,                  /* cleanup */
  gtls_version,                  /* version */
  Curl_none_check_cxn,           /* check_cxn */
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
  Curl_none_set_engine,          /* set_engine */
  Curl_none_set_engine_default,  /* set_engine_default */
  Curl_none_engines_list,        /* engines_list */
  Curl_none_false_start,         /* false_start */
  gtls_sha256sum,                /* sha256sum */
  NULL,                          /* associate_connection */
  NULL,                          /* disassociate_connection */
  NULL,                          /* free_multi_ssl_backend_data */
  gtls_recv,                     /* recv decrypted data */
  gtls_send,                     /* send data to encrypt */
};

#endif /* USE_GNUTLS */







<





2013
2014
2015
2016
2017
2018
2019

2020
2021
2022
2023
2024
  Curl_none_set_engine,          /* set_engine */
  Curl_none_set_engine_default,  /* set_engine_default */
  Curl_none_engines_list,        /* engines_list */
  Curl_none_false_start,         /* false_start */
  gtls_sha256sum,                /* sha256sum */
  NULL,                          /* associate_connection */
  NULL,                          /* disassociate_connection */

  gtls_recv,                     /* recv decrypted data */
  gtls_send,                     /* send data to encrypt */
};

#endif /* USE_GNUTLS */
Changes to jni/curl/lib/vtls/gtls.h.
26
27
28
29
30
31
32

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47













48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

#include "curl_setup.h"
#include <curl/curl.h>

#ifdef USE_GNUTLS

#include <gnutls/gnutls.h>


#ifdef HAVE_GNUTLS_SRP
/* the function exists */
#ifdef USE_TLS_SRP
/* the functionality is not disabled */
#define USE_GNUTLS_SRP
#endif
#endif

struct Curl_easy;
struct Curl_cfilter;
struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;














struct gtls_ctx {
  gnutls_session_t session;
  gnutls_certificate_credentials_t cred;
#ifdef USE_GNUTLS_SRP
  gnutls_srp_client_credentials_t srp_client_cred;
#endif
  CURLcode io_result; /* result of last IO cfilter operation */
  BIT(trust_setup); /* x509 anchors + CRLs have been set up */
};

typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
                                        struct Curl_easy *data,
                                        void *user_data);

CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,







>















>
>
>
>
>
>
>
>
>
>
>
>
>


|




|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76

#include "curl_setup.h"
#include <curl/curl.h>

#ifdef USE_GNUTLS

#include <gnutls/gnutls.h>
#include "timeval.h"

#ifdef HAVE_GNUTLS_SRP
/* the function exists */
#ifdef USE_TLS_SRP
/* the functionality is not disabled */
#define USE_GNUTLS_SRP
#endif
#endif

struct Curl_easy;
struct Curl_cfilter;
struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;

struct gtls_shared_creds {
  gnutls_certificate_credentials_t creds;
  char *CAfile; /* CAfile path used to generate X509 store */
  struct curltime time; /* when the shared creds was created */
  size_t refcount;
  BIT(trust_setup); /* x509 anchors + CRLs have been set up */
};

CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data,
                                       struct gtls_shared_creds **pcreds);
CURLcode Curl_gtls_shared_creds_up_ref(struct gtls_shared_creds *creds);
void Curl_gtls_shared_creds_free(struct gtls_shared_creds **pcreds);

struct gtls_ctx {
  gnutls_session_t session;
  struct gtls_shared_creds *shared_creds;
#ifdef USE_GNUTLS_SRP
  gnutls_srp_client_credentials_t srp_client_cred;
#endif
  CURLcode io_result; /* result of last IO cfilter operation */
  BIT(sent_shutdown);
};

typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
                                        struct Curl_easy *data,
                                        void *user_data);

CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
Changes to jni/curl/lib/vtls/hostcheck.c.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 * Match a hostname against a wildcard pattern.
 * E.g.
 *  "foo.host.com" matches "*.host.com".
 *
 * We use the matching rule described in RFC6125, section 6.4.3.
 * https://datatracker.ietf.org/doc/html/rfc6125#section-6.4.3
 *
 * In addition: ignore trailing dots in the host names and wildcards, so that
 * the names are used normalized. This is what the browsers do.
 *
 * Do not allow wildcard matching on IP numbers. There are apparently
 * certificates being used with an IP address in the CN field, thus making no
 * apparent distinction between a name and an IP. We need to detect the use of
 * an IP address and not wildcard match on such names.
 *







|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 * Match a hostname against a wildcard pattern.
 * E.g.
 *  "foo.host.com" matches "*.host.com".
 *
 * We use the matching rule described in RFC6125, section 6.4.3.
 * https://datatracker.ietf.org/doc/html/rfc6125#section-6.4.3
 *
 * In addition: ignore trailing dots in the hostnames and wildcards, so that
 * the names are used normalized. This is what the browsers do.
 *
 * Do not allow wildcard matching on IP numbers. There are apparently
 * certificates being used with an IP address in the CN field, thus making no
 * apparent distinction between a name and an IP. We need to detect the use of
 * an IP address and not wildcard match on such names.
 *
Changes to jni/curl/lib/vtls/hostcheck.h.
22
23
24
25
26
27
28
29
30
31
32
33
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include <curl/curl.h>

/* returns TRUE if there's a match */
bool Curl_cert_hostcheck(const char *match_pattern, size_t matchlen,
                         const char *hostname, size_t hostlen);

#endif /* HEADER_CURL_HOSTCHECK_H */







|




22
23
24
25
26
27
28
29
30
31
32
33
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include <curl/curl.h>

/* returns TRUE if there is a match */
bool Curl_cert_hostcheck(const char *match_pattern, size_t matchlen,
                         const char *hostname, size_t hostlen);

#endif /* HEADER_CURL_HOSTCHECK_H */
Changes to jni/curl/lib/vtls/mbedtls.c.
71
72
73
74
75
76
77

78
79
80
81
82
83
84
#include "strcase.h"
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
#include "mbedtls.h"
#include "vtls.h"
#include "vtls_int.h"

#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "multiif.h"
#include "mbedtls_threadlock.h"
#include "strdup.h"








>







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include "strcase.h"
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
#include "mbedtls.h"
#include "vtls.h"
#include "vtls_int.h"
#include "x509asn1.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "multiif.h"
#include "mbedtls_threadlock.h"
#include "strdup.h"

106
107
108
109
110
111
112


113
114
115
116
117
118
119
#endif
  mbedtls_pk_context pk;
  mbedtls_ssl_config config;
#ifdef HAS_ALPN
  const char *protocols[3];
#endif
  int *ciphersuites;


};

/* apply threading? */
#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
    defined(_WIN32)
#define THREADING_SUPPORT
#endif







>
>







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#endif
  mbedtls_pk_context pk;
  mbedtls_ssl_config config;
#ifdef HAS_ALPN
  const char *protocols[3];
#endif
  int *ciphersuites;
  BIT(initialized); /* mbedtls_ssl_context is initialized */
  BIT(sent_shutdown);
};

/* apply threading? */
#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
    defined(_WIN32)
#define THREADING_SUPPORT
#endif
477
478
479
480
481
482
483














484
485
486
487
488
489
490

  /* mbedtls_ssl_conf_ciphersuites(): The ciphersuites array is not copied.
     It must remain valid for the lifetime of the SSL configuration */
  backend->ciphersuites = selected;
  mbedtls_ssl_conf_ciphersuites(&backend->config, backend->ciphersuites);
  return CURLE_OK;
}















static CURLcode
mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;







>
>
>
>
>
>
>
>
>
>
>
>
>
>







480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507

  /* mbedtls_ssl_conf_ciphersuites(): The ciphersuites array is not copied.
     It must remain valid for the lifetime of the SSL configuration */
  backend->ciphersuites = selected;
  mbedtls_ssl_conf_ciphersuites(&backend->config, backend->ciphersuites);
  return CURLE_OK;
}

#ifdef TLS13_SUPPORT
static int mbed_no_verify(void *udata, mbedtls_x509_crt *crt,
                          int depth, uint32_t *flags)
{
  (void)udata;
  (void)crt;
  (void)depth;
  /* we clear any faults the mbedtls' own verification found.
   * See <https://github.com/Mbed-TLS/mbedtls/issues/9210> */
  *flags = 0;
  return 0;
}
#endif

static CURLcode
mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
500
501
502
503
504
505
506

507
508
509
510
511
512
513
  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
  const char * const ssl_crlfile = ssl_config->primary.CRLfile;
  const char *hostname = connssl->peer.hostname;
  int ret = -1;
  char errorbuf[128];

  DEBUGASSERT(backend);


  if((conn_config->version == CURL_SSLVERSION_SSLv2) ||
     (conn_config->version == CURL_SSLVERSION_SSLv3)) {
    failf(data, "Not supported SSL version");
    return CURLE_NOT_BUILT_IN;
  }








>







517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
  const char * const ssl_crlfile = ssl_config->primary.CRLfile;
  const char *hostname = connssl->peer.hostname;
  int ret = -1;
  char errorbuf[128];

  DEBUGASSERT(backend);
  DEBUGASSERT(!backend->initialized);

  if((conn_config->version == CURL_SSLVERSION_SSLv2) ||
     (conn_config->version == CURL_SSLVERSION_SSLv3)) {
    failf(data, "Not supported SSL version");
    return CURLE_NOT_BUILT_IN;
  }

632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
      return CURLE_OUT_OF_MEMORY;
    ret = mbedtls_x509_crt_parse(&backend->clicert, newblob,
                                 ssl_cert_blob->len + 1);
    free(newblob);

    if(ret) {
      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
      failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
            ssl_config->key, -ret, errorbuf);
      return CURLE_SSL_CERTPROBLEM;
    }
  }

  /* Load the client private key */
  mbedtls_pk_init(&backend->pk);







|







650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
      return CURLE_OUT_OF_MEMORY;
    ret = mbedtls_x509_crt_parse(&backend->clicert, newblob,
                                 ssl_cert_blob->len + 1);
    free(newblob);

    if(ret) {
      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
      failf(data, "Error reading client cert data %s - mbedTLS: (-0x%04X) %s",
            ssl_config->key, -ret, errorbuf);
      return CURLE_SSL_CERTPROBLEM;
    }
  }

  /* Load the client private key */
  mbedtls_pk_init(&backend->pk);
733
734
735
736
737
738
739







740



741

742
743
744
745
746
747
748
                                    MBEDTLS_SSL_IS_CLIENT,
                                    MBEDTLS_SSL_TRANSPORT_STREAM,
                                    MBEDTLS_SSL_PRESET_DEFAULT);
  if(ret) {
    failf(data, "mbedTLS: ssl_config failed");
    return CURLE_SSL_CONNECT_ERROR;
  }











  mbedtls_ssl_init(&backend->ssl);


  /* new profile with RSA min key len = 1024 ... */
  mbedtls_ssl_conf_cert_profile(&backend->config,
                                &mbedtls_x509_crt_profile_fr);

  switch(conn_config->version) {
  case CURL_SSLVERSION_DEFAULT:







>
>
>
>
>
>
>
|
>
>
>

>







751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
                                    MBEDTLS_SSL_IS_CLIENT,
                                    MBEDTLS_SSL_TRANSPORT_STREAM,
                                    MBEDTLS_SSL_PRESET_DEFAULT);
  if(ret) {
    failf(data, "mbedTLS: ssl_config failed");
    return CURLE_SSL_CONNECT_ERROR;
  }
#ifdef TLS13_SUPPORT
  if(!verifypeer) {
    /* Default verify behaviour changed in mbedtls v3.6.0 with TLS v1.3.
     * On 1.3 connections, the handshake fails by default without trust
     * anchors. We override this questionable change by installing our
     * own verify callback that clears all errors. */
    mbedtls_ssl_conf_verify(&backend->config, mbed_no_verify, cf);
  }
#endif


  mbedtls_ssl_init(&backend->ssl);
  backend->initialized = TRUE;

  /* new profile with RSA min key len = 1024 ... */
  mbedtls_ssl_conf_cert_profile(&backend->config,
                                &mbedtls_x509_crt_profile_fr);

  switch(conn_config->version) {
  case CURL_SSLVERSION_DEFAULT:
781
782
783
784
785
786
787
788

789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818

  mbedtls_ssl_set_bio(&backend->ssl, cf,
                      mbedtls_bio_cf_write,
                      mbedtls_bio_cf_read,
                      NULL /*  rev_timeout() */);

  if(conn_config->cipher_list) {
    ret = mbed_set_selected_ciphers(data, backend, conn_config->cipher_list);

    if(ret) {
      failf(data, "mbedTLS: failed to set cipher suites");
      return ret;
    }
  }
  else {
    mbedtls_ssl_conf_ciphersuites(&backend->config,
                                  mbedtls_ssl_list_ciphersuites());
  }


#if defined(MBEDTLS_SSL_RENEGOTIATION)
  mbedtls_ssl_conf_renegotiation(&backend->config,
                                 MBEDTLS_SSL_RENEGOTIATION_ENABLED);
#endif

#if defined(MBEDTLS_SSL_SESSION_TICKETS)
  mbedtls_ssl_conf_session_tickets(&backend->config,
                                   MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
#endif

  /* Check if there's a cached ID we can/should use here! */
  if(ssl_config->primary.sessionid) {
    void *old_session = NULL;

    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
      ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
      if(ret) {
        Curl_ssl_sessionid_unlock(data);







|
>
|

|


















|
|







810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848

  mbedtls_ssl_set_bio(&backend->ssl, cf,
                      mbedtls_bio_cf_write,
                      mbedtls_bio_cf_read,
                      NULL /*  rev_timeout() */);

  if(conn_config->cipher_list) {
    CURLcode result = mbed_set_selected_ciphers(data, backend,
                                                conn_config->cipher_list);
    if(result != CURLE_OK) {
      failf(data, "mbedTLS: failed to set cipher suites");
      return result;
    }
  }
  else {
    mbedtls_ssl_conf_ciphersuites(&backend->config,
                                  mbedtls_ssl_list_ciphersuites());
  }


#if defined(MBEDTLS_SSL_RENEGOTIATION)
  mbedtls_ssl_conf_renegotiation(&backend->config,
                                 MBEDTLS_SSL_RENEGOTIATION_ENABLED);
#endif

#if defined(MBEDTLS_SSL_SESSION_TICKETS)
  mbedtls_ssl_conf_session_tickets(&backend->config,
                                   MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
#endif

  /* Check if there is a cached ID we can/should use here! */
  if(ssl_config->primary.cache_session) {
    void *old_session = NULL;

    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
      ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
      if(ret) {
        Curl_ssl_sessionid_unlock(data);
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
  if(connssl->alpn) {
    struct alpn_proto_buf proto;
    size_t i;

    for(i = 0; i < connssl->alpn->count; ++i) {
      backend->protocols[i] = connssl->alpn->entries[i];
    }
    /* this function doesn't clone the protocols array, which is why we need
       to keep it around */
    if(mbedtls_ssl_conf_alpn_protocols(&backend->config,
                                       &backend->protocols[0])) {
      failf(data, "Failed setting ALPN protocols");
      return CURLE_SSL_CONNECT_ERROR;
    }
    Curl_alpn_to_proto_str(&proto, connssl->alpn);







|







880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
  if(connssl->alpn) {
    struct alpn_proto_buf proto;
    size_t i;

    for(i = 0; i < connssl->alpn->count; ++i) {
      backend->protocols[i] = connssl->alpn->entries[i];
    }
    /* this function does not clone the protocols array, which is why we need
       to keep it around */
    if(mbedtls_ssl_conf_alpn_protocols(&backend->config,
                                       &backend->protocols[0])) {
      failf(data, "Failed setting ALPN protocols");
      return CURLE_SSL_CONNECT_ERROR;
    }
    Curl_alpn_to_proto_str(&proto, connssl->alpn);
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894






















































895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925




926
927
928




929
930
931
932
933
934




935
936
937
938
939



940
941
942
943
944
945
946
   * - 4 Verbose
   */
  mbedtls_debug_set_threshold(4);
#endif

  /* give application a chance to interfere with mbedTLS set up. */
  if(data->set.ssl.fsslctx) {
    ret = (*data->set.ssl.fsslctx)(data, &backend->config,
                                   data->set.ssl.fsslctxp);
    if(ret) {
      failf(data, "error signaled by ssl ctx callback");
      return ret;
    }
  }

  connssl->connecting_state = ssl_connect_2;

  return CURLE_OK;
}























































static CURLcode
mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  int ret;
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  const mbedtls_x509_crt *peercert;
  char cipher_str[64];
  uint16_t cipher_id;
#ifndef CURL_DISABLE_PROXY
  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
  const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#endif

  DEBUGASSERT(backend);

  ret = mbedtls_ssl_handshake(&backend->ssl);

  if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
    connssl->connecting_state = ssl_connect_2_reading;
    return CURLE_OK;
  }
  else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
    connssl->connecting_state = ssl_connect_2_writing;
    return CURLE_OK;




  }
  else if(ret) {
    char errorbuf[128];




    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
    failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
          -ret, errorbuf);
    return CURLE_SSL_CONNECT_ERROR;
  }





  cipher_id = (uint16_t)
              mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
  mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), true);
  infof(data, "mbedTLS: Handshake complete, cipher is %s", cipher_str);




  ret = mbedtls_ssl_get_verify_result(&backend->ssl);

  if(!conn_config->verifyhost)
    /* Ignore hostname errors if verifyhost is disabled */
    ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;

  if(ret && conn_config->verifypeer) {







|
|
|

|







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










<
<













|



|

>
>
>
>



>
>
>
>

|




>
>
>
>
|
|
|
|
|
>
>
>







906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988


989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
   * - 4 Verbose
   */
  mbedtls_debug_set_threshold(4);
#endif

  /* give application a chance to interfere with mbedTLS set up. */
  if(data->set.ssl.fsslctx) {
    CURLcode result = (*data->set.ssl.fsslctx)(data, &backend->config,
                                               data->set.ssl.fsslctxp);
    if(result != CURLE_OK) {
      failf(data, "error signaled by ssl ctx callback");
      return result;
    }
  }

  connssl->connecting_state = ssl_connect_2;

  return CURLE_OK;
}

static int count_server_cert(const mbedtls_x509_crt *peercert)
{
  int count = 1;

  DEBUGASSERT(peercert);

  while(peercert->next) {
    ++count;
    peercert = peercert->next;
  }
  return count;
}

static CURLcode collect_server_cert_single(struct Curl_easy *data,
                                           const mbedtls_x509_crt *server_cert,
                                           int idx)
{
  const char *beg, *end;

  DEBUGASSERT(server_cert);

  beg = (const char *)server_cert->raw.p;
  end = beg + server_cert->raw.len;
  return Curl_extract_certinfo(data, idx, beg, end);
}

static CURLcode collect_server_cert(struct Curl_cfilter *cf,
                                    struct Curl_easy *data,
                                    const struct mbedtls_x509_crt *peercert)
{
#ifndef CURL_DISABLE_VERBOSE_STRINGS
  const bool show_verbose_server_cert = data->set.verbose;
#else
  const bool show_verbose_server_cert = false;
#endif
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
  int i, count;

  if(!show_verbose_server_cert && !ssl_config->certinfo)
    return CURLE_OK;

  if(!peercert)
    return result;

  count = count_server_cert(peercert);
  result = Curl_ssl_init_certinfo(data, count);
  for(i = 0 ; !result && peercert ; i++) {
    result = collect_server_cert_single(data, peercert, i);
    peercert = peercert->next;
  }
  return result;
}

static CURLcode
mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  int ret;
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  const mbedtls_x509_crt *peercert;


#ifndef CURL_DISABLE_PROXY
  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
  const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#endif

  DEBUGASSERT(backend);

  ret = mbedtls_ssl_handshake(&backend->ssl);

  if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
    connssl->io_need = CURL_SSL_IO_NEED_RECV;
    return CURLE_OK;
  }
  else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
    connssl->io_need = CURL_SSL_IO_NEED_SEND;
    return CURLE_OK;
  }
  else if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
    failf(data, "peer certificate could not be verified");
    return CURLE_PEER_FAILED_VERIFICATION;
  }
  else if(ret) {
    char errorbuf[128];
#if MBEDTLS_VERSION_NUMBER >= 0x03020000
    CURL_TRC_CF(data, cf, "TLS version %04X",
                mbedtls_ssl_get_version_number(&backend->ssl));
#endif
    mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
    failf(data, "ssl_handshake returned: (-0x%04X) %s",
          -ret, errorbuf);
    return CURLE_SSL_CONNECT_ERROR;
  }

#if MBEDTLS_VERSION_NUMBER >= 0x03020000
  {
    char cipher_str[64];
    uint16_t cipher_id;
    cipher_id = (uint16_t)
                mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
    mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), true);
    infof(data, "mbedTLS: Handshake complete, cipher is %s", cipher_str);
  }
#else
  infof(data, "mbedTLS: Handshake complete");
#endif
  ret = mbedtls_ssl_get_verify_result(&backend->ssl);

  if(!conn_config->verifyhost)
    /* Ignore hostname errors if verifyhost is disabled */
    ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;

  if(ret && conn_config->verifypeer) {
959
960
961
962
963
964
965






966
967
968
969
970
971
972
    else if(ret & MBEDTLS_X509_BADCERT_FUTURE)
      failf(data, "Cert verify failed: BADCERT_FUTURE");

    return CURLE_PEER_FAILED_VERIFICATION;
  }

  peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);







  if(peercert && data->set.verbose) {
#ifndef MBEDTLS_X509_REMOVE_INFO
    const size_t bufsize = 16384;
    char *buffer = malloc(bufsize);

    if(!buffer)







>
>
>
>
>
>







1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
    else if(ret & MBEDTLS_X509_BADCERT_FUTURE)
      failf(data, "Cert verify failed: BADCERT_FUTURE");

    return CURLE_PEER_FAILED_VERIFICATION;
  }

  peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);

  if(peercert) {
    const CURLcode result = collect_server_cert(cf, data, peercert);
    if(result)
      return result;
  }

  if(peercert && data->set.verbose) {
#ifndef MBEDTLS_X509_REMOVE_INFO
    const size_t bufsize = 16384;
    char *buffer = malloc(bufsize);

    if(!buffer)
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);

  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
  DEBUGASSERT(backend);

  if(ssl_config->primary.sessionid) {
    int ret;
    mbedtls_ssl_session *our_ssl_sessionid;
    void *old_ssl_sessionid = NULL;

    our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
    if(!our_ssl_sessionid)
      return CURLE_OUT_OF_MEMORY;

    mbedtls_ssl_session_init(our_ssl_sessionid);

    ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid);
    if(ret) {
      if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED)
        mbedtls_ssl_session_free(our_ssl_sessionid);
      free(our_ssl_sessionid);
      failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
      return CURLE_SSL_CONNECT_ERROR;
    }

    /* If there's already a matching session in the cache, delete it */
    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
                              &old_ssl_sessionid, NULL))
      Curl_ssl_delsessionid(data, old_ssl_sessionid);

    retcode = Curl_ssl_addsessionid(cf, data, &connssl->peer,
                                    our_ssl_sessionid, 0,
                                    mbedtls_session_free);
    Curl_ssl_sessionid_unlock(data);
    if(retcode)
      return retcode;
  }

  connssl->connecting_state = ssl_connect_done;








|


<
















|

|
<
<
<
<
|
|







1187
1188
1189
1190
1191
1192
1193
1194
1195
1196

1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215




1216
1217
1218
1219
1220
1221
1222
1223
1224
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);

  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
  DEBUGASSERT(backend);

  if(ssl_config->primary.cache_session) {
    int ret;
    mbedtls_ssl_session *our_ssl_sessionid;


    our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
    if(!our_ssl_sessionid)
      return CURLE_OUT_OF_MEMORY;

    mbedtls_ssl_session_init(our_ssl_sessionid);

    ret = mbedtls_ssl_get_session(&backend->ssl, our_ssl_sessionid);
    if(ret) {
      if(ret != MBEDTLS_ERR_SSL_ALLOC_FAILED)
        mbedtls_ssl_session_free(our_ssl_sessionid);
      free(our_ssl_sessionid);
      failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
      return CURLE_SSL_CONNECT_ERROR;
    }

    /* If there is already a matching session in the cache, delete it */
    Curl_ssl_sessionid_lock(data);
    retcode = Curl_ssl_set_sessionid(cf, data, &connssl->peer,




                                     our_ssl_sessionid, 0,
                                     mbedtls_session_free);
    Curl_ssl_sessionid_unlock(data);
    if(retcode)
      return retcode;
  }

  connssl->connecting_state = ssl_connect_done;

1137
1138
1139
1140
1141
1142
1143


1144



1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156


























































































1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183


1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202


1203
1204
1205
1206
1207
1208
1209
1210





1211
1212
1213
1214
1215
1216
1217
  int ret = -1;

  (void)data;
  DEBUGASSERT(backend);
  ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);

  if(ret < 0) {


    *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?



      CURLE_AGAIN : CURLE_SEND_ERROR;
    ret = -1;
  }

  return ret;
}

static void mbedtls_close_all(struct Curl_easy *data)
{
  (void)data;
}



























































































static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
  char buf[32];

  (void)data;
  DEBUGASSERT(backend);

  /* Maybe the server has already sent a close notify alert.
     Read it to avoid an RST on the TCP connection. */
  (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));

  mbedtls_pk_free(&backend->pk);
  mbedtls_x509_crt_free(&backend->clicert);
  mbedtls_x509_crt_free(&backend->cacert);
#ifdef MBEDTLS_X509_CRL_PARSE_C
  mbedtls_x509_crl_free(&backend->crl);
#endif
  Curl_safefree(backend->ciphersuites);
  mbedtls_ssl_config_free(&backend->config);
  mbedtls_ssl_free(&backend->ssl);
  mbedtls_ctr_drbg_free(&backend->ctr_drbg);
#ifndef THREADING_SUPPORT
  mbedtls_entropy_free(&backend->entropy);
#endif /* THREADING_SUPPORT */


}

static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
                         char *buf, size_t buffersize,
                         CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
  int ret = -1;
  ssize_t len = -1;

  (void)data;
  DEBUGASSERT(backend);

  ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
                         buffersize);

  if(ret <= 0) {


    if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
      return 0;

    *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
#ifdef TLS13_SUPPORT
              || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
#endif
    ) ? CURLE_AGAIN : CURLE_RECV_ERROR;





    return -1;
  }

  len = ret;

  return len;
}







>
>
|
>
>
>
|











>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





<



|
<
<
<
<
|
|
|

|

|
|
|
|

|

>
>

















<

>
>


<





>
>
>
>
>







1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354

1355
1356
1357
1358




1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390

1391
1392
1393
1394
1395

1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
  int ret = -1;

  (void)data;
  DEBUGASSERT(backend);
  ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);

  if(ret < 0) {
    CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X",
                len, -ret);
    *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_WRITE)
#ifdef TLS13_SUPPORT
      || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
#endif
      )? CURLE_AGAIN : CURLE_SEND_ERROR;
    ret = -1;
  }

  return ret;
}

static void mbedtls_close_all(struct Curl_easy *data)
{
  (void)data;
}

static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 bool send_shutdown, bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
  unsigned char buf[1024];
  CURLcode result = CURLE_OK;
  int ret;
  size_t i;

  DEBUGASSERT(backend);

  if(!backend->initialized || cf->shutdown) {
    *done = TRUE;
    return CURLE_OK;
  }

  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  *done = FALSE;

  if(!backend->sent_shutdown) {
    /* do this only once */
    backend->sent_shutdown = TRUE;
    if(send_shutdown) {
      ret = mbedtls_ssl_close_notify(&backend->ssl);
      switch(ret) {
      case 0: /* we sent it, receive from the server */
        break;
      case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: /* server also closed */
        *done = TRUE;
        goto out;
      case MBEDTLS_ERR_SSL_WANT_READ:
        connssl->io_need = CURL_SSL_IO_NEED_RECV;
        goto out;
      case MBEDTLS_ERR_SSL_WANT_WRITE:
        connssl->io_need = CURL_SSL_IO_NEED_SEND;
        goto out;
      default:
        CURL_TRC_CF(data, cf, "mbedtls_shutdown error -0x%04X", -ret);
        result = CURLE_RECV_ERROR;
        goto out;
      }
    }
  }

  /* SSL should now have started the shutdown from our side. Since it
   * was not complete, we are lacking the close notify from the server. */
  for(i = 0; i < 10; ++i) {
    ret = mbedtls_ssl_read(&backend->ssl, buf, sizeof(buf));
    /* This seems to be a bug in mbedTLS TLSv1.3 where it reports
     * WANT_READ, but has not encountered an EAGAIN. */
    if(ret == MBEDTLS_ERR_SSL_WANT_READ)
      ret = mbedtls_ssl_read(&backend->ssl, buf, sizeof(buf));
#ifdef TLS13_SUPPORT
    if(ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
      continue;
#endif
    if(ret <= 0)
      break;
  }

  if(ret > 0) {
    /* still data coming in? */
    CURL_TRC_CF(data, cf, "mbedtls_shutdown, still getting data");
  }
  else if(ret == 0 || (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)) {
    /* We got the close notify alert and are done. */
    CURL_TRC_CF(data, cf, "mbedtls_shutdown done");
    *done = TRUE;
  }
  else if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
    CURL_TRC_CF(data, cf, "mbedtls_shutdown, need RECV");
    connssl->io_need = CURL_SSL_IO_NEED_RECV;
  }
  else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
    CURL_TRC_CF(data, cf, "mbedtls_shutdown, need SEND");
    connssl->io_need = CURL_SSL_IO_NEED_SEND;
  }
  else {
    CURL_TRC_CF(data, cf, "mbedtls_shutdown error -0x%04X", -ret);
    result = CURLE_RECV_ERROR;
  }

out:
  cf->shutdown = (result || *done);
  return result;
}

static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;


  (void)data;
  DEBUGASSERT(backend);
  if(backend->initialized) {




    mbedtls_pk_free(&backend->pk);
    mbedtls_x509_crt_free(&backend->clicert);
    mbedtls_x509_crt_free(&backend->cacert);
#ifdef MBEDTLS_X509_CRL_PARSE_C
    mbedtls_x509_crl_free(&backend->crl);
#endif
    Curl_safefree(backend->ciphersuites);
    mbedtls_ssl_config_free(&backend->config);
    mbedtls_ssl_free(&backend->ssl);
    mbedtls_ctr_drbg_free(&backend->ctr_drbg);
#ifndef THREADING_SUPPORT
    mbedtls_entropy_free(&backend->entropy);
#endif /* THREADING_SUPPORT */
    backend->initialized = FALSE;
  }
}

static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
                         char *buf, size_t buffersize,
                         CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct mbed_ssl_backend_data *backend =
    (struct mbed_ssl_backend_data *)connssl->backend;
  int ret = -1;
  ssize_t len = -1;

  (void)data;
  DEBUGASSERT(backend);

  ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
                         buffersize);

  if(ret <= 0) {
    CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
                buffersize, -ret);
    if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
      return 0;

    *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
#ifdef TLS13_SUPPORT
              || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
#endif
    ) ? CURLE_AGAIN : CURLE_RECV_ERROR;
    if(*curlcode != CURLE_AGAIN) {
      char errorbuf[128];
      mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
      failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
    }
    return -1;
  }

  len = ret;

  return len;
}
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* Find out how much more time we're allowed */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }
    retcode = mbed_connect_step1(cf, data);
    if(retcode)
      return retcode;
  }

  while(ssl_connect_2 == connssl->connecting_state ||
        ssl_connect_2_reading == connssl->connecting_state ||
        ssl_connect_2_writing == connssl->connecting_state) {

    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it's available. */
    if(connssl->connecting_state == ssl_connect_2_reading
       || connssl->connecting_state == ssl_connect_2_writing) {

      curl_socket_t writefd = ssl_connect_2_writing ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking ? 0 : timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;







|












|
<
<










|
|
<

|
|
|
|







1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501


1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513

1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* Find out how much more time we are allowed */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }
    retcode = mbed_connect_step1(cf, data);
    if(retcode)
      return retcode;
  }

  while(ssl_connect_2 == connssl->connecting_state) {



    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it is available. */
    if(connssl->io_need) {


      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
                              sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
                             sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking ? 0 : timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;
1349
1350
1351
1352
1353
1354
1355

1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
    /* Run transaction, and return to the caller if it failed or if
     * this connection is part of a multi handle and this loop would
     * execute again. This permits the owner of a multi handle to
     * abort a connection attempt before step2 has completed while
     * ensuring that a client using select() or epoll() will always
     * have a valid fdset to wait on.
     */

    retcode = mbed_connect_step2(cf, data);
    if(retcode || (nonblocking &&
                   (ssl_connect_2 == connssl->connecting_state ||
                    ssl_connect_2_reading == connssl->connecting_state ||
                    ssl_connect_2_writing == connssl->connecting_state)))
      return retcode;

  } /* repeat step2 until all transactions are done. */

  if(ssl_connect_3 == connssl->connecting_state) {
    retcode = mbed_connect_step3(cf, data);
    if(retcode)







>

|
|
<
<







1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551


1552
1553
1554
1555
1556
1557
1558
    /* Run transaction, and return to the caller if it failed or if
     * this connection is part of a multi handle and this loop would
     * execute again. This permits the owner of a multi handle to
     * abort a connection attempt before step2 has completed while
     * ensuring that a client using select() or epoll() will always
     * have a valid fdset to wait on.
     */
    connssl->io_need = CURL_SSL_IO_NEED_NONE;
    retcode = mbed_connect_step2(cf, data);
    if(retcode ||
       (nonblocking && (ssl_connect_2 == connssl->connecting_state)))


      return retcode;

  } /* repeat step2 until all transactions are done. */

  if(ssl_connect_3 == connssl->connecting_state) {
    retcode = mbed_connect_step3(cf, data);
    if(retcode)
1470
1471
1472
1473
1474
1475
1476

1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
}

const struct Curl_ssl Curl_ssl_mbedtls = {
  { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */

  SSLSUPP_CA_PATH |
  SSLSUPP_CAINFO_BLOB |

  SSLSUPP_PINNEDPUBKEY |
  SSLSUPP_SSL_CTX |
  SSLSUPP_HTTPS_PROXY,

  sizeof(struct mbed_ssl_backend_data),

  mbedtls_init,                     /* init */
  mbedtls_cleanup,                  /* cleanup */
  mbedtls_version,                  /* version */
  Curl_none_check_cxn,              /* check_cxn */
  Curl_none_shutdown,               /* shutdown */
  mbedtls_data_pending,             /* data_pending */
  mbedtls_random,                   /* random */
  Curl_none_cert_status_request,    /* cert_status_request */
  mbedtls_connect,                  /* connect */
  mbedtls_connect_nonblocking,      /* connect_nonblocking */
  Curl_ssl_adjust_pollset,          /* adjust_pollset */
  mbedtls_get_internals,            /* get_internals */
  mbedtls_close,                    /* close_one */
  mbedtls_close_all,                /* close_all */
  Curl_none_set_engine,             /* set_engine */
  Curl_none_set_engine_default,     /* set_engine_default */
  Curl_none_engines_list,           /* engines_list */
  Curl_none_false_start,            /* false_start */
  mbedtls_sha256sum,                /* sha256sum */
  NULL,                             /* associate_connection */
  NULL,                             /* disassociate_connection */
  NULL,                             /* free_multi_ssl_backend_data */
  mbed_recv,                        /* recv decrypted data */
  mbed_send,                        /* send data to encrypt */
};

#endif /* USE_MBEDTLS */







>










|
















<





1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695

1696
1697
1698
1699
1700
}

const struct Curl_ssl Curl_ssl_mbedtls = {
  { CURLSSLBACKEND_MBEDTLS, "mbedtls" }, /* info */

  SSLSUPP_CA_PATH |
  SSLSUPP_CAINFO_BLOB |
  SSLSUPP_CERTINFO |
  SSLSUPP_PINNEDPUBKEY |
  SSLSUPP_SSL_CTX |
  SSLSUPP_HTTPS_PROXY,

  sizeof(struct mbed_ssl_backend_data),

  mbedtls_init,                     /* init */
  mbedtls_cleanup,                  /* cleanup */
  mbedtls_version,                  /* version */
  Curl_none_check_cxn,              /* check_cxn */
  mbedtls_shutdown,                 /* shutdown */
  mbedtls_data_pending,             /* data_pending */
  mbedtls_random,                   /* random */
  Curl_none_cert_status_request,    /* cert_status_request */
  mbedtls_connect,                  /* connect */
  mbedtls_connect_nonblocking,      /* connect_nonblocking */
  Curl_ssl_adjust_pollset,          /* adjust_pollset */
  mbedtls_get_internals,            /* get_internals */
  mbedtls_close,                    /* close_one */
  mbedtls_close_all,                /* close_all */
  Curl_none_set_engine,             /* set_engine */
  Curl_none_set_engine_default,     /* set_engine_default */
  Curl_none_engines_list,           /* engines_list */
  Curl_none_false_start,            /* false_start */
  mbedtls_sha256sum,                /* sha256sum */
  NULL,                             /* associate_connection */
  NULL,                             /* disassociate_connection */

  mbed_recv,                        /* recv decrypted data */
  mbed_send,                        /* send data to encrypt */
};

#endif /* USE_MBEDTLS */
Changes to jni/curl/lib/vtls/openssl.c.
249
250
251
252
253
254
255







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#else
# if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
#   define OSSL_PACKAGE "quictls"
# else
#   define OSSL_PACKAGE "OpenSSL"
#endif
#endif








#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
/* up2date versions of OpenSSL maintain reasonably secure defaults without
 * breaking compatibility, so it is better not to override the defaults in curl
 */
#define DEFAULT_CIPHER_SELECTION NULL
#else
/* ... but it is not the case with old versions of OpenSSL */
#define DEFAULT_CIPHER_SELECTION \
  "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
#endif

#ifdef HAVE_OPENSSL_SRP
/* the function exists */
#ifdef USE_TLS_SRP







>
>
>
>
>
>
>







|







249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#else
# if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
#   define OSSL_PACKAGE "quictls"
# else
#   define OSSL_PACKAGE "OpenSSL"
#endif
#endif

#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
typedef size_t numcert_t;
#else
typedef int numcert_t;
#endif
#define ossl_valsize_t numcert_t

#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
/* up2date versions of OpenSSL maintain reasonably secure defaults without
 * breaking compatibility, so it is better not to override the defaults in curl
 */
#define DEFAULT_CIPHER_SELECTION NULL
#else
/* not the case with old versions of OpenSSL */
#define DEFAULT_CIPHER_SELECTION \
  "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
#endif

#ifdef HAVE_OPENSSL_SRP
/* the function exists */
#ifdef USE_TLS_SRP
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/* What API version do we use? */
#if defined(LIBRESSL_VERSION_NUMBER)
#define USE_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f)
#else /* !LIBRESSL_VERSION_NUMBER */
#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
#endif /* !LIBRESSL_VERSION_NUMBER */

#if defined(HAVE_SSL_X509_STORE_SHARE)
struct multi_ssl_backend_data {
  char *CAfile;         /* CAfile path used to generate X509 store */
  X509_STORE *store;    /* cached X509 store or NULL if none */
  struct curltime time; /* when the cached store was created */
};
#endif /* HAVE_SSL_X509_STORE_SHARE */

#define push_certinfo(_label, _num)             \
do {                              \
  long info_len = BIO_get_mem_data(mem, &ptr); \
  Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
  if(1 != BIO_reset(mem))                                        \
    break;                                                       \
} while(0)







<
<
<
<
<
<
<
<







310
311
312
313
314
315
316








317
318
319
320
321
322
323
/* What API version do we use? */
#if defined(LIBRESSL_VERSION_NUMBER)
#define USE_PRE_1_1_API (LIBRESSL_VERSION_NUMBER < 0x2070000f)
#else /* !LIBRESSL_VERSION_NUMBER */
#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
#endif /* !LIBRESSL_VERSION_NUMBER */









#define push_certinfo(_label, _num)             \
do {                              \
  long info_len = BIO_get_mem_data(mem, &ptr); \
  Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
  if(1 != BIO_reset(mem))                                        \
    break;                                                       \
} while(0)
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391

  if((int)sk_X509_EXTENSION_num(exts) <= 0)
    /* no extensions, bail out */
    return;

  for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
    ASN1_OBJECT *obj;
    X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
    BUF_MEM *biomem;
    char namebuf[128];
    BIO *bio_out = BIO_new(BIO_s_mem());

    if(!bio_out)
      return;








|







376
377
378
379
380
381
382
383
384
385
386
387
388
389
390

  if((int)sk_X509_EXTENSION_num(exts) <= 0)
    /* no extensions, bail out */
    return;

  for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
    ASN1_OBJECT *obj;
    X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, (ossl_valsize_t)i);
    BUF_MEM *biomem;
    char namebuf[128];
    BIO *bio_out = BIO_new(BIO_s_mem());

    if(!bio_out)
      return;

399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
    BIO_get_mem_ptr(bio_out, &biomem);
    Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data,
                               biomem->length);
    BIO_free(bio_out);
  }
}

#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
typedef size_t numcert_t;
#else
typedef int numcert_t;
#endif

CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
{
  CURLcode result;
  STACK_OF(X509) *sk;
  int i;
  numcert_t numcerts;
  BIO *mem;







<
<
<
<
<
<







398
399
400
401
402
403
404






405
406
407
408
409
410
411
    BIO_get_mem_ptr(bio_out, &biomem);
    Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data,
                               biomem->length);
    BIO_free(bio_out);
  }
}







CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
{
  CURLcode result;
  STACK_OF(X509) *sk;
  int i;
  numcert_t numcerts;
  BIO *mem;
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  mem = BIO_new(BIO_s_mem());
  if(!mem) {
    return CURLE_OUT_OF_MEMORY;
  }

  for(i = 0; i < (int)numcerts; i++) {
    ASN1_INTEGER *num;
    X509 *x = sk_X509_value(sk, i);
    EVP_PKEY *pubkey = NULL;
    int j;
    char *ptr;
    const ASN1_BIT_STRING *psig = NULL;

    X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
    push_certinfo("Subject", i);







|







427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  mem = BIO_new(BIO_s_mem());
  if(!mem) {
    return CURLE_OUT_OF_MEMORY;
  }

  for(i = 0; i < (int)numcerts; i++) {
    ASN1_INTEGER *num;
    X509 *x = sk_X509_value(sk, (ossl_valsize_t)i);
    EVP_PKEY *pubkey = NULL;
    int j;
    char *ptr;
    const ASN1_BIT_STRING *psig = NULL;

    X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
    push_certinfo("Subject", i);
723
724
725
726
727
728
729



730
731
732
733
734
735
736
737
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
  ssize_t nwritten;
  CURLcode result = CURLE_SEND_ERROR;

  DEBUGASSERT(data);



  nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
  CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
              blen, (int)nwritten, result);
  BIO_clear_retry_flags(bio);
  octx->io_result = result;
  if(nwritten < 0) {
    if(CURLE_AGAIN == result)
      BIO_set_retry_write(bio);







>
>
>
|







716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
  ssize_t nwritten;
  CURLcode result = CURLE_SEND_ERROR;

  DEBUGASSERT(data);
  if(blen < 0)
    return 0;

  nwritten = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, &result);
  CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
              blen, (int)nwritten, result);
  BIO_clear_retry_flags(bio);
  octx->io_result = result;
  if(nwritten < 0) {
    if(CURLE_AGAIN == result)
      BIO_set_retry_write(bio);
748
749
750
751
752
753
754


755
756
757
758
759
760
761
762
763
  ssize_t nread;
  CURLcode result = CURLE_RECV_ERROR;

  DEBUGASSERT(data);
  /* OpenSSL catches this case, so should we. */
  if(!buf)
    return 0;



  nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
  CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d",
              blen, (int)nread, result);
  BIO_clear_retry_flags(bio);
  octx->io_result = result;
  if(nread < 0) {
    if(CURLE_AGAIN == result)
      BIO_set_retry_read(bio);







>
>

|







744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
  ssize_t nread;
  CURLcode result = CURLE_RECV_ERROR;

  DEBUGASSERT(data);
  /* OpenSSL catches this case, so should we. */
  if(!buf)
    return 0;
  if(blen < 0)
    return 0;

  nread = Curl_conn_cf_recv(cf->next, data, buf, (size_t)blen, &result);
  CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d",
              blen, (int)nread, result);
  BIO_clear_retry_flags(bio);
  octx->io_result = result;
  if(nread < 0) {
    if(CURLE_AGAIN == result)
      BIO_set_retry_read(bio);
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
  (void)ssl;

  Curl_tls_keylog_write_line(line);
}
#else
/*
 * ossl_log_tls12_secret is called by libcurl to make the CLIENT_RANDOMs if the
 * OpenSSL being used doesn't have native support for doing that.
 */
static void
ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
{
  const SSL_SESSION *session = SSL_get_session(ssl);
  unsigned char client_random[SSL3_RANDOM_SIZE];
  unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
  int master_key_length = 0;

  if(!session || *keylog_done)
    return;

#if OPENSSL_VERSION_NUMBER >= 0x10100000L &&    \
  !(defined(LIBRESSL_VERSION_NUMBER) &&         \
    LIBRESSL_VERSION_NUMBER < 0x20700000L)
  /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
   * we have a valid SSL context if we have a non-NULL session. */
  SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
  master_key_length = (int)
    SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH);
#else
  if(ssl->s3 && session->master_key_length > 0) {
    master_key_length = session->master_key_length;







|















|







838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
  (void)ssl;

  Curl_tls_keylog_write_line(line);
}
#else
/*
 * ossl_log_tls12_secret is called by libcurl to make the CLIENT_RANDOMs if the
 * OpenSSL being used does not have native support for doing that.
 */
static void
ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
{
  const SSL_SESSION *session = SSL_get_session(ssl);
  unsigned char client_random[SSL3_RANDOM_SIZE];
  unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
  int master_key_length = 0;

  if(!session || *keylog_done)
    return;

#if OPENSSL_VERSION_NUMBER >= 0x10100000L &&    \
  !(defined(LIBRESSL_VERSION_NUMBER) &&         \
    LIBRESSL_VERSION_NUMBER < 0x20700000L)
  /* ssl->s3 is not checked in OpenSSL 1.1.0-pre6, but let's assume that
   * we have a valid SSL context if we have a non-NULL session. */
  SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
  master_key_length = (int)
    SSL_SESSION_get_master_key(session, master_key, SSL_MAX_MASTER_KEY_LENGTH);
#else
  if(ssl->s3 && session->master_key_length > 0) {
    master_key_length = session->master_key_length;
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
}

static int passwd_callback(char *buf, int num, int encrypting,
                           void *global_passwd)
{
  DEBUGASSERT(0 == encrypting);

  if(!encrypting) {
    int klen = curlx_uztosi(strlen((char *)global_passwd));
    if(num > klen) {
      memcpy(buf, global_passwd, klen + 1);
      return klen;
    }
  }
  return 0;







|







957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
}

static int passwd_callback(char *buf, int num, int encrypting,
                           void *global_passwd)
{
  DEBUGASSERT(0 == encrypting);

  if(!encrypting && num >= 0) {
    int klen = curlx_uztosi(strlen((char *)global_passwd));
    if(num > klen) {
      memcpy(buf, global_passwd, klen + 1);
      return klen;
    }
  }
  return 0;
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
  do {
    unsigned char randb[64];
    size_t len = sizeof(randb);
    size_t i, i_max;
    for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
      struct curltime tv = Curl_now();
      Curl_wait_ms(1);
      tv.tv_sec *= i + 1;
      tv.tv_usec *= (unsigned int)i + 2;
      tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) *
                    (i + 3)) << 8;
      tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec +
                                     Curl_now().tv_usec) *
                                    (i + 4)) << 16;
      memcpy(&randb[i * sizeof(struct curltime)], &tv,
             sizeof(struct curltime));
    }
    RAND_add(randb, (int)len, (double)len/2);
  } while(!rand_enough());

  {
    /* generates a default path for the random seed file */
    char fname[256];
    fname[0] = 0; /* blank it first */
    RAND_file_name(fname, sizeof(fname));
    if(fname[0]) {
      /* we got a file name to try */
      RAND_load_file(fname, RAND_LOAD_LENGTH);
      if(rand_enough())
        return CURLE_OK;
    }
  }

  infof(data, "libcurl is now using a weak random seed");







|
|
|
|
<
|
|












|







1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018

1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
  do {
    unsigned char randb[64];
    size_t len = sizeof(randb);
    size_t i, i_max;
    for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
      struct curltime tv = Curl_now();
      Curl_wait_ms(1);
      tv.tv_sec *= (time_t)i + 1;
      tv.tv_usec *= (int)i + 2;
      tv.tv_sec ^= ((Curl_now().tv_sec + (time_t)Curl_now().tv_usec) *
                    (time_t)(i + 3)) << 8;

      tv.tv_usec ^= (int) ((Curl_now().tv_sec + (time_t)Curl_now().tv_usec) *
                           (time_t)(i + 4)) << 16;
      memcpy(&randb[i * sizeof(struct curltime)], &tv,
             sizeof(struct curltime));
    }
    RAND_add(randb, (int)len, (double)len/2);
  } while(!rand_enough());

  {
    /* generates a default path for the random seed file */
    char fname[256];
    fname[0] = 0; /* blank it first */
    RAND_file_name(fname, sizeof(fname));
    if(fname[0]) {
      /* we got a filename to try */
      RAND_load_file(fname, RAND_LOAD_LENGTH);
      if(rand_enough())
        return CURLE_OK;
    }
  }

  infof(data, "libcurl is now using a weak random seed");
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
                " '%s' [%s]", cert_file,
                ossl_strerror(ERR_get_error(), error_buffer,
                              sizeof(error_buffer)));
          return 0;
        }

        if(!params.cert) {
          failf(data, "ssl engine didn't initialized the certificate "
                "properly.");
          return 0;
        }

        if(SSL_CTX_use_certificate(ctx, params.cert) != 1) {
          failf(data, "unable to set client certificate [%s]",
                ossl_strerror(ERR_get_error(), error_buffer,
                              sizeof(error_buffer)));
          return 0;
        }
        X509_free(params.cert); /* we don't need the handle any more... */
      }
      else {
        failf(data, "crypto engine not set, can't load certificate");
        return 0;
      }
    }
    break;
#else
    failf(data, "file type ENG for certificate not implemented");
    return 0;







|










|


|







1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
                " '%s' [%s]", cert_file,
                ossl_strerror(ERR_get_error(), error_buffer,
                              sizeof(error_buffer)));
          return 0;
        }

        if(!params.cert) {
          failf(data, "ssl engine did not initialized the certificate "
                "properly.");
          return 0;
        }

        if(SSL_CTX_use_certificate(ctx, params.cert) != 1) {
          failf(data, "unable to set client certificate [%s]",
                ossl_strerror(ERR_get_error(), error_buffer,
                              sizeof(error_buffer)));
          return 0;
        }
        X509_free(params.cert); /* we do not need the handle any more... */
      }
      else {
        failf(data, "crypto engine not set, cannot load certificate");
        return 0;
      }
    }
    break;
#else
    failf(data, "file type ENG for certificate not implemented");
    return 0;
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
      /* Set Certificate Verification chain */
      if(ca) {
        while(sk_X509_num(ca)) {
          /*
           * Note that sk_X509_pop() is used below to make sure the cert is
           * removed from the stack properly before getting passed to
           * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously
           * we used sk_X509_value() instead, but then we'd clean it in the
           * subsequent sk_X509_pop_free() call.
           */
          X509 *x = sk_X509_pop(ca);
          if(!SSL_CTX_add_client_CA(ctx, x)) {
            X509_free(x);
            failf(data, "cannot add certificate to client CA list");
            goto fail;







|







1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
      /* Set Certificate Verification chain */
      if(ca) {
        while(sk_X509_num(ca)) {
          /*
           * Note that sk_X509_pop() is used below to make sure the cert is
           * removed from the stack properly before getting passed to
           * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously
           * we used sk_X509_value() instead, but then we would clean it in the
           * subsequent sk_X509_pop_free() call.
           */
          X509 *x = sk_X509_pop(ca);
          if(!SSL_CTX_add_client_CA(ctx, x)) {
            X509_free(x);
            failf(data, "cannot add certificate to client CA list");
            goto fail;
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
          return 0;
        }
        if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
          failf(data, "unable to set private key");
          EVP_PKEY_free(priv_key);
          return 0;
        }
        EVP_PKEY_free(priv_key);  /* we don't need the handle any more... */
      }
      else {
        failf(data, "crypto engine not set, can't load private key");
        return 0;
      }
    }
    break;
#else
    failf(data, "file type ENG for private key not supported");
    return 0;







|


|







1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
          return 0;
        }
        if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
          failf(data, "unable to set private key");
          EVP_PKEY_free(priv_key);
          return 0;
        }
        EVP_PKEY_free(priv_key);  /* we do not need the handle any more... */
      }
      else {
        failf(data, "crypto engine not set, cannot load private key");
        return 0;
      }
    }
    break;
#else
    failf(data, "file type ENG for private key not supported");
    return 0;
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
      EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl));
      EVP_PKEY_free(pktmp);
    }

#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) &&       \
  !defined(OPENSSL_NO_DEPRECATED_3_0)
    {
      /* If RSA is used, don't check the private key if its flags indicate
       * it doesn't support it. */
      EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
      int pktype;
#ifdef HAVE_OPAQUE_EVP_PKEY
      pktype = EVP_PKEY_id(priv_key);
#else
      pktype = priv_key->type;
#endif







|
|







1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
      EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl));
      EVP_PKEY_free(pktmp);
    }

#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) &&       \
  !defined(OPENSSL_NO_DEPRECATED_3_0)
    {
      /* If RSA is used, do not check the private key if its flags indicate
       * it does not support it. */
      EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
      int pktype;
#ifdef HAVE_OPAQUE_EVP_PKEY
      pktype = EVP_PKEY_id(priv_key);
#else
      pktype = priv_key->type;
#endif
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691

  rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
  BIO_get_mem_ptr(bio_out, &biomem);

  if((size_t)biomem->length < size)
    size = biomem->length;
  else
    size--; /* don't overwrite the buffer end */

  memcpy(buf, biomem->data, size);
  buf[size] = 0;

  BIO_free(bio_out);

  return !rc;







|







1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688

  rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
  BIO_get_mem_ptr(bio_out, &biomem);

  if((size_t)biomem->length < size)
    size = biomem->length;
  else
    size--; /* do not overwrite the buffer end */

  memcpy(buf, biomem->data, size);
  buf[size] = 0;

  BIO_free(bio_out);

  return !rc;
1868
1869
1870
1871
1872
1873
1874










































































































1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
    }
    list = beg;
  }
#endif
  (void) data;
  return list;
}











































































































static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;

  (void)data;
  DEBUGASSERT(octx);

  if(octx->ssl) {
    /* Send the TLS shutdown if we are still connected *and* if
     * the peer did not already close the connection. */
    if(cf->next && cf->next->connected && !connssl->peer_closed) {
      char buf[1024];
      int nread, err;
      long sslerr;

      /* Maybe the server has already sent a close notify alert.
         Read it to avoid an RST on the TCP connection. */
      ERR_clear_error();
      nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
      err = SSL_get_error(octx->ssl, nread);
      if(!nread && err == SSL_ERROR_ZERO_RETURN) {
        CURLcode result;
        ssize_t n;
        size_t blen = sizeof(buf);
        CURL_TRC_CF(data, cf, "peer has shutdown TLS");
        /* SSL_read() will not longer touch the socket, let's receive
         * directly from the next filter to see if the underlying
         * connection has also been closed. */
        n = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
        if(!n) {
          connssl->peer_closed = TRUE;
          CURL_TRC_CF(data, cf, "peer closed connection");
        }
      }
      ERR_clear_error();
      if(connssl->peer_closed) {
        /* As the peer closed, we do not expect it to read anything more we
         * may send. It may be harmful, leading to TCP RST and delaying
         * a lingering close. Just leave. */
        CURL_TRC_CF(data, cf, "not from sending TLS shutdown on "
                    "connection closed by peer");
      }
      else if(SSL_shutdown(octx->ssl) == 1) {
        CURL_TRC_CF(data, cf, "SSL shutdown finished");
      }
      else {
        nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
        err = SSL_get_error(octx->ssl, nread);
        switch(err) {
        case SSL_ERROR_NONE: /* this is not an error */
        case SSL_ERROR_ZERO_RETURN: /* no more data */
          CURL_TRC_CF(data, cf, "SSL shutdown, EOF from server");
          break;
        case SSL_ERROR_WANT_READ:
          /* SSL has send its notify and now wants to read the reply
           * from the server. We are not really interested in that. */
          CURL_TRC_CF(data, cf, "SSL shutdown sent");
          break;
        case SSL_ERROR_WANT_WRITE:
          CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
          break;
        default:
          sslerr = ERR_get_error();
          CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s', errno %d",
                      (sslerr ?
                       ossl_strerror(sslerr, buf, sizeof(buf)) :
                       SSL_ERROR_to_str(err)),
                      SOCKERRNO);
          break;
        }
      }

      ERR_clear_error();
      SSL_set_connect_state(octx->ssl);
    }

    SSL_free(octx->ssl);
    octx->ssl = NULL;
  }
  if(octx->ssl_ctx) {
    SSL_CTX_free(octx->ssl_ctx);
    octx->ssl_ctx = NULL;
    octx->x509_store_setup = FALSE;
  }
  if(octx->bio_method) {
    ossl_bio_cf_method_free(octx->bio_method);
    octx->bio_method = NULL;
  }
}

/*
 * This function is called to shut down the SSL layer but keep the
 * socket open (CCC - Clear Command Channel)
 */
static int ossl_shutdown(struct Curl_cfilter *cf,
                         struct Curl_easy *data)
{
  int retval = 0;
  struct ssl_connect_data *connssl = cf->ctx;
  char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
                    to be at least 256 bytes long. */
  unsigned long sslerror;
  int nread;
  int buffsize;
  int err;
  bool done = FALSE;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  int loop = 10;

  DEBUGASSERT(octx);

#ifndef CURL_DISABLE_FTP
  /* This has only been tested on the proftpd server, and the mod_tls code
     sends a close notify alert without waiting for a close notify alert in
     response. Thus we wait for a close notify alert from the server, but
     we do not send one. Let's hope other servers do the same... */

  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
    (void)SSL_shutdown(octx->ssl);
#endif

  if(octx->ssl) {
    buffsize = (int)sizeof(buf);
    while(!done && loop--) {
      int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
                                 SSL_SHUTDOWN_TIMEOUT);
      if(what > 0) {
        ERR_clear_error();

        /* Something to read, let's do it and hope that it is the close
           notify alert from the server */
        nread = SSL_read(octx->ssl, buf, buffsize);
        err = SSL_get_error(octx->ssl, nread);

        switch(err) {
        case SSL_ERROR_NONE: /* this is not an error */
        case SSL_ERROR_ZERO_RETURN: /* no more data */
          /* This is the expected response. There was no data but only
             the close notify alert */
          done = TRUE;
          break;
        case SSL_ERROR_WANT_READ:
          /* there's data pending, re-invoke SSL_read() */
          infof(data, "SSL_ERROR_WANT_READ");
          break;
        case SSL_ERROR_WANT_WRITE:
          /* SSL wants a write. Really odd. Let's bail out. */
          infof(data, "SSL_ERROR_WANT_WRITE");
          done = TRUE;
          break;
        default:
          /* openssl/ssl.h says "look at error stack/return value/errno" */
          sslerror = ERR_get_error();
          failf(data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d",
                (sslerror ?
                 ossl_strerror(sslerror, buf, sizeof(buf)) :
                 SSL_ERROR_to_str(err)),
                SOCKERRNO);
          done = TRUE;
          break;
        }
      }
      else if(0 == what) {
        /* timeout */
        failf(data, "SSL shutdown timeout");
        done = TRUE;
      }
      else {
        /* anything that gets here is fatally bad */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        retval = -1;
        done = TRUE;
      }
    } /* while()-loop for the select() */

    if(data->set.verbose) {
#ifdef HAVE_SSL_GET_SHUTDOWN
      switch(SSL_get_shutdown(octx->ssl)) {
      case SSL_SENT_SHUTDOWN:
        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN");
        break;
      case SSL_RECEIVED_SHUTDOWN:
        infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN");
        break;
      case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
              "SSL_RECEIVED__SHUTDOWN");
        break;
      }
#endif
    }

    SSL_free(octx->ssl);
    octx->ssl = NULL;
  }
  return retval;
}

static void ossl_session_free(void *sessionid, size_t idsize)
{
  /* free the ID */
  (void)idsize;
  SSL_SESSION_free(sessionid);
}








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987




































































1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001












































































































2002
2003
2004
2005
2006
2007
2008
    }
    list = beg;
  }
#endif
  (void) data;
  return list;
}

static CURLcode ossl_shutdown(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              bool send_shutdown, bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  CURLcode result = CURLE_OK;
  char buf[1024];
  int nread, err;
  unsigned long sslerr;
  size_t i;

  DEBUGASSERT(octx);
  if(!octx->ssl || cf->shutdown) {
    *done = TRUE;
    goto out;
  }

  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  *done = FALSE;
  if(!(SSL_get_shutdown(octx->ssl) & SSL_SENT_SHUTDOWN)) {
    /* We have not started the shutdown from our side yet. Check
     * if the server already sent us one. */
    ERR_clear_error();
    for(i = 0; i < 10; ++i) {
      nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
      CURL_TRC_CF(data, cf, "SSL shutdown not sent, read -> %d", nread);
      if(nread <= 0)
        break;
    }
    err = SSL_get_error(octx->ssl, nread);
    if(!nread && err == SSL_ERROR_ZERO_RETURN) {
      bool input_pending;
      /* Yes, it did. */
      if(!send_shutdown) {
        CURL_TRC_CF(data, cf, "SSL shutdown received, not sending");
        *done = TRUE;
        goto out;
      }
      else if(!cf->next->cft->is_alive(cf->next, data, &input_pending)) {
        /* Server closed the connection after its closy notify. It
         * seems not interested to see our close notify, so do not
         * send it. We are done. */
        connssl->peer_closed = TRUE;
        CURL_TRC_CF(data, cf, "peer closed connection");
        *done = TRUE;
        goto out;
      }
    }
    if(send_shutdown && SSL_shutdown(octx->ssl) == 1) {
      CURL_TRC_CF(data, cf, "SSL shutdown finished");
      *done = TRUE;
      goto out;
    }
  }

  /* SSL should now have started the shutdown from our side. Since it
   * was not complete, we are lacking the close notify from the server. */
  for(i = 0; i < 10; ++i) {
    ERR_clear_error();
    nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
    CURL_TRC_CF(data, cf, "SSL shutdown read -> %d", nread);
    if(nread <= 0)
      break;
  }
  if(SSL_get_shutdown(octx->ssl) & SSL_RECEIVED_SHUTDOWN) {
    CURL_TRC_CF(data, cf, "SSL shutdown received, finished");
    *done = TRUE;
    goto out;
  }
  err = SSL_get_error(octx->ssl, nread);
  switch(err) {
  case SSL_ERROR_ZERO_RETURN: /* no more data */
    CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed");
    *done = TRUE;
    break;
  case SSL_ERROR_NONE: /* just did not get anything */
  case SSL_ERROR_WANT_READ:
    /* SSL has send its notify and now wants to read the reply
     * from the server. We are not really interested in that. */
    CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
    connssl->io_need = CURL_SSL_IO_NEED_RECV;
    break;
  case SSL_ERROR_WANT_WRITE:
    CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
    connssl->io_need = CURL_SSL_IO_NEED_SEND;
    break;
  default:
    /* Server seems to have closed the connection without sending us
     * a close notify. */
    sslerr = ERR_get_error();
    CURL_TRC_CF(data, cf, "SSL shutdown, ignore recv error: '%s', errno %d",
                (sslerr ?
                 ossl_strerror(sslerr, buf, sizeof(buf)) :
                 SSL_ERROR_to_str(err)),
                SOCKERRNO);
    *done = TRUE;
    result = CURLE_OK;
    break;
  }

out:
  cf->shutdown = (result || *done);
  return result;
}

static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;

  (void)data;
  DEBUGASSERT(octx);

  if(octx->ssl) {




































































    SSL_free(octx->ssl);
    octx->ssl = NULL;
  }
  if(octx->ssl_ctx) {
    SSL_CTX_free(octx->ssl_ctx);
    octx->ssl_ctx = NULL;
    octx->x509_store_setup = FALSE;
  }
  if(octx->bio_method) {
    ossl_bio_cf_method_free(octx->bio_method);
    octx->bio_method = NULL;
  }
}













































































































static void ossl_session_free(void *sessionid, size_t idsize)
{
  /* free the ID */
  (void)idsize;
  SSL_SESSION_free(sessionid);
}

2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
  ERR_remove_thread_state(NULL);
#endif
}

/* ====================================================== */

/*
 * Match subjectAltName against the host name.
 */
static bool subj_alt_hostcheck(struct Curl_easy *data,
                               const char *match_pattern,
                               size_t matchlen,
                               const char *hostname,
                               size_t hostlen,
                               const char *dispname)







|







2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
  ERR_remove_thread_state(NULL);
#endif
}

/* ====================================================== */

/*
 * Match subjectAltName against the hostname.
 */
static bool subj_alt_hostcheck(struct Curl_easy *data,
                               const char *match_pattern,
                               size_t matchlen,
                               const char *hostname,
                               size_t hostlen,
                               const char *dispname)
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
   If a subjectAltName extension of type dNSName is present, that MUST
   be used as the identity. Otherwise, the (most specific) Common Name
   field in the Subject field of the certificate MUST be used. Although
   the use of the Common Name is existing practice, it is deprecated and
   Certification Authorities are encouraged to use the dNSName instead.

   Matching is performed using the matching rules specified by
   [RFC2459].  If more than one identity of a given type is present in
   the certificate (e.g., more than one dNSName name, a match in any one
   of the set is considered acceptable.) Names may contain the wildcard
   character * which is considered to match any single domain name
   component or component fragment. E.g., *.a.com matches foo.a.com but
   not bar.foo.a.com. f*.com matches foo.com but not bar.com.

   In some cases, the URI is specified as an IP address rather than a







|







2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
   If a subjectAltName extension of type dNSName is present, that MUST
   be used as the identity. Otherwise, the (most specific) Common Name
   field in the Subject field of the certificate MUST be used. Although
   the use of the Common Name is existing practice, it is deprecated and
   Certification Authorities are encouraged to use the dNSName instead.

   Matching is performed using the matching rules specified by
   [RFC2459]. If more than one identity of a given type is present in
   the certificate (e.g., more than one dNSName name, a match in any one
   of the set is considered acceptable.) Names may contain the wildcard
   character * which is considered to match any single domain name
   component or component fragment. E.g., *.a.com matches foo.a.com but
   not bar.foo.a.com. f*.com matches foo.com but not bar.com.

   In some cases, the URI is specified as an IP address rather than a
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
    int numalts;
    int i;
#endif
    bool dnsmatched = FALSE;
    bool ipmatched = FALSE;

    /* get amount of alternatives, RFC2459 claims there MUST be at least
       one, but we don't depend on it... */
    numalts = sk_GENERAL_NAME_num(altnames);

    /* loop through all alternatives - until a dnsmatch */
    for(i = 0; (i < numalts) && !dnsmatched; i++) {
      /* get a handle to alternative name number i */
      const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);

      if(check->type == GEN_DNS)
        dNSName = TRUE;
      else if(check->type == GEN_IPADD)
        iPAddress = TRUE;

      /* only check alternatives of the same type the target is */
      if(check->type == target) {
        /* get data and length */
        const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5);
        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);

        switch(target) {
        case GEN_DNS: /* name/pattern comparison */
          /* The OpenSSL man page explicitly says: "In general it cannot be
             assumed that the data returned by ASN1_STRING_data() is null
             terminated or does not contain embedded nulls." But also that
             "The actual format of the data will depend on the actual string
             type itself: for example for an IA5String the data will be ASCII"

             It has been however verified that in 0.9.6 and 0.9.7, IA5String
             is always null-terminated.
          */
          if((altlen == strlen(altptr)) &&
             /* if this isn't true, there was an embedded zero in the name
                string and we cannot match it. */
             subj_alt_hostcheck(data, altptr, altlen,
                                peer->hostname, hostlen,
                                peer->dispname)) {
            dnsmatched = TRUE;
          }
          break;







|




















|









|







2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
    int numalts;
    int i;
#endif
    bool dnsmatched = FALSE;
    bool ipmatched = FALSE;

    /* get amount of alternatives, RFC2459 claims there MUST be at least
       one, but we do not depend on it... */
    numalts = sk_GENERAL_NAME_num(altnames);

    /* loop through all alternatives - until a dnsmatch */
    for(i = 0; (i < numalts) && !dnsmatched; i++) {
      /* get a handle to alternative name number i */
      const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);

      if(check->type == GEN_DNS)
        dNSName = TRUE;
      else if(check->type == GEN_IPADD)
        iPAddress = TRUE;

      /* only check alternatives of the same type the target is */
      if(check->type == target) {
        /* get data and length */
        const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5);
        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);

        switch(target) {
        case GEN_DNS: /* name/pattern comparison */
          /* The OpenSSL manpage explicitly says: "In general it cannot be
             assumed that the data returned by ASN1_STRING_data() is null
             terminated or does not contain embedded nulls." But also that
             "The actual format of the data will depend on the actual string
             type itself: for example for an IA5String the data will be ASCII"

             It has been however verified that in 0.9.6 and 0.9.7, IA5String
             is always null-terminated.
          */
          if((altlen == strlen(altptr)) &&
             /* if this is not true, there was an embedded zero in the name
                string and we cannot match it. */
             subj_alt_hostcheck(data, altptr, altlen,
                                peer->hostname, hostlen,
                                peer->dispname)) {
            dnsmatched = TRUE;
          }
          break;
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
      matched = TRUE;
  }

  if(matched)
    /* an alternative name matched */
    ;
  else if(dNSName || iPAddress) {
    const char *tname = (peer->type == CURL_SSL_PEER_DNS) ? "host name" :
                        (peer->type == CURL_SSL_PEER_IPV4) ?
                        "ipv4 address" : "ipv6 address";
    infof(data, " subjectAltName does not match %s %s", tname, peer->dispname);
    failf(data, "SSL: no alternative certificate subject name matches "
          "target %s '%s'", tname, peer->dispname);
    result = CURLE_PEER_FAILED_VERIFICATION;
  }







|







2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
      matched = TRUE;
  }

  if(matched)
    /* an alternative name matched */
    ;
  else if(dNSName || iPAddress) {
    const char *tname = (peer->type == CURL_SSL_PEER_DNS) ? "hostname" :
                        (peer->type == CURL_SSL_PEER_IPV4) ?
                        "ipv4 address" : "ipv6 address";
    infof(data, " subjectAltName does not match %s %s", tname, peer->dispname);
    failf(data, "SSL: no alternative certificate subject name matches "
          "target %s '%s'", tname, peer->dispname);
    result = CURLE_PEER_FAILED_VERIFICATION;
  }
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361

2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383

2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
      failf(data,
            "SSL: unable to obtain common name from peer certificate");
      result = CURLE_PEER_FAILED_VERIFICATION;
    }
    else if(!Curl_cert_hostcheck((const char *)peer_CN,
                                 peerlen, peer->hostname, hostlen)) {
      failf(data, "SSL: certificate subject name '%s' does not match "
            "target host name '%s'", peer_CN, peer->dispname);
      result = CURLE_PEER_FAILED_VERIFICATION;
    }
    else {
      infof(data, " common name: %s (matched)", peer_CN);
    }
    if(peer_CN)
      OPENSSL_free(peer_CN);
  }

  return result;
}

#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
  !defined(OPENSSL_NO_OCSP)
static CURLcode verifystatus(struct Curl_cfilter *cf,
                             struct Curl_easy *data)

{
  struct ssl_connect_data *connssl = cf->ctx;
  int i, ocsp_status;
#if defined(OPENSSL_IS_AWSLC)
  const uint8_t *status;
#else
  unsigned char *status;
#endif
  const unsigned char *p;
  CURLcode result = CURLE_OK;
  OCSP_RESPONSE *rsp = NULL;
  OCSP_BASICRESP *br = NULL;
  X509_STORE     *st = NULL;
  STACK_OF(X509) *ch = NULL;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  X509 *cert;
  OCSP_CERTID *id = NULL;
  int cert_status, crl_reason;
  ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
  int ret;
  long len;


  DEBUGASSERT(octx);

  len = SSL_get_tlsext_status_ocsp_resp(octx->ssl, &status);

  if(!status) {
    failf(data, "No OCSP response received");
    result = CURLE_SSL_INVALIDCERTSTATUS;
    goto end;
  }
  p = status;







|















|
>

<












<







>


|







2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290

2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302

2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
      failf(data,
            "SSL: unable to obtain common name from peer certificate");
      result = CURLE_PEER_FAILED_VERIFICATION;
    }
    else if(!Curl_cert_hostcheck((const char *)peer_CN,
                                 peerlen, peer->hostname, hostlen)) {
      failf(data, "SSL: certificate subject name '%s' does not match "
            "target hostname '%s'", peer_CN, peer->dispname);
      result = CURLE_PEER_FAILED_VERIFICATION;
    }
    else {
      infof(data, " common name: %s (matched)", peer_CN);
    }
    if(peer_CN)
      OPENSSL_free(peer_CN);
  }

  return result;
}

#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
  !defined(OPENSSL_NO_OCSP)
static CURLcode verifystatus(struct Curl_cfilter *cf,
                             struct Curl_easy *data,
                             struct ossl_ctx *octx)
{

  int i, ocsp_status;
#if defined(OPENSSL_IS_AWSLC)
  const uint8_t *status;
#else
  unsigned char *status;
#endif
  const unsigned char *p;
  CURLcode result = CURLE_OK;
  OCSP_RESPONSE *rsp = NULL;
  OCSP_BASICRESP *br = NULL;
  X509_STORE     *st = NULL;
  STACK_OF(X509) *ch = NULL;

  X509 *cert;
  OCSP_CERTID *id = NULL;
  int cert_status, crl_reason;
  ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
  int ret;
  long len;

  (void)cf;
  DEBUGASSERT(octx);

  len = (long)SSL_get_tlsext_status_ocsp_resp(octx->ssl, &status);

  if(!status) {
    failf(data, "No OCSP response received");
    result = CURLE_SSL_INVALIDCERTSTATUS;
    goto end;
  }
  p = status;
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
  }
  st = SSL_CTX_get_cert_store(octx->ssl_ctx);

#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
     (defined(LIBRESSL_VERSION_NUMBER) &&                               \
      LIBRESSL_VERSION_NUMBER <= 0x2040200fL))
  /* The authorized responder cert in the OCSP response MUST be signed by the
     peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert,
     no problem, but if it's an intermediate cert OpenSSL has a bug where it
     expects this issuer to be present in the chain embedded in the OCSP
     response. So we add it if necessary. */

  /* First make sure the peer cert chain includes both a peer and an issuer,
     and the OCSP response contains a responder cert. */
  if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) {
    X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1);







|
|







2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
  }
  st = SSL_CTX_get_cert_store(octx->ssl_ctx);

#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
     (defined(LIBRESSL_VERSION_NUMBER) &&                               \
      LIBRESSL_VERSION_NUMBER <= 0x2040200fL))
  /* The authorized responder cert in the OCSP response MUST be signed by the
     peer cert's issuer (see RFC6960 section 4.2.2.2). If that is a root cert,
     no problem, but if it is an intermediate cert OpenSSL has a bug where it
     expects this issuer to be present in the chain embedded in the OCSP
     response. So we add it if necessary. */

  /* First make sure the peer cert chain includes both a peer and an issuer,
     and the OCSP response contains a responder cert. */
  if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) {
    X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1);
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
  if(!cert) {
    failf(data, "Error getting peer certificate");
    result = CURLE_SSL_INVALIDCERTSTATUS;
    goto end;
  }

  for(i = 0; i < (int)sk_X509_num(ch); i++) {
    X509 *issuer = sk_X509_value(ch, i);
    if(X509_check_issued(issuer, cert) == X509_V_OK) {
      id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
      break;
    }
  }
  X509_free(cert);








|







2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
  if(!cert) {
    failf(data, "Error getting peer certificate");
    result = CURLE_SSL_INVALIDCERTSTATUS;
    goto end;
  }

  for(i = 0; i < (int)sk_X509_num(ch); i++) {
    X509 *issuer = sk_X509_value(ch, (ossl_valsize_t)i);
    if(X509_check_issued(issuer, cert) == X509_V_OK) {
      id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
      break;
    }
  }
  X509_free(cert);

2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535

  return result;
}
#endif

#endif /* USE_OPENSSL */

/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
   and thus this cannot be done there. */
#ifdef SSL_CTRL_SET_MSG_CALLBACK

static const char *ssl_msg_type(int ssl_ver, int msg)
{
#ifdef SSL2_VERSION_MAJOR
  if(ssl_ver == SSL2_VERSION_MAJOR) {







|







2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462

  return result;
}
#endif

#endif /* USE_OPENSSL */

/* The SSL_CTRL_SET_MSG_CALLBACK does not exist in ancient OpenSSL versions
   and thus this cannot be done there. */
#ifdef SSL_CTRL_SET_MSG_CALLBACK

static const char *ssl_msg_type(int ssl_ver, int msg)
{
#ifdef SSL2_VERSION_MAJOR
  if(ssl_ver == SSL2_VERSION_MAJOR) {
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
    char ssl_buf[1024];
    int msg_type, txt_len;

    /* the info given when the version is zero is not that useful for us */

    ssl_ver >>= 8; /* check the upper 8 bits only below */

    /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
     * always pass-up content-type as 0. But the interesting message-type
     * is at 'buf[0]'.
     */
    if(ssl_ver == SSL3_VERSION_MAJOR && content_type)
      tls_rt_name = tls_rt_type(content_type);
    else
      tls_rt_name = "";







|







2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
    char ssl_buf[1024];
    int msg_type, txt_len;

    /* the info given when the version is zero is not that useful for us */

    ssl_ver >>= 8; /* check the upper 8 bits only below */

    /* SSLv2 does not seem to have TLS record-type headers, so OpenSSL
     * always pass-up content-type as 0. But the interesting message-type
     * is at 'buf[0]'.
     */
    if(ssl_ver == SSL3_VERSION_MAJOR && content_type)
      tls_rt_name = tls_rt_type(content_type);
    else
      tls_rt_name = "";
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
    break;
#else
    return CURLE_NOT_BUILT_IN;
#endif
  }

  /* CURL_SSLVERSION_DEFAULT means that no option was selected.
     We don't want to pass 0 to SSL_CTX_set_min_proto_version as
     it would enable all versions down to the lowest supported by
     the library.
     So we skip this, and stay with the library default
  */
  if(curl_ssl_version_min != CURL_SSLVERSION_DEFAULT) {
    if(!SSL_CTX_set_min_proto_version(ctx, ossl_ssl_version_min)) {
      return CURLE_SSL_CONNECT_ERROR;
    }
  }

  /* ... then, TLS max version */
  curl_ssl_version_max = conn_config->version_max;

  /* convert curl max SSL version option to OpenSSL constant */
  switch(curl_ssl_version_max) {
  case CURL_SSLVERSION_MAX_TLSv1_0:
    ossl_ssl_version_max = TLS1_VERSION;
    break;
  case CURL_SSLVERSION_MAX_TLSv1_1:







|











|







2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
    break;
#else
    return CURLE_NOT_BUILT_IN;
#endif
  }

  /* CURL_SSLVERSION_DEFAULT means that no option was selected.
     We do not want to pass 0 to SSL_CTX_set_min_proto_version as
     it would enable all versions down to the lowest supported by
     the library.
     So we skip this, and stay with the library default
  */
  if(curl_ssl_version_min != CURL_SSLVERSION_DEFAULT) {
    if(!SSL_CTX_set_min_proto_version(ctx, ossl_ssl_version_min)) {
      return CURLE_SSL_CONNECT_ERROR;
    }
  }

  /* ... then, TLS max version */
  curl_ssl_version_max = (long)conn_config->version_max;

  /* convert curl max SSL version option to OpenSSL constant */
  switch(curl_ssl_version_max) {
  case CURL_SSLVERSION_MAX_TLSv1_0:
    ossl_ssl_version_max = TLS1_VERSION;
    break;
  case CURL_SSLVERSION_MAX_TLSv1_1:
2846
2847
2848
2849
2850
2851
2852



2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
}
#endif

#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
typedef uint32_t ctx_option_t;
#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
typedef uint64_t ctx_option_t;



#else
typedef long ctx_option_t;
#endif

#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */
static CURLcode
ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
                                       struct Curl_cfilter *cf,
                                       struct Curl_easy *data)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  long ssl_version = conn_config->version;
  long ssl_version_max = conn_config->version_max;

  (void) data; /* In case it's unused. */

  switch(ssl_version) {
  case CURL_SSLVERSION_TLSv1_3:
#ifdef TLS1_3_VERSION
  {
    struct ssl_connect_data *connssl = cf->ctx;
    struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;







>
>
>







|
|





|







2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
}
#endif

#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
typedef uint32_t ctx_option_t;
#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
typedef uint64_t ctx_option_t;
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L && \
  !defined(LIBRESSL_VERSION_NUMBER)
typedef unsigned long ctx_option_t;
#else
typedef long ctx_option_t;
#endif

#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */
static CURLcode
ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
                                    struct Curl_cfilter *cf,
                                    struct Curl_easy *data)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  long ssl_version = conn_config->version;
  long ssl_version_max = conn_config->version_max;

  (void) data; /* In case it is unused. */

  switch(ssl_version) {
  case CURL_SSLVERSION_TLSv1_3:
#ifdef TLS1_3_VERSION
  {
    struct ssl_connect_data *connssl = cf->ctx;
    struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982

CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               const struct ssl_peer *peer,
                               SSL_SESSION *session)
{
  const struct ssl_config_data *config;
  bool isproxy;
  bool added = FALSE;

  if(!cf || !data)
    goto out;

  isproxy = Curl_ssl_cf_is_proxy(cf);

  config = Curl_ssl_cf_get_config(cf, data);
  if(config->primary.sessionid) {
    bool incache;
    void *old_session = NULL;

    Curl_ssl_sessionid_lock(data);
    if(isproxy)
      incache = FALSE;
    else
      incache = !(Curl_ssl_getsessionid(cf, data, peer,
                                        &old_session, NULL));
    if(incache && (old_session != session)) {
      infof(data, "old SSL session ID is stale, removing");
      Curl_ssl_delsessionid(data, old_session);
      incache = FALSE;
    }

    if(!incache) {
      added = TRUE;
      Curl_ssl_addsessionid(cf, data, peer, session, 0, ossl_session_free);
    }
    Curl_ssl_sessionid_unlock(data);
  }

out:
  if(!added)
    ossl_session_free(session, 0);
  return CURLE_OK;
}

/* The "new session" callback must return zero if the session can be removed
 * or non-zero if the session has been put into the session cache.
 */
static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
{







|
<




<
<

|
<
<


<
<
<
|
|
<
<
<
<
<
|
<
<
<
<




|

|







2863
2864
2865
2866
2867
2868
2869
2870

2871
2872
2873
2874


2875
2876


2877
2878



2879
2880





2881




2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895

CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               const struct ssl_peer *peer,
                               SSL_SESSION *session)
{
  const struct ssl_config_data *config;
  CURLcode result = CURLE_OK;


  if(!cf || !data)
    goto out;



  config = Curl_ssl_cf_get_config(cf, data);
  if(config->primary.cache_session) {



    Curl_ssl_sessionid_lock(data);



    result = Curl_ssl_set_sessionid(cf, data, peer, session, 0,
                                    ossl_session_free);





    session = NULL; /* call has taken ownership */




    Curl_ssl_sessionid_unlock(data);
  }

out:
  if(session)
    ossl_session_free(session, 0);
  return result;
}

/* The "new session" callback must return zero if the session can be removed
 * or non-zero if the session has been put into the session cache.
 */
static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
{
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
  if(!inf) {
    BIO_free(cbio);
    return CURLE_SSL_CACERT_BADFILE;
  }

  /* add each entry from PEM file to x509_store */
  for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
    itmp = sk_X509_INFO_value(inf, i);
    if(itmp->x509) {
      if(X509_STORE_add_cert(store, itmp->x509)) {
        ++count;
      }
      else {
        /* set count to 0 to return an error */
        count = 0;







|







2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
  if(!inf) {
    BIO_free(cbio);
    return CURLE_SSL_CACERT_BADFILE;
  }

  /* add each entry from PEM file to x509_store */
  for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
    itmp = sk_X509_INFO_value(inf, (ossl_valsize_t)i);
    if(itmp->x509) {
      if(X509_STORE_add_cert(store, itmp->x509)) {
        ++count;
      }
      else {
        /* set count to 0 to return an error */
        count = 0;
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
      }
    }
  }

  sk_X509_INFO_pop_free(inf, X509_INFO_free);
  BIO_free(cbio);

  /* if we didn't end up importing anything, treat that as an error */
  return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE;
}

#if defined(USE_WIN32_CRYPTO)
static CURLcode import_windows_cert_store(struct Curl_easy *data,
                                          const char *name,
                                          X509_STORE *store,







|







2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
      }
    }
  }

  sk_X509_INFO_pop_free(inf, X509_INFO_free);
  BIO_free(cbio);

  /* if we did not end up importing anything, treat that as an error */
  return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE;
}

#if defined(USE_WIN32_CRYPTO)
static CURLcode import_windows_cert_store(struct Curl_easy *data,
                                          const char *name,
                                          X509_STORE *store,
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
        }
        else
          continue;
      }
      else
        continue;

      x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
      if(!x509)
        continue;

      /* Try to import the certificate. This may fail for legitimate
         reasons such as duplicate certificate, which is allowed by MS but
         not OpenSSL. */
      if(X509_STORE_add_cert(store, x509) == 1) {







|







3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
        }
        else
          continue;
      }
      else
        continue;

      x509 = d2i_X509(NULL, &encoded_cert, (long)pContext->cbCertEncoded);
      if(!x509)
        continue;

      /* Try to import the certificate. This may fail for legitimate
         reasons such as duplicate certificate, which is allowed by MS but
         not OpenSSL. */
      if(X509_STORE_add_cert(store, x509) == 1) {
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
      infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
      infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
    }

#ifdef CURL_CA_FALLBACK
    if(!ssl_cafile && !ssl_capath &&
       !imported_native_ca && !imported_ca_info_blob) {
      /* verifying the peer without any CA certificates won't
         work so use openssl's built-in default as fallback */
      X509_STORE_set_default_paths(store);
    }
#endif
  }

  if(ssl_crlfile) {
    /* tell OpenSSL where to find CRL file that is used to check certificate







|
|







3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
      infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
      infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
    }

#ifdef CURL_CA_FALLBACK
    if(!ssl_cafile && !ssl_capath &&
       !imported_native_ca && !imported_ca_info_blob) {
      /* verifying the peer without any CA certificates will not
         work so use OpenSSL's built-in default as fallback */
      X509_STORE_set_default_paths(store);
    }
#endif
  }

  if(ssl_crlfile) {
    /* tell OpenSSL where to find CRL file that is used to check certificate
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
                         X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);

    infof(data, "  CRLfile: %s", ssl_crlfile);
  }

  if(verifypeer) {
    /* Try building a chain using issuers in the trusted store first to avoid
       problems with server-sent legacy intermediates.  Newer versions of
       OpenSSL do alternate chain checking by default but we do not know how to
       determine that in a reliable manner.
       https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
    */
#if defined(X509_V_FLAG_TRUSTED_FIRST)
    X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
#endif







|







3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
                         X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);

    infof(data, "  CRLfile: %s", ssl_crlfile);
  }

  if(verifypeer) {
    /* Try building a chain using issuers in the trusted store first to avoid
       problems with server-sent legacy intermediates. Newer versions of
       OpenSSL do alternate chain checking by default but we do not know how to
       determine that in a reliable manner.
       https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
    */
#if defined(X509_V_FLAG_TRUSTED_FIRST)
    X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
#endif
3351
3352
3353
3354
3355
3356
3357

























3358
3359
3360
3361



3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386

3387
3388
3389
3390
3391

3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411



3412
3413
3414


3415




3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
#endif
  }

  return result;
}

#if defined(HAVE_SSL_X509_STORE_SHARE)

























static bool cached_x509_store_expired(const struct Curl_easy *data,
                                      const struct multi_ssl_backend_data *mb)
{
  const struct ssl_general_config *cfg = &data->set.general_ssl;



  struct curltime now = Curl_now();
  timediff_t elapsed_ms = Curl_timediff(now, mb->time);
  timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;

  if(timeout_ms < 0)
    return false;

  return elapsed_ms >= timeout_ms;
}

static bool cached_x509_store_different(
  struct Curl_cfilter *cf,
  const struct multi_ssl_backend_data *mb)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  if(!mb->CAfile || !conn_config->CAfile)
    return mb->CAfile != conn_config->CAfile;

  return strcmp(mb->CAfile, conn_config->CAfile);
}

static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
                                         const struct Curl_easy *data)
{
  struct Curl_multi *multi = data->multi;

  X509_STORE *store = NULL;

  DEBUGASSERT(multi);
  if(multi &&
     multi->ssl_backend_data &&

     multi->ssl_backend_data->store &&
     !cached_x509_store_expired(data, multi->ssl_backend_data) &&
     !cached_x509_store_different(cf, multi->ssl_backend_data)) {
    store = multi->ssl_backend_data->store;
  }

  return store;
}

static void set_cached_x509_store(struct Curl_cfilter *cf,
                                  const struct Curl_easy *data,
                                  X509_STORE *store)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct Curl_multi *multi = data->multi;
  struct multi_ssl_backend_data *mbackend;

  DEBUGASSERT(multi);
  if(!multi)
    return;




  if(!multi->ssl_backend_data) {
    multi->ssl_backend_data = calloc(1, sizeof(struct multi_ssl_backend_data));


    if(!multi->ssl_backend_data)




      return;
  }

  mbackend = multi->ssl_backend_data;

  if(X509_STORE_up_ref(store)) {
    char *CAfile = NULL;

    if(conn_config->CAfile) {
      CAfile = strdup(conn_config->CAfile);
      if(!CAfile) {
        X509_STORE_free(store);
        return;
      }
    }

    if(mbackend->store) {
      X509_STORE_free(mbackend->store);
      free(mbackend->CAfile);
    }

    mbackend->time = Curl_now();
    mbackend->store = store;
    mbackend->CAfile = CAfile;
  }
}

CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   SSL_CTX *ssl_ctx)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  CURLcode result = CURLE_OK;
  X509_STORE *cached_store;
  bool cache_criteria_met;

  /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
     or no source is provided and we are falling back to openssl's built-in
     default. */
  cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
    conn_config->verifypeer &&
    !conn_config->CApath &&
    !conn_config->ca_info_blob &&
    !ssl_config->primary.CRLfile &&
    !ssl_config->native_ca_store;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|


>
>
>
|
|
|

<
|
|
<


|
|
|












>



|
|
>
|
|
|
|











|




>
>
>

|
|
>
>
|
>
>
>
>

|
|
<












|
|
|


|
|
|














|







3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306

3307
3308

3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368

3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
#endif
  }

  return result;
}

#if defined(HAVE_SSL_X509_STORE_SHARE)

/* key to use at `multi->proto_hash` */
#define MPROTO_OSSL_X509_KEY   "tls:ossl:x509:share"

struct ossl_x509_share {
  char *CAfile;         /* CAfile path used to generate X509 store */
  X509_STORE *store;    /* cached X509 store or NULL if none */
  struct curltime time; /* when the cached store was created */
};

static void oss_x509_share_free(void *key, size_t key_len, void *p)
{
  struct ossl_x509_share *share = p;
  DEBUGASSERT(key_len == (sizeof(MPROTO_OSSL_X509_KEY)-1));
  DEBUGASSERT(!memcmp(MPROTO_OSSL_X509_KEY, key, key_len));
  (void)key;
  (void)key_len;
  if(share->store) {
    X509_STORE_free(share->store);
  }
  free(share->CAfile);
  free(share);
}

static bool
cached_x509_store_expired(const struct Curl_easy *data,
                          const struct ossl_x509_share *mb)
{
  const struct ssl_general_config *cfg = &data->set.general_ssl;
  if(cfg->ca_cache_timeout < 0)
    return FALSE;
  else {
    struct curltime now = Curl_now();
    timediff_t elapsed_ms = Curl_timediff(now, mb->time);
    timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;


    return elapsed_ms >= timeout_ms;
  }

}

static bool
cached_x509_store_different(struct Curl_cfilter *cf,
                            const struct ossl_x509_share *mb)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  if(!mb->CAfile || !conn_config->CAfile)
    return mb->CAfile != conn_config->CAfile;

  return strcmp(mb->CAfile, conn_config->CAfile);
}

static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
                                         const struct Curl_easy *data)
{
  struct Curl_multi *multi = data->multi;
  struct ossl_x509_share *share;
  X509_STORE *store = NULL;

  DEBUGASSERT(multi);
  share = multi? Curl_hash_pick(&multi->proto_hash,
                                (void *)MPROTO_OSSL_X509_KEY,
                                sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
  if(share && share->store &&
     !cached_x509_store_expired(data, share) &&
     !cached_x509_store_different(cf, share)) {
    store = share->store;
  }

  return store;
}

static void set_cached_x509_store(struct Curl_cfilter *cf,
                                  const struct Curl_easy *data,
                                  X509_STORE *store)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct Curl_multi *multi = data->multi;
  struct ossl_x509_share *share;

  DEBUGASSERT(multi);
  if(!multi)
    return;
  share = Curl_hash_pick(&multi->proto_hash,
                         (void *)MPROTO_OSSL_X509_KEY,
                         sizeof(MPROTO_OSSL_X509_KEY)-1);

  if(!share) {
    share = calloc(1, sizeof(*share));
    if(!share)
      return;
    if(!Curl_hash_add2(&multi->proto_hash,
                       (void *)MPROTO_OSSL_X509_KEY,
                       sizeof(MPROTO_OSSL_X509_KEY)-1,
                       share, oss_x509_share_free)) {
      free(share);
      return;
    }
  }


  if(X509_STORE_up_ref(store)) {
    char *CAfile = NULL;

    if(conn_config->CAfile) {
      CAfile = strdup(conn_config->CAfile);
      if(!CAfile) {
        X509_STORE_free(store);
        return;
      }
    }

    if(share->store) {
      X509_STORE_free(share->store);
      free(share->CAfile);
    }

    share->time = Curl_now();
    share->store = store;
    share->CAfile = CAfile;
  }
}

CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   SSL_CTX *ssl_ctx)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  CURLcode result = CURLE_OK;
  X509_STORE *cached_store;
  bool cache_criteria_met;

  /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
     or no source is provided and we are falling back to OpenSSL's built-in
     default. */
  cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
    conn_config->verifypeer &&
    !conn_config->CApath &&
    !conn_config->ca_info_blob &&
    !ssl_config->primary.CRLfile &&
    !ssl_config->native_ca_store;
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
  CURLcode result = CURLE_OK;
  const char *ciphers;
  SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
  ctx_option_t ctx_options = 0;
  void *ssl_sessionid = NULL;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  const long int ssl_version = conn_config->version;
  char * const ssl_cert = ssl_config->primary.clientcert;
  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
  const char * const ssl_cert_type = ssl_config->cert_type;
  const bool verifypeer = conn_config->verifypeer;
  char error_buffer[256];
#ifdef USE_ECH
  struct ssl_connect_data *connssl = cf->ctx;
#endif

  /* Make funny stuff to get random input */
  result = ossl_seed(data);
  if(result)
    return result;

  ssl_config->certverifyresult = !X509_V_OK;

  switch(transport) {
  case TRNSPRT_TCP:
    /* check to see if we've been told to use an explicit SSL/TLS version */
    switch(ssl_version) {
    case CURL_SSLVERSION_DEFAULT:
    case CURL_SSLVERSION_TLSv1:
    case CURL_SSLVERSION_TLSv1_0:
    case CURL_SSLVERSION_TLSv1_1:
    case CURL_SSLVERSION_TLSv1_2:
    case CURL_SSLVERSION_TLSv1_3:
      /* it will be handled later with the context options */







|





<
<
<










|
|







3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461



3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
  CURLcode result = CURLE_OK;
  const char *ciphers;
  SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
  ctx_option_t ctx_options = 0;
  void *ssl_sessionid = NULL;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  const long int ssl_version_min = conn_config->version;
  char * const ssl_cert = ssl_config->primary.clientcert;
  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
  const char * const ssl_cert_type = ssl_config->cert_type;
  const bool verifypeer = conn_config->verifypeer;
  char error_buffer[256];




  /* Make funny stuff to get random input */
  result = ossl_seed(data);
  if(result)
    return result;

  ssl_config->certverifyresult = !X509_V_OK;

  switch(transport) {
  case TRNSPRT_TCP:
    /* check to see if we have been told to use an explicit SSL/TLS version */
    switch(ssl_version_min) {
    case CURL_SSLVERSION_DEFAULT:
    case CURL_SSLVERSION_TLSv1:
    case CURL_SSLVERSION_TLSv1_0:
    case CURL_SSLVERSION_TLSv1_1:
    case CURL_SSLVERSION_TLSv1_2:
    case CURL_SSLVERSION_TLSv1_3:
      /* it will be handled later with the context options */
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557

3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
      return CURLE_NOT_BUILT_IN;
    default:
      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
      return CURLE_SSL_CONNECT_ERROR;
    }
    break;
  case TRNSPRT_QUIC:
    if((ssl_version != CURL_SSLVERSION_DEFAULT) &&
       (ssl_version < CURL_SSLVERSION_TLSv1_3)) {
      failf(data, "QUIC needs at least TLS version 1.3");
      return CURLE_SSL_CONNECT_ERROR;
     }

#ifdef USE_OPENSSL_QUIC
    req_method = OSSL_QUIC_client_method();
#elif (OPENSSL_VERSION_NUMBER >= 0x10100000L)
    req_method = TLS_method();
#else
    req_method = SSLv23_client_method();
#endif
    break;
  default:
    failf(data, "unsupported transport %d in SSL init", transport);
    return CURLE_SSL_CONNECT_ERROR;
  }


  DEBUGASSERT(!octx->ssl_ctx);
  octx->ssl_ctx = SSL_CTX_new(req_method);

  if(!octx->ssl_ctx) {
    failf(data, "SSL: couldn't create a context: %s",
          ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
    return CURLE_OUT_OF_MEMORY;
  }

  if(cb_setup) {
    result = cb_setup(cf, data, cb_user_data);
    if(result)
      return result;
  }

#ifdef SSL_CTRL_SET_MSG_CALLBACK
  if(data->set.fdebug && data->set.verbose) {
    /* the SSL trace callback is only used for verbose logging */
    SSL_CTX_set_msg_callback(octx->ssl_ctx, ossl_trace);
    SSL_CTX_set_msg_callback_arg(octx->ssl_ctx, cf);
  }
#endif

  /* OpenSSL contains code to work around lots of bugs and flaws in various
     SSL-implementations. SSL_CTX_set_options() is used to enabled those
     work-arounds. The man page for this option states that SSL_OP_ALL enables
     all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
     enable the bug workaround options if compatibility with somewhat broken
     implementations is desired."

     The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to
     disable "rfc4507bis session ticket support". rfc4507bis was later turned
     into the proper RFC5077: https://datatracker.ietf.org/doc/html/rfc5077

     The enabled extension concerns the session management. I wonder how often
     libcurl stops a connection and then resumes a TLS session. Also, sending
     the session data is some overhead. I suggest that you just use your
     proposed patch (which explicitly disables TICKET).







|
|


|
>


















|




















|




|







3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
      return CURLE_NOT_BUILT_IN;
    default:
      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
      return CURLE_SSL_CONNECT_ERROR;
    }
    break;
  case TRNSPRT_QUIC:
    if(conn_config->version_max &&
       (conn_config->version_max != CURL_SSLVERSION_MAX_TLSv1_3)) {
      failf(data, "QUIC needs at least TLS version 1.3");
      return CURLE_SSL_CONNECT_ERROR;
    }

#ifdef USE_OPENSSL_QUIC
    req_method = OSSL_QUIC_client_method();
#elif (OPENSSL_VERSION_NUMBER >= 0x10100000L)
    req_method = TLS_method();
#else
    req_method = SSLv23_client_method();
#endif
    break;
  default:
    failf(data, "unsupported transport %d in SSL init", transport);
    return CURLE_SSL_CONNECT_ERROR;
  }


  DEBUGASSERT(!octx->ssl_ctx);
  octx->ssl_ctx = SSL_CTX_new(req_method);

  if(!octx->ssl_ctx) {
    failf(data, "SSL: could not create a context: %s",
          ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
    return CURLE_OUT_OF_MEMORY;
  }

  if(cb_setup) {
    result = cb_setup(cf, data, cb_user_data);
    if(result)
      return result;
  }

#ifdef SSL_CTRL_SET_MSG_CALLBACK
  if(data->set.fdebug && data->set.verbose) {
    /* the SSL trace callback is only used for verbose logging */
    SSL_CTX_set_msg_callback(octx->ssl_ctx, ossl_trace);
    SSL_CTX_set_msg_callback_arg(octx->ssl_ctx, cf);
  }
#endif

  /* OpenSSL contains code to work around lots of bugs and flaws in various
     SSL-implementations. SSL_CTX_set_options() is used to enabled those
     work-arounds. The manpage for this option states that SSL_OP_ALL enables
     all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
     enable the bug workaround options if compatibility with somewhat broken
     implementations is desired."

     The "-no_ticket" option was introduced in OpenSSL 0.9.8j. it is a flag to
     disable "rfc4507bis session ticket support". rfc4507bis was later turned
     into the proper RFC5077: https://datatracker.ietf.org/doc/html/rfc5077

     The enabled extension concerns the session management. I wonder how often
     libcurl stops a connection and then resumes a TLS session. Also, sending
     the session data is some overhead. I suggest that you just use your
     proposed patch (which explicitly disables TICKET).
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660

#ifdef SSL_OP_NO_COMPRESSION
  ctx_options |= SSL_OP_NO_COMPRESSION;
#endif

#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
  /* mitigate CVE-2010-4180 */
  ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
#endif

#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
  /* unless the user explicitly asks to allow the protocol vulnerability we
     use the work-around */
  if(!ssl_config->enable_beast)
    ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif

  switch(ssl_version) {
  case CURL_SSLVERSION_SSLv2:
  case CURL_SSLVERSION_SSLv3:
    return CURLE_NOT_BUILT_IN;

    /* "--tlsv<x.y>" options mean TLS >= version <x.y> */
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */







|






|


|







3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607

#ifdef SSL_OP_NO_COMPRESSION
  ctx_options |= SSL_OP_NO_COMPRESSION;
#endif

#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
  /* mitigate CVE-2010-4180 */
  ctx_options &= ~(ctx_option_t)SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
#endif

#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
  /* unless the user explicitly asks to allow the protocol vulnerability we
     use the work-around */
  if(!ssl_config->enable_beast)
    ctx_options &= ~(ctx_option_t)SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif

  switch(ssl_version_min) {
  case CURL_SSLVERSION_SSLv2:
  case CURL_SSLVERSION_SSLv3:
    return CURLE_NOT_BUILT_IN;

    /* "--tlsv<x.y>" options mean TLS >= version <x.y> */
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1: /* TLS >= version 1.0 */
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
#ifdef USE_OPENSSL_SRP
  if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) {
    char * const ssl_username = ssl_config->primary.username;
    char * const ssl_password = ssl_config->primary.password;
    infof(data, "Using TLS-SRP username: %s", ssl_username);

    if(!SSL_CTX_set_srp_username(octx->ssl_ctx, ssl_username)) {
      failf(data, "Unable to set SRP user name");
      return CURLE_BAD_FUNCTION_ARGUMENT;
    }
    if(!SSL_CTX_set_srp_password(octx->ssl_ctx, ssl_password)) {
      failf(data, "failed setting SRP password");
      return CURLE_BAD_FUNCTION_ARGUMENT;
    }
    if(!conn_config->cipher_list) {







|







3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
#ifdef USE_OPENSSL_SRP
  if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) {
    char * const ssl_username = ssl_config->primary.username;
    char * const ssl_password = ssl_config->primary.password;
    infof(data, "Using TLS-SRP username: %s", ssl_username);

    if(!SSL_CTX_set_srp_username(octx->ssl_ctx, ssl_username)) {
      failf(data, "Unable to set SRP username");
      return CURLE_BAD_FUNCTION_ARGUMENT;
    }
    if(!SSL_CTX_set_srp_password(octx->ssl_ctx, ssl_password)) {
      failf(data, "failed setting SRP password");
      return CURLE_BAD_FUNCTION_ARGUMENT;
    }
    if(!conn_config->cipher_list) {
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
#ifdef HAVE_KEYLOG_CALLBACK
  if(Curl_tls_keylog_enabled()) {
    SSL_CTX_set_keylog_callback(octx->ssl_ctx, ossl_keylog_callback);
  }
#endif

  if(cb_new_session) {
    /* Enable the session cache because it's a prerequisite for the
     * "new session" callback. Use the "external storage" mode to prevent
     * OpenSSL from creating an internal session cache.
     */
    SSL_CTX_set_session_cache_mode(octx->ssl_ctx,
                                   SSL_SESS_CACHE_CLIENT |
                                   SSL_SESS_CACHE_NO_INTERNAL);
    SSL_CTX_sess_set_new_cb(octx->ssl_ctx, cb_new_session);







|







3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
#ifdef HAVE_KEYLOG_CALLBACK
  if(Curl_tls_keylog_enabled()) {
    SSL_CTX_set_keylog_callback(octx->ssl_ctx, ossl_keylog_callback);
  }
#endif

  if(cb_new_session) {
    /* Enable the session cache because it is a prerequisite for the
     * "new session" callback. Use the "external storage" mode to prevent
     * OpenSSL from creating an internal session cache.
     */
    SSL_CTX_set_session_cache_mode(octx->ssl_ctx,
                                   SSL_SESS_CACHE_CLIENT |
                                   SSL_SESS_CACHE_NO_INTERNAL);
    SSL_CTX_sess_set_new_cb(octx->ssl_ctx, cb_new_session);
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
  }

  /* Let's make an SSL structure */
  if(octx->ssl)
    SSL_free(octx->ssl);
  octx->ssl = SSL_new(octx->ssl_ctx);
  if(!octx->ssl) {
    failf(data, "SSL: couldn't create a context (handle)");
    return CURLE_OUT_OF_MEMORY;
  }

  SSL_set_app_data(octx->ssl, ssl_user_data);

#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
  !defined(OPENSSL_NO_OCSP)







|







3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
  }

  /* Let's make an SSL structure */
  if(octx->ssl)
    SSL_free(octx->ssl);
  octx->ssl = SSL_new(octx->ssl_ctx);
  if(!octx->ssl) {
    failf(data, "SSL: could not create a context (handle)");
    return CURLE_OUT_OF_MEMORY;
  }

  SSL_set_app_data(octx->ssl, ssl_user_data);

#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
  !defined(OPENSSL_NO_OCSP)
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
      if(!b64) {
        infof(data, "ECH: ECHConfig from command line empty");
        return CURLE_SSL_CONNECT_ERROR;
      }
      ech_config_len = 2 * strlen(b64);
      result = Curl_base64_decode(b64, &ech_config, &ech_config_len);
      if(result || !ech_config) {
        infof(data, "ECH: can't base64 decode ECHConfig from command line");
        if(data->set.tls_ech & CURLECH_HARD)
          return result;
      }
      if(SSL_set1_ech_config_list(octx->ssl, ech_config,
                                  ech_config_len) != 1) {
        infof(data, "ECH: SSL_ECH_set1_echconfig failed");
        if(data->set.tls_ech & CURLECH_HARD) {







|







3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
      if(!b64) {
        infof(data, "ECH: ECHConfig from command line empty");
        return CURLE_SSL_CONNECT_ERROR;
      }
      ech_config_len = 2 * strlen(b64);
      result = Curl_base64_decode(b64, &ech_config, &ech_config_len);
      if(result || !ech_config) {
        infof(data, "ECH: cannot base64 decode ECHConfig from command line");
        if(data->set.tls_ech & CURLECH_HARD)
          return result;
      }
      if(SSL_set1_ech_config_list(octx->ssl, ech_config,
                                  ech_config_len) != 1) {
        infof(data, "ECH: SSL_ECH_set1_echconfig failed");
        if(data->set.tls_ech & CURLECH_HARD) {
3906
3907
3908
3909
3910
3911
3912

3913
3914
3915
3916
3917
3918
3919
3920
        trying_ech_now = 1;
# endif
      infof(data, "ECH: ECHConfig from command line");
    }
    else {
      struct Curl_dns_entry *dns = NULL;


      dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
      if(!dns) {
        infof(data, "ECH: requested but no DNS info available");
        if(data->set.tls_ech & CURLECH_HARD)
          return CURLE_SSL_CONNECT_ERROR;
      }
      else {
        struct Curl_https_rrinfo *rinfo = NULL;







>
|







3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
        trying_ech_now = 1;
# endif
      infof(data, "ECH: ECHConfig from command line");
    }
    else {
      struct Curl_dns_entry *dns = NULL;

      if(peer->hostname)
        dns = Curl_fetch_addr(data, peer->hostname, peer->port);
      if(!dns) {
        infof(data, "ECH: requested but no DNS info available");
        if(data->set.tls_ech & CURLECH_HARD)
          return CURLE_SSL_CONNECT_ERROR;
      }
      else {
        struct Curl_https_rrinfo *rinfo = NULL;
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
            infof(data, "ECH: SSL_set1_ech_config_list failed (boring)");
            if(data->set.tls_ech & CURLECH_HARD)
              return CURLE_SSL_CONNECT_ERROR;
          }
# endif
          else {
            trying_ech_now = 1;
            infof(data, "ECH: imported ECHConfigList of length %ld", elen);
          }
        }
        else {
          infof(data, "ECH: requested but no ECHConfig available");
          if(data->set.tls_ech & CURLECH_HARD)
            return CURLE_SSL_CONNECT_ERROR;
        }
        Curl_resolv_unlock(data, dns);
      }
    }
# ifdef OPENSSL_IS_BORINGSSL
    if(trying_ech_now && outername) {
      infof(data, "ECH: setting public_name not supported with boringssl");
      return CURLE_SSL_CONNECT_ERROR;
    }
# else
    if(trying_ech_now && outername) {
      infof(data, "ECH: inner: '%s', outer: '%s'",
            connssl->peer.hostname, outername);
      result = SSL_ech_set_server_names(octx->ssl,
                                        connssl->peer.hostname, outername,
                                        0 /* do send outer */);
      if(result != 1) {
        infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
        return CURLE_SSL_CONNECT_ERROR;
      }
    }
# endif  /* not BORING */
    if(trying_ech_now
       && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) {
      infof(data, "ECH: Can't force TLSv1.3 [ERROR]");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
#endif  /* USE_ECH */

#endif

  octx->reused_session = FALSE;
  if(ssl_config->primary.sessionid && transport == TRNSPRT_TCP) {
    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, NULL)) {
      /* we got a session id, use it! */
      if(!SSL_set_session(octx->ssl, ssl_sessionid)) {
        Curl_ssl_sessionid_unlock(data);
        failf(data, "SSL: SSL_set_session failed: %s",
              ossl_strerror(ERR_get_error(), error_buffer,







|












|





|

|









|








|







3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
            infof(data, "ECH: SSL_set1_ech_config_list failed (boring)");
            if(data->set.tls_ech & CURLECH_HARD)
              return CURLE_SSL_CONNECT_ERROR;
          }
# endif
          else {
            trying_ech_now = 1;
            infof(data, "ECH: imported ECHConfigList of length %zu", elen);
          }
        }
        else {
          infof(data, "ECH: requested but no ECHConfig available");
          if(data->set.tls_ech & CURLECH_HARD)
            return CURLE_SSL_CONNECT_ERROR;
        }
        Curl_resolv_unlock(data, dns);
      }
    }
# ifdef OPENSSL_IS_BORINGSSL
    if(trying_ech_now && outername) {
      infof(data, "ECH: setting public_name not supported with BoringSSL");
      return CURLE_SSL_CONNECT_ERROR;
    }
# else
    if(trying_ech_now && outername) {
      infof(data, "ECH: inner: '%s', outer: '%s'",
            peer->hostname ? peer->hostname : "NULL", outername);
      result = SSL_ech_set_server_names(octx->ssl,
                                        peer->hostname, outername,
                                        0 /* do send outer */);
      if(result != 1) {
        infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
        return CURLE_SSL_CONNECT_ERROR;
      }
    }
# endif  /* not BORING */
    if(trying_ech_now
       && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) {
      infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
#endif  /* USE_ECH */

#endif

  octx->reused_session = FALSE;
  if(ssl_config->primary.cache_session && transport == TRNSPRT_TCP) {
    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, NULL)) {
      /* we got a session id, use it! */
      if(!SSL_set_session(octx->ssl, ssl_sessionid)) {
        Curl_ssl_sessionid_unlock(data);
        failf(data, "SSL: SSL_set_session failed: %s",
              ossl_strerror(ERR_get_error(), error_buffer,
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
    return CURLE_OUT_OF_MEMORY;

  BIO_set_data(bio, cf);
#ifdef HAVE_SSL_SET0_WBIO
  /* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works
   * without backward compat quirks. Every call takes one reference, so we
   * up it and pass. SSL* then owns it and will free.
   * We check on the function in configure, since libressl and friends
   * each have their own versions to add support for this. */
  BIO_up_ref(bio);
  SSL_set0_rbio(octx->ssl, bio);
  SSL_set0_wbio(octx->ssl, bio);
#else
  SSL_set_bio(octx->ssl, bio, bio);
#endif







|







3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
    return CURLE_OUT_OF_MEMORY;

  BIO_set_data(bio, cf);
#ifdef HAVE_SSL_SET0_WBIO
  /* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works
   * without backward compat quirks. Every call takes one reference, so we
   * up it and pass. SSL* then owns it and will free.
   * We check on the function in configure, since LibreSSL and friends
   * each have their own versions to add support for this. */
  BIO_up_ref(bio);
  SSL_set0_rbio(octx->ssl, bio);
  SSL_set0_wbio(octx->ssl, bio);
#else
  SSL_set_bio(octx->ssl, bio, bio);
#endif
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138

4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
                                   struct Curl_easy *data)
{
  int err;
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
              || ssl_connect_2_reading == connssl->connecting_state
              || ssl_connect_2_writing == connssl->connecting_state);
  DEBUGASSERT(octx);


  ERR_clear_error();

  err = SSL_connect(octx->ssl);

  if(!octx->x509_store_setup) {
    /* After having send off the ClientHello, we prepare the x509
     * store to verify the coming certificate from the server */
    CURLcode result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
    if(result)
      return result;
    octx->x509_store_setup = TRUE;
  }

#ifndef HAVE_KEYLOG_CALLBACK
  if(Curl_tls_keylog_enabled()) {
    /* If key logging is enabled, wait for the handshake to complete and then
     * proceed with logging secrets (for TLS 1.2 or older).
     */
    bool done = FALSE;
    ossl_log_tls12_secret(octx->ssl, &done);
    octx->keylog_done = done;
  }
#endif

  /* 1  is fine
     0  is "not successful but was shut down controlled"
     <0 is "handshake was not successful, because a fatal error occurred" */
  if(1 != err) {
    int detail = SSL_get_error(octx->ssl, err);

    if(SSL_ERROR_WANT_READ == detail) {
      connssl->connecting_state = ssl_connect_2_reading;
      return CURLE_OK;
    }
    if(SSL_ERROR_WANT_WRITE == detail) {
      connssl->connecting_state = ssl_connect_2_writing;
      return CURLE_OK;
    }
#ifdef SSL_ERROR_WANT_ASYNC
    if(SSL_ERROR_WANT_ASYNC == detail) {
      connssl->connecting_state = ssl_connect_2;
      return CURLE_OK;
    }







|
<
<


>














<
|
|
|
|
|
<
<









|



|







4075
4076
4077
4078
4079
4080
4081
4082


4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099

4100
4101
4102
4103
4104


4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
                                   struct Curl_easy *data)
{
  int err;
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state);


  DEBUGASSERT(octx);

  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  ERR_clear_error();

  err = SSL_connect(octx->ssl);

  if(!octx->x509_store_setup) {
    /* After having send off the ClientHello, we prepare the x509
     * store to verify the coming certificate from the server */
    CURLcode result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
    if(result)
      return result;
    octx->x509_store_setup = TRUE;
  }

#ifndef HAVE_KEYLOG_CALLBACK

  /* If key logging is enabled, wait for the handshake to complete and then
   * proceed with logging secrets (for TLS 1.2 or older).
   */
  if(Curl_tls_keylog_enabled() && !octx->keylog_done)
    ossl_log_tls12_secret(octx->ssl, &octx->keylog_done);


#endif

  /* 1  is fine
     0  is "not successful but was shut down controlled"
     <0 is "handshake was not successful, because a fatal error occurred" */
  if(1 != err) {
    int detail = SSL_get_error(octx->ssl, err);

    if(SSL_ERROR_WANT_READ == detail) {
      connssl->io_need = CURL_SSL_IO_NEED_RECV;
      return CURLE_OK;
    }
    if(SSL_ERROR_WANT_WRITE == detail) {
      connssl->io_need = CURL_SSL_IO_NEED_SEND;
      return CURLE_OK;
    }
#ifdef SSL_ERROR_WANT_ASYNC
    if(SSL_ERROR_WANT_ASYNC == detail) {
      connssl->connecting_state = ssl_connect_2;
      return CURLE_OK;
    }
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
      sslerr_t errdetail;
      char error_buffer[256]="";
      CURLcode result;
      long lerr;
      int lib;
      int reason;

      /* the connection failed, we're not waiting for anything else. */
      connssl->connecting_state = ssl_connect_2;

      /* Get the earliest error code from the thread's error queue and remove
         the entry. */
      errdetail = ERR_get_error();

      /* Extract which lib and reason */







|







4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
      sslerr_t errdetail;
      char error_buffer[256]="";
      CURLcode result;
      long lerr;
      int lib;
      int reason;

      /* the connection failed, we are not waiting for anything else. */
      connssl->connecting_state = ssl_connect_2;

      /* Get the earliest error code from the thread's error queue and remove
         the entry. */
      errdetail = ERR_get_error();

      /* Extract which lib and reason */
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
      else {
        result = CURLE_SSL_CONNECT_ERROR;
        ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
      }

      /* detail is already set to the SSL error above */

      /* If we e.g. use SSLv2 request-method and the server doesn't like us
       * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
       * the SO_ERROR is also lost.
       */
      if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
        char extramsg[80]="";
        int sockerr = SOCKERRNO;








|







4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
      else {
        result = CURLE_SSL_CONNECT_ERROR;
        ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
      }

      /* detail is already set to the SSL error above */

      /* If we e.g. use SSLv2 request-method and the server does not like us
       * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
       * the SO_ERROR is also lost.
       */
      if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
        char extramsg[80]="";
        int sockerr = SOCKERRNO;

4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
      return result;
    }
  }
  else {
    int psigtype_nid = NID_undef;
    const char *negotiated_group_name = NULL;

    /* we connected fine, we're not waiting for anything else. */
    connssl->connecting_state = ssl_connect_3;

#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
    SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid);
#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
    negotiated_group_name = SSL_get0_group_name(octx->ssl);
#else







|







4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
      return result;
    }
  }
  else {
    int psigtype_nid = NID_undef;
    const char *negotiated_group_name = NULL;

    /* we connected fine, we are not waiting for anything else. */
    connssl->connecting_state = ssl_connect_3;

#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
    SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid);
#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
    negotiated_group_name = SSL_get0_group_name(octx->ssl);
#else
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
  /* Scratch */
  int len1 = 0, len2 = 0;
  unsigned char *buff1 = NULL, *temp = NULL;

  /* Result is returned to caller */
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;

  /* if a path wasn't specified, don't pin */
  if(!pinnedpubkey)
    return CURLE_OK;

  if(!cert)
    return result;

  do {







|







4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
  /* Scratch */
  int len1 = 0, len2 = 0;
  unsigned char *buff1 = NULL, *temp = NULL;

  /* Result is returned to caller */
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;

  /* if a path was not specified, do not pin */
  if(!pinnedpubkey)
    return CURLE_OK;

  if(!cert)
    return result;

  do {
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
      break; /* failed */

    /* https://www.openssl.org/docs/crypto/d2i_X509.html */
    len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);

    /*
     * These checks are verifying we got back the same values as when we
     * sized the buffer. It's pretty weak since they should always be the
     * same. But it gives us something to test.
     */
    if((len1 != len2) || !temp || ((temp - buff1) != len1))
      break; /* failed */

    /* End Gyrations */








|







4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
      break; /* failed */

    /* https://www.openssl.org/docs/crypto/d2i_X509.html */
    len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);

    /*
     * These checks are verifying we got back the same values as when we
     * sized the buffer. it is pretty weak since they should always be the
     * same. But it gives us something to test.
     */
    if((len1 != len2) || !temp || ((temp - buff1) != len1))
      break; /* failed */

    /* End Gyrations */

4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561

  octx->server_cert = SSL_get1_peer_certificate(octx->ssl);
  if(!octx->server_cert) {
    BIO_free(mem);
    if(!strict)
      return CURLE_OK;

    failf(data, "SSL: couldn't get peer certificate");
    return CURLE_PEER_FAILED_VERIFICATION;
  }

  infof(data, "%s certificate:",
        Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");

  rc = x509_name_oneline(X509_get_subject_name(octx->server_cert),







|







4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505

  octx->server_cert = SSL_get1_peer_certificate(octx->ssl);
  if(!octx->server_cert) {
    BIO_free(mem);
    if(!strict)
      return CURLE_OK;

    failf(data, "SSL: could not get peer certificate");
    return CURLE_PEER_FAILED_VERIFICATION;
  }

  infof(data, "%s certificate:",
        Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");

  rc = x509_name_oneline(X509_get_subject_name(octx->server_cert),
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
    }
  }

  rc = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
                         buffer, sizeof(buffer));
  if(rc) {
    if(strict)
      failf(data, "SSL: couldn't get X509-issuer name");
    result = CURLE_PEER_FAILED_VERIFICATION;
  }
  else {
    infof(data, " issuer: %s", buffer);

    /* We could do all sorts of certificate verification stuff here before
       deallocating the certificate. */







|







4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
    }
  }

  rc = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
                         buffer, sizeof(buffer));
  if(rc) {
    if(strict)
      failf(data, "SSL: could not get X509-issuer name");
    result = CURLE_PEER_FAILED_VERIFICATION;
  }
  else {
    infof(data, " issuer: %s", buffer);

    /* We could do all sorts of certificate verification stuff here before
       deallocating the certificate. */
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
  }

  infof_certstack(data, octx->ssl);

#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
  !defined(OPENSSL_NO_OCSP)
  if(conn_config->verifystatus && !octx->reused_session) {
    /* don't do this after Session ID reuse */
    result = verifystatus(cf, data);
    if(result) {
      /* when verifystatus failed, remove the session id from the cache again
         if present */
      if(!Curl_ssl_cf_is_proxy(cf)) {
        void *old_ssl_sessionid = NULL;
        bool incache;
        Curl_ssl_sessionid_lock(data);







|
|







4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
  }

  infof_certstack(data, octx->ssl);

#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
  !defined(OPENSSL_NO_OCSP)
  if(conn_config->verifystatus && !octx->reused_session) {
    /* do not do this after Session ID reuse */
    result = verifystatus(cf, data, octx);
    if(result) {
      /* when verifystatus failed, remove the session id from the cache again
         if present */
      if(!Curl_ssl_cf_is_proxy(cf)) {
        void *old_ssl_sessionid = NULL;
        bool incache;
        Curl_ssl_sessionid_lock(data);
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
      octx->server_cert = NULL;
      return result;
    }
  }
#endif

  if(!strict)
    /* when not strict, we don't bother about the verify cert problems */
    result = CURLE_OK;

#ifndef CURL_DISABLE_PROXY
  ptr = Curl_ssl_cf_is_proxy(cf)?
    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else







|







4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
      octx->server_cert = NULL;
      return result;
    }
  }
#endif

  if(!strict)
    /* when not strict, we do not bother about the verify cert problems */
    result = CURLE_OK;

#ifndef CURL_DISABLE_PROXY
  ptr = Curl_ssl_cf_is_proxy(cf)?
    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;

  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);

  /*
   * We check certificates to authenticate the server; otherwise we risk
   * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
   * verify the peer, ignore faults and failures from the server cert
   * operations.
   */

  result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer);
  if(!result)
    connssl->connecting_state = ssl_connect_done;







|







4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
  struct ssl_connect_data *connssl = cf->ctx;
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;

  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);

  /*
   * We check certificates to authenticate the server; otherwise we risk
   * man-in-the-middle attack; NEVERTHELESS, if we are told explicitly not to
   * verify the peer, ignore faults and failures from the server cert
   * operations.
   */

  result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer);
  if(!result)
    connssl->connecting_state = ssl_connect_done;
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* Find out how much more time we're allowed */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time is already up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = ossl_connect_step1(cf, data);
    if(result)
      goto out;
  }

  while(ssl_connect_2 == connssl->connecting_state ||
        ssl_connect_2_reading == connssl->connecting_state ||
        ssl_connect_2_writing == connssl->connecting_state) {

    /* check allowed time left */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      result = CURLE_OPERATION_TIMEDOUT;
      goto out;
    }

    /* if ssl is expecting something, check if it's available. */
    if(!nonblocking &&
       (connssl->connecting_state == ssl_connect_2_reading ||
        connssl->connecting_state == ssl_connect_2_writing)) {

      curl_socket_t writefd = ssl_connect_2_writing ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        result = CURLE_SSL_CONNECT_ERROR;







|













|
<
<











|
|
<
<

|
|
|
|







4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744


4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757


4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* Find out how much more time we are allowed */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time is already up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = ossl_connect_step1(cf, data);
    if(result)
      goto out;
  }

  while(ssl_connect_2 == connssl->connecting_state) {



    /* check allowed time left */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      result = CURLE_OPERATION_TIMEDOUT;
      goto out;
    }

    /* if ssl is expecting something, check if it is available. */
    if(!nonblocking && connssl->io_need) {



      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
                              sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
                             sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        result = CURLE_SSL_CONNECT_ERROR;
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
    /* Run transaction, and return to the caller if it failed or if this
     * connection is done nonblocking and this loop would execute again. This
     * permits the owner of a multi handle to abort a connection attempt
     * before step2 has completed while ensuring that a client using select()
     * or epoll() will always have a valid fdset to wait on.
     */
    result = ossl_connect_step2(cf, data);
    if(result || (nonblocking &&
                  (ssl_connect_2 == connssl->connecting_state ||
                   ssl_connect_2_reading == connssl->connecting_state ||
                   ssl_connect_2_writing == connssl->connecting_state)))
      goto out;

  } /* repeat step2 until all transactions are done. */

  if(ssl_connect_3 == connssl->connecting_state) {
    result = ossl_connect_step3(cf, data);
    if(result)







|
<
<
<







4781
4782
4783
4784
4785
4786
4787
4788



4789
4790
4791
4792
4793
4794
4795
    /* Run transaction, and return to the caller if it failed or if this
     * connection is done nonblocking and this loop would execute again. This
     * permits the owner of a multi handle to abort a connection attempt
     * before step2 has completed while ensuring that a client using select()
     * or epoll() will always have a valid fdset to wait on.
     */
    result = ossl_connect_step2(cf, data);
    if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))



      goto out;

  } /* repeat step2 until all transactions are done. */

  if(ssl_connect_3 == connssl->connecting_state) {
    result = ossl_connect_step3(cf, data);
    if(result)
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
      if(cf->sockindex == FIRSTSOCKET)
        /* mark the connection for close if it is indeed the control
           connection */
        connclose(conn, "TLS close_notify");
      break;
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
      /* there's data pending, re-invoke SSL_read() */
      *curlcode = CURLE_AGAIN;
      nread = -1;
      goto out;
    default:
      /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
         value/errno" */
      /* https://www.openssl.org/docs/crypto/ERR_get_error.html */







|







4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
      if(cf->sockindex == FIRSTSOCKET)
        /* mark the connection for close if it is indeed the control
           connection */
        connclose(conn, "TLS close_notify");
      break;
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
      /* there is data pending, re-invoke SSL_read() */
      *curlcode = CURLE_AGAIN;
      nread = -1;
      goto out;
    default:
      /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
         value/errno" */
      /* https://www.openssl.org/docs/crypto/ERR_get_error.html */
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
        *curlcode = CURLE_RECV_ERROR;
        nread = -1;
        goto out;
      }
      /* For debug builds be a little stricter and error on any
         SSL_ERROR_SYSCALL. For example a server may have closed the connection
         abruptly without a close_notify alert. For compatibility with older
         peers we don't do this by default. #4624

         We can use this to gauge how many users may be affected, and
         if it goes ok eventually transition to allow in dev and release with
         the newest OpenSSL: #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) */
#ifdef DEBUGBUILD
      if(err == SSL_ERROR_SYSCALL) {
        int sockerr = SOCKERRNO;







|







4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
        *curlcode = CURLE_RECV_ERROR;
        nread = -1;
        goto out;
      }
      /* For debug builds be a little stricter and error on any
         SSL_ERROR_SYSCALL. For example a server may have closed the connection
         abruptly without a close_notify alert. For compatibility with older
         peers we do not do this by default. #4624

         We can use this to gauge how many users may be affected, and
         if it goes ok eventually transition to allow in dev and release with
         the newest OpenSSL: #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) */
#ifdef DEBUGBUILD
      if(err == SSL_ERROR_SYSCALL) {
        int sockerr = SOCKERRNO;
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
}

static size_t ossl_version(char *buffer, size_t size)
{
#ifdef LIBRESSL_VERSION_NUMBER
#ifdef HAVE_OPENSSL_VERSION
  char *p;
  int count;
  const char *ver = OpenSSL_version(OPENSSL_VERSION);
  const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
  if(strncasecompare(ver, expected, sizeof(expected) - 1)) {
    ver += sizeof(expected) - 1;
  }
  count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver);
  for(p = buffer; *p; ++p) {







|







5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
}

static size_t ossl_version(char *buffer, size_t size)
{
#ifdef LIBRESSL_VERSION_NUMBER
#ifdef HAVE_OPENSSL_VERSION
  char *p;
  size_t count;
  const char *ver = OpenSSL_version(OPENSSL_VERSION);
  const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
  if(strncasecompare(ver, expected, sizeof(expected) - 1)) {
    ver += sizeof(expected) - 1;
  }
  count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver);
  for(p = buffer; *p; ++p) {
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
/* can be called with data == NULL */
static CURLcode ossl_random(struct Curl_easy *data,
                            unsigned char *entropy, size_t length)
{
  int rc;
  if(data) {
    if(ossl_seed(data)) /* Initiate the seed if not already done */
      return CURLE_FAILED_INIT; /* couldn't seed for some reason */
  }
  else {
    if(!rand_enough())
      return CURLE_FAILED_INIT;
  }
  /* RAND_bytes() returns 1 on success, 0 otherwise.  */
  rc = RAND_bytes(entropy, curlx_uztosi(length));
  return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
}

#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */
                               size_t tmplen,
                               unsigned char *sha256sum /* output */,







|






|







5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
/* can be called with data == NULL */
static CURLcode ossl_random(struct Curl_easy *data,
                            unsigned char *entropy, size_t length)
{
  int rc;
  if(data) {
    if(ossl_seed(data)) /* Initiate the seed if not already done */
      return CURLE_FAILED_INIT; /* could not seed for some reason */
  }
  else {
    if(!rand_enough())
      return CURLE_FAILED_INIT;
  }
  /* RAND_bytes() returns 1 on success, 0 otherwise.  */
  rc = RAND_bytes(entropy, (ossl_valsize_t)curlx_uztosi(length));
  return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
}

#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */
                               size_t tmplen,
                               unsigned char *sha256sum /* output */,
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266

5267
5268
5269
5270
5271
5272
5273
  /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  DEBUGASSERT(octx);
  return info == CURLINFO_TLS_SESSION ?
    (void *)octx->ssl_ctx : (void *)octx->ssl;
}

static void ossl_free_multi_ssl_backend_data(
  struct multi_ssl_backend_data *mbackend)
{
#if defined(HAVE_SSL_X509_STORE_SHARE)
  if(mbackend->store) {
    X509_STORE_free(mbackend->store);
  }
  free(mbackend->CAfile);
  free(mbackend);
#else /* HAVE_SSL_X509_STORE_SHARE */
  (void)mbackend;
#endif /* HAVE_SSL_X509_STORE_SHARE */
}

const struct Curl_ssl Curl_ssl_openssl = {
  { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */

  SSLSUPP_CA_PATH |
  SSLSUPP_CAINFO_BLOB |
  SSLSUPP_CERTINFO |
  SSLSUPP_PINNEDPUBKEY |
  SSLSUPP_SSL_CTX |
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
  SSLSUPP_TLS13_CIPHERSUITES |
#endif
#ifdef USE_ECH
  SSLSUPP_ECH |
#endif

  SSLSUPP_HTTPS_PROXY,

  sizeof(struct ossl_ctx),

  ossl_init,                /* init */
  ossl_cleanup,             /* cleanup */
  ossl_version,             /* version */







<
<
<
<
<
<
<
<
<
<
<
<
<
<














>







5169
5170
5171
5172
5173
5174
5175














5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
  /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
  struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
  DEBUGASSERT(octx);
  return info == CURLINFO_TLS_SESSION ?
    (void *)octx->ssl_ctx : (void *)octx->ssl;
}















const struct Curl_ssl Curl_ssl_openssl = {
  { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */

  SSLSUPP_CA_PATH |
  SSLSUPP_CAINFO_BLOB |
  SSLSUPP_CERTINFO |
  SSLSUPP_PINNEDPUBKEY |
  SSLSUPP_SSL_CTX |
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
  SSLSUPP_TLS13_CIPHERSUITES |
#endif
#ifdef USE_ECH
  SSLSUPP_ECH |
#endif
  SSLSUPP_CA_CACHE |
  SSLSUPP_HTTPS_PROXY,

  sizeof(struct ossl_ctx),

  ossl_init,                /* init */
  ossl_cleanup,             /* cleanup */
  ossl_version,             /* version */
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
  ossl_sha256sum,           /* sha256sum */
#else
  NULL,                     /* sha256sum */
#endif
  NULL,                     /* use of data in this connection */
  NULL,                     /* remote of data from this connection */
  ossl_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
  ossl_recv,                /* recv decrypted data */
  ossl_send,                /* send data to encrypt */
};

#endif /* USE_OPENSSL */







<





5213
5214
5215
5216
5217
5218
5219

5220
5221
5222
5223
5224
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
  ossl_sha256sum,           /* sha256sum */
#else
  NULL,                     /* sha256sum */
#endif
  NULL,                     /* use of data in this connection */
  NULL,                     /* remote of data from this connection */

  ossl_recv,                /* recv decrypted data */
  ossl_send,                /* send data to encrypt */
};

#endif /* USE_OPENSSL */
Changes to jni/curl/lib/vtls/openssl.h.
41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
56
  /* these ones requires specific SSL-types */
  SSL_CTX* ssl_ctx;
  SSL*     ssl;
  X509*    server_cert;
  BIO_METHOD *bio_method;
  CURLcode io_result;       /* result of last BIO cfilter operation */
#ifndef HAVE_KEYLOG_CALLBACK
  /* Set to true once a valid keylog entry has been created to avoid dupes. */

  BIT(keylog_done);
#endif
  BIT(x509_store_setup);            /* x509 store has been set up */
  BIT(reused_session);              /* session-ID was reused for this */
};

typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf,
                                        struct Curl_easy *data,







|
>
|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  /* these ones requires specific SSL-types */
  SSL_CTX* ssl_ctx;
  SSL*     ssl;
  X509*    server_cert;
  BIO_METHOD *bio_method;
  CURLcode io_result;       /* result of last BIO cfilter operation */
#ifndef HAVE_KEYLOG_CALLBACK
  /* Set to true once a valid keylog entry has been created to avoid dupes.
     This is a bool and not a bitfield because it is passed by address. */
  bool keylog_done;
#endif
  BIT(x509_store_setup);            /* x509 store has been set up */
  BIT(reused_session);              /* session-ID was reused for this */
};

typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf,
                                        struct Curl_easy *data,
Changes to jni/curl/lib/vtls/rustls.c.
44
45
46
47
48
49
50

51
52
53
54
55
56
57

struct rustls_ssl_backend_data
{
  const struct rustls_client_config *config;
  struct rustls_connection *conn;
  size_t plain_out_buffered;
  BIT(data_in_pending);

};

/* For a given rustls_result error code, return the best-matching CURLcode. */
static CURLcode map_error(rustls_result r)
{
  if(rustls_result_is_cert_error(r)) {
    return CURLE_PEER_FAILED_VERIFICATION;







>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

struct rustls_ssl_backend_data
{
  const struct rustls_client_config *config;
  struct rustls_connection *conn;
  size_t plain_out_buffered;
  BIT(data_in_pending);
  BIT(sent_shutdown);
};

/* For a given rustls_result error code, return the best-matching CURLcode. */
static CURLcode map_error(rustls_result r)
{
  if(rustls_result_is_cert_error(r)) {
    return CURLE_PEER_FAILED_VERIFICATION;
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    if(CURLE_AGAIN == result)
      ret = EAGAIN;
    else
      ret = EINVAL;
  }
  else if(nread == 0)
    connssl->peer_closed = TRUE;
  *out_n = (int)nread;
  CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
              len, nread, result);
  return ret;
}

static int
write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
  struct io_ctx *io_ctx = userdata;
  CURLcode result;
  int ret = 0;
  ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
                                       (const char *)buf, len, &result);
  if(nwritten < 0) {
    nwritten = 0;
    if(CURLE_AGAIN == result)
      ret = EAGAIN;
    else
      ret = EINVAL;
  }
  *out_n = (int)nwritten;
  CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
              len, nwritten, result);
  return ret;
}

static ssize_t tls_recv_more(struct Curl_cfilter *cf,
                             struct Curl_easy *data, CURLcode *err)







|




















|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    if(CURLE_AGAIN == result)
      ret = EAGAIN;
    else
      ret = EINVAL;
  }
  else if(nread == 0)
    connssl->peer_closed = TRUE;
  *out_n = (uintptr_t)nread;
  CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
              len, nread, result);
  return ret;
}

static int
write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
  struct io_ctx *io_ctx = userdata;
  CURLcode result;
  int ret = 0;
  ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
                                       (const char *)buf, len, &result);
  if(nwritten < 0) {
    nwritten = 0;
    if(CURLE_AGAIN == result)
      ret = EAGAIN;
    else
      ret = EINVAL;
  }
  *out_n = (uintptr_t)nwritten;
  CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
              len, nwritten, result);
  return ret;
}

static ssize_t tls_recv_more(struct Curl_cfilter *cf,
                             struct Curl_easy *data, CURLcode *err)
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
 * On each run:
 *  - Read a chunk of bytes from the socket into rustls' TLS input buffer.
 *  - Tell rustls to process any new packets.
 *  - Read out as many plaintext bytes from rustls as possible, until hitting
 *    error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
 *
 * It's okay to call this function with plainbuf == NULL and plainlen == 0.
 * In that case, it will copy bytes from the socket into rustls' TLS input
 * buffer, and process packets, but won't consume bytes from rustls' plaintext
 * output buffer.
 */
static ssize_t
cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
            char *plainbuf, size_t plainlen, CURLcode *err)
{
  struct ssl_connect_data *const connssl = cf->ctx;
  struct rustls_ssl_backend_data *const backend =







|
|
|
|







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
 * On each run:
 *  - Read a chunk of bytes from the socket into rustls' TLS input buffer.
 *  - Tell rustls to process any new packets.
 *  - Read out as many plaintext bytes from rustls as possible, until hitting
 *    error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
 *
 * it is okay to call this function with plainbuf == NULL and plainlen == 0. In
 * that case, it will copy bytes from the socket into rustls' TLS input
 * buffer, and process packets, but will not consume bytes from rustls'
 * plaintext output buffer.
 */
static ssize_t
cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
            char *plainbuf, size_t plainlen, CURLcode *err)
{
  struct ssl_connect_data *const connssl = cf->ctx;
  struct rustls_ssl_backend_data *const backend =
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
      failf(data, "rustls: peer closed TCP connection "
        "without first closing TLS connection");
      *err = CURLE_RECV_ERROR;
      nread = -1;
      goto out;
    }
    else if(rresult != RUSTLS_RESULT_OK) {
      /* n always equals 0 in this case, don't need to check it */
      char errorbuf[255];
      size_t errorlen;
      rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
      failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
      *err = CURLE_RECV_ERROR;
      nread = -1;
      goto out;







|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
      failf(data, "rustls: peer closed TCP connection "
        "without first closing TLS connection");
      *err = CURLE_RECV_ERROR;
      nread = -1;
      goto out;
    }
    else if(rresult != RUSTLS_RESULT_OK) {
      /* n always equals 0 in this case, do not need to check it */
      char errorbuf[255];
      size_t errorlen;
      rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
      failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
      *err = CURLE_RECV_ERROR;
      nread = -1;
      goto out;
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319

/*
 * On each call:
 *  - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
 *  - Fully drain rustls' plaintext output buffer into the socket until
 *    we get either an error or EAGAIN/EWOULDBLOCK.
 *
 * It's okay to call this function with plainbuf == NULL and plainlen == 0.
 * In that case, it won't read anything into rustls' plaintext input buffer.
 * It will only drain rustls' plaintext output buffer into the socket.
 */
static ssize_t
cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
        const void *plainbuf, size_t plainlen, CURLcode *err)
{
  struct ssl_connect_data *const connssl = cf->ctx;







|
|







305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

/*
 * On each call:
 *  - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
 *  - Fully drain rustls' plaintext output buffer into the socket until
 *    we get either an error or EAGAIN/EWOULDBLOCK.
 *
 * it is okay to call this function with plainbuf == NULL and plainlen == 0.
 * In that case, it will not read anything into rustls' plaintext input buffer.
 * It will only drain rustls' plaintext output buffer into the socket.
 */
static ssize_t
cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
        const void *plainbuf, size_t plainlen, CURLcode *err)
{
  struct ssl_connect_data *const connssl = cf->ctx;
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  const char * const ssl_cafile =
    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
    (ca_info_blob ? NULL : conn_config->CAfile);
  const bool verifypeer = conn_config->verifypeer;
  const char *hostname = connssl->peer.hostname;
  char errorbuf[256];
  size_t errorlen;
  int result;

  DEBUGASSERT(backend);
  rconn = backend->conn;

  config_builder = rustls_client_config_builder_new();
  if(connssl->alpn) {
    struct alpn_proto_buf proto;







|







435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
  const char * const ssl_cafile =
    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
    (ca_info_blob ? NULL : conn_config->CAfile);
  const bool verifypeer = conn_config->verifypeer;
  const char *hostname = connssl->peer.hostname;
  char errorbuf[256];
  size_t errorlen;
  rustls_result result;

  DEBUGASSERT(backend);
  rconn = backend->conn;

  config_builder = rustls_client_config_builder_new();
  if(connssl->alpn) {
    struct alpn_proto_buf proto;
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
                                                    connssl->alpn->count);
    Curl_alpn_to_proto_str(&proto, connssl->alpn);
    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
  }
  if(!verifypeer) {
    rustls_client_config_builder_dangerous_set_certificate_verifier(
      config_builder, cr_verify_none);
    /* rustls doesn't support IP addresses (as of 0.19.0), and will reject
     * connections created with an IP address, even when certificate
     * verification is turned off. Set a placeholder hostname and disable
     * SNI. */
    if(cr_hostname_is_ip(hostname)) {
      rustls_client_config_builder_set_enable_sni(config_builder, false);
      hostname = "example.invalid";
    }
  }
  else if(ca_info_blob || ssl_cafile) {
    roots_builder = rustls_root_cert_store_builder_new();

    if(ca_info_blob) {
      /* Enable strict parsing only if verification isn't disabled. */
      result = rustls_root_cert_store_builder_add_pem(roots_builder,
                                                      ca_info_blob->data,
                                                      ca_info_blob->len,
                                                      verifypeer);
      if(result != RUSTLS_RESULT_OK) {
        failf(data, "rustls: failed to parse trusted certificates from blob");
        rustls_root_cert_store_builder_free(roots_builder);
        rustls_client_config_free(
          rustls_client_config_builder_build(config_builder));
        return CURLE_SSL_CACERT_BADFILE;
      }
    }
    else if(ssl_cafile) {
      /* Enable strict parsing only if verification isn't disabled. */
      result = rustls_root_cert_store_builder_load_roots_from_file(
        roots_builder, ssl_cafile, verifypeer);
      if(result != RUSTLS_RESULT_OK) {
        failf(data, "rustls: failed to load trusted certificates");
        rustls_root_cert_store_builder_free(roots_builder);
        rustls_client_config_free(
          rustls_client_config_builder_build(config_builder));







|












|













|







458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
                                                    connssl->alpn->count);
    Curl_alpn_to_proto_str(&proto, connssl->alpn);
    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
  }
  if(!verifypeer) {
    rustls_client_config_builder_dangerous_set_certificate_verifier(
      config_builder, cr_verify_none);
    /* rustls does not support IP addresses (as of 0.19.0), and will reject
     * connections created with an IP address, even when certificate
     * verification is turned off. Set a placeholder hostname and disable
     * SNI. */
    if(cr_hostname_is_ip(hostname)) {
      rustls_client_config_builder_set_enable_sni(config_builder, false);
      hostname = "example.invalid";
    }
  }
  else if(ca_info_blob || ssl_cafile) {
    roots_builder = rustls_root_cert_store_builder_new();

    if(ca_info_blob) {
      /* Enable strict parsing only if verification is not disabled. */
      result = rustls_root_cert_store_builder_add_pem(roots_builder,
                                                      ca_info_blob->data,
                                                      ca_info_blob->len,
                                                      verifypeer);
      if(result != RUSTLS_RESULT_OK) {
        failf(data, "rustls: failed to parse trusted certificates from blob");
        rustls_root_cert_store_builder_free(roots_builder);
        rustls_client_config_free(
          rustls_client_config_builder_build(config_builder));
        return CURLE_SSL_CACERT_BADFILE;
      }
    }
    else if(ssl_cafile) {
      /* Enable strict parsing only if verification is not disabled. */
      result = rustls_root_cert_store_builder_load_roots_from_file(
        roots_builder, ssl_cafile, verifypeer);
      if(result != RUSTLS_RESULT_OK) {
        failf(data, "rustls: failed to load trusted certificates");
        rustls_root_cert_store_builder_free(roots_builder);
        rustls_client_config_free(
          rustls_client_config_builder_build(config_builder));
600
601
602
603
604
605
606

607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627

628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643

  /* Read/write data until the handshake is done or the socket would block. */
  for(;;) {
    /*
    * Connection has been established according to rustls. Set send/recv
    * handlers, and update the state machine.
    */

    if(!rustls_connection_is_handshaking(rconn)) {
      infof(data, "Done handshaking");
      /* rustls claims it is no longer handshaking *before* it has
       * send its FINISHED message off. We attempt to let it write
       * one more time. Oh my.
       */
      cr_set_negotiated_alpn(cf, data, rconn);
      cr_send(cf, data, NULL, 0, &tmperr);
      if(tmperr == CURLE_AGAIN) {
        connssl->connecting_state = ssl_connect_2_writing;
        return CURLE_OK;
      }
      else if(tmperr != CURLE_OK) {
        return tmperr;
      }
      /* REALLY Done with the handshake. */
      connssl->state = ssl_connection_complete;
      *done = TRUE;
      return CURLE_OK;
    }


    wants_read = rustls_connection_wants_read(rconn);
    wants_write = rustls_connection_wants_write(rconn) ||
                  backend->plain_out_buffered;
    DEBUGASSERT(wants_read || wants_write);
    writefd = wants_write?sockfd:CURL_SOCKET_BAD;
    readfd = wants_read?sockfd:CURL_SOCKET_BAD;

    connssl->connecting_state = wants_write?
      ssl_connect_2_writing : ssl_connect_2_reading;
    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "rustls: operation timed out before socket check");
      return CURLE_OPERATION_TIMEDOUT;







>









|











>







<
<







601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637


638
639
640
641
642
643
644

  /* Read/write data until the handshake is done or the socket would block. */
  for(;;) {
    /*
    * Connection has been established according to rustls. Set send/recv
    * handlers, and update the state machine.
    */
    connssl->io_need = CURL_SSL_IO_NEED_NONE;
    if(!rustls_connection_is_handshaking(rconn)) {
      infof(data, "Done handshaking");
      /* rustls claims it is no longer handshaking *before* it has
       * send its FINISHED message off. We attempt to let it write
       * one more time. Oh my.
       */
      cr_set_negotiated_alpn(cf, data, rconn);
      cr_send(cf, data, NULL, 0, &tmperr);
      if(tmperr == CURLE_AGAIN) {
        connssl->io_need = CURL_SSL_IO_NEED_SEND;
        return CURLE_OK;
      }
      else if(tmperr != CURLE_OK) {
        return tmperr;
      }
      /* REALLY Done with the handshake. */
      connssl->state = ssl_connection_complete;
      *done = TRUE;
      return CURLE_OK;
    }

    connssl->connecting_state = ssl_connect_2;
    wants_read = rustls_connection_wants_read(rconn);
    wants_write = rustls_connection_wants_write(rconn) ||
                  backend->plain_out_buffered;
    DEBUGASSERT(wants_read || wants_write);
    writefd = wants_write?sockfd:CURL_SOCKET_BAD;
    readfd = wants_read?sockfd:CURL_SOCKET_BAD;



    /* check allowed time left */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "rustls: operation timed out before socket check");
      return CURLE_OPERATION_TIMEDOUT;
657
658
659
660
661
662
663




664
665
666
667
668
669
670
        CURL_FORMAT_TIMEDIFF_T " ms", socket_check_timeout);
      return CURLE_OPERATION_TIMEDOUT;
    }
    if(0 == what) {
      CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
            wants_read&&wants_write ? "writing and reading" :
            wants_write ? "writing" : "reading");




      return CURLE_OK;
    }
    /* socket is readable or writable */

    if(wants_write) {
      CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
      cr_send(cf, data, NULL, 0, &tmperr);







>
>
>
>







658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
        CURL_FORMAT_TIMEDIFF_T " ms", socket_check_timeout);
      return CURLE_OPERATION_TIMEDOUT;
    }
    if(0 == what) {
      CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
            wants_read&&wants_write ? "writing and reading" :
            wants_write ? "writing" : "reading");
      if(wants_write)
        connssl->io_need |= CURL_SSL_IO_NEED_SEND;
      if(wants_read)
        connssl->io_need |= CURL_SSL_IO_NEED_RECV;
      return CURLE_OK;
    }
    /* socket is readable or writable */

    if(wants_write) {
      CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
      cr_send(cf, data, NULL, 0, &tmperr);
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
          return tmperr;
        }
      }
    }
  }

  /* We should never fall through the loop. We should return either because
     the handshake is done or because we can't read/write without blocking. */
  DEBUGASSERT(false);
}

static CURLcode
cr_connect_nonblocking(struct Curl_cfilter *cf,
                       struct Curl_easy *data, bool *done)
{







|







696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
          return tmperr;
        }
      }
    }
  }

  /* We should never fall through the loop. We should return either because
     the handshake is done or because we cannot read/write without blocking. */
  DEBUGASSERT(false);
}

static CURLcode
cr_connect_nonblocking(struct Curl_cfilter *cf,
                       struct Curl_easy *data, bool *done)
{
718
719
720
721
722
723
724
725
726

727

728
729
730
731
732
733


734
































































735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
                 CURLINFO info UNUSED_PARAM)
{
  struct rustls_ssl_backend_data *backend =
    (struct rustls_ssl_backend_data *)connssl->backend;
  DEBUGASSERT(backend);
  return &backend->conn;
}

static void

cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)

{
  struct ssl_connect_data *connssl = cf->ctx;
  struct rustls_ssl_backend_data *backend =
    (struct rustls_ssl_backend_data *)connssl->backend;
  CURLcode tmperr = CURLE_OK;
  ssize_t n = 0;



































































  DEBUGASSERT(backend);
  if(backend->conn && !connssl->peer_closed) {
    CURL_TRC_CF(data, cf, "closing connection, send notify");
    rustls_connection_send_close_notify(backend->conn);
    n = cr_send(cf, data, NULL, 0, &tmperr);
    if(n < 0) {
      failf(data, "rustls: error sending close_notify: %d", tmperr);
    }

    rustls_connection_free(backend->conn);
    backend->conn = NULL;
  }
  if(backend->config) {
    rustls_client_config_free(backend->config);
    backend->config = NULL;
  }








|
>
|
>




|
|
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
<
<
<
<
<
<
<







723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809







810
811
812
813
814
815
816
                 CURLINFO info UNUSED_PARAM)
{
  struct rustls_ssl_backend_data *backend =
    (struct rustls_ssl_backend_data *)connssl->backend;
  DEBUGASSERT(backend);
  return &backend->conn;
}

static CURLcode
cr_shutdown(struct Curl_cfilter *cf,
            struct Curl_easy *data,
            bool send_shutdown, bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct rustls_ssl_backend_data *backend =
    (struct rustls_ssl_backend_data *)connssl->backend;
  CURLcode result = CURLE_OK;
  ssize_t nwritten, nread;
  char buf[1024];
  size_t i;

  DEBUGASSERT(backend);
  if(!backend->conn || cf->shutdown) {
    *done = TRUE;
    goto out;
  }

  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  *done = FALSE;

  if(!backend->sent_shutdown) {
    /* do this only once */
    backend->sent_shutdown = TRUE;
    if(send_shutdown) {
      rustls_connection_send_close_notify(backend->conn);
    }
  }

  nwritten = cr_send(cf, data, NULL, 0, &result);
  if(nwritten < 0) {
    if(result == CURLE_AGAIN) {
      connssl->io_need = CURL_SSL_IO_NEED_SEND;
      result = CURLE_OK;
      goto out;
    }
    DEBUGASSERT(result);
    CURL_TRC_CF(data, cf, "shutdown send failed: %d", result);
    goto out;
  }

  for(i = 0; i < 10; ++i) {
    nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result);
    if(nread <= 0)
      break;
  }

  if(nread > 0) {
    /* still data coming in? */
  }
  else if(nread == 0) {
    /* We got the close notify alert and are done. */
    *done = TRUE;
  }
  else if(result == CURLE_AGAIN) {
    connssl->io_need = CURL_SSL_IO_NEED_RECV;
    result = CURLE_OK;
  }
  else {
    DEBUGASSERT(result);
    CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
  }

out:
  cf->shutdown = (result || *done);
  return result;
}

static void
cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct rustls_ssl_backend_data *backend =
    (struct rustls_ssl_backend_data *)connssl->backend;

  (void)data;
  DEBUGASSERT(backend);
  if(backend->conn) {







    rustls_connection_free(backend->conn);
    backend->conn = NULL;
  }
  if(backend->config) {
    rustls_client_config_free(backend->config);
    backend->config = NULL;
  }
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
  SSLSUPP_HTTPS_PROXY,
  sizeof(struct rustls_ssl_backend_data),

  Curl_none_init,                  /* init */
  Curl_none_cleanup,               /* cleanup */
  cr_version,                      /* version */
  Curl_none_check_cxn,             /* check_cxn */
  Curl_none_shutdown,              /* shutdown */
  cr_data_pending,                 /* data_pending */
  Curl_none_random,                /* random */
  Curl_none_cert_status_request,   /* cert_status_request */
  cr_connect_blocking,             /* connect */
  cr_connect_nonblocking,          /* connect_nonblocking */
  Curl_ssl_adjust_pollset,         /* adjust_pollset */
  cr_get_internals,                /* get_internals */
  cr_close,                        /* close_one */
  Curl_none_close_all,             /* close_all */
  Curl_none_set_engine,            /* set_engine */
  Curl_none_set_engine_default,    /* set_engine_default */
  Curl_none_engines_list,          /* engines_list */
  Curl_none_false_start,           /* false_start */
  NULL,                            /* sha256sum */
  NULL,                            /* associate_connection */
  NULL,                            /* disassociate_connection */
  NULL,                            /* free_multi_ssl_backend_data */
  cr_recv,                         /* recv decrypted data */
  cr_send,                         /* send data to encrypt */
};

#endif /* USE_RUSTLS */







|
















<





828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851

852
853
854
855
856
  SSLSUPP_HTTPS_PROXY,
  sizeof(struct rustls_ssl_backend_data),

  Curl_none_init,                  /* init */
  Curl_none_cleanup,               /* cleanup */
  cr_version,                      /* version */
  Curl_none_check_cxn,             /* check_cxn */
  cr_shutdown,                     /* shutdown */
  cr_data_pending,                 /* data_pending */
  Curl_none_random,                /* random */
  Curl_none_cert_status_request,   /* cert_status_request */
  cr_connect_blocking,             /* connect */
  cr_connect_nonblocking,          /* connect_nonblocking */
  Curl_ssl_adjust_pollset,         /* adjust_pollset */
  cr_get_internals,                /* get_internals */
  cr_close,                        /* close_one */
  Curl_none_close_all,             /* close_all */
  Curl_none_set_engine,            /* set_engine */
  Curl_none_set_engine_default,    /* set_engine_default */
  Curl_none_engines_list,          /* engines_list */
  Curl_none_false_start,           /* false_start */
  NULL,                            /* sha256sum */
  NULL,                            /* associate_connection */
  NULL,                            /* disassociate_connection */

  cr_recv,                         /* recv decrypted data */
  cr_send,                         /* send data to encrypt */
};

#endif /* USE_RUSTLS */
Changes to jni/curl/lib/vtls/schannel.c.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 */

#include "curl_setup.h"

#ifdef USE_SCHANNEL

#ifndef USE_WINDOWS_SSPI
#  error "Can't compile SCHANNEL support without SSPI."
#endif

#include "schannel.h"
#include "schannel_int.h"
#include "vtls.h"
#include "vtls_int.h"
#include "strcase.h"







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 */

#include "curl_setup.h"

#ifdef USE_SCHANNEL

#ifndef USE_WINDOWS_SSPI
#  error "cannot compile SCHANNEL support without SSPI."
#endif

#include "schannel.h"
#include "schannel_int.h"
#include "vtls.h"
#include "vtls_int.h"
#include "strcase.h"
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
static CURLcode
schannel_set_ssl_version_min_max(DWORD *enabled_protocols,
                                 struct Curl_cfilter *cf,
                                 struct Curl_easy *data)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  long ssl_version = conn_config->version;
  long ssl_version_max = conn_config->version_max;
  long i = ssl_version;

  switch(ssl_version_max) {
  case CURL_SSLVERSION_MAX_NONE:
  case CURL_SSLVERSION_MAX_DEFAULT:

    /* Windows Server 2022 and newer (including Windows 11) support TLS 1.3







|







167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
static CURLcode
schannel_set_ssl_version_min_max(DWORD *enabled_protocols,
                                 struct Curl_cfilter *cf,
                                 struct Curl_easy *data)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  long ssl_version = conn_config->version;
  long ssl_version_max = (long)conn_config->version_max;
  long i = ssl_version;

  switch(ssl_version_max) {
  case CURL_SSLVERSION_MAX_NONE:
  case CURL_SSLVERSION_MAX_DEFAULT:

    /* Windows Server 2022 and newer (including Windows 11) support TLS 1.3
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  char *startCur = ciphers;
  int algCount = 0;
  while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) {
    long alg = strtol(startCur, 0, 0);
    if(!alg)
      alg = get_alg_id_by_name(startCur);
    if(alg)
      algIds[algCount++] = alg;
    else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
                     sizeof("USE_STRONG_CRYPTO") - 1) ||
            !strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
                     sizeof("SCH_USE_STRONG_CRYPTO") - 1))
      schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO;
    else
      return CURLE_SSL_CIPHER;
    startCur = strchr(startCur, ':');
    if(startCur)
      startCur++;
  }
  schannel_cred->palgSupportedAlgs = algIds;
  schannel_cred->cSupportedAlgs = algCount;
  return CURLE_OK;
}

#ifdef HAS_CLIENT_CERT_PATH

/* Function allocates memory for store_path only if CURLE_OK is returned */
static CURLcode







|












|







360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  char *startCur = ciphers;
  int algCount = 0;
  while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) {
    long alg = strtol(startCur, 0, 0);
    if(!alg)
      alg = get_alg_id_by_name(startCur);
    if(alg)
      algIds[algCount++] = (ALG_ID)alg;
    else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
                     sizeof("USE_STRONG_CRYPTO") - 1) ||
            !strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
                     sizeof("SCH_USE_STRONG_CRYPTO") - 1))
      schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO;
    else
      return CURLE_SSL_CIPHER;
    startCur = strchr(startCur, ':');
    if(startCur)
      startCur++;
  }
  schannel_cred->palgSupportedAlgs = algIds;
  schannel_cred->cSupportedAlgs = (DWORD)algCount;
  return CURLE_OK;
}

#ifdef HAS_CLIENT_CERT_PATH

/* Function allocates memory for store_path only if CURLE_OK is returned */
static CURLcode
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
    flags |= SCH_CRED_NO_SERVERNAME_CHECK;
    DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
                 "comparing the supplied target name with the subject "
                 "names in server certificates."));
  }

  if(!ssl_config->auto_client_cert) {
    flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
    flags |= SCH_CRED_NO_DEFAULT_CREDS;
    infof(data, "schannel: disabled automatic use of client certificate");
  }
  else
    infof(data, "schannel: enabled automatic use of client certificate");

  switch(conn_config->version) {







|







509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
    flags |= SCH_CRED_NO_SERVERNAME_CHECK;
    DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
                 "comparing the supplied target name with the subject "
                 "names in server certificates."));
  }

  if(!ssl_config->auto_client_cert) {
    flags &= ~(DWORD)SCH_CRED_USE_DEFAULT_CREDS;
    flags |= SCH_CRED_NO_DEFAULT_CREDS;
    infof(data, "schannel: disabled automatic use of client certificate");
  }
  else
    infof(data, "schannel: enabled automatic use of client certificate");

  switch(conn_config->version) {
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
        (PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM;
      crypto_settings_idx++;
    }

    tls_parameters.pDisabledCrypto = crypto_settings;

    /* The number of blocked suites */
    tls_parameters.cDisabledCrypto = crypto_settings_idx;
    credentials.pTlsParameters = &tls_parameters;
    credentials.cTlsParameters = 1;

    credentials.dwVersion = SCH_CREDENTIALS_VERSION;
    credentials.dwFlags = flags | SCH_USE_STRONG_CRYPTO;

    credentials.pTlsParameters->grbitDisabledProtocols =







|







946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
        (PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM;
      crypto_settings_idx++;
    }

    tls_parameters.pDisabledCrypto = crypto_settings;

    /* The number of blocked suites */
    tls_parameters.cDisabledCrypto = (DWORD)crypto_settings_idx;
    credentials.pTlsParameters = &tls_parameters;
    credentials.cTlsParameters = 1;

    credentials.dwVersion = SCH_CREDENTIALS_VERSION;
    credentials.dwFlags = flags | SCH_USE_STRONG_CRYPTO;

    credentials.pTlsParameters->grbitDisabledProtocols =
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
                                         SECPKG_CRED_OUTBOUND, NULL,
                                         &credentials, NULL, NULL,
                                         &backend->cred->cred_handle,
                                         &backend->cred->time_stamp);
  }
  else {
    /* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
       doesn't document it, currently Schannel will not negotiate TLS 1.3 when
       SCHANNEL_CRED is used. */
    ALG_ID algIds[NUM_CIPHERS];
    char *ciphers = conn_config->cipher_list;
    SCHANNEL_CRED schannel_cred = { 0 };
    schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
    schannel_cred.dwFlags = flags;
    schannel_cred.grbitEnabledProtocols = enabled_protocols;







|







972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
                                         SECPKG_CRED_OUTBOUND, NULL,
                                         &credentials, NULL, NULL,
                                         &backend->cred->cred_handle,
                                         &backend->cred->time_stamp);
  }
  else {
    /* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
       does not document it, currently Schannel will not negotiate TLS 1.3 when
       SCHANNEL_CRED is used. */
    ALG_ID algIds[NUM_CIPHERS];
    char *ciphers = conn_config->cipher_list;
    SCHANNEL_CRED schannel_cred = { 0 };
    schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
    schannel_cred.dwFlags = flags;
    schannel_cred.grbitEnabledProtocols = enabled_protocols;
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
       algorithms that may not be supported by all servers. */
    infof(data, "schannel: Windows version is old and may not be able to "
          "connect to some servers due to lack of SNI, algorithms, etc.");
  }

#ifdef HAS_ALPN
  /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
     Also it doesn't seem to be supported for Wine, see curl bug #983. */
  backend->use_alpn = connssl->alpn &&
    !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
                    "wine_get_version") &&
    curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
                                 VERSION_GREATER_THAN_EQUAL);
#else
  backend->use_alpn = false;
#endif

#ifdef _WIN32_WCE
#ifdef HAS_MANUAL_VERIFY_API
  /* certificate validation on CE doesn't seem to work right; we'll
   * do it following a more manual process. */
  backend->use_manual_cred_validation = true;
#else
#error "compiler too old to support requisite manual cert verify for Win CE"
#endif
#else
#ifdef HAS_MANUAL_VERIFY_API







|











|







1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
       algorithms that may not be supported by all servers. */
    infof(data, "schannel: Windows version is old and may not be able to "
          "connect to some servers due to lack of SNI, algorithms, etc.");
  }

#ifdef HAS_ALPN
  /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
     Also it does not seem to be supported for Wine, see curl bug #983. */
  backend->use_alpn = connssl->alpn &&
    !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
                    "wine_get_version") &&
    curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
                                 VERSION_GREATER_THAN_EQUAL);
#else
  backend->use_alpn = false;
#endif

#ifdef _WIN32_WCE
#ifdef HAS_MANUAL_VERIFY_API
  /* certificate validation on CE does not seem to work right; we will
   * do it following a more manual process. */
  backend->use_manual_cred_validation = true;
#else
#error "compiler too old to support requisite manual cert verify for Win CE"
#endif
#else
#ifdef HAS_MANUAL_VERIFY_API
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  }
#endif
#endif

  backend->cred = NULL;

  /* check for an existing reusable credential handle */
  if(ssl_config->primary.sessionid) {
    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
                              (void **)&old_cred, NULL)) {
      backend->cred = old_cred;
      DEBUGF(infof(data, "schannel: reusing existing credential handle"));

      /* increment the reference counter of the credential/session handle */







|







1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  }
#endif
#endif

  backend->cred = NULL;

  /* check for an existing reusable credential handle */
  if(ssl_config->primary.cache_session) {
    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
                              (void **)&old_cred, NULL)) {
      backend->cred = old_cred;
      DEBUGF(infof(data, "schannel: reusing existing credential handle"));

      /* increment the reference counter of the credential/session handle */
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
    failf(data, "schannel: unable to allocate memory");
    return CURLE_OUT_OF_MEMORY;
  }

  /* Schannel InitializeSecurityContext:
     https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx

     At the moment we don't pass inbuf unless we're using ALPN since we only
     use it for that, and Wine (for which we currently disable ALPN) is giving
     us problems with inbuf regardless. https://github.com/curl/curl/issues/983
  */
  sspi_status = s_pSecFn->InitializeSecurityContext(
    &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
    backend->req_flags, 0, 0,
    (backend->use_alpn ? &inbuf_desc : NULL),







|







1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
    failf(data, "schannel: unable to allocate memory");
    return CURLE_OUT_OF_MEMORY;
  }

  /* Schannel InitializeSecurityContext:
     https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx

     At the moment we do not pass inbuf unless we are using ALPN since we only
     use it for that, and Wine (for which we currently disable ALPN) is giving
     us problems with inbuf regardless. https://github.com/curl/curl/issues/983
  */
  sspi_status = s_pSecFn->InitializeSecurityContext(
    &backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
    backend->req_flags, 0, 0,
    (backend->use_alpn ? &inbuf_desc : NULL),
1328
1329
1330
1331
1332
1333
1334
1335

1336
1337
1338
1339
1340
1341
1342
  SECURITY_STATUS sspi_status = SEC_E_OK;
  CURLcode result;
  bool doread;
  const char *pubkey_ptr;

  DEBUGASSERT(backend);

  doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;


  DEBUGF(infof(data,
               "schannel: SSL/TLS connection with %s port %d (step 2/3)",
               connssl->peer.hostname, connssl->peer.port));

  if(!backend->cred || !backend->ctxt)
    return CURLE_SSL_CONNECT_ERROR;







|
>







1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
  SECURITY_STATUS sspi_status = SEC_E_OK;
  CURLcode result;
  bool doread;
  const char *pubkey_ptr;

  DEBUGASSERT(backend);

  doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? FALSE : TRUE;
  connssl->io_need = CURL_SSL_IO_NEED_NONE;

  DEBUGF(infof(data,
               "schannel: SSL/TLS connection with %s port %d (step 2/3)",
               connssl->peer.hostname, connssl->peer.port));

  if(!backend->cred || !backend->ctxt)
    return CURLE_SSL_CONNECT_ERROR;
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
      nread = Curl_conn_cf_recv(cf->next, data,
                               (char *) (backend->encdata_buffer +
                                         backend->encdata_offset),
                               backend->encdata_length -
                               backend->encdata_offset,
                               &result);
      if(result == CURLE_AGAIN) {
        if(connssl->connecting_state != ssl_connect_2_writing)
          connssl->connecting_state = ssl_connect_2_reading;
        DEBUGF(infof(data, "schannel: failed to receive handshake, "
                     "need more data"));
        return CURLE_OK;
      }
      else if((result != CURLE_OK) || (nread == 0)) {
        failf(data, "schannel: failed to receive handshake, "
              "SSL/TLS connection failed");







|
<







1390
1391
1392
1393
1394
1395
1396
1397

1398
1399
1400
1401
1402
1403
1404
      nread = Curl_conn_cf_recv(cf->next, data,
                               (char *) (backend->encdata_buffer +
                                         backend->encdata_offset),
                               backend->encdata_length -
                               backend->encdata_offset,
                               &result);
      if(result == CURLE_AGAIN) {
        connssl->io_need = CURL_SSL_IO_NEED_RECV;

        DEBUGF(infof(data, "schannel: failed to receive handshake, "
                     "need more data"));
        return CURLE_OK;
      }
      else if((result != CURLE_OK) || (nread == 0)) {
        failf(data, "schannel: failed to receive handshake, "
              "SSL/TLS connection failed");
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470

    /* free buffer for received handshake data */
    Curl_safefree(inbuf[0].pvBuffer);

    /* check if the handshake was incomplete */
    if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
      backend->encdata_is_incomplete = true;
      connssl->connecting_state = ssl_connect_2_reading;
      DEBUGF(infof(data,
                   "schannel: received incomplete message, need more data"));
      return CURLE_OK;
    }

    /* If the server has requested a client certificate, attempt to continue
       the handshake without one. This will allow connections to servers which
       request a client certificate but do not require it. */
    if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
       !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
      backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
      connssl->connecting_state = ssl_connect_2_writing;
      DEBUGF(infof(data,
                   "schannel: a client certificate has been requested"));
      return CURLE_OK;
    }

    /* check if the handshake needs to be continued */
    if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {







|











|







1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470

    /* free buffer for received handshake data */
    Curl_safefree(inbuf[0].pvBuffer);

    /* check if the handshake was incomplete */
    if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
      backend->encdata_is_incomplete = true;
      connssl->io_need = CURL_SSL_IO_NEED_RECV;
      DEBUGF(infof(data,
                   "schannel: received incomplete message, need more data"));
      return CURLE_OK;
    }

    /* If the server has requested a client certificate, attempt to continue
       the handshake without one. This will allow connections to servers which
       request a client certificate but do not require it. */
    if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
       !(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
      backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
      connssl->io_need = CURL_SSL_IO_NEED_SEND;
      DEBUGF(infof(data,
                   "schannel: a client certificate has been requested"));
      return CURLE_OK;
    }

    /* check if the handshake needs to be continued */
    if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541

    /* check if there was additional remaining encrypted data */
    if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
      DEBUGF(infof(data, "schannel: encrypted data length: %lu",
                   inbuf[1].cbBuffer));
      /*
        There are two cases where we could be getting extra data here:
        1) If we're renegotiating a connection and the handshake is already
        complete (from the server perspective), it can encrypted app data
        (not handshake data) in an extra buffer at this point.
        2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
        connection and this extra data is part of the handshake.
        We should process the data immediately; waiting for the socket to
        be ready may fail since the server is done sending handshake data.
      */







|







1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541

    /* check if there was additional remaining encrypted data */
    if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
      DEBUGF(infof(data, "schannel: encrypted data length: %lu",
                   inbuf[1].cbBuffer));
      /*
        There are two cases where we could be getting extra data here:
        1) If we are renegotiating a connection and the handshake is already
        complete (from the server perspective), it can encrypted app data
        (not handshake data) in an extra buffer at this point.
        2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
        connection and this extra data is part of the handshake.
        We should process the data immediately; waiting for the socket to
        be ready may fail since the server is done sending handshake data.
      */
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
      backend->encdata_offset = 0;
    }
    break;
  }

  /* check if the handshake needs to be continued */
  if(sspi_status == SEC_I_CONTINUE_NEEDED) {
    connssl->connecting_state = ssl_connect_2_reading;
    return CURLE_OK;
  }

  /* check if the handshake is complete */
  if(sspi_status == SEC_E_OK) {
    connssl->connecting_state = ssl_connect_3;
    DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));







|







1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
      backend->encdata_offset = 0;
    }
    break;
  }

  /* check if the handshake needs to be continued */
  if(sspi_status == SEC_I_CONTINUE_NEEDED) {
    connssl->io_need = CURL_SSL_IO_NEED_RECV;
    return CURLE_OK;
  }

  /* check if the handshake is complete */
  if(sspi_status == SEC_E_OK) {
    connssl->connecting_state = ssl_connect_3;
    DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
  if(conn_config->verifypeer && backend->use_manual_cred_validation) {
    /* Certificate verification also verifies the hostname if verifyhost */
    return Curl_verify_certificate(cf, data);
  }
#endif

  /* Verify the hostname manually when certificate verification is disabled,
     because in that case Schannel won't verify it. */
  if(!conn_config->verifypeer && conn_config->verifyhost)
    return Curl_verify_host(cf, data);

  return CURLE_OK;
}

static bool







|







1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
  if(conn_config->verifypeer && backend->use_manual_cred_validation) {
    /* Certificate verification also verifies the hostname if verifyhost */
    return Curl_verify_certificate(cf, data);
  }
#endif

  /* Verify the hostname manually when certificate verification is disabled,
     because in that case Schannel will not verify it. */
  if(!conn_config->verifypeer && conn_config->verifyhost)
    return Curl_verify_host(cf, data);

  return CURLE_OK;
}

static bool
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798

1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
      if(!backend->recv_renegotiating)
        Curl_alpn_set_negotiated(cf, data, NULL, 0);
    }
  }
#endif

  /* save the current session data for possible reuse */
  if(ssl_config->primary.sessionid) {
    bool incache;
    struct Curl_schannel_cred *old_cred = NULL;

    Curl_ssl_sessionid_lock(data);
    incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
                                      (void **)&old_cred, NULL));
    if(incache) {
      if(old_cred != backend->cred) {
        DEBUGF(infof(data,
                     "schannel: old credential handle is stale, removing"));
        /* we're not taking old_cred ownership here, no refcount++ is needed */
        Curl_ssl_delsessionid(data, (void *)old_cred);
        incache = FALSE;
      }
    }
    if(!incache) {
      /* Up ref count since call takes ownership */
      backend->cred->refcount++;
      result = Curl_ssl_addsessionid(cf, data, &connssl->peer, backend->cred,
                                     sizeof(struct Curl_schannel_cred),
                                     schannel_session_free);
      if(result) {
        Curl_ssl_sessionid_unlock(data);

        return result;
      }
    }
    Curl_ssl_sessionid_unlock(data);
  }

  if(data->set.ssl.certinfo) {
    int certs_count = 0;
    sspi_status =
      s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
                                       SECPKG_ATTR_REMOTE_CERT_CONTEXT,







|
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
|
|
<
|
>
|
<
<
<







1768
1769
1770
1771
1772
1773
1774
1775



1776












1777
1778
1779
1780
1781

1782
1783
1784



1785
1786
1787
1788
1789
1790
1791
      if(!backend->recv_renegotiating)
        Curl_alpn_set_negotiated(cf, data, NULL, 0);
    }
  }
#endif

  /* save the current session data for possible reuse */
  if(ssl_config->primary.cache_session) {



    Curl_ssl_sessionid_lock(data);












    /* Up ref count since call takes ownership */
    backend->cred->refcount++;
    result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, backend->cred,
                                    sizeof(struct Curl_schannel_cred),
                                    schannel_session_free);

    Curl_ssl_sessionid_unlock(data);
    if(result)
      return result;



  }

  if(data->set.ssl.certinfo) {
    int certs_count = 0;
    sspi_status =
      s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
                                       SECPKG_ATTR_REMOTE_CERT_CONTEXT,
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* check out how much more time we're allowed */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL/TLS connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = schannel_connect_step1(cf, data);
    if(result)
      return result;
  }

  while(ssl_connect_2 == connssl->connecting_state ||
        ssl_connect_2_reading == connssl->connecting_state ||
        ssl_connect_2_writing == connssl->connecting_state) {

    /* check out how much more time we're allowed */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL/TLS connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it's available. */
    if(connssl->connecting_state == ssl_connect_2_reading
       || connssl->connecting_state == ssl_connect_2_writing) {

      curl_socket_t writefd = ssl_connect_2_writing ==
        connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading ==
        connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking ? 0 : timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;







|













|
<
<

|








|
|
<

|
|
|
|







1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852


1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864

1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* check out how much more time we are allowed */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL/TLS connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = schannel_connect_step1(cf, data);
    if(result)
      return result;
  }

  while(ssl_connect_2 == connssl->connecting_state) {



    /* check out how much more time we are allowed */
    timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL/TLS connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it is available. */
    if(connssl->io_need) {


      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
                              sockfd : CURL_SOCKET_BAD;
      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
                             sockfd : CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking ? 0 : timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
     * this connection is part of a multi handle and this loop would
     * execute again. This permits the owner of a multi handle to
     * abort a connection attempt before step2 has completed while
     * ensuring that a client using select() or epoll() will always
     * have a valid fdset to wait on.
     */
    result = schannel_connect_step2(cf, data);
    if(result || (nonblocking &&
                  (ssl_connect_2 == connssl->connecting_state ||
                   ssl_connect_2_reading == connssl->connecting_state ||
                   ssl_connect_2_writing == connssl->connecting_state)))
      return result;

  } /* repeat step2 until all transactions are done. */

  if(ssl_connect_3 == connssl->connecting_state) {
    result = schannel_connect_step3(cf, data);
    if(result)







|
<
<
<







1893
1894
1895
1896
1897
1898
1899
1900



1901
1902
1903
1904
1905
1906
1907
     * this connection is part of a multi handle and this loop would
     * execute again. This permits the owner of a multi handle to
     * abort a connection attempt before step2 has completed while
     * ensuring that a client using select() or epoll() will always
     * have a valid fdset to wait on.
     */
    result = schannel_connect_step2(cf, data);
    if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))



      return result;

  } /* repeat step2 until all transactions are done. */

  if(ssl_connect_3 == connssl->connecting_state) {
    result = schannel_connect_step3(cf, data);
    if(result)
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
  if(sspi_status == SEC_E_OK) {
    written = 0;

    /* send the encrypted message including header, data and trailer */
    len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;

    /*
      It's important to send the full message which includes the header,
      encrypted payload, and trailer.  Until the client receives all the
      data a coherent message has not been delivered and the client
      can't read any of it.

      If we wanted to buffer the unwritten encrypted bytes, we would
      tell the client that all data it has requested to be sent has been
      sent. The unwritten encrypted bytes would be the first bytes to
      send on the next invocation.
      Here's the catch with this - if we tell the client that all the
      bytes have been sent, will the client call this method again to







|
|

|







2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
  if(sspi_status == SEC_E_OK) {
    written = 0;

    /* send the encrypted message including header, data and trailer */
    len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;

    /*
      it is important to send the full message which includes the header,
      encrypted payload, and trailer. Until the client receives all the
      data a coherent message has not been delivered and the client
      cannot read any of it.

      If we wanted to buffer the unwritten encrypted bytes, we would
      tell the client that all data it has requested to be sent has been
      sent. The unwritten encrypted bytes would be the first bytes to
      send on the next invocation.
      Here's the catch with this - if we tell the client that all the
      bytes have been sent, will the client call this method again to
2125
2126
2127
2128
2129
2130
2131
2132
2133

2134
2135
2136
2137
2138
2139
2140
  size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
  struct schannel_ssl_backend_data *backend =
    (struct schannel_ssl_backend_data *)connssl->backend;

  DEBUGASSERT(backend);

  /****************************************************************************
   * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
   * The pattern for return error is set *err, optional infof, goto cleanup.

   *
   * Our priority is to always return as much decrypted data to the caller as
   * possible, even if an error occurs. The state of the decrypted buffer must
   * always be valid. Transfer of decrypted data to the caller's buffer is
   * handled in the cleanup.
   */








|
|
>







2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
  size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
  struct schannel_ssl_backend_data *backend =
    (struct schannel_ssl_backend_data *)connssl->backend;

  DEBUGASSERT(backend);

  /****************************************************************************
   * Do not return or set backend->recv_unrecoverable_err unless in the
   * cleanup. The pattern for return error is set *err, optional infof, goto
   * cleanup.
   *
   * Our priority is to always return as much decrypted data to the caller as
   * possible, even if an error occurs. The state of the decrypted buffer must
   * always be valid. Transfer of decrypted data to the caller's buffer is
   * handled in the cleanup.
   */

2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
    goto cleanup;
  }
  else if(backend->recv_sspi_close_notify) {
    /* once a server has indicated shutdown there is no more encrypted data */
    infof(data, "schannel: server indicated shutdown in a prior call");
    goto cleanup;
  }
  /* It's debatable what to return when !len. Regardless we can't return
     immediately because there may be data to decrypt (in the case we want to
     decrypt all encrypted cached data) so handle !len later in cleanup.
  */
  else if(len && !backend->recv_connection_closed) {
    /* increase enc buffer in order to fit the requested amount of data */
    size = backend->encdata_length - backend->encdata_offset;
    if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||







|







2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
    goto cleanup;
  }
  else if(backend->recv_sspi_close_notify) {
    /* once a server has indicated shutdown there is no more encrypted data */
    infof(data, "schannel: server indicated shutdown in a prior call");
    goto cleanup;
  }
  /* it is debatable what to return when !len. Regardless we cannot return
     immediately because there may be data to decrypt (in the case we want to
     decrypt all encrypted cached data) so handle !len later in cleanup.
  */
  else if(len && !backend->recv_connection_closed) {
    /* increase enc buffer in order to fit the requested amount of data */
    size = backend->encdata_length - backend->encdata_offset;
    if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323

2324
2325
2326
2327
2328
2329
2330
        backend->encdata_offset = 0;
      }

      /* check if server wants to renegotiate the connection context */
      if(sspi_status == SEC_I_RENEGOTIATE) {
        infof(data, "schannel: remote party requests renegotiation");
        if(*err && *err != CURLE_AGAIN) {
          infof(data, "schannel: can't renegotiate, an error is pending");
          goto cleanup;
        }

        /* begin renegotiation */
        infof(data, "schannel: renegotiating SSL/TLS connection");
        connssl->state = ssl_connection_negotiating;
        connssl->connecting_state = ssl_connect_2_writing;

        backend->recv_renegotiating = true;
        *err = schannel_connect_common(cf, data, FALSE, &done);
        backend->recv_renegotiating = false;
        if(*err) {
          infof(data, "schannel: renegotiation failed");
          goto cleanup;
        }







|






|
>







2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
        backend->encdata_offset = 0;
      }

      /* check if server wants to renegotiate the connection context */
      if(sspi_status == SEC_I_RENEGOTIATE) {
        infof(data, "schannel: remote party requests renegotiation");
        if(*err && *err != CURLE_AGAIN) {
          infof(data, "schannel: cannot renegotiate, an error is pending");
          goto cleanup;
        }

        /* begin renegotiation */
        infof(data, "schannel: renegotiating SSL/TLS connection");
        connssl->state = ssl_connection_negotiating;
        connssl->connecting_state = ssl_connect_2;
        connssl->io_need = CURL_SSL_IO_NEED_SEND;
        backend->recv_renegotiating = true;
        *err = schannel_connect_common(cf, data, FALSE, &done);
        backend->recv_renegotiating = false;
        if(*err) {
          infof(data, "schannel: renegotiation failed");
          goto cleanup;
        }
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393

cleanup:
  /* Warning- there is no guarantee the encdata state is valid at this point */
  DEBUGF(infof(data, "schannel: schannel_recv cleanup"));

  /* Error if the connection has closed without a close_notify.

     The behavior here is a matter of debate. We don't want to be vulnerable
     to a truncation attack however there's some browser precedent for
     ignoring the close_notify for compatibility reasons.

     Additionally, Windows 2000 (v5.0) is a special case since it seems it
     doesn't return close_notify. In that case if the connection was closed we
     assume it was graceful (close_notify) since there doesn't seem to be a
     way to tell.
  */
  if(len && !backend->decdata_offset && backend->recv_connection_closed &&
     !backend->recv_sspi_close_notify) {
    bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
                                                VERSION_EQUAL);








|
|



|
|







2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371

cleanup:
  /* Warning- there is no guarantee the encdata state is valid at this point */
  DEBUGF(infof(data, "schannel: schannel_recv cleanup"));

  /* Error if the connection has closed without a close_notify.

     The behavior here is a matter of debate. We do not want to be vulnerable
     to a truncation attack however there is some browser precedent for
     ignoring the close_notify for compatibility reasons.

     Additionally, Windows 2000 (v5.0) is a special case since it seems it
     does not return close_notify. In that case if the connection was closed we
     assume it was graceful (close_notify) since there does not seem to be a
     way to tell.
  */
  if(len && !backend->decdata_offset && backend->recv_connection_closed &&
     !backend->recv_sspi_close_notify) {
    bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT,
                                                VERSION_EQUAL);

2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
    *err = CURLE_OK;
    return (ssize_t)size;
  }

  if(!*err && !backend->recv_connection_closed)
    *err = CURLE_AGAIN;

  /* It's debatable what to return when !len. We could return whatever error
     we got from decryption but instead we override here so the return is
     consistent.
  */
  if(!len)
    *err = CURLE_OK;

  return *err ? -1 : 0;







|







2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
    *err = CURLE_OK;
    return (ssize_t)size;
  }

  if(!*err && !backend->recv_connection_closed)
    *err = CURLE_AGAIN;

  /* it is debatable what to return when !len. We could return whatever error
     we got from decryption but instead we override here so the return is
     consistent.
  */
  if(!len)
    *err = CURLE_OK;

  return *err ? -1 : 0;
2471
2472
2473
2474
2475
2476
2477
2478
2479

2480
2481
2482
2483
2484
2485
2486






2487
2488
2489
2490




2491
2492
2493
2494
2495





2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514


2515
2516
2517
2518
2519
2520
2521
  else
    return FALSE;
}

/* shut down the SSL connection and clean up related memory.
   this function can be called multiple times on the same connection including
   if the SSL connection failed (eg connection made but failed handshake). */
static int schannel_shutdown(struct Curl_cfilter *cf,
                             struct Curl_easy *data)

{
  /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
   * Shutting Down an Schannel Connection
   */
  struct ssl_connect_data *connssl = cf->ctx;
  struct schannel_ssl_backend_data *backend =
    (struct schannel_ssl_backend_data *)connssl->backend;







  DEBUGASSERT(data);
  DEBUGASSERT(backend);





  if(backend->ctxt) {
    infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
          connssl->peer.hostname, connssl->peer.port);
  }






  if(backend->cred && backend->ctxt) {
    SecBufferDesc BuffDesc;
    SecBuffer Buffer;
    SECURITY_STATUS sspi_status;
    SecBuffer outbuf;
    SecBufferDesc outbuf_desc;
    CURLcode result;
    DWORD dwshut = SCHANNEL_SHUTDOWN;

    InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
    InitSecBufferDesc(&BuffDesc, &Buffer, 1);

    sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
                                              &BuffDesc);

    if(sspi_status != SEC_E_OK) {
      char buffer[STRERROR_LEN];
      failf(data, "schannel: ApplyControlToken failure: %s",
            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));


    }

    /* setup output buffer */
    InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
    InitSecBufferDesc(&outbuf_desc, &outbuf, 1);

    sspi_status = s_pSecFn->InitializeSecurityContext(







|
|
>







>
>
>
>
>
>




>
>
>
>





>
>
>
>
>
|





<












>
>







2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495

2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
  else
    return FALSE;
}

/* shut down the SSL connection and clean up related memory.
   this function can be called multiple times on the same connection including
   if the SSL connection failed (eg connection made but failed handshake). */
static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  bool send_shutdown, bool *done)
{
  /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
   * Shutting Down an Schannel Connection
   */
  struct ssl_connect_data *connssl = cf->ctx;
  struct schannel_ssl_backend_data *backend =
    (struct schannel_ssl_backend_data *)connssl->backend;
  CURLcode result = CURLE_OK;

  if(cf->shutdown) {
    *done = TRUE;
    return CURLE_OK;
  }

  DEBUGASSERT(data);
  DEBUGASSERT(backend);

  /* Not supported in schannel */
  (void)send_shutdown;

  *done = FALSE;
  if(backend->ctxt) {
    infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
          connssl->peer.hostname, connssl->peer.port);
  }

  if(!backend->ctxt || cf->shutdown) {
    *done = TRUE;
    goto out;
  }

  if(backend->cred && backend->ctxt && !backend->sent_shutdown) {
    SecBufferDesc BuffDesc;
    SecBuffer Buffer;
    SECURITY_STATUS sspi_status;
    SecBuffer outbuf;
    SecBufferDesc outbuf_desc;

    DWORD dwshut = SCHANNEL_SHUTDOWN;

    InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
    InitSecBufferDesc(&BuffDesc, &Buffer, 1);

    sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
                                              &BuffDesc);

    if(sspi_status != SEC_E_OK) {
      char buffer[STRERROR_LEN];
      failf(data, "schannel: ApplyControlToken failure: %s",
            Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
      result = CURLE_SEND_ERROR;
      goto out;
    }

    /* setup output buffer */
    InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
    InitSecBufferDesc(&outbuf_desc, &outbuf, 1);

    sspi_status = s_pSecFn->InitializeSecurityContext(
2534
2535
2536
2537
2538
2539
2540

2541

2542
2543


2544


2545




2546




















































2547
2548
2549
2550
2551
2552
2553

    if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
      /* send close message which is in output buffer */
      ssize_t written = Curl_conn_cf_send(cf->next, data,
                                          outbuf.pvBuffer, outbuf.cbBuffer,
                                          &result);
      s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);

      if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {

        infof(data, "schannel: failed to send close msg: %s"
              " (bytes written: %zd)", curl_easy_strerror(result), written);


      }


    }




  }





















































  /* free SSPI Schannel API security context handle */
  if(backend->ctxt) {
    DEBUGF(infof(data, "schannel: clear security context handle"));
    s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
    Curl_safefree(backend->ctxt);
  }







>
|
>
|
|
>
>
|
>
>
|
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610

    if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
      /* send close message which is in output buffer */
      ssize_t written = Curl_conn_cf_send(cf->next, data,
                                          outbuf.pvBuffer, outbuf.cbBuffer,
                                          &result);
      s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
      if(!result) {
        if(written < (ssize_t)outbuf.cbBuffer) {
          /* TODO: handle partial sends */
          infof(data, "schannel: failed to send close msg: %s"
                " (bytes written: %zd)", curl_easy_strerror(result), written);
          result = CURLE_SEND_ERROR;
          goto out;
        }
        backend->sent_shutdown = TRUE;
        *done = TRUE;
      }
      else if(result == CURLE_AGAIN) {
        connssl->io_need = CURL_SSL_IO_NEED_SEND;
        result = CURLE_OK;
        goto out;
      }
      else {
        if(!backend->recv_connection_closed) {
          infof(data, "schannel: error sending close msg: %d", result);
          result = CURLE_SEND_ERROR;
          goto out;
        }
        /* Looks like server already closed the connection.
         * An error to send our close notify is not a failure. */
        *done = TRUE;
        result = CURLE_OK;
      }
    }
  }

  /* If the connection seems open and we have not seen the close notify
   * from the server yet, try to receive it. */
  if(backend->cred && backend->ctxt &&
     !backend->recv_sspi_close_notify && !backend->recv_connection_closed) {
    char buffer[1024];
    ssize_t nread;

    nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result);
    if(nread > 0) {
      /* still data coming in? */
    }
    else if(nread == 0) {
      /* We got the close notify alert and are done. */
      backend->recv_connection_closed = TRUE;
      *done = TRUE;
    }
    else if(nread < 0 && result == CURLE_AGAIN) {
      connssl->io_need = CURL_SSL_IO_NEED_RECV;
    }
    else {
      CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
      result = CURLE_RECV_ERROR;
    }
  }

out:
  cf->shutdown = (result || *done);
  return result;
}

static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct schannel_ssl_backend_data *backend =
    (struct schannel_ssl_backend_data *)connssl->backend;

  DEBUGASSERT(data);
  DEBUGASSERT(backend);

  /* free SSPI Schannel API security context handle */
  if(backend->ctxt) {
    DEBUGF(infof(data, "schannel: clear security context handle"));
    s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
    Curl_safefree(backend->ctxt);
  }
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607

  /* free internal buffer for received decrypted data */
  if(backend->decdata_buffer) {
    Curl_safefree(backend->decdata_buffer);
    backend->decdata_length = 0;
    backend->decdata_offset = 0;
  }

  return CURLE_OK;
}

static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  schannel_shutdown(cf, data);
}

static int schannel_init(void)
{
  return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
}

static void schannel_cleanup(void)
{
  Curl_sspi_global_cleanup();
}

static size_t schannel_version(char *buffer, size_t size)
{
  size = msnprintf(buffer, size, "Schannel");

  return size;
}

static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
                                unsigned char *entropy, size_t length)
{
  (void)data;








<
<
<
<
<
<
<














|
<
<







2627
2628
2629
2630
2631
2632
2633







2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648


2649
2650
2651
2652
2653
2654
2655

  /* free internal buffer for received decrypted data */
  if(backend->decdata_buffer) {
    Curl_safefree(backend->decdata_buffer);
    backend->decdata_length = 0;
    backend->decdata_offset = 0;
  }







}

static int schannel_init(void)
{
  return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
}

static void schannel_cleanup(void)
{
  Curl_sspi_global_cleanup();
}

static size_t schannel_version(char *buffer, size_t size)
{
  return msnprintf(buffer, size, "Schannel");


}

static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
                                unsigned char *entropy, size_t length)
{
  (void)data;

2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
  CERT_CONTEXT *pCertContextServer = NULL;

  /* Result is returned to caller */
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;

  DEBUGASSERT(backend);

  /* if a path wasn't specified, don't pin */
  if(!pinnedpubkey)
    return CURLE_OK;

  do {
    SECURITY_STATUS sspi_status;
    const char *x509_der;
    DWORD x509_der_len;







|







2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
  CERT_CONTEXT *pCertContextServer = NULL;

  /* Result is returned to caller */
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;

  DEBUGASSERT(backend);

  /* if a path was not specified, do not pin */
  if(!pinnedpubkey)
    return CURLE_OK;

  do {
    SECURITY_STATUS sspi_status;
    const char *x509_der;
    DWORD x509_der_len;
2680
2681
2682
2683
2684
2685
2686







2687
2688
2689
2690
2691
2692
2693
static void schannel_checksum(const unsigned char *input,
                              size_t inputlen,
                              unsigned char *checksum,
                              size_t checksumlen,
                              DWORD provType,
                              const unsigned int algId)
{







  HCRYPTPROV hProv = 0;
  HCRYPTHASH hHash = 0;
  DWORD cbHashSize = 0;
  DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
  DWORD dwChecksumLen = (DWORD)checksumlen;

  /* since this can fail in multiple ways, zero memory first so we never







>
>
>
>
>
>
>







2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
static void schannel_checksum(const unsigned char *input,
                              size_t inputlen,
                              unsigned char *checksum,
                              size_t checksumlen,
                              DWORD provType,
                              const unsigned int algId)
{
#ifdef CURL_WINDOWS_APP
  (void)input;
  (void)inputlen;
  (void)provType;
  (void)algId;
  memset(checksum, 0, checksumlen);
#else
  HCRYPTPROV hProv = 0;
  HCRYPTHASH hHash = 0;
  DWORD cbHashSize = 0;
  DWORD dwHashSizeLen = (DWORD)sizeof(cbHashSize);
  DWORD dwChecksumLen = (DWORD)checksumlen;

  /* since this can fail in multiple ways, zero memory first so we never
2720
2721
2722
2723
2724
2725
2726

2727
2728
2729
2730
2731
2732
2733
  } while(0);

  if(hHash)
    CryptDestroyHash(hHash);

  if(hProv)
    CryptReleaseContext(hProv, 0);

}

static CURLcode schannel_sha256sum(const unsigned char *input,
                                   size_t inputlen,
                                   unsigned char *sha256sum,
                                   size_t sha256len)
{







>







2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
  } while(0);

  if(hHash)
    CryptDestroyHash(hHash);

  if(hProv)
    CryptReleaseContext(hProv, 0);
#endif
}

static CURLcode schannel_sha256sum(const unsigned char *input,
                                   size_t inputlen,
                                   unsigned char *sha256sum,
                                   size_t sha256len)
{
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768


2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814















2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836


2837



2838




2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851

HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
                                               const struct Curl_easy *data)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct Curl_multi *multi = data->multi;
  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
  struct schannel_multi_ssl_backend_data *mbackend;
  const struct ssl_general_config *cfg = &data->set.general_ssl;
  timediff_t timeout_ms;
  timediff_t elapsed_ms;
  struct curltime now;
  unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH];

  DEBUGASSERT(multi);

  if(!multi || !multi->ssl_backend_data) {
    return NULL;
  }

  mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;


  if(!mbackend->cert_store) {
    return NULL;
  }

  /* zero ca_cache_timeout completely disables caching */
  if(!cfg->ca_cache_timeout) {
    return NULL;
  }

  /* check for cache timeout by using the cached_x509_store_expired timediff
     calculation pattern from openssl.c.
     negative timeout means retain forever. */
  timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
  if(timeout_ms >= 0) {
    now = Curl_now();
    elapsed_ms = Curl_timediff(now, mbackend->time);
    if(elapsed_ms >= timeout_ms) {
      return NULL;
    }
  }

  if(ca_info_blob) {
    if(!mbackend->CAinfo_blob_digest) {
      return NULL;
    }
    if(mbackend->CAinfo_blob_size != ca_info_blob->len) {
      return NULL;
    }
    schannel_sha256sum((const unsigned char *)ca_info_blob->data,
                       ca_info_blob->len,
                       info_blob_digest,
                       CURL_SHA256_DIGEST_LENGTH);
    if(memcmp(mbackend->CAinfo_blob_digest,
              info_blob_digest,
              CURL_SHA256_DIGEST_LENGTH)) {
        return NULL;
    }
  }
  else {
    if(!conn_config->CAfile || !mbackend->CAfile ||
       strcmp(mbackend->CAfile, conn_config->CAfile)) {
      return NULL;
    }
  }

  return mbackend->cert_store;















}

bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
                                         const struct Curl_easy *data,
                                         HCERTSTORE cert_store)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct Curl_multi *multi = data->multi;
  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
  struct schannel_multi_ssl_backend_data *mbackend;
  unsigned char *CAinfo_blob_digest = NULL;
  size_t CAinfo_blob_size = 0;
  char *CAfile = NULL;

  DEBUGASSERT(multi);

  if(!multi) {
    return false;
  }

  if(!multi->ssl_backend_data) {
    multi->ssl_backend_data =


      calloc(1, sizeof(struct schannel_multi_ssl_backend_data));



    if(!multi->ssl_backend_data) {




      return false;
    }
  }

  mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;


  if(ca_info_blob) {
    CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
    if(!CAinfo_blob_digest) {
      return false;
    }
    schannel_sha256sum((const unsigned char *)ca_info_blob->data,







|








|



|
>
>
|














|






|


|






|






|
|




|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









|










|
|
>
>
|
>
>
>
|
>
>
>
>



<
<
<







2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923



2924
2925
2926
2927
2928
2929
2930

HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
                                               const struct Curl_easy *data)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct Curl_multi *multi = data->multi;
  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
  struct schannel_cert_share *share;
  const struct ssl_general_config *cfg = &data->set.general_ssl;
  timediff_t timeout_ms;
  timediff_t elapsed_ms;
  struct curltime now;
  unsigned char info_blob_digest[CURL_SHA256_DIGEST_LENGTH];

  DEBUGASSERT(multi);

  if(!multi) {
    return NULL;
  }

  share = Curl_hash_pick(&multi->proto_hash,
                         (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
                         sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
  if(!share || !share->cert_store) {
    return NULL;
  }

  /* zero ca_cache_timeout completely disables caching */
  if(!cfg->ca_cache_timeout) {
    return NULL;
  }

  /* check for cache timeout by using the cached_x509_store_expired timediff
     calculation pattern from openssl.c.
     negative timeout means retain forever. */
  timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
  if(timeout_ms >= 0) {
    now = Curl_now();
    elapsed_ms = Curl_timediff(now, share->time);
    if(elapsed_ms >= timeout_ms) {
      return NULL;
    }
  }

  if(ca_info_blob) {
    if(!share->CAinfo_blob_digest) {
      return NULL;
    }
    if(share->CAinfo_blob_size != ca_info_blob->len) {
      return NULL;
    }
    schannel_sha256sum((const unsigned char *)ca_info_blob->data,
                       ca_info_blob->len,
                       info_blob_digest,
                       CURL_SHA256_DIGEST_LENGTH);
    if(memcmp(share->CAinfo_blob_digest,
              info_blob_digest,
              CURL_SHA256_DIGEST_LENGTH)) {
        return NULL;
    }
  }
  else {
    if(!conn_config->CAfile || !share->CAfile ||
       strcmp(share->CAfile, conn_config->CAfile)) {
      return NULL;
    }
  }

  return share->cert_store;
}

static void schannel_cert_share_free(void *key, size_t key_len, void *p)
{
  struct schannel_cert_share *share = p;
  DEBUGASSERT(key_len == (sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1));
  DEBUGASSERT(!memcmp(MPROTO_SCHANNEL_CERT_SHARE_KEY, key, key_len));
  (void)key;
  (void)key_len;
  if(share->cert_store) {
    CertCloseStore(share->cert_store, 0);
  }
  free(share->CAinfo_blob_digest);
  free(share->CAfile);
  free(share);
}

bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
                                         const struct Curl_easy *data,
                                         HCERTSTORE cert_store)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct Curl_multi *multi = data->multi;
  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
  struct schannel_cert_share *share;
  unsigned char *CAinfo_blob_digest = NULL;
  size_t CAinfo_blob_size = 0;
  char *CAfile = NULL;

  DEBUGASSERT(multi);

  if(!multi) {
    return false;
  }

  share = Curl_hash_pick(&multi->proto_hash,
                         (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
                         sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
  if(!share) {
    share = calloc(1, sizeof(*share));
    if(!share) {
      return false;
    }
    if(!Curl_hash_add2(&multi->proto_hash,
                       (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
                       sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
                       share, schannel_cert_share_free)) {
      free(share);
      return false;
    }
  }




  if(ca_info_blob) {
    CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
    if(!CAinfo_blob_digest) {
      return false;
    }
    schannel_sha256sum((const unsigned char *)ca_info_blob->data,
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900

2901

2902

2903
2904
2905
2906
2907
2908
2909
      if(!CAfile) {
        return false;
      }
    }
  }

  /* free old cache data */
  if(mbackend->cert_store) {
    CertCloseStore(mbackend->cert_store, 0);
  }
  free(mbackend->CAinfo_blob_digest);
  free(mbackend->CAfile);

  mbackend->time = Curl_now();
  mbackend->cert_store = cert_store;
  mbackend->CAinfo_blob_digest = CAinfo_blob_digest;
  mbackend->CAinfo_blob_size = CAinfo_blob_size;
  mbackend->CAfile = CAfile;
  return true;
}

static void schannel_free_multi_ssl_backend_data(
  struct multi_ssl_backend_data *msbd)
{
  struct schannel_multi_ssl_backend_data *mbackend =
    (struct schannel_multi_ssl_backend_data*)msbd;
  if(mbackend->cert_store) {
    CertCloseStore(mbackend->cert_store, 0);
  }
  free(mbackend->CAinfo_blob_digest);
  free(mbackend->CAfile);
  free(mbackend);
}

const struct Curl_ssl Curl_ssl_schannel = {
  { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */

  SSLSUPP_CERTINFO |
#ifdef HAS_MANUAL_VERIFY_API
  SSLSUPP_CAINFO_BLOB |
#endif

  SSLSUPP_PINNEDPUBKEY |

  SSLSUPP_TLS13_CIPHERSUITES |

  SSLSUPP_HTTPS_PROXY,

  sizeof(struct schannel_ssl_backend_data),

  schannel_init,                     /* init */
  schannel_cleanup,                  /* cleanup */
  schannel_version,                  /* version */







|
|

|
|

|
|
|
|
|

<
<
<
<
<
<
<
<
<
<
<
<
<









>

>

>







2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957













2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
      if(!CAfile) {
        return false;
      }
    }
  }

  /* free old cache data */
  if(share->cert_store) {
    CertCloseStore(share->cert_store, 0);
  }
  free(share->CAinfo_blob_digest);
  free(share->CAfile);

  share->time = Curl_now();
  share->cert_store = cert_store;
  share->CAinfo_blob_digest = CAinfo_blob_digest;
  share->CAinfo_blob_size = CAinfo_blob_size;
  share->CAfile = CAfile;
  return true;













}

const struct Curl_ssl Curl_ssl_schannel = {
  { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */

  SSLSUPP_CERTINFO |
#ifdef HAS_MANUAL_VERIFY_API
  SSLSUPP_CAINFO_BLOB |
#endif
#ifndef CURL_WINDOWS_APP
  SSLSUPP_PINNEDPUBKEY |
#endif
  SSLSUPP_TLS13_CIPHERSUITES |
  SSLSUPP_CA_CACHE |
  SSLSUPP_HTTPS_PROXY,

  sizeof(struct schannel_ssl_backend_data),

  schannel_init,                     /* init */
  schannel_cleanup,                  /* cleanup */
  schannel_version,                  /* version */
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
  Curl_none_set_engine,              /* set_engine */
  Curl_none_set_engine_default,      /* set_engine_default */
  Curl_none_engines_list,            /* engines_list */
  Curl_none_false_start,             /* false_start */
  schannel_sha256sum,                /* sha256sum */
  NULL,                              /* associate_connection */
  NULL,                              /* disassociate_connection */
  schannel_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
  schannel_recv,                     /* recv decrypted data */
  schannel_send,                     /* send data to encrypt */
};

#endif /* USE_SCHANNEL */







<





2990
2991
2992
2993
2994
2995
2996

2997
2998
2999
3000
3001
  Curl_none_set_engine,              /* set_engine */
  Curl_none_set_engine_default,      /* set_engine_default */
  Curl_none_engines_list,            /* engines_list */
  Curl_none_false_start,             /* false_start */
  schannel_sha256sum,                /* sha256sum */
  NULL,                              /* associate_connection */
  NULL,                              /* disassociate_connection */

  schannel_recv,                     /* recv decrypted data */
  schannel_send,                     /* send data to encrypt */
};

#endif /* USE_SCHANNEL */
Changes to jni/curl/lib/vtls/schannel_int.h.
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curl_setup.h"

#ifdef USE_SCHANNEL

#if defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN)

#define HAS_MANUAL_VERIFY_API
#endif

#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)   \
  && !defined(DISABLE_SCHANNEL_CLIENT_CERT)
#define HAS_CLIENT_CERT_PATH
#endif







|
>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curl_setup.h"

#ifdef USE_SCHANNEL

#if (defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN)) \
  && !defined(CURL_WINDOWS_APP)
#define HAS_MANUAL_VERIFY_API
#endif

#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX)   \
  && !defined(DISABLE_SCHANNEL_CLIENT_CERT)
#define HAS_CLIENT_CERT_PATH
#endif
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

160
161



162
163
164
165
166
167
168
169
  struct Curl_schannel_cred *cred;
  struct Curl_schannel_ctxt *ctxt;
  SecPkgContext_StreamSizes stream_sizes;
  size_t encdata_length, decdata_length;
  size_t encdata_offset, decdata_offset;
  unsigned char *encdata_buffer, *decdata_buffer;
  /* encdata_is_incomplete: if encdata contains only a partial record that
     can't be decrypted without another recv() (that is, status is
     SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds
     more bytes into encdata then set this back to false. */
  bool encdata_is_incomplete;
  unsigned long req_flags, ret_flags;
  CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
  bool recv_sspi_close_notify; /* true if connection closed by close_notify */
  bool recv_connection_closed; /* true if connection closed, regardless how */
  bool recv_renegotiating;     /* true if recv is doing renegotiation */
  bool use_alpn; /* true if ALPN is used for this connection */
#ifdef HAS_MANUAL_VERIFY_API
  bool use_manual_cred_validation; /* true if manual cred validation is used */
#endif

};




struct schannel_multi_ssl_backend_data {
  unsigned char *CAinfo_blob_digest; /* CA info blob digest */
  size_t CAinfo_blob_size;           /* CA info blob size */
  char *CAfile;                      /* CAfile path used to generate
                                        certificate store */
  HCERTSTORE cert_store;             /* cached certificate store or
                                        NULL if none */
  struct curltime time;              /* when the cached store was created */







|












>


>
>
>
|







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  struct Curl_schannel_cred *cred;
  struct Curl_schannel_ctxt *ctxt;
  SecPkgContext_StreamSizes stream_sizes;
  size_t encdata_length, decdata_length;
  size_t encdata_offset, decdata_offset;
  unsigned char *encdata_buffer, *decdata_buffer;
  /* encdata_is_incomplete: if encdata contains only a partial record that
     cannot be decrypted without another recv() (that is, status is
     SEC_E_INCOMPLETE_MESSAGE) then set this true. after an recv() adds
     more bytes into encdata then set this back to false. */
  bool encdata_is_incomplete;
  unsigned long req_flags, ret_flags;
  CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
  bool recv_sspi_close_notify; /* true if connection closed by close_notify */
  bool recv_connection_closed; /* true if connection closed, regardless how */
  bool recv_renegotiating;     /* true if recv is doing renegotiation */
  bool use_alpn; /* true if ALPN is used for this connection */
#ifdef HAS_MANUAL_VERIFY_API
  bool use_manual_cred_validation; /* true if manual cred validation is used */
#endif
  BIT(sent_shutdown);
};

/* key to use at `multi->proto_hash` */
#define MPROTO_SCHANNEL_CERT_SHARE_KEY   "tls:schannel:cert:share"

struct schannel_cert_share {
  unsigned char *CAinfo_blob_digest; /* CA info blob digest */
  size_t CAinfo_blob_size;           /* CA info blob size */
  char *CAfile;                      /* CAfile path used to generate
                                        certificate store */
  HCERTSTORE cert_store;             /* cached certificate store or
                                        NULL if none */
  struct curltime time;              /* when the cached store was created */
Changes to jni/curl/lib/vtls/schannel_verify.c.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 * only be invoked by code in schannel.c.
 */

#include "curl_setup.h"

#ifdef USE_SCHANNEL
#ifndef USE_WINDOWS_SSPI
#  error "Can't compile SCHANNEL support without SSPI."
#endif

#include "schannel.h"
#include "schannel_int.h"

#include "vtls.h"
#include "vtls_int.h"







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 * only be invoked by code in schannel.c.
 */

#include "curl_setup.h"

#ifdef USE_SCHANNEL
#ifndef USE_WINDOWS_SSPI
#  error "cannot compile SCHANNEL support without SSPI."
#endif

#include "schannel.h"
#include "schannel_int.h"

#include "vtls.h"
#include "vtls_int.h"
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

static int is_cr_or_lf(char c)
{
  return c == '\r' || c == '\n';
}

/* Search the substring needle,needlelen into string haystack,haystacklen
 * Strings don't need to be terminated by a '\0'.
 * Similar of OSX/Linux memmem (not available on Visual Studio).
 * Return position of beginning of first occurrence or NULL if not found
 */
static const char *c_memmem(const void *haystack, size_t haystacklen,
                            const void *needle, size_t needlelen)
{
  const char *p;







|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

static int is_cr_or_lf(char c)
{
  return c == '\r' || c == '\n';
}

/* Search the substring needle,needlelen into string haystack,haystacklen
 * Strings do not need to be terminated by a '\0'.
 * Similar of OSX/Linux memmem (not available on Visual Studio).
 * Return position of beginning of first occurrence or NULL if not found
 */
static const char *c_memmem(const void *haystack, size_t haystacklen,
                            const void *needle, size_t needlelen)
{
  const char *p;
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348






349
350
351
352
353
354
355
  return result;
}

#endif /* HAS_MANUAL_VERIFY_API */

/*
 * Returns the number of characters necessary to populate all the host_names.
 * If host_names is not NULL, populate it with all the host names. Each string
 * in the host_names is null-terminated and the last string is double
 * null-terminated. If no DNS names are found, a single null-terminated empty
 * string is returned.
 */
static DWORD cert_get_name_string(struct Curl_easy *data,
                                  CERT_CONTEXT *cert_context,
                                  LPTSTR host_names,
                                  DWORD length)
{
  DWORD actual_length = 0;






  BOOL compute_content = FALSE;
  CERT_INFO *cert_info = NULL;
  CERT_EXTENSION *extension = NULL;
  CRYPT_DECODE_PARA decode_para = {0, 0, 0};
  CERT_ALT_NAME_INFO *alt_name_info = NULL;
  DWORD alt_name_info_size = 0;
  BOOL ret_val = FALSE;







|










>
>
>
>
>
>







331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  return result;
}

#endif /* HAS_MANUAL_VERIFY_API */

/*
 * Returns the number of characters necessary to populate all the host_names.
 * If host_names is not NULL, populate it with all the hostnames. Each string
 * in the host_names is null-terminated and the last string is double
 * null-terminated. If no DNS names are found, a single null-terminated empty
 * string is returned.
 */
static DWORD cert_get_name_string(struct Curl_easy *data,
                                  CERT_CONTEXT *cert_context,
                                  LPTSTR host_names,
                                  DWORD length)
{
  DWORD actual_length = 0;
#if defined(CURL_WINDOWS_APP)
  (void)data;
  (void)cert_context;
  (void)host_names;
  (void)length;
#else
  BOOL compute_content = FALSE;
  CERT_INFO *cert_info = NULL;
  CERT_EXTENSION *extension = NULL;
  CRYPT_DECODE_PARA decode_para = {0, 0, 0};
  CERT_ALT_NAME_INFO *alt_name_info = NULL;
  DWORD alt_name_info_size = 0;
  BOOL ret_val = FALSE;
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459

460
461
462
463
464
465
466
    current_length = wcslen(entry->pwszDNSName) + 1;
    if(!compute_content) {
      actual_length += (DWORD)current_length;
      continue;
    }
    /* Sanity check to prevent buffer overrun. */
    if((actual_length + current_length) > length) {
      failf(data, "schannel: Not enough memory to list all host names.");
      break;
    }
    dns_w = entry->pwszDNSName;
    /* pwszDNSName is in ia5 string format and hence doesn't contain any
     * non-ascii characters. */
    while(*dns_w != '\0') {
      *current_pos++ = (char)(*dns_w++);
    }
    *current_pos++ = '\0';
    actual_length += (DWORD)current_length;
  }
  if(compute_content) {
    /* Last string has double null-terminator. */
    *current_pos = '\0';
  }

  return actual_length;
}

/* Verify the server's hostname */
CURLcode Curl_verify_host(struct Curl_cfilter *cf,
                          struct Curl_easy *data)
{







|



|


|








>







443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
    current_length = wcslen(entry->pwszDNSName) + 1;
    if(!compute_content) {
      actual_length += (DWORD)current_length;
      continue;
    }
    /* Sanity check to prevent buffer overrun. */
    if((actual_length + current_length) > length) {
      failf(data, "schannel: Not enough memory to list all hostnames.");
      break;
    }
    dns_w = entry->pwszDNSName;
    /* pwszDNSName is in ia5 string format and hence does not contain any
     * non-ascii characters. */
    while(*dns_w != '\0') {
      *current_pos++ = (TCHAR)(*dns_w++);
    }
    *current_pos++ = '\0';
    actual_length += (DWORD)current_length;
  }
  if(compute_content) {
    /* Last string has double null-terminator. */
    *current_pos = '\0';
  }
#endif
  return actual_length;
}

/* Verify the server's hostname */
CURLcode Curl_verify_host(struct Curl_cfilter *cf,
                          struct Curl_easy *data)
{
Changes to jni/curl/lib/vtls/sectransp.c.
25
26
27
28
29
30
31


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

/*
 * Source file for all iOS and macOS SecureTransport-specific code for the
 * TLS/SSL layer. No code but vtls.c should ever call or use these functions.
 */

#include "curl_setup.h"



#include "urldata.h" /* for the Curl_easy definition */
#include "curl_base64.h"
#include "strtok.h"
#include "multiif.h"
#include "strcase.h"
#include "x509asn1.h"
#include "strerror.h"

#ifdef USE_SECTRANSP

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#endif /* __clang__ */

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress"
#pragma GCC diagnostic ignored "-Wundef"
#pragma GCC diagnostic ignored "-Wunreachable-code"
#endif

#include <limits.h>

#include <Security/Security.h>
/* For some reason, when building for iOS, the omnibus header above does
 * not include SecureTransport.h as of iOS SDK 5.1. */







>
>








|
<



|





<
<







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50
51


52
53
54
55
56
57
58

/*
 * Source file for all iOS and macOS SecureTransport-specific code for the
 * TLS/SSL layer. No code but vtls.c should ever call or use these functions.
 */

#include "curl_setup.h"

#ifdef USE_SECTRANSP

#include "urldata.h" /* for the Curl_easy definition */
#include "curl_base64.h"
#include "strtok.h"
#include "multiif.h"
#include "strcase.h"
#include "x509asn1.h"
#include "strerror.h"
#include "cipher_suite.h"


#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
#endif /* __clang__ */

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress"


#endif

#include <limits.h>

#include <Security/Security.h>
/* For some reason, when building for iOS, the omnibus header above does
 * not include SecureTransport.h as of iOS SDK 5.1. */
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
   In general, you want to build this using the most recent OS SDK, since some
   features require curl to be built against the latest SDK. TLS 1.1 and 1.2
   support, for instance, require the macOS 10.8 SDK or later. TLS 1.3
   requires the macOS 10.13 or iOS 11 SDK or later. */
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
#error "The Secure Transport back-end requires Leopard or later."
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */

#define CURL_BUILD_IOS 0
#define CURL_BUILD_IOS_7 0
#define CURL_BUILD_IOS_9 0
#define CURL_BUILD_IOS_11 0
#define CURL_BUILD_IOS_13 0







|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
   In general, you want to build this using the most recent OS SDK, since some
   features require curl to be built against the latest SDK. TLS 1.1 and 1.2
   support, for instance, require the macOS 10.8 SDK or later. TLS 1.3
   requires the macOS 10.13 or iOS 11 SDK or later. */
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
#error "The Secure Transport backend requires Leopard or later."
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */

#define CURL_BUILD_IOS 0
#define CURL_BUILD_IOS_7 0
#define CURL_BUILD_IOS_9 0
#define CURL_BUILD_IOS_11 0
#define CURL_BUILD_IOS_13 0
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#define CURL_SUPPORT_MAC_10_5 0
#define CURL_SUPPORT_MAC_10_6 0
#define CURL_SUPPORT_MAC_10_7 0
#define CURL_SUPPORT_MAC_10_8 0
#define CURL_SUPPORT_MAC_10_9 0

#else
#error "The Secure Transport back-end requires iOS or macOS."
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */

#if CURL_BUILD_MAC
#include <sys/sysctl.h>
#endif /* CURL_BUILD_MAC */

#include "sendf.h"







|







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#define CURL_SUPPORT_MAC_10_5 0
#define CURL_SUPPORT_MAC_10_6 0
#define CURL_SUPPORT_MAC_10_7 0
#define CURL_SUPPORT_MAC_10_8 0
#define CURL_SUPPORT_MAC_10_9 0

#else
#error "The Secure Transport backend requires iOS or macOS."
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */

#if CURL_BUILD_MAC
#include <sys/sysctl.h>
#endif /* CURL_BUILD_MAC */

#include "sendf.h"
140
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242

243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698




699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769

770
771
772
773
774
775
776
777
778
779
780
781

782
783
784
785
786
787
788
789
790
791
#include "strdup.h"

#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"


/* From MacTypes.h (which we can't include because it isn't present in iOS: */

#define ioErr -36
#define paramErr -50

struct st_ssl_backend_data {
  SSLContextRef ssl_ctx;
  bool ssl_direction; /* true if writing, false if reading */
  size_t ssl_write_buffered_length;
};

struct st_cipher {
  const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
  const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
  SSLCipherSuite num; /* Cipher suite code/number defined in IANA registry */
  bool weak; /* Flag to mark cipher as weak based on previous implementation
                of Secure Transport back-end by CURL */
};

/* Macro to initialize st_cipher data structure: stringify id to name, cipher
   number/id, 'weak' suite flag
 */
#define CIPHER_DEF(num, alias, weak) \
  { #num, alias, num, weak }

/*
 Macro to initialize st_cipher data structure with name, code (IANA cipher
 number/id value), and 'weak' suite flag. The first 28 cipher suite numbers
 have the same IANA code for both SSL and TLS standards: numbers 0x0000 to
 0x001B. They have different names though. The first 4 letters of the cipher
 suite name are the protocol name: "SSL_" or "TLS_", rest of the IANA name is
 the same for both SSL and TLS cipher suite name.
 The second part of the problem is that macOS/iOS SDKs don't define all TLS
 codes but only 12 of them. The SDK defines all SSL codes though, i.e. SSL_NUM
 constant is always defined for those 28 ciphers while TLS_NUM is defined only
 for 12 of the first 28 ciphers. Those 12 TLS cipher codes match to
 corresponding SSL enum value and represent the same cipher suite. Therefore
 we'll use the SSL enum value for those cipher suites because it is defined
 for all 28 of them.
 We make internal data consistent and based on TLS names, i.e. all st_cipher
 item names start with the "TLS_" prefix.
 Summarizing all the above, those 28 first ciphers are presented in our table
 with both TLS and SSL names. Their cipher numbers are assigned based on the
 SDK enum value for the SSL cipher, which matches to IANA TLS number.
 */
#define CIPHER_DEF_SSLTLS(num_wo_prefix, alias, weak) \
  { "TLS_" #num_wo_prefix, alias, SSL_##num_wo_prefix, weak }

/*
 Cipher suites were marked as weak based on the following:
 RC4 encryption - rfc7465, the document contains a list of deprecated ciphers.
     Marked in the code below as weak.
 RC2 encryption - many mentions, was found vulnerable to a relatively easy
     attack https://link.springer.com/chapter/10.1007%2F3-540-69710-1_14
     Marked in the code below as weak.
 DES and IDEA encryption - rfc5469, has a list of deprecated ciphers.
     Marked in the code below as weak.
 Anonymous Diffie-Hellman authentication and anonymous elliptic curve
     Diffie-Hellman - vulnerable to a man-in-the-middle attack. Deprecated by
     RFC 4346 aka TLS 1.1 (section A.5, page 60)
 Null bulk encryption suites - not encrypted communication
 Export ciphers, i.e. ciphers with restrictions to be used outside the US for
     software exported to some countries, they were excluded from TLS 1.1
     version. More precisely, they were noted as ciphers which MUST NOT be
     negotiated in RFC 4346 aka TLS 1.1 (section A.5, pages 60 and 61).
     All of those filters were considered weak because they contain a weak
     algorithm like DES, RC2 or RC4, and already considered weak by other
     criteria.
 3DES - NIST deprecated it and is going to retire it by 2023
 https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
     OpenSSL https://www.openssl.org/blog/blog/2016/08/24/sweet32/ also
     deprecated those ciphers. Some other libraries also consider it
     vulnerable or at least not strong enough.

 CBC ciphers are vulnerable with SSL3.0 and TLS1.0:
 https://www.cisco.com/c/en/us/support/docs/security/email-security-appliance
 /118518-technote-esa-00.html
     We don't take care of this issue because it is resolved by later TLS
     versions and for us, it requires more complicated checks, we need to
     check a protocol version also. Vulnerability doesn't look very critical
     and we do not filter out those cipher suites.
 */

#define CIPHER_WEAK_NOT_ENCRYPTED   TRUE
#define CIPHER_WEAK_RC_ENCRYPTION   TRUE
#define CIPHER_WEAK_DES_ENCRYPTION  TRUE
#define CIPHER_WEAK_IDEA_ENCRYPTION TRUE
#define CIPHER_WEAK_ANON_AUTH       TRUE
#define CIPHER_WEAK_3DES_ENCRYPTION TRUE
#define CIPHER_STRONG_ENOUGH        FALSE

/* Please do not change the order of the first ciphers available for SSL.
   Do not insert and do not delete any of them. Code below
   depends on their order and continuity.
   If you add a new cipher, please maintain order by number, i.e.
   insert in between existing items to appropriate place based on
   cipher suite IANA number

*/
static const struct st_cipher ciphertable[] = {
  /* SSL version 3.0 and initial TLS 1.0 cipher suites.
     Defined since SDK 10.2.8 */
  CIPHER_DEF_SSLTLS(NULL_WITH_NULL_NULL,                           /* 0x0000 */
                    NULL,
                    CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF_SSLTLS(RSA_WITH_NULL_MD5,                             /* 0x0001 */
                    "NULL-MD5",
                    CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF_SSLTLS(RSA_WITH_NULL_SHA,                             /* 0x0002 */
                    "NULL-SHA",
                    CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC4_40_MD5,                    /* 0x0003 */
                    "EXP-RC4-MD5",
                    CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_MD5,                          /* 0x0004 */
                    "RC4-MD5",
                    CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_SHA,                          /* 0x0005 */
                    "RC4-SHA",
                    CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC2_CBC_40_MD5,                /* 0x0006 */
                    "EXP-RC2-CBC-MD5",
                    CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF_SSLTLS(RSA_WITH_IDEA_CBC_SHA,                         /* 0x0007 */
                    "IDEA-CBC-SHA",
                    CIPHER_WEAK_IDEA_ENCRYPTION),
  CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_DES40_CBC_SHA,                 /* 0x0008 */
                    "EXP-DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(RSA_WITH_DES_CBC_SHA,                          /* 0x0009 */
                    "DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(RSA_WITH_3DES_EDE_CBC_SHA,                     /* 0x000A */
                    "DES-CBC3-SHA",
                    CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DH_DSS_EXPORT_WITH_DES40_CBC_SHA,              /* 0x000B */
                    "EXP-DH-DSS-DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DH_DSS_WITH_DES_CBC_SHA,                       /* 0x000C */
                    "DH-DSS-DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DH_DSS_WITH_3DES_EDE_CBC_SHA,                  /* 0x000D */
                    "DH-DSS-DES-CBC3-SHA",
                    CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DH_RSA_EXPORT_WITH_DES40_CBC_SHA,              /* 0x000E */
                    "EXP-DH-RSA-DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DH_RSA_WITH_DES_CBC_SHA,                       /* 0x000F */
                    "DH-RSA-DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DH_RSA_WITH_3DES_EDE_CBC_SHA,                  /* 0x0010 */
                    "DH-RSA-DES-CBC3-SHA",
                    CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,             /* 0x0011 */
                    "EXP-EDH-DSS-DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DHE_DSS_WITH_DES_CBC_SHA,                      /* 0x0012 */
                    "EDH-DSS-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DHE_DSS_WITH_3DES_EDE_CBC_SHA,                 /* 0x0013 */
                    "DHE-DSS-DES-CBC3-SHA",
                    CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,             /* 0x0014 */
                    "EXP-EDH-RSA-DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DHE_RSA_WITH_DES_CBC_SHA,                      /* 0x0015 */
                    "EDH-RSA-DES-CBC-SHA",
                    CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DHE_RSA_WITH_3DES_EDE_CBC_SHA,                 /* 0x0016 */
                    "DHE-RSA-DES-CBC3-SHA",
                    CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_RC4_40_MD5,                /* 0x0017 */
                    "EXP-ADH-RC4-MD5",
                    CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF_SSLTLS(DH_anon_WITH_RC4_128_MD5,                      /* 0x0018 */
                    "ADH-RC4-MD5",
                    CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_DES40_CBC_SHA,             /* 0x0019 */
                    "EXP-ADH-DES-CBC-SHA",
                    CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF_SSLTLS(DH_anon_WITH_DES_CBC_SHA,                      /* 0x001A */
                    "ADH-DES-CBC-SHA",
                    CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF_SSLTLS(DH_anon_WITH_3DES_EDE_CBC_SHA,                 /* 0x001B */
                    "ADH-DES-CBC3-SHA",
                    CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_NULL_SHA,                       /* 0x001C */
             NULL,
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA,               /* 0x001D */
             NULL,
             CIPHER_STRONG_ENOUGH),

#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
  /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */
  CIPHER_DEF(TLS_PSK_WITH_NULL_SHA,                                /* 0x002C */
             "PSK-NULL-SHA",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA,                            /* 0x002D */
             "DHE-PSK-NULL-SHA",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA,                            /* 0x002E */
             "RSA-PSK-NULL-SHA",
             CIPHER_WEAK_NOT_ENCRYPTED),
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */

  /* TLS addenda using AES, per RFC 3268. Defined since SDK 10.4u */
  CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA,                         /* 0x002F */
             "AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA,                      /* 0x0030 */
             "DH-DSS-AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA,                      /* 0x0031 */
             "DH-RSA-AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA,                     /* 0x0032 */
             "DHE-DSS-AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA,                     /* 0x0033 */
             "DHE-RSA-AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA,                     /* 0x0034 */
             "ADH-AES128-SHA",
             CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA,                         /* 0x0035 */
             "AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA,                      /* 0x0036 */
             "DH-DSS-AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA,                      /* 0x0037 */
             "DH-RSA-AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA,                     /* 0x0038 */
             "DHE-DSS-AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA,                     /* 0x0039 */
             "DHE-RSA-AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA,                     /* 0x003A */
             "ADH-AES256-SHA",
             CIPHER_WEAK_ANON_AUTH),

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  /* TLS 1.2 addenda, RFC 5246 */
  /* Server provided RSA certificate for key exchange. */
  CIPHER_DEF(TLS_RSA_WITH_NULL_SHA256,                             /* 0x003B */
             "NULL-SHA256",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256,                      /* 0x003C */
             "AES128-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256,                      /* 0x003D */
             "AES256-SHA256",
             CIPHER_STRONG_ENOUGH),
  /* Server-authenticated (and optionally client-authenticated)
     Diffie-Hellman. */
  CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA256,                   /* 0x003E */
             "DH-DSS-AES128-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA256,                   /* 0x003F */
             "DH-RSA-AES128-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,                  /* 0x0040 */
             "DHE-DSS-AES128-SHA256",
             CIPHER_STRONG_ENOUGH),

  /* TLS 1.2 addenda, RFC 5246 */
  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,                  /* 0x0067 */
             "DHE-RSA-AES128-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA256,                   /* 0x0068 */
             "DH-DSS-AES256-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA256,                   /* 0x0069 */
             "DH-RSA-AES256-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,                  /* 0x006A */
             "DHE-DSS-AES256-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,                  /* 0x006B */
             "DHE-RSA-AES256-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA256,                  /* 0x006C */
             "ADH-AES128-SHA256",
             CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA256,                  /* 0x006D */
             "ADH-AES256-SHA256",
             CIPHER_WEAK_ANON_AUTH),
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */

#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
  /* Addendum from RFC 4279, TLS PSK */
  CIPHER_DEF(TLS_PSK_WITH_RC4_128_SHA,                             /* 0x008A */
             "PSK-RC4-SHA",
             CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF(TLS_PSK_WITH_3DES_EDE_CBC_SHA,                        /* 0x008B */
             "PSK-3DES-EDE-CBC-SHA",
             CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA,                         /* 0x008C */
             "PSK-AES128-CBC-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA,                         /* 0x008D */
             "PSK-AES256-CBC-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_PSK_WITH_RC4_128_SHA,                         /* 0x008E */
             "DHE-PSK-RC4-SHA",
             CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,                    /* 0x008F */
             "DHE-PSK-3DES-EDE-CBC-SHA",
             CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA,                     /* 0x0090 */
             "DHE-PSK-AES128-CBC-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA,                     /* 0x0091 */
             "DHE-PSK-AES256-CBC-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_RSA_PSK_WITH_RC4_128_SHA,                         /* 0x0092 */
             "RSA-PSK-RC4-SHA",
             CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,                    /* 0x0093 */
             "RSA-PSK-3DES-EDE-CBC-SHA",
             CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA,                     /* 0x0094 */
             "RSA-PSK-AES128-CBC-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA,                     /* 0x0095 */
             "RSA-PSK-AES256-CBC-SHA",
             CIPHER_STRONG_ENOUGH),
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites
     for TLS. */
  CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256,                      /* 0x009C */
             "AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384,                      /* 0x009D */
             "AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,                  /* 0x009E */
             "DHE-RSA-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,                  /* 0x009F */
             "DHE-RSA-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_GCM_SHA256,                   /* 0x00A0 */
             "DH-RSA-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_GCM_SHA384,                   /* 0x00A1 */
             "DH-RSA-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,                  /* 0x00A2 */
             "DHE-DSS-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,                  /* 0x00A3 */
             "DHE-DSS-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_GCM_SHA256,                   /* 0x00A4 */
             "DH-DSS-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_GCM_SHA384,                   /* 0x00A5 */
             "DH-DSS-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DH_anon_WITH_AES_128_GCM_SHA256,                  /* 0x00A6 */
             "ADH-AES128-GCM-SHA256",
             CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF(TLS_DH_anon_WITH_AES_256_GCM_SHA384,                  /* 0x00A7 */
             "ADH-AES256-GCM-SHA384",
             CIPHER_WEAK_ANON_AUTH),
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */

#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
  /* RFC 5487 - PSK with SHA-256/384 and AES GCM */
  CIPHER_DEF(TLS_PSK_WITH_AES_128_GCM_SHA256,                      /* 0x00A8 */
             "PSK-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_PSK_WITH_AES_256_GCM_SHA384,                      /* 0x00A9 */
             "PSK-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,                  /* 0x00AA */
             "DHE-PSK-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,                  /* 0x00AB */
             "DHE-PSK-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,                  /* 0x00AC */
             "RSA-PSK-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,                  /* 0x00AD */
             "RSA-PSK-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA256,                      /* 0x00AE */
             "PSK-AES128-CBC-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA384,                      /* 0x00AF */
             "PSK-AES256-CBC-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_PSK_WITH_NULL_SHA256,                             /* 0x00B0 */
             "PSK-NULL-SHA256",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_PSK_WITH_NULL_SHA384,                             /* 0x00B1 */
             "PSK-NULL-SHA384",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,                  /* 0x00B2 */
             "DHE-PSK-AES128-CBC-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,                  /* 0x00B3 */
             "DHE-PSK-AES256-CBC-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA256,                         /* 0x00B4 */
             "DHE-PSK-NULL-SHA256",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA384,                         /* 0x00B5 */
             "DHE-PSK-NULL-SHA384",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,                  /* 0x00B6 */
             "RSA-PSK-AES128-CBC-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,                  /* 0x00B7 */
             "RSA-PSK-AES256-CBC-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA256,                         /* 0x00B8 */
             "RSA-PSK-NULL-SHA256",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA384,                         /* 0x00B9 */
             "RSA-PSK-NULL-SHA384",
             CIPHER_WEAK_NOT_ENCRYPTED),
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */

  /* RFC 5746 - Secure Renegotiation. This is not a real suite,
     it is a response to initiate negotiation again */
  CIPHER_DEF(TLS_EMPTY_RENEGOTIATION_INFO_SCSV,                    /* 0x00FF */
             NULL,
             CIPHER_STRONG_ENOUGH),

#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
  /* TLS 1.3 standard cipher suites for ChaCha20+Poly1305.
     Note: TLS 1.3 ciphersuites do not specify the key exchange
     algorithm -- they only specify the symmetric ciphers.
     Cipher alias name matches to OpenSSL cipher name, and for
     TLS 1.3 ciphers */
  CIPHER_DEF(TLS_AES_128_GCM_SHA256,                               /* 0x1301 */
             NULL,  /* The OpenSSL cipher name matches to the IANA name */
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_AES_256_GCM_SHA384,                               /* 0x1302 */
             NULL,  /* The OpenSSL cipher name matches to the IANA name */
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_CHACHA20_POLY1305_SHA256,                         /* 0x1303 */
             NULL,  /* The OpenSSL cipher name matches to the IANA name */
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_AES_128_CCM_SHA256,                               /* 0x1304 */
             NULL,  /* The OpenSSL cipher name matches to the IANA name */
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_AES_128_CCM_8_SHA256,                             /* 0x1305 */
             NULL,  /* The OpenSSL cipher name matches to the IANA name */
             CIPHER_STRONG_ENOUGH),
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */

#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
  /* ECDSA addenda, RFC 4492 */
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_NULL_SHA,                         /* 0xC001 */
             "ECDH-ECDSA-NULL-SHA",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_RC4_128_SHA,                      /* 0xC002 */
             "ECDH-ECDSA-RC4-SHA",
             CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,                 /* 0xC003 */
             "ECDH-ECDSA-DES-CBC3-SHA",
             CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,                  /* 0xC004 */
             "ECDH-ECDSA-AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,                  /* 0xC005 */
             "ECDH-ECDSA-AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_NULL_SHA,                        /* 0xC006 */
             "ECDHE-ECDSA-NULL-SHA",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,                     /* 0xC007 */
             "ECDHE-ECDSA-RC4-SHA",
             CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,                /* 0xC008 */
             "ECDHE-ECDSA-DES-CBC3-SHA",
             CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,                 /* 0xC009 */
             "ECDHE-ECDSA-AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,                 /* 0xC00A */
             "ECDHE-ECDSA-AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_NULL_SHA,                           /* 0xC00B */
             "ECDH-RSA-NULL-SHA",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_RC4_128_SHA,                        /* 0xC00C */
             "ECDH-RSA-RC4-SHA",
             CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,                   /* 0xC00D */
             "ECDH-RSA-DES-CBC3-SHA",
             CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,                    /* 0xC00E */
             "ECDH-RSA-AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,                    /* 0xC00F */
             "ECDH-RSA-AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_NULL_SHA,                          /* 0xC010 */
             "ECDHE-RSA-NULL-SHA",
             CIPHER_WEAK_NOT_ENCRYPTED),
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_RC4_128_SHA,                       /* 0xC011 */
             "ECDHE-RSA-RC4-SHA",
             CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,                  /* 0xC012 */
             "ECDHE-RSA-DES-CBC3-SHA",
             CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,                   /* 0xC013 */
             "ECDHE-RSA-AES128-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,                   /* 0xC014 */
             "ECDHE-RSA-AES256-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_anon_WITH_NULL_SHA,                          /* 0xC015 */
             "AECDH-NULL-SHA",
             CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF(TLS_ECDH_anon_WITH_RC4_128_SHA,                       /* 0xC016 */
             "AECDH-RC4-SHA",
             CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,                  /* 0xC017 */
             "AECDH-DES-CBC3-SHA",
             CIPHER_WEAK_3DES_ENCRYPTION),
  CIPHER_DEF(TLS_ECDH_anon_WITH_AES_128_CBC_SHA,                   /* 0xC018 */
             "AECDH-AES128-SHA",
             CIPHER_WEAK_ANON_AUTH),
  CIPHER_DEF(TLS_ECDH_anon_WITH_AES_256_CBC_SHA,                   /* 0xC019 */
             "AECDH-AES256-SHA",
             CIPHER_WEAK_ANON_AUTH),
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  /* Addenda from rfc 5289  Elliptic Curve Cipher Suites with
     HMAC SHA-256/384. */
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,              /* 0xC023 */
             "ECDHE-ECDSA-AES128-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,              /* 0xC024 */
             "ECDHE-ECDSA-AES256-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,               /* 0xC025 */
             "ECDH-ECDSA-AES128-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,               /* 0xC026 */
             "ECDH-ECDSA-AES256-SHA384",
             CIPHER_STRONG_ENOUGH),




  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,                /* 0xC027 */
             "ECDHE-RSA-AES128-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,                /* 0xC028 */
             "ECDHE-RSA-AES256-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,                 /* 0xC029 */
             "ECDH-RSA-AES128-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,                 /* 0xC02A */
             "ECDH-RSA-AES256-SHA384",
             CIPHER_STRONG_ENOUGH),
  /* Addenda from rfc 5289  Elliptic Curve Cipher Suites with
     SHA-256/384 and AES Galois Counter Mode (GCM) */
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,              /* 0xC02B */
             "ECDHE-ECDSA-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,              /* 0xC02C */
             "ECDHE-ECDSA-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,               /* 0xC02D */
             "ECDH-ECDSA-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,               /* 0xC02E */
             "ECDH-ECDSA-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,                /* 0xC02F */
             "ECDHE-RSA-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,                /* 0xC030 */
             "ECDHE-RSA-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,                 /* 0xC031 */
             "ECDH-RSA-AES128-GCM-SHA256",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,                 /* 0xC032 */
             "ECDH-RSA-AES256-GCM-SHA384",
             CIPHER_STRONG_ENOUGH),
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */

#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
  /* ECDHE_PSK Cipher Suites for Transport Layer Security (TLS), RFC 5489 */
  CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,                   /* 0xC035 */
             "ECDHE-PSK-AES128-CBC-SHA",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,                   /* 0xC036 */
             "ECDHE-PSK-AES256-CBC-SHA",
             CIPHER_STRONG_ENOUGH),
#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */

#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
  /* Addenda from rfc 7905  ChaCha20-Poly1305 Cipher Suites for
     Transport Layer Security (TLS). */
  CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,          /* 0xCCA8 */
             "ECDHE-RSA-CHACHA20-POLY1305",
             CIPHER_STRONG_ENOUGH),
  CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,        /* 0xCCA9 */
             "ECDHE-ECDSA-CHACHA20-POLY1305",
             CIPHER_STRONG_ENOUGH),
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */

#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
  /* ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS),
     RFC 7905 */
  CIPHER_DEF(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256,                /* 0xCCAB */
             "PSK-CHACHA20-POLY1305",
             CIPHER_STRONG_ENOUGH),
#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */

  /* Tags for SSL 2 cipher kinds which are not specified for SSL 3.
     Defined since SDK 10.2.8 */

  CIPHER_DEF(SSL_RSA_WITH_RC2_CBC_MD5,                             /* 0xFF80 */
             NULL,
             CIPHER_WEAK_RC_ENCRYPTION),
  CIPHER_DEF(SSL_RSA_WITH_IDEA_CBC_MD5,                            /* 0xFF81 */
             NULL,
             CIPHER_WEAK_IDEA_ENCRYPTION),
  CIPHER_DEF(SSL_RSA_WITH_DES_CBC_MD5,                             /* 0xFF82 */
             NULL,
             CIPHER_WEAK_DES_ENCRYPTION),
  CIPHER_DEF(SSL_RSA_WITH_3DES_EDE_CBC_MD5,                        /* 0xFF83 */
             NULL,
             CIPHER_WEAK_3DES_ENCRYPTION),

};

#define NUM_OF_CIPHERS sizeof(ciphertable)/sizeof(ciphertable[0])


/* pinned public key support tests */

/* version 1 supports macOS 10.12+ and iOS 10+ */
#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
    (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED  >= 101200))







|
>







<
|
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
|
|
|
<
<
|
|
>
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



<
<
|
<
<
|
<
<
|
<
<
|
<
<
>
>
>
>
|
<
<
|
<
<
|
<
<
|
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<


<
<
<
<
<
<
<
<
<
<

<
<
|
<
<
|
<
<
<

<
<
<
<
<
<
<
|
<
<
>
|
<
<
|
<
<
|
<
<
<
<
<
>


|







139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

155






156
































































157







158
159
160


161
162
163
164
165


















































166




































































167

















168
































































































































































































169





























170

























171


172


























173


174

















175
176
177


178


179


180


181


182
183
184
185
186


187


188


189




190


191








192


193








194
195










196


197


198



199







200


201
202


203


204





205
206
207
208
209
210
211
212
213
214
215
#include "strdup.h"

#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"


/* From MacTypes.h (which we cannot include because it is not present in
   iOS: */
#define ioErr -36
#define paramErr -50

struct st_ssl_backend_data {
  SSLContextRef ssl_ctx;
  bool ssl_direction; /* true if writing, false if reading */
  size_t ssl_write_buffered_length;

  BIT(sent_shutdown);






};








































































/* Create the list of default ciphers to use by making an intersection of the
 * ciphers supported by Secure Transport and the list below, using the order
 * of the former.


 * This list is based on TLS recommendations by Mozilla, balancing between
 * security and wide compatibility: "Most ciphers that are not clearly broken
 * and dangerous to use are supported"
 */
static const uint16_t default_ciphers[] = {


















































  TLS_RSA_WITH_3DES_EDE_CBC_SHA,                    /* 0x000A */




































































  TLS_RSA_WITH_AES_128_CBC_SHA,                     /* 0x002F */

















  TLS_RSA_WITH_AES_256_CBC_SHA,                     /* 0x0035 */






























































































































































































































#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS

























  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,             /* 0xC009 */


  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,             /* 0xC00A */


























  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,               /* 0xC013 */


  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,               /* 0xC014 */

















#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS


  TLS_RSA_WITH_AES_128_CBC_SHA256,                  /* 0x003C */


  TLS_RSA_WITH_AES_256_CBC_SHA256,                  /* 0x003D */


  TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,              /* 0x0067 */


  TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,              /* 0x006B */


  TLS_RSA_WITH_AES_128_GCM_SHA256,                  /* 0x009C */
  TLS_RSA_WITH_AES_256_GCM_SHA384,                  /* 0x009D */
  TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,              /* 0x009E */
  TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,              /* 0x009F */
  TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,          /* 0xC023 */


  TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,          /* 0xC024 */


  TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,            /* 0xC027 */


  TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,            /* 0xC028 */




  TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,          /* 0xC02B */


  TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,          /* 0xC02C */








  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,            /* 0xC02F */


  TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,            /* 0xC030 */








#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */











#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11


  TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,      /* 0xCCA8 */


  TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,    /* 0xCCA9 */











  /* TLSv1.3 is not supported by sectransp, but there is also other


   * code referencing TLSv1.3, like: kTLSProtocol13 ? */
  TLS_AES_128_GCM_SHA256,                           /* 0x1301 */


  TLS_AES_256_GCM_SHA384,                           /* 0x1302 */


  TLS_CHACHA20_POLY1305_SHA256,                     /* 0x1303 */





#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
};

#define DEFAULT_CIPHERS_LEN sizeof(default_ciphers)/sizeof(default_ciphers[0])


/* pinned public key support tests */

/* version 1 supports macOS 10.12+ and iOS 10+ */
#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
    (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED  >= 101200))
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826

static const unsigned char rsa2048SpkiHeader[] = {
                                       0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
                                       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
                                       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
                                       0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
#ifdef SECTRANSP_PINNEDPUBKEY_V1
/* the *new* version doesn't return DER encoded ecdsa certs like the old... */
static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
                                       0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
                                       0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
                                       0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
                                       0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
                                       0x42, 0x00};








|







236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

static const unsigned char rsa2048SpkiHeader[] = {
                                       0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
                                       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
                                       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
                                       0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
#ifdef SECTRANSP_PINNEDPUBKEY_V1
/* the *new* version does not return DER encoded ecdsa certs like the old... */
static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
                                       0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
                                       0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
                                       0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
                                       0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
                                       0x42, 0x00};

902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
  else if((size_t)nwritten < *dataLength) {
    rtn = errSSLWouldBlock;
  }
  *dataLength = nwritten;
  return rtn;
}

CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher)
{
  /* The first ciphers in the ciphertable are continuous. Here we do small
     optimization and instead of loop directly get SSL name by cipher number.
  */
  size_t i;
  if(cipher <= SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA) {
    return ciphertable[cipher].name;
  }
  /* Iterate through the rest of the ciphers */
  for(i = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA + 1; i < NUM_OF_CIPHERS;
      ++i) {
    if(ciphertable[i].num == cipher) {
      return ciphertable[i].name;
    }
  }
  return ciphertable[SSL_NULL_WITH_NULL_NULL].name;
}

#if CURL_BUILD_MAC
CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
{
  int mib[2];
  char *os_version;
  size_t os_version_len;
  char *os_version_major, *os_version_minor;







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







326
327
328
329
330
331
332



















333
334
335
336
337
338
339
  else if((size_t)nwritten < *dataLength) {
    rtn = errSSLWouldBlock;
  }
  *dataLength = nwritten;
  return rtn;
}




















#if CURL_BUILD_MAC
CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
{
  int mib[2];
  char *os_version;
  size_t os_version_len;
  char *os_version_major, *os_version_minor;
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
  *major = atoi(os_version_major);
  *minor = atoi(os_version_minor);
  free(os_version);
}
#endif /* CURL_BUILD_MAC */

/* Apple provides a myriad of ways of getting information about a certificate
   into a string. Some aren't available under iOS or newer cats. So here's
   a unified function for getting a string describing the certificate that
   ought to work in all cats starting with Leopard. */
CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
{
  CFStringRef server_cert_summary = CFSTR("(null)");

#if CURL_BUILD_IOS
  /* iOS: There's only one way to do this. */
  server_cert_summary = SecCertificateCopySubjectSummary(cert);
#else
#if CURL_BUILD_MAC_10_7
  /* Lion & later: Get the long description if we can. */
  if(SecCertificateCopyLongDescription)
    server_cert_summary =
      SecCertificateCopyLongDescription(NULL, cert, NULL);
  else
#endif /* CURL_BUILD_MAC_10_7 */
#if CURL_BUILD_MAC_10_6
  /* Snow Leopard: Get the certificate summary. */
  if(SecCertificateCopySubjectSummary)
    server_cert_summary = SecCertificateCopySubjectSummary(cert);
  else
#endif /* CURL_BUILD_MAC_10_6 */
  /* Leopard is as far back as we go... */
  (void)SecCertificateCopyCommonName(cert, &server_cert_summary);
#endif /* CURL_BUILD_IOS */
  return server_cert_summary;







|
|
|





|




|






|







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
  *major = atoi(os_version_major);
  *minor = atoi(os_version_minor);
  free(os_version);
}
#endif /* CURL_BUILD_MAC */

/* Apple provides a myriad of ways of getting information about a certificate
   into a string. Some are not available under iOS or newer cats. Here's a
   unified function for getting a string describing the certificate that ought
   to work in all cats starting with Leopard. */
CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
{
  CFStringRef server_cert_summary = CFSTR("(null)");

#if CURL_BUILD_IOS
  /* iOS: There is only one way to do this. */
  server_cert_summary = SecCertificateCopySubjectSummary(cert);
#else
#if CURL_BUILD_MAC_10_7
  /* Lion & later: Get the long description if we can. */
  if(&SecCertificateCopyLongDescription)
    server_cert_summary =
      SecCertificateCopyLongDescription(NULL, cert, NULL);
  else
#endif /* CURL_BUILD_MAC_10_7 */
#if CURL_BUILD_MAC_10_6
  /* Snow Leopard: Get the certificate summary. */
  if(&SecCertificateCopySubjectSummary)
    server_cert_summary = SecCertificateCopySubjectSummary(cert);
  else
#endif /* CURL_BUILD_MAC_10_6 */
  /* Leopard is as far back as we go... */
  (void)SecCertificateCopyCommonName(cert, &server_cert_summary);
#endif /* CURL_BUILD_IOS */
  return server_cert_summary;
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
      result = CURLE_OUT_OF_MEMORY;
    }
  }
  else {
    size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
    cbuf = calloc(1, cbuf_size);
    if(cbuf) {
      if(!CFStringGetCString(c, cbuf, cbuf_size,
                             kCFStringEncodingUTF8)) {
        failf(data, "SSL: invalid CA certificate subject");
        result = CURLE_PEER_FAILED_VERIFICATION;
      }
      else
        /* pass back the buffer */
        *certp = cbuf;
    }
    else {
      failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size);
      result = CURLE_OUT_OF_MEMORY;
    }
  }
  if(result)
    free(cbuf);
  CFRelease(c);
  return result;
}

#if CURL_SUPPORT_MAC_10_6
/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
   deprecation warnings, so let's not compile this unless it's necessary: */
static OSStatus CopyIdentityWithLabelOldSchool(char *label,
                                               SecIdentityRef *out_c_a_k)
{
  OSStatus status = errSecItemNotFound;
  SecKeychainAttributeList attr_list;
  SecKeychainAttribute attr;
  SecKeychainSearchRef search = NULL;







|









|











|







416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
      result = CURLE_OUT_OF_MEMORY;
    }
  }
  else {
    size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
    cbuf = calloc(1, cbuf_size);
    if(cbuf) {
      if(!CFStringGetCString(c, cbuf, (CFIndex)cbuf_size,
                             kCFStringEncodingUTF8)) {
        failf(data, "SSL: invalid CA certificate subject");
        result = CURLE_PEER_FAILED_VERIFICATION;
      }
      else
        /* pass back the buffer */
        *certp = cbuf;
    }
    else {
      failf(data, "SSL: could not allocate %zu bytes of memory", cbuf_size);
      result = CURLE_OUT_OF_MEMORY;
    }
  }
  if(result)
    free(cbuf);
  CFRelease(c);
  return result;
}

#if CURL_SUPPORT_MAC_10_6
/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
   deprecation warnings, so let's not compile this unless it is necessary: */
static OSStatus CopyIdentityWithLabelOldSchool(char *label,
                                               SecIdentityRef *out_c_a_k)
{
  OSStatus status = errSecItemNotFound;
  SecKeychainAttributeList attr_list;
  SecKeychainAttribute attr;
  SecKeychainSearchRef search = NULL;
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
  CFArrayRef keys_list;
  CFIndex keys_list_count;
  CFIndex i;

  /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
     kSecClassIdentity was introduced in Lion. If both exist, let's use them
     to find the certificate. */
  if(SecItemCopyMatching && kSecClassIdentity) {
    CFTypeRef keys[5];
    CFTypeRef values[5];
    CFDictionaryRef query_dict;
    CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
      kCFStringEncodingUTF8);

    /* Set up our search criteria and expected results: */
    values[0] = kSecClassIdentity; /* we want a certificate and a key */
    keys[0] = kSecClass;
    values[1] = kCFBooleanTrue;    /* we want a reference */
    keys[1] = kSecReturnRef;
    values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the
                                    * label matching below worked correctly */
    keys[2] = kSecMatchLimit;
    /* identity searches need a SecPolicyRef in order to work */
    values[3] = SecPolicyCreateSSL(false, NULL);
    keys[3] = kSecMatchPolicy;
    /* match the name of the certificate (doesn't work in macOS 10.12.1) */
    values[4] = label_cf;
    keys[4] = kSecAttrLabel;
    query_dict = CFDictionaryCreate(NULL, (const void **)keys,
                                    (const void **)values, 5L,
                                    &kCFCopyStringDictionaryKeyCallBacks,
                                    &kCFTypeDictionaryValueCallBacks);
    CFRelease(values[3]);

    /* Do we have a match? */
    status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);

    /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity,
     * we need to find the correct identity ourselves */
    if(status == noErr) {
      keys_list_count = CFArrayGetCount(keys_list);
      *out_cert_and_key = NULL;
      status = 1;
      for(i = 0; i<keys_list_count; i++) {
        OSStatus err = noErr;







|

















|











|







491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
  CFArrayRef keys_list;
  CFIndex keys_list_count;
  CFIndex i;

  /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
     kSecClassIdentity was introduced in Lion. If both exist, let's use them
     to find the certificate. */
  if(&SecItemCopyMatching && kSecClassIdentity) {
    CFTypeRef keys[5];
    CFTypeRef values[5];
    CFDictionaryRef query_dict;
    CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
      kCFStringEncodingUTF8);

    /* Set up our search criteria and expected results: */
    values[0] = kSecClassIdentity; /* we want a certificate and a key */
    keys[0] = kSecClass;
    values[1] = kCFBooleanTrue;    /* we want a reference */
    keys[1] = kSecReturnRef;
    values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the
                                    * label matching below worked correctly */
    keys[2] = kSecMatchLimit;
    /* identity searches need a SecPolicyRef in order to work */
    values[3] = SecPolicyCreateSSL(false, NULL);
    keys[3] = kSecMatchPolicy;
    /* match the name of the certificate (does not work in macOS 10.12.1) */
    values[4] = label_cf;
    keys[4] = kSecAttrLabel;
    query_dict = CFDictionaryCreate(NULL, (const void **)keys,
                                    (const void **)values, 5L,
                                    &kCFCopyStringDictionaryKeyCallBacks,
                                    &kCFTypeDictionaryValueCallBacks);
    CFRelease(values[3]);

    /* Do we have a match? */
    status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);

    /* Because kSecAttrLabel matching does not work with kSecClassIdentity,
     * we need to find the correct identity ourselves */
    if(status == noErr) {
      keys_list_count = CFArrayGetCount(keys_list);
      *out_cert_and_key = NULL;
      status = 1;
      for(i = 0; i<keys_list_count; i++) {
        OSStatus err = noErr;
1190
1191
1192
1193
1194
1195
1196
1197

1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
  /* These constants are documented as having first appeared in 10.6 but they
     raise linker errors when used on that cat for some reason. */
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
  bool resource_imported;

  if(blob) {
    pkcs_data = CFDataCreate(kCFAllocatorDefault,
                             (const unsigned char *)blob->data, blob->len);

    status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
    resource_imported = (pkcs_data != NULL);
  }
  else {
    pkcs_url =
      CFURLCreateFromFileSystemRepresentation(NULL,
                                              (const UInt8 *)cPath,
                                              strlen(cPath), false);
    resource_imported =
      CFURLCreateDataAndPropertiesFromResource(NULL,
                                               pkcs_url, &pkcs_data,
                                               NULL, NULL, &status);
  }

  if(resource_imported) {







|
>







|







595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  /* These constants are documented as having first appeared in 10.6 but they
     raise linker errors when used on that cat for some reason. */
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
  bool resource_imported;

  if(blob) {
    pkcs_data = CFDataCreate(kCFAllocatorDefault,
                             (const unsigned char *)blob->data,
                             (CFIndex)blob->len);
    status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
    resource_imported = (pkcs_data != NULL);
  }
  else {
    pkcs_url =
      CFURLCreateFromFileSystemRepresentation(NULL,
                                              (const UInt8 *)cPath,
                                              (CFIndex)strlen(cPath), false);
    resource_imported =
      CFURLCreateDataAndPropertiesFromResource(NULL,
                                               pkcs_url, &pkcs_data,
                                               NULL, NULL, &status);
  }

  if(resource_imported) {
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
      CFRelease(options);
    }


  /* On macOS SecPKCS12Import will always add the client certificate to
   * the Keychain.
   *
   * As this doesn't match iOS, and apps may not want to see their client
   * certificate saved in the user's keychain, we use SecItemImport
   * with a NULL keychain to avoid importing it.
   *
   * This returns a SecCertificateRef from which we can construct a
   * SecIdentityRef.
   */
#elif CURL_BUILD_MAC_10_7







|







633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
      CFRelease(options);
    }


  /* On macOS SecPKCS12Import will always add the client certificate to
   * the Keychain.
   *
   * As this does not match iOS, and apps may not want to see their client
   * certificate saved in the user's keychain, we use SecItemImport
   * with a NULL keychain to avoid importing it.
   *
   * This returns a SecCertificateRef from which we can construct a
   * SecIdentityRef.
   */
#elif CURL_BUILD_MAC_10_7
1323
1324
1325
1326
1327
1328
1329
1330

1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
      *darwinver = kTLSProtocol11;
      return CURLE_OK;
    case CURL_SSLVERSION_TLSv1_2:
      *darwinver = kTLSProtocol12;
      return CURLE_OK;
    case CURL_SSLVERSION_TLSv1_3:
      /* TLS 1.3 support first appeared in iOS 11 and macOS 10.13 */
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1

      if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
        *darwinver = kTLSProtocol13;
        return CURLE_OK;
      }
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
          HAVE_BUILTIN_AVAILABLE == 1 */
      break;
  }
  return CURLE_SSL_CONNECT_ERROR;
}
#endif

static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,







|
>





|







729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
      *darwinver = kTLSProtocol11;
      return CURLE_OK;
    case CURL_SSLVERSION_TLSv1_2:
      *darwinver = kTLSProtocol12;
      return CURLE_OK;
    case CURL_SSLVERSION_TLSv1_3:
      /* TLS 1.3 support first appeared in iOS 11 and macOS 10.13 */
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
    defined(HAVE_BUILTIN_AVAILABLE)
      if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
        *darwinver = kTLSProtocol13;
        return CURLE_OK;
      }
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
          defined(HAVE_BUILTIN_AVAILABLE) */
      break;
  }
  return CURLE_SSL_CONNECT_ERROR;
}
#endif

static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
1352
1353
1354
1355
1356
1357
1358
1359

1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
  long max_supported_version_by_os;

  DEBUGASSERT(backend);

  /* macOS 10.5-10.7 supported TLS 1.0 only.
     macOS 10.8 and later, and iOS 5 and later, added TLS 1.1 and 1.2.
     macOS 10.13 and later, and iOS 11 and later, added TLS 1.3. */
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1

  if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
    max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_3;
  }
  else {
    max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
  }
#else
  max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
          HAVE_BUILTIN_AVAILABLE == 1 */

  switch(ssl_version) {
    case CURL_SSLVERSION_DEFAULT:
    case CURL_SSLVERSION_TLSv1:
      ssl_version = CURL_SSLVERSION_TLSv1_0;
      break;
  }

  switch(ssl_version_max) {
    case CURL_SSLVERSION_MAX_NONE:
    case CURL_SSLVERSION_MAX_DEFAULT:
      ssl_version_max = max_supported_version_by_os;
      break;
  }

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  if(SSLSetProtocolVersionMax) {
    SSLProtocol darwin_ver_min = kTLSProtocol1;
    SSLProtocol darwin_ver_max = kTLSProtocol1;
    CURLcode result = sectransp_version_from_curl(&darwin_ver_min,
                                                  ssl_version);
    if(result) {
      failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
      return result;







|
>









|
















|







759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
  long max_supported_version_by_os;

  DEBUGASSERT(backend);

  /* macOS 10.5-10.7 supported TLS 1.0 only.
     macOS 10.8 and later, and iOS 5 and later, added TLS 1.1 and 1.2.
     macOS 10.13 and later, and iOS 11 and later, added TLS 1.3. */
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
    defined(HAVE_BUILTIN_AVAILABLE)
  if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
    max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_3;
  }
  else {
    max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
  }
#else
  max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
          defined(HAVE_BUILTIN_AVAILABLE) */

  switch(ssl_version) {
    case CURL_SSLVERSION_DEFAULT:
    case CURL_SSLVERSION_TLSv1:
      ssl_version = CURL_SSLVERSION_TLSv1_0;
      break;
  }

  switch(ssl_version_max) {
    case CURL_SSLVERSION_MAX_NONE:
    case CURL_SSLVERSION_MAX_DEFAULT:
      ssl_version_max = max_supported_version_by_os;
      break;
  }

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  if(&SSLSetProtocolVersionMax) {
    SSLProtocol darwin_ver_min = kTLSProtocol1;
    SSLProtocol darwin_ver_max = kTLSProtocol1;
    CURLcode result = sectransp_version_from_curl(&darwin_ver_min,
                                                  ssl_version);
    if(result) {
      failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
      return result;
1435
1436
1437
1438
1439
1440
1441
1442

1443

















1444
1445
1446
1447
1448
1449



1450
1451
1452
1453
1454


















1455


1456



1457
1458

1459
1460



1461

1462

1463



1464












1465

1466









1467
1468
1469
1470
1471
1472

1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507


1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521

1522
1523
1524

1525
1526
1527
1528
1529
1530
1531
1532
1533
1534




1535
1536
1537
1538
1539
1540
1541

1542
1543
1544

1545
1546
1547
1548
1549
1550
1551
1552

1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566

1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589

1590


1591
1592
1593



1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619

1620
1621
1622
1623
1624
1625
1626



1627
1628
1629
1630
1631
1632
1633
1634
1635





1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
#endif  /* CURL_SUPPORT_MAC_10_8 */
  }
#endif  /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
  failf(data, "Secure Transport: cannot set SSL protocol");
  return CURLE_SSL_CONNECT_ERROR;
}

static bool is_cipher_suite_strong(SSLCipherSuite suite_num)

{

















  size_t i;
  for(i = 0; i < NUM_OF_CIPHERS; ++i) {
    if(ciphertable[i].num == suite_num) {
      return !ciphertable[i].weak;
    }
  }



  /* If the cipher is not in our list, assume it is a new one
     and therefore strong. Previous implementation was the same,
     if cipher suite is not in the list, it was considered strong enough */
  return true;
}





















static bool sectransp_is_separator(char c)



{
  /* Return whether character is a cipher list separator. */

  switch(c) {
  case ' ':



  case '\t':

  case ':':

  case ',':



  case ';':












    return true;

  }









  return false;
}

static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
                                              SSLContextRef ssl_ctx)
{

  size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
  SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
  OSStatus err = noErr;

#if CURL_BUILD_MAC
  int darwinver_maj = 0, darwinver_min = 0;

  GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
#endif /* CURL_BUILD_MAC */

  /* Disable cipher suites that ST supports but are not safe. These ciphers
     are unlikely to be used in any case since ST gives other ciphers a much
     higher priority, but it's probably better that we not connect at all than
     to give the user a false sense of security if the server only supports
     insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
  err = SSLGetNumberSupportedCiphers(ssl_ctx, &all_ciphers_count);
  if(err != noErr) {
    failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d",
          err);
    return CURLE_SSL_CIPHER;
  }
  all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
  if(!all_ciphers) {
    failf(data, "SSL: Failed to allocate memory for all ciphers");
    return CURLE_OUT_OF_MEMORY;
  }
  allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
  if(!allowed_ciphers) {
    Curl_safefree(all_ciphers);
    failf(data, "SSL: Failed to allocate memory for allowed ciphers");
    return CURLE_OUT_OF_MEMORY;
  }
  err = SSLGetSupportedCiphers(ssl_ctx, all_ciphers,
                               &all_ciphers_count);
  if(err != noErr) {


    Curl_safefree(all_ciphers);
    Curl_safefree(allowed_ciphers);
    return CURLE_SSL_CIPHER;
  }
  for(i = 0UL ; i < all_ciphers_count ; i++) {
#if CURL_BUILD_MAC
   /* There's a known bug in early versions of Mountain Lion where ST's ECC
      ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
      Work around the problem here by disabling those ciphers if we are
      running in an affected version of OS X. */
    if(darwinver_maj == 12 && darwinver_min <= 3 &&
       all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
      continue;
    }

#endif /* CURL_BUILD_MAC */
    if(is_cipher_suite_strong(all_ciphers[i])) {
      allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];

    }
  }
  err = SSLSetEnabledCiphers(ssl_ctx, allowed_ciphers,
                             allowed_ciphers_count);
  Curl_safefree(all_ciphers);
  Curl_safefree(allowed_ciphers);
  if(err != noErr) {
    failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
    return CURLE_SSL_CIPHER;
  }




  return CURLE_OK;
}

static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
                                               SSLContextRef ssl_ctx,
                                               const char *ciphers)
{

  size_t ciphers_count = 0;
  const char *cipher_start = ciphers;
  OSStatus err = noErr;

  SSLCipherSuite selected_ciphers[NUM_OF_CIPHERS];

  if(!ciphers)
    return CURLE_OK;

  while(sectransp_is_separator(*ciphers))  /* Skip initial separators. */
    ciphers++;
  if(!*ciphers)

    return CURLE_OK;

  cipher_start = ciphers;
  while(*cipher_start && ciphers_count < NUM_OF_CIPHERS) {
    bool cipher_found = FALSE;
    size_t cipher_len = 0;
    const char *cipher_end = NULL;
    bool tls_name = FALSE;
    size_t i;

    /* Skip separators */
    while(sectransp_is_separator(*cipher_start))
      cipher_start++;
    if(*cipher_start == '\0') {

      break;
    }
    /* Find last position of a cipher in the ciphers string */
    cipher_end = cipher_start;
    while(*cipher_end != '\0' && !sectransp_is_separator(*cipher_end)) {
      ++cipher_end;
    }

    /* IANA cipher names start with the TLS_ or SSL_ prefix.
       If the 4th symbol of the cipher is '_' we look for a cipher in the
       table by its (TLS) name.
       Otherwise, we try to match cipher by an alias. */
    if(cipher_start[3] == '_') {
      tls_name = TRUE;
    }
    /* Iterate through the cipher table and look for the cipher, starting
       the cipher number 0x01 because the 0x00 is not the real cipher */
    cipher_len = cipher_end - cipher_start;
    for(i = 1; i < NUM_OF_CIPHERS; ++i) {
      const char *table_cipher_name = NULL;
      if(tls_name) {
        table_cipher_name = ciphertable[i].name;
      }

      else if(ciphertable[i].alias_name) {


        table_cipher_name = ciphertable[i].alias_name;
      }
      else {



        continue;
      }
      /* Compare a part of the string between separators with a cipher name
         in the table and make sure we matched the whole cipher name */
      if(strncmp(cipher_start, table_cipher_name, cipher_len) == 0
          && table_cipher_name[cipher_len] == '\0') {
        selected_ciphers[ciphers_count] = ciphertable[i].num;
        ++ciphers_count;
        cipher_found = TRUE;
        break;
      }
    }
    if(!cipher_found) {
      /* It would be more human-readable if we print the wrong cipher name
         but we don't want to allocate any additional memory and copy the name
         into it, then add it into logs.
         Also, we do not modify an original cipher list string. We just point
         to positions where cipher starts and ends in the cipher list string.
         The message is a bit cryptic and longer than necessary but can be
         understood by humans. */
      failf(data, "SSL: cipher string \"%s\" contains unsupported cipher name"
            " starting position %zd and ending position %zd",
            ciphers,
            cipher_start - ciphers,
            cipher_end - ciphers);
      return CURLE_SSL_CIPHER;

    }
    if(*cipher_end) {
      cipher_start = cipher_end + 1;
    }
    else {
      break;
    }



  }
  /* All cipher suites in the list are found. Report to logs as-is */
  infof(data, "SSL: Setting cipher suites list \"%s\"", ciphers);

  err = SSLSetEnabledCiphers(ssl_ctx, selected_ciphers, ciphers_count);
  if(err != noErr) {
    failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
    return CURLE_SSL_CIPHER;
  }





  return CURLE_OK;
}

static void sectransp_session_free(void *sessionid, size_t idsize)
{
  /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
     cached session ID inside the Security framework. There is a private
     function that does this, but I don't want to have to explain to you why I
     got your application rejected from the App Store due to the use of a
     private API, so the best we can do is free up our own char array that we
     created way back in sectransp_connect_step1... */
  (void)idsize;
  Curl_safefree(sessionid);
}








|
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
|
|
|
|
>
>
>
|
<
<
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
|
>
>
>

|
>
|
|
>
>
>
|
>
|
>
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
|





>
|
<
|
|
<
<
|
<
<

<
<
<
<
<
|
<
<
<
<
<
<
|
<
<
<
<
<
<
|
|

|
|
|
>
>
|
|
|
|
<
<
<
<
<
<
<
<
<

>
|
|
|
>
|
|
|
<
<
<


|

>
>
>
>
|






>
|
|
|
>
|
|
<
<

<
|
|
>
|
|
<
<
<
<
<
<
<

<
<
|
|
>
|
|
<
<
<
<
|
|
<
<
<
<
|
<
<
<
<
<
<
<
<
<
|
>
|
>
>
|
|
|
>
>
>
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
<
|
|
<
|
<
<
<
>

|
|
|
<
<
|
>
>
>

<
<

|


|

>
>
>
>
>
|






|







843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870

871
872
873
874
875
876
877
878


879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954

955
956


957


958





959






960






961
962
963
964
965
966
967
968
969
970
971
972









973
974
975
976
977
978
979
980
981



982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003


1004

1005
1006
1007
1008
1009







1010


1011
1012
1013
1014
1015




1016
1017




1018









1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031













1032
1033
1034

1035
1036

1037



1038
1039
1040
1041
1042


1043
1044
1045
1046
1047


1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
#endif  /* CURL_SUPPORT_MAC_10_8 */
  }
#endif  /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
  failf(data, "Secure Transport: cannot set SSL protocol");
  return CURLE_SSL_CONNECT_ERROR;
}

static int sectransp_cipher_suite_get_str(uint16_t id, char *buf,
                                          size_t buf_size, bool prefer_rfc)
{
  /* are these fortezza suites even supported ? */
  if(id == SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA)
    msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA");
  else if(id == SSL_FORTEZZA_DMS_WITH_NULL_SHA)
    msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_NULL_SHA");
  /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
  else if(id == TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
    msnprintf(buf, buf_size, "%s", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
  /* do we still need to support these SSL2-only ciphers ? */
  else if(id == SSL_RSA_WITH_RC2_CBC_MD5)
    msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_RC2_CBC_MD5");
  else if(id == SSL_RSA_WITH_IDEA_CBC_MD5)
    msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_IDEA_CBC_MD5");
  else if(id == SSL_RSA_WITH_DES_CBC_MD5)
    msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_DES_CBC_MD5");
  else if(id == SSL_RSA_WITH_3DES_EDE_CBC_MD5)
    msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_3DES_EDE_CBC_MD5");
  else

    return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
  return 0;
}

static uint16_t sectransp_cipher_suite_walk_str(const char **str,
                                                const char **end)
{
  uint16_t id = Curl_cipher_suite_walk_str(str, end);


  size_t len = *end - *str;

  if(!id) {
    /* are these fortezza suites even supported ? */
    if(strncasecompare("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA", *str, len))
      id = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA;
    else if(strncasecompare("SSL_FORTEZZA_DMS_WITH_NULL_SHA", *str, len))
      id = SSL_FORTEZZA_DMS_WITH_NULL_SHA;
    /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
    else if(strncasecompare("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", *str, len))
      id = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
    /* do we still need to support these SSL2-only ciphers ? */
    else if(strncasecompare("SSL_RSA_WITH_RC2_CBC_MD5", *str, len))
      id = SSL_RSA_WITH_RC2_CBC_MD5;
    else if(strncasecompare("SSL_RSA_WITH_IDEA_CBC_MD5", *str, len))
      id = SSL_RSA_WITH_IDEA_CBC_MD5;
    else if(strncasecompare("SSL_RSA_WITH_DES_CBC_MD5", *str, len))
      id = SSL_RSA_WITH_DES_CBC_MD5;
    else if(strncasecompare("SSL_RSA_WITH_3DES_EDE_CBC_MD5", *str, len))
      id = SSL_RSA_WITH_3DES_EDE_CBC_MD5;
  }
  return id;
}

/* allocated memory must be freed */
static SSLCipherSuite * sectransp_get_supported_ciphers(SSLContextRef ssl_ctx,
                                                        size_t *len)
{
  SSLCipherSuite *ciphers = NULL;
  OSStatus err = noErr;
  *len = 0;

  err = SSLGetNumberSupportedCiphers(ssl_ctx, len);
  if(err != noErr)
    goto failed;

  ciphers = malloc(*len * sizeof(SSLCipherSuite));
  if(!ciphers)
    goto failed;

  err = SSLGetSupportedCiphers(ssl_ctx, ciphers, len);
  if(err != noErr)
    goto failed;

#if CURL_BUILD_MAC
  {
    int maj = 0, min = 0;
    GetDarwinVersionNumber(&maj, &min);
    /* There is a known bug in early versions of Mountain Lion where ST's ECC
       ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
       Work around the problem here by disabling those ciphers if we are
       running in an affected version of OS X. */
    if(maj == 12 && min <= 3) {
      size_t i = 0, j = 0;
      for(; i < *len; i++) {
        if(ciphers[i] >= 0xC001 && ciphers[i] <= 0xC032)
          continue;
        ciphers[j++] = ciphers[i];
      }
      *len = j;
    }
  }
#endif

  return ciphers;
failed:
  *len = 0;
  Curl_safefree(ciphers);
  return NULL;
}

static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
                                              SSLContextRef ssl_ctx)
{
  CURLcode ret = CURLE_SSL_CIPHER;
  size_t count = 0, i, j;

  OSStatus err;
  size_t supported_len;


  SSLCipherSuite *ciphers = NULL;








  ciphers = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);






  if(!ciphers) {






    failf(data, "SSL: Failed to get supported ciphers");
    goto failed;
  }

  /* Intersect the ciphers supported by Secure Transport with the default
   * ciphers, using the order of the former. */
  for(i = 0; i < supported_len; i++) {
    for(j = 0; j < DEFAULT_CIPHERS_LEN; j++) {
      if(default_ciphers[j] == ciphers[i]) {
        ciphers[count++] = ciphers[i];
        break;
      }









    }
  }

  if(count == 0) {
    failf(data, "SSL: no supported default ciphers");
    goto failed;
  }

  err = SSLSetEnabledCiphers(ssl_ctx, ciphers, count);



  if(err != noErr) {
    failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
    goto failed;
  }

  ret = CURLE_OK;
failed:
  Curl_safefree(ciphers);
  return ret;
}

static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
                                               SSLContextRef ssl_ctx,
                                               const char *ciphers)
{
  CURLcode ret = CURLE_SSL_CIPHER;
  size_t count = 0, i;
  const char *ptr, *end;
  OSStatus err;
  size_t supported_len;
  SSLCipherSuite *supported = NULL;
  SSLCipherSuite *selected = NULL;




  supported = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
  if(!supported) {
    failf(data, "SSL: Failed to get supported ciphers");
    goto failed;
  }










  selected = malloc(supported_len * sizeof(SSLCipherSuite));
  if(!selected) {
    failf(data, "SSL: Failed to allocate memory");
    goto failed;
  }





  for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {




    uint16_t id = sectransp_cipher_suite_walk_str(&ptr, &end);










    /* Check if cipher is supported */
    if(id) {
      for(i = 0; i < supported_len && supported[i] != id; i++);
      if(i == supported_len)
        id = 0;
    }
    if(!id) {
      if(ptr[0] != '\0')
        infof(data, "SSL: unknown cipher in list: \"%.*s\"", (int) (end - ptr),
              ptr);
      continue;
    }














    /* No duplicates allowed (so selected cannot overflow) */
    for(i = 0; i < count && selected[i] != id; i++);

    if(i < count) {
      infof(data, "SSL: duplicate cipher in list: \"%.*s\"", (int) (end - ptr),

            ptr);



      continue;
    }

    selected[count++] = id;
  }



  if(count == 0) {
    failf(data, "SSL: no supported cipher in list");
    goto failed;
  }



  err = SSLSetEnabledCiphers(ssl_ctx, selected, count);
  if(err != noErr) {
    failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
    goto failed;
  }

  ret = CURLE_OK;
failed:
  Curl_safefree(supported);
  Curl_safefree(selected);
  return ret;
}

static void sectransp_session_free(void *sessionid, size_t idsize)
{
  /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
     cached session ID inside the Security framework. There is a private
     function that does this, but I do not want to have to explain to you why I
     got your application rejected from the App Store due to the use of a
     private API, so the best we can do is free up our own char array that we
     created way back in sectransp_connect_step1... */
  (void)idsize;
  Curl_safefree(sessionid);
}

1661
1662
1663
1664
1665
1666
1667

1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716

1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
    (ssl_cablob ? NULL : conn_config->CAfile);
  const bool verifypeer = conn_config->verifypeer;
  char * const ssl_cert = ssl_config->primary.clientcert;
  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
  char *ciphers;
  OSStatus err = noErr;

#if CURL_BUILD_MAC
  int darwinver_maj = 0, darwinver_min = 0;

  DEBUGASSERT(backend);

  CURL_TRC_CF(data, cf, "connect_step1");
  GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
#endif /* CURL_BUILD_MAC */

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  if(SSLCreateContext) {  /* use the newer API if available */
    if(backend->ssl_ctx)
      CFRelease(backend->ssl_ctx);
    backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
    if(!backend->ssl_ctx) {
      failf(data, "SSL: couldn't create a context");
      return CURLE_OUT_OF_MEMORY;
    }
  }
  else {
  /* The old ST API does not exist under iOS, so don't compile it: */
#if CURL_SUPPORT_MAC_10_8
    if(backend->ssl_ctx)
      (void)SSLDisposeContext(backend->ssl_ctx);
    err = SSLNewContext(false, &(backend->ssl_ctx));
    if(err != noErr) {
      failf(data, "SSL: couldn't create a context: OSStatus %d", err);
      return CURLE_OUT_OF_MEMORY;
    }
#endif /* CURL_SUPPORT_MAC_10_8 */
  }
#else
  if(backend->ssl_ctx)
    (void)SSLDisposeContext(backend->ssl_ctx);
  err = SSLNewContext(false, &(backend->ssl_ctx));
  if(err != noErr) {
    failf(data, "SSL: couldn't create a context: OSStatus %d", err);
    return CURLE_OUT_OF_MEMORY;
  }
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
  backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */

  /* check to see if we've been told to use an explicit SSL/TLS version */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  if(SSLSetProtocolVersionMax) {
    switch(conn_config->version) {
    case CURL_SSLVERSION_TLSv1:
      (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1

      if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
        (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol13);
      }
      else {
        (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
      }
#else
      (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
          HAVE_BUILTIN_AVAILABLE == 1 */
      break;
    case CURL_SSLVERSION_DEFAULT:
    case CURL_SSLVERSION_TLSv1_0:
    case CURL_SSLVERSION_TLSv1_1:
    case CURL_SSLVERSION_TLSv1_2:
    case CURL_SSLVERSION_TLSv1_3:
      {
        CURLcode result = set_ssl_version_min_max(cf, data);
        if(result != CURLE_OK)
          return result;
        break;
      }
    case CURL_SSLVERSION_SSLv3:
    case CURL_SSLVERSION_SSLv2:
      failf(data, "SSL versions not supported");
      return CURLE_NOT_BUILT_IN;
    default:
      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
      return CURLE_SSL_CONNECT_ERROR;







>










|




|




|





|









|





|

|



|
>









|






<
|
|
|
|
<







1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157

1158
1159
1160
1161

1162
1163
1164
1165
1166
1167
1168
    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
    (ssl_cablob ? NULL : conn_config->CAfile);
  const bool verifypeer = conn_config->verifypeer;
  char * const ssl_cert = ssl_config->primary.clientcert;
  const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
  char *ciphers;
  OSStatus err = noErr;
  CURLcode result;
#if CURL_BUILD_MAC
  int darwinver_maj = 0, darwinver_min = 0;

  DEBUGASSERT(backend);

  CURL_TRC_CF(data, cf, "connect_step1");
  GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
#endif /* CURL_BUILD_MAC */

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  if(&SSLCreateContext) {  /* use the newer API if available */
    if(backend->ssl_ctx)
      CFRelease(backend->ssl_ctx);
    backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
    if(!backend->ssl_ctx) {
      failf(data, "SSL: could not create a context");
      return CURLE_OUT_OF_MEMORY;
    }
  }
  else {
  /* The old ST API does not exist under iOS, so do not compile it: */
#if CURL_SUPPORT_MAC_10_8
    if(backend->ssl_ctx)
      (void)SSLDisposeContext(backend->ssl_ctx);
    err = SSLNewContext(false, &(backend->ssl_ctx));
    if(err != noErr) {
      failf(data, "SSL: could not create a context: OSStatus %d", err);
      return CURLE_OUT_OF_MEMORY;
    }
#endif /* CURL_SUPPORT_MAC_10_8 */
  }
#else
  if(backend->ssl_ctx)
    (void)SSLDisposeContext(backend->ssl_ctx);
  err = SSLNewContext(false, &(backend->ssl_ctx));
  if(err != noErr) {
    failf(data, "SSL: could not create a context: OSStatus %d", err);
    return CURLE_OUT_OF_MEMORY;
  }
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
  backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */

  /* check to see if we have been told to use an explicit SSL/TLS version */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
  if(&SSLSetProtocolVersionMax) {
    switch(conn_config->version) {
    case CURL_SSLVERSION_TLSv1:
      (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
    defined(HAVE_BUILTIN_AVAILABLE)
      if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
        (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol13);
      }
      else {
        (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
      }
#else
      (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
          defined(HAVE_BUILTIN_AVAILABLE) */
      break;
    case CURL_SSLVERSION_DEFAULT:
    case CURL_SSLVERSION_TLSv1_0:
    case CURL_SSLVERSION_TLSv1_1:
    case CURL_SSLVERSION_TLSv1_2:
    case CURL_SSLVERSION_TLSv1_3:

      result = set_ssl_version_min_max(cf, data);
      if(result != CURLE_OK)
        return result;
      break;

    case CURL_SSLVERSION_SSLv3:
    case CURL_SSLVERSION_SSLv2:
      failf(data, "SSL versions not supported");
      return CURLE_NOT_BUILT_IN;
    default:
      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
      return CURLE_SSL_CONNECT_ERROR;
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
                                         kTLSProtocol12,
                                         true);
      break;
    case CURL_SSLVERSION_TLSv1_0:
    case CURL_SSLVERSION_TLSv1_1:
    case CURL_SSLVERSION_TLSv1_2:
    case CURL_SSLVERSION_TLSv1_3:
      {
        CURLcode result = set_ssl_version_min_max(cf, data);
        if(result != CURLE_OK)
          return result;
        break;
      }
    case CURL_SSLVERSION_SSLv3:
    case CURL_SSLVERSION_SSLv2:
      failf(data, "SSL versions not supported");
      return CURLE_NOT_BUILT_IN;
    default:
      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
      return CURLE_SSL_CONNECT_ERROR;







<
|
|
|
|
<







1186
1187
1188
1189
1190
1191
1192

1193
1194
1195
1196

1197
1198
1199
1200
1201
1202
1203
                                         kTLSProtocol12,
                                         true);
      break;
    case CURL_SSLVERSION_TLSv1_0:
    case CURL_SSLVERSION_TLSv1_1:
    case CURL_SSLVERSION_TLSv1_2:
    case CURL_SSLVERSION_TLSv1_3:

      result = set_ssl_version_min_max(cf, data);
      if(result != CURLE_OK)
        return result;
      break;

    case CURL_SSLVERSION_SSLv3:
    case CURL_SSLVERSION_SSLv2:
      failf(data, "SSL versions not supported");
      return CURLE_NOT_BUILT_IN;
    default:
      failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
      return CURLE_SSL_CONNECT_ERROR;
1813
1814
1815
1816
1817
1818
1819
1820

1821
1822
1823
1824
1825
1826
1827
    return CURLE_NOT_BUILT_IN;
  default:
    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */

#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1

  if(connssl->alpn) {
    if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
      struct alpn_proto_buf proto;
      size_t i;
      CFStringRef cstr;
      CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
                                                       &kCFTypeArrayCallBacks);







|
>







1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
    return CURLE_NOT_BUILT_IN;
  default:
    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */

#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
    defined(HAVE_BUILTIN_AVAILABLE)
  if(connssl->alpn) {
    if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
      struct alpn_proto_buf proto;
      size_t i;
      CFStringRef cstr;
      CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
                                                       &kCFTypeArrayCallBacks);
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
      CFTypeRef certs_c[1];
      CFArrayRef certs;

      /* If we found one, print it out: */
      err = SecIdentityCopyCertificate(cert_and_key, &cert);
      if(err == noErr) {
        char *certp;
        CURLcode result = CopyCertSubject(data, cert, &certp);
        if(!result) {
          infof(data, "Client certificate: %s", certp);
          free(certp);
        }

        CFRelease(cert);
        if(result == CURLE_PEER_FAILED_VERIFICATION)







|







1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
      CFTypeRef certs_c[1];
      CFArrayRef certs;

      /* If we found one, print it out: */
      err = SecIdentityCopyCertificate(cert_and_key, &cert);
      if(err == noErr) {
        char *certp;
        result = CopyCertSubject(data, cert, &certp);
        if(!result) {
          infof(data, "Client certificate: %s", certp);
          free(certp);
        }

        CFRelease(cert);
        if(result == CURLE_PEER_FAILED_VERIFICATION)
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
                    cert_showfilename_error);
        break;
      case -25260: /* errSecPassphraseRequired */
        failf(data, "SSL The certificate \"%s\" requires a password.",
                    cert_showfilename_error);
        break;
      case errSecItemNotFound:
        failf(data, "SSL: Can't find the certificate \"%s\" and its private "
                    "key in the Keychain.", cert_showfilename_error);
        break;
      default:
        failf(data, "SSL: Can't load the certificate \"%s\" and its private "
                    "key: OSStatus %d", cert_showfilename_error, err);
        break;
      }
      return CURLE_SSL_CERTPROBLEM;
    }
  }

  /* SSL always tries to verify the peer, this only says whether it should
   * fail to connect if the verification fails, or if it should continue
   * anyway. In the latter case the result of the verification is checked with
   * SSL_get_verify_result() below. */
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
  /* Snow Leopard introduced the SSLSetSessionOption() function, but due to
     a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
     works, it doesn't work as expected under Snow Leopard, Lion or
     Mountain Lion.
     So we need to call SSLSetEnableCertVerify() on those older cats in order
     to disable certificate validation if the user turned that off.
     (SecureTransport will always validate the certificate chain by
     default.)
  Note:
  Darwin 11.x.x is Lion (10.7)
  Darwin 12.x.x is Mountain Lion (10.8)
  Darwin 13.x.x is Mavericks (10.9)
  Darwin 14.x.x is Yosemite (10.10)
  Darwin 15.x.x is El Capitan (10.11)
  */
#if CURL_BUILD_MAC
  if(SSLSetSessionOption && darwinver_maj >= 13) {
#else
  if(SSLSetSessionOption) {
#endif /* CURL_BUILD_MAC */
    bool break_on_auth = !conn_config->verifypeer ||
      ssl_cafile || ssl_cablob;
    err = SSLSetSessionOption(backend->ssl_ctx,
                              kSSLSessionOptionBreakOnServerAuth,
                              break_on_auth);
    if(err != noErr) {







|



|














|













|

|







1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
                    cert_showfilename_error);
        break;
      case -25260: /* errSecPassphraseRequired */
        failf(data, "SSL The certificate \"%s\" requires a password.",
                    cert_showfilename_error);
        break;
      case errSecItemNotFound:
        failf(data, "SSL: cannot find the certificate \"%s\" and its private "
                    "key in the Keychain.", cert_showfilename_error);
        break;
      default:
        failf(data, "SSL: cannot load the certificate \"%s\" and its private "
                    "key: OSStatus %d", cert_showfilename_error, err);
        break;
      }
      return CURLE_SSL_CERTPROBLEM;
    }
  }

  /* SSL always tries to verify the peer, this only says whether it should
   * fail to connect if the verification fails, or if it should continue
   * anyway. In the latter case the result of the verification is checked with
   * SSL_get_verify_result() below. */
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
  /* Snow Leopard introduced the SSLSetSessionOption() function, but due to
     a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
     works, it does not work as expected under Snow Leopard, Lion or
     Mountain Lion.
     So we need to call SSLSetEnableCertVerify() on those older cats in order
     to disable certificate validation if the user turned that off.
     (SecureTransport will always validate the certificate chain by
     default.)
  Note:
  Darwin 11.x.x is Lion (10.7)
  Darwin 12.x.x is Mountain Lion (10.8)
  Darwin 13.x.x is Mavericks (10.9)
  Darwin 14.x.x is Yosemite (10.10)
  Darwin 15.x.x is El Capitan (10.11)
  */
#if CURL_BUILD_MAC
  if(&SSLSetSessionOption && darwinver_maj >= 13) {
#else
  if(&SSLSetSessionOption) {
#endif /* CURL_BUILD_MAC */
    bool break_on_auth = !conn_config->verifypeer ||
      ssl_cafile || ssl_cablob;
    err = SSLSetSessionOption(backend->ssl_ctx,
                              kSSLSessionOptionBreakOnServerAuth,
                              break_on_auth);
    if(err != noErr) {
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */

  if((ssl_cafile || ssl_cablob) && verifypeer) {
    bool is_cert_data = ssl_cablob != NULL;
    bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);

    if(!(is_cert_file || is_cert_data)) {
      failf(data, "SSL: can't load CA certificate file %s",
            ssl_cafile ? ssl_cafile : "(blob memory)");
      return CURLE_SSL_CACERT_BADFILE;
    }
  }

  /* Configure hostname check. SNI is used if available.
   * Both hostname check and SNI require SSLSetPeerDomainName().







|







1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */

  if((ssl_cafile || ssl_cablob) && verifypeer) {
    bool is_cert_data = ssl_cablob != NULL;
    bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);

    if(!(is_cert_file || is_cert_data)) {
      failf(data, "SSL: cannot load CA certificate file %s",
            ssl_cafile ? ssl_cafile : "(blob memory)");
      return CURLE_SSL_CACERT_BADFILE;
    }
  }

  /* Configure hostname check. SNI is used if available.
   * Both hostname check and SNI require SSLSetPeerDomainName().
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
  }
  else {
    infof(data, "WARNING: disabling hostname validation also disables SNI.");
  }

  ciphers = conn_config->cipher_list;
  if(ciphers) {
    err = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
  }
  else {
    err = sectransp_set_default_ciphers(data, backend->ssl_ctx);
  }
  if(err != noErr) {
    failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. "
          "Error code: %d", err);
    return CURLE_SSL_CIPHER;
  }

#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
  /* We want to enable 1/n-1 when using a CBC cipher unless the user
     specifically doesn't want us doing that: */
  if(SSLSetSessionOption) {
    SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
                        !ssl_config->enable_beast);
    SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
                      ssl_config->falsestart); /* false start support */
  }
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */

  /* Check if there's a cached ID we can/should use here! */
  if(ssl_config->primary.sessionid) {
    char *ssl_sessionid;
    size_t ssl_sessionid_len;

    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
                              (void **)&ssl_sessionid, &ssl_sessionid_len)) {
      /* we got a session id, use it! */
      err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
      Curl_ssl_sessionid_unlock(data);
      if(err != noErr) {
        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
        return CURLE_SSL_CONNECT_ERROR;
      }
      /* Informational message */
      infof(data, "SSL reusing session ID");
    }
    /* If there isn't one, then let's make one up! This has to be done prior
       to starting the handshake. */
    else {
      CURLcode result;
      ssl_sessionid =
        aprintf("%s:%d:%d:%s:%d",
                ssl_cafile ? ssl_cafile : "(blob memory)",
                verifypeer, conn_config->verifyhost, connssl->peer.hostname,
                connssl->peer.port);
      ssl_sessionid_len = strlen(ssl_sessionid);

      err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
      if(err != noErr) {
        Curl_ssl_sessionid_unlock(data);
        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
        return CURLE_SSL_CONNECT_ERROR;
      }

      result = Curl_ssl_addsessionid(cf, data, &connssl->peer, ssl_sessionid,
                                     ssl_sessionid_len,
                                     sectransp_session_free);
      Curl_ssl_sessionid_unlock(data);
      if(result)
        return result;
    }
  }

  err = SSLSetIOFuncs(backend->ssl_ctx,







|


|

|

|





|
|







|
|
















|


<














|
|
|







1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498

1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
  }
  else {
    infof(data, "WARNING: disabling hostname validation also disables SNI.");
  }

  ciphers = conn_config->cipher_list;
  if(ciphers) {
    result = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
  }
  else {
    result = sectransp_set_default_ciphers(data, backend->ssl_ctx);
  }
  if(result != CURLE_OK) {
    failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. "
          "Error code: %d", (int)result);
    return CURLE_SSL_CIPHER;
  }

#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
  /* We want to enable 1/n-1 when using a CBC cipher unless the user
     specifically does not want us doing that: */
  if(&SSLSetSessionOption) {
    SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
                        !ssl_config->enable_beast);
    SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
                      ssl_config->falsestart); /* false start support */
  }
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */

  /* Check if there is a cached ID we can/should use here! */
  if(ssl_config->primary.cache_session) {
    char *ssl_sessionid;
    size_t ssl_sessionid_len;

    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
                              (void **)&ssl_sessionid, &ssl_sessionid_len)) {
      /* we got a session id, use it! */
      err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
      Curl_ssl_sessionid_unlock(data);
      if(err != noErr) {
        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
        return CURLE_SSL_CONNECT_ERROR;
      }
      /* Informational message */
      infof(data, "SSL reusing session ID");
    }
    /* If there is not one, then let's make one up! This has to be done prior
       to starting the handshake. */
    else {

      ssl_sessionid =
        aprintf("%s:%d:%d:%s:%d",
                ssl_cafile ? ssl_cafile : "(blob memory)",
                verifypeer, conn_config->verifyhost, connssl->peer.hostname,
                connssl->peer.port);
      ssl_sessionid_len = strlen(ssl_sessionid);

      err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
      if(err != noErr) {
        Curl_ssl_sessionid_unlock(data);
        failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
        return CURLE_SSL_CONNECT_ERROR;
      }

      result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, ssl_sessionid,
                                      ssl_sessionid_len,
                                      sectransp_session_free);
      Curl_ssl_sessionid_unlock(data);
      if(result)
        return result;
    }
  }

  err = SSLSetIOFuncs(backend->ssl_ctx,
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
}

static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
{
  char *sep_start, *sep_end, *cert_start, *cert_end;
  size_t i, j, err;
  size_t len;
  unsigned char *b64;

  /* Jump through the separators at the beginning of the certificate. */
  sep_start = strstr(in, "-----");
  if(!sep_start)
    return 0;
  cert_start = strstr(sep_start + 1, "-----");
  if(!cert_start)







|







1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
}

static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
{
  char *sep_start, *sep_end, *cert_start, *cert_end;
  size_t i, j, err;
  size_t len;
  char *b64;

  /* Jump through the separators at the beginning of the certificate. */
  sep_start = strstr(in, "-----");
  if(!sep_start)
    return 0;
  cert_start = strstr(sep_start + 1, "-----");
  if(!cert_start)
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221

  *out = Curl_dyn_uptr(&certs);
  *outlen = Curl_dyn_len(&certs);

  return 0;
}

static int append_cert_to_array(struct Curl_easy *data,
                                const unsigned char *buf, size_t buflen,
                                CFMutableArrayRef array)
{
    char *certp;
    CURLcode result;
    SecCertificateRef cacert;
    CFDataRef certdata;

    certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
    if(!certdata) {
      failf(data, "SSL: failed to allocate array for CA certificate");
      return CURLE_OUT_OF_MEMORY;
    }

    cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
    CFRelease(certdata);







|
|
|






|







1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642

  *out = Curl_dyn_uptr(&certs);
  *outlen = Curl_dyn_len(&certs);

  return 0;
}

static CURLcode append_cert_to_array(struct Curl_easy *data,
                                     const unsigned char *buf, size_t buflen,
                                     CFMutableArrayRef array)
{
    char *certp;
    CURLcode result;
    SecCertificateRef cacert;
    CFDataRef certdata;

    certdata = CFDataCreate(kCFAllocatorDefault, buf, (CFIndex)buflen);
    if(!certdata) {
      failf(data, "SSL: failed to allocate array for CA certificate");
      return CURLE_OUT_OF_MEMORY;
    }

    cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
    CFRelease(certdata);
2244
2245
2246
2247
2248
2249
2250
2251

2252
2253
2254
2255
2256
2257
2258
}

static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                const unsigned char *certbuf, size_t buflen,
                                SSLContextRef ctx)
{
  int n = 0, rc;

  long res;
  unsigned char *der;
  size_t derlen, offset = 0;
  OSStatus ret;
  SecTrustResultType trust_eval;
  CFMutableArrayRef array = NULL;
  SecTrustRef trust = NULL;







|
>







1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
}

static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                const unsigned char *certbuf, size_t buflen,
                                SSLContextRef ctx)
{
  int n = 0;
  CURLcode rc;
  long res;
  unsigned char *der;
  size_t derlen, offset = 0;
  OSStatus ret;
  SecTrustResultType trust_eval;
  CFMutableArrayRef array = NULL;
  SecTrustRef trust = NULL;
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
  unsigned char *pubkey = NULL, *realpubkey = NULL;
  const unsigned char *spkiHeader = NULL;
  CFDataRef publicKeyBits = NULL;

  /* Result is returned to caller */
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;

  /* if a path wasn't specified, don't pin */
  if(!pinnedpubkey)
    return CURLE_OK;


  if(!ctx)
    return result;








|







1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
  unsigned char *pubkey = NULL, *realpubkey = NULL;
  const unsigned char *spkiHeader = NULL;
  CFDataRef publicKeyBits = NULL;

  /* Result is returned to caller */
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;

  /* if a path was not specified, do not pin */
  if(!pinnedpubkey)
    return CURLE_OK;


  if(!ctx)
    return result;

2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
    CFRelease(keyRef);
    if(!publicKeyBits)
      break;

#elif SECTRANSP_PINNEDPUBKEY_V2

    {
        OSStatus success;
        success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
                                &publicKeyBits);
        CFRelease(keyRef);
        if(success != errSecSuccess || !publicKeyBits)
          break;
    }

#endif /* SECTRANSP_PINNEDPUBKEY_V2 */

    pubkeylen = CFDataGetLength(publicKeyBits);
    pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits);

    switch(pubkeylen) {
      case 526:
        /* 4096 bit RSA pubkeylen == 526 */
        spkiHeader = rsa4096SpkiHeader;
        break;







|
|
|
|
|
|




|







1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
    CFRelease(keyRef);
    if(!publicKeyBits)
      break;

#elif SECTRANSP_PINNEDPUBKEY_V2

    {
      OSStatus success;
      success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
                              &publicKeyBits);
      CFRelease(keyRef);
      if(success != errSecSuccess || !publicKeyBits)
        break;
    }

#endif /* SECTRANSP_PINNEDPUBKEY_V2 */

    pubkeylen = (size_t)CFDataGetLength(publicKeyBits);
    pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits);

    switch(pubkeylen) {
      case 526:
        /* 4096 bit RSA pubkeylen == 526 */
        spkiHeader = rsa4096SpkiHeader;
        break;
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540

2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
  struct st_ssl_backend_data *backend =
    (struct st_ssl_backend_data *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  OSStatus err;
  SSLCipherSuite cipher;
  SSLProtocol protocol = 0;

  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
              || ssl_connect_2_reading == connssl->connecting_state
              || ssl_connect_2_writing == connssl->connecting_state);
  DEBUGASSERT(backend);
  CURL_TRC_CF(data, cf, "connect_step2");

  /* Here goes nothing: */
check_handshake:

  err = SSLHandshake(backend->ssl_ctx);

  if(err != noErr) {
    switch(err) {
      case errSSLWouldBlock:  /* they're not done with us yet */
        connssl->connecting_state = backend->ssl_direction ?
            ssl_connect_2_writing : ssl_connect_2_reading;
        return CURLE_OK;

      /* The below is errSSLServerAuthCompleted; it's not defined in
        Leopard's headers */
      case -9841:
        if((conn_config->CAfile || conn_config->ca_info_blob) &&
           conn_config->verifypeer) {
          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
                                        conn_config->ca_info_blob,
                                        backend->ssl_ctx);







|
<
<





>




|
|
|


|







1948
1949
1950
1951
1952
1953
1954
1955


1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
  struct st_ssl_backend_data *backend =
    (struct st_ssl_backend_data *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  OSStatus err;
  SSLCipherSuite cipher;
  SSLProtocol protocol = 0;

  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state);


  DEBUGASSERT(backend);
  CURL_TRC_CF(data, cf, "connect_step2");

  /* Here goes nothing: */
check_handshake:
  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  err = SSLHandshake(backend->ssl_ctx);

  if(err != noErr) {
    switch(err) {
      case errSSLWouldBlock:  /* they are not done with us yet */
        connssl->io_need = backend->ssl_direction ?
            CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
        return CURLE_OK;

      /* The below is errSSLServerAuthCompleted; it is not defined in
        Leopard's headers */
      case -9841:
        if((conn_config->CAfile || conn_config->ca_info_blob) &&
           conn_config->verifypeer) {
          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
                                        conn_config->ca_info_blob,
                                        backend->ssl_ctx);
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
        break;
      case errSSLPeerUnknownCA:
        failf(data, "SSL server rejected the client certificate due to "
              "the certificate being signed by an unknown certificate "
              "authority");
        break;

      /* This error is raised if the server's cert didn't match the server's
         host name: */
      case errSSLHostNameMismatch:
        failf(data, "SSL certificate peer verification failed, the "
              "certificate did not match \"%s\"\n", connssl->peer.dispname);
        return CURLE_PEER_FAILED_VERIFICATION;

      /* Problem with SSL / TLS negotiation */
      case errSSLNegotiation:







|
|







2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
        break;
      case errSSLPeerUnknownCA:
        failf(data, "SSL server rejected the client certificate due to "
              "the certificate being signed by an unknown certificate "
              "authority");
        break;

      /* This error is raised if the server's cert did not match the server's
         hostname: */
      case errSSLHostNameMismatch:
        failf(data, "SSL certificate peer verification failed, the "
              "certificate did not match \"%s\"\n", connssl->peer.dispname);
        return CURLE_PEER_FAILED_VERIFICATION;

      /* Problem with SSL / TLS negotiation */
      case errSSLNegotiation:
2755
2756
2757
2758
2759
2760
2761

2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779



2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814

2815
2816
2817
2818
2819
2820
2821
        failf(data, "Unknown SSL protocol error in connection to %s:%d",
              connssl->peer.hostname, err);
        break;
    }
    return CURLE_SSL_CONNECT_ERROR;
  }
  else {

    /* we have been connected fine, we're not waiting for anything else. */
    connssl->connecting_state = ssl_connect_3;

#ifdef SECTRANSP_PINNEDPUBKEY
    if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
      CURLcode result =
        pkp_pin_peer_pubkey(data, backend->ssl_ctx,
                            data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
      if(result) {
        failf(data, "SSL: public key does not match pinned public key");
        return result;
      }
    }
#endif /* SECTRANSP_PINNEDPUBKEY */

    /* Informational message */
    (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher);
    (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);



    switch(protocol) {
      case kSSLProtocol2:
        infof(data, "SSL 2.0 connection using %s",
              TLSCipherNameForNumber(cipher));
        break;
      case kSSLProtocol3:
        infof(data, "SSL 3.0 connection using %s",
              TLSCipherNameForNumber(cipher));
        break;
      case kTLSProtocol1:
        infof(data, "TLS 1.0 connection using %s",
              TLSCipherNameForNumber(cipher));
        break;
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
      case kTLSProtocol11:
        infof(data, "TLS 1.1 connection using %s",
              TLSCipherNameForNumber(cipher));
        break;
      case kTLSProtocol12:
        infof(data, "TLS 1.2 connection using %s",
              TLSCipherNameForNumber(cipher));
        break;
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
      case kTLSProtocol13:
        infof(data, "TLS 1.3 connection using %s",
              TLSCipherNameForNumber(cipher));
        break;
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
      default:
        infof(data, "Unknown protocol connection");
        break;
    }

#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1

    if(connssl->alpn) {
      if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
        CFArrayRef alpnArr = NULL;
        CFStringRef chosenProtocol = NULL;
        err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr);

        if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1)







>
|

















>
>
>


|
<


|
<


|
<



|
<


|
<




|
<







|
>







2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207

2208
2209
2210

2211
2212
2213

2214
2215
2216
2217

2218
2219
2220

2221
2222
2223
2224
2225

2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
        failf(data, "Unknown SSL protocol error in connection to %s:%d",
              connssl->peer.hostname, err);
        break;
    }
    return CURLE_SSL_CONNECT_ERROR;
  }
  else {
    char cipher_str[64];
    /* we have been connected fine, we are not waiting for anything else. */
    connssl->connecting_state = ssl_connect_3;

#ifdef SECTRANSP_PINNEDPUBKEY
    if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
      CURLcode result =
        pkp_pin_peer_pubkey(data, backend->ssl_ctx,
                            data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
      if(result) {
        failf(data, "SSL: public key does not match pinned public key");
        return result;
      }
    }
#endif /* SECTRANSP_PINNEDPUBKEY */

    /* Informational message */
    (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher);
    (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);

    sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str,
                                   sizeof(cipher_str), true);
    switch(protocol) {
      case kSSLProtocol2:
        infof(data, "SSL 2.0 connection using %s", cipher_str);

        break;
      case kSSLProtocol3:
        infof(data, "SSL 3.0 connection using %s", cipher_str);

        break;
      case kTLSProtocol1:
        infof(data, "TLS 1.0 connection using %s", cipher_str);

        break;
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
      case kTLSProtocol11:
        infof(data, "TLS 1.1 connection using %s", cipher_str);

        break;
      case kTLSProtocol12:
        infof(data, "TLS 1.2 connection using %s", cipher_str);

        break;
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
      case kTLSProtocol13:
        infof(data, "TLS 1.3 connection using %s", cipher_str);

        break;
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
      default:
        infof(data, "Unknown protocol connection");
        break;
    }

#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
    defined(HAVE_BUILTIN_AVAILABLE)
    if(connssl->alpn) {
      if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
        CFArrayRef alpnArr = NULL;
        CFStringRef chosenProtocol = NULL;
        err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr);

        if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1)
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
        else
          infof(data, VTLS_INFOF_NO_ALPN);

        Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
                            BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);

        /* chosenProtocol is a reference to the string within alpnArr
           and doesn't need to be freed separately */
        if(alpnArr)
          CFRelease(alpnArr);
      }
    }
#endif

    return CURLE_OK;







|







2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
        else
          infof(data, VTLS_INFOF_NO_ALPN);

        Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
                            BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);

        /* chosenProtocol is a reference to the string within alpnArr
           and does not need to be freed separately */
        if(alpnArr)
          CFRelease(alpnArr);
      }
    }
#endif

    return CURLE_OK;
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
    }
    CFRelease(trust);
  }
#else
  /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
     The function SecTrustGetCertificateAtIndex() is officially present
     in Lion, but it is unfortunately also present in Snow Leopard as
     private API and doesn't work as expected. So we have to look for
     a different symbol to make sure this code is only executed under
     Lion or later. */
  if(SecTrustCopyPublicKey) {
#pragma unused(server_certs)
    err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
    /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
       a null trust, so be on guard for that: */
    if(err == noErr && trust) {
      count = SecTrustGetCertificateCount(trust);
      if(ssl_config->certinfo)







|


|







2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
    }
    CFRelease(trust);
  }
#else
  /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
     The function SecTrustGetCertificateAtIndex() is officially present
     in Lion, but it is unfortunately also present in Snow Leopard as
     private API and does not work as expected. So we have to look for
     a different symbol to make sure this code is only executed under
     Lion or later. */
  if(&SecTrustCopyPublicKey) {
#pragma unused(server_certs)
    err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
    /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
       a null trust, so be on guard for that: */
    if(err == noErr && trust) {
      count = SecTrustGetCertificateCount(trust);
      if(ssl_config->certinfo)
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* Find out how much more time we're allowed */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = sectransp_connect_step1(cf, data);
    if(result)
      return result;
  }

  while(ssl_connect_2 == connssl->connecting_state ||
        ssl_connect_2_reading == connssl->connecting_state ||
        ssl_connect_2_writing == connssl->connecting_state) {

    /* check allowed time left */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it's available. */
    if(connssl->connecting_state == ssl_connect_2_reading ||
       connssl->connecting_state == ssl_connect_2_writing) {

      curl_socket_t writefd = ssl_connect_2_writing ==
      connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading ==
      connssl->connecting_state?sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking ? 0 : timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;







|













|
<
<










|
|
<

|
|
|
|







2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467


2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479

2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* Find out how much more time we are allowed */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = sectransp_connect_step1(cf, data);
    if(result)
      return result;
  }

  while(ssl_connect_2 == connssl->connecting_state) {



    /* check allowed time left */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it is available. */
    if(connssl->io_need) {


      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
                              sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
                             sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking ? 0 : timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
    /* Run transaction, and return to the caller if it failed or if this
     * connection is done nonblocking and this loop would execute again. This
     * permits the owner of a multi handle to abort a connection attempt
     * before step2 has completed while ensuring that a client using select()
     * or epoll() will always have a valid fdset to wait on.
     */
    result = sectransp_connect_step2(cf, data);
    if(result || (nonblocking &&
                  (ssl_connect_2 == connssl->connecting_state ||
                   ssl_connect_2_reading == connssl->connecting_state ||
                   ssl_connect_2_writing == connssl->connecting_state)))
      return result;

  } /* repeat step2 until all transactions are done. */


  if(ssl_connect_3 == connssl->connecting_state) {
    result = sectransp_connect_step3(cf, data);







|
<
<
<







2507
2508
2509
2510
2511
2512
2513
2514



2515
2516
2517
2518
2519
2520
2521
    /* Run transaction, and return to the caller if it failed or if this
     * connection is done nonblocking and this loop would execute again. This
     * permits the owner of a multi handle to abort a connection attempt
     * before step2 has completed while ensuring that a client using select()
     * or epoll() will always have a valid fdset to wait on.
     */
    result = sectransp_connect_step2(cf, data);
    if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))



      return result;

  } /* repeat step2 until all transactions are done. */


  if(ssl_connect_3 == connssl->connecting_state) {
    result = sectransp_connect_step3(cf, data);
3141
3142
3143
3144
3145
3146
3147






















































































3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
  if(result)
    return result;

  DEBUGASSERT(done);

  return CURLE_OK;
}























































































static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct st_ssl_backend_data *backend =
    (struct st_ssl_backend_data *)connssl->backend;

  (void) data;

  DEBUGASSERT(backend);

  if(backend->ssl_ctx) {
    CURL_TRC_CF(data, cf, "close");
    (void)SSLClose(backend->ssl_ctx);
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
    if(SSLCreateContext)
      CFRelease(backend->ssl_ctx);
#if CURL_SUPPORT_MAC_10_8
    else
      (void)SSLDisposeContext(backend->ssl_ctx);
#endif  /* CURL_SUPPORT_MAC_10_8 */
#else
    (void)SSLDisposeContext(backend->ssl_ctx);
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
    backend->ssl_ctx = NULL;
  }
}

static int sectransp_shutdown(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct st_ssl_backend_data *backend =
    (struct st_ssl_backend_data *)connssl->backend;
  ssize_t nread;
  int what;
  int rc;
  char buf[120];
  int loop = 10; /* avoid getting stuck */
  CURLcode result;

  DEBUGASSERT(backend);

  if(!backend->ssl_ctx)
    return 0;

#ifndef CURL_DISABLE_FTP
  if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
    return 0;
#endif

  sectransp_close(cf, data);

  rc = 0;

  what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
                         SSL_SHUTDOWN_TIMEOUT);

  CURL_TRC_CF(data, cf, "shutdown");
  while(loop--) {
    if(what < 0) {
      /* anything that gets here is fatally bad */
      failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
      rc = -1;
      break;
    }

    if(!what) {                                /* timeout */
      failf(data, "SSL shutdown timeout");
      break;
    }

    /* Something to read, let's do it and hope that it is the close
     notify alert from the server. No way to SSL_Read now, so use read(). */

    nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);

    if(nread < 0) {
      failf(data, "read: %s", curl_easy_strerror(result));
      rc = -1;
    }

    if(nread <= 0)
      break;

    what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0);
  }

  return rc;
}

static size_t sectransp_version(char *buffer, size_t size)
{
  return msnprintf(buffer, size, "SecureTransport");
}

static bool sectransp_data_pending(struct Curl_cfilter *cf,
                                   const struct Curl_easy *data)







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













<

|












<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660

2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674































































2675
2676
2677
2678
2679
2680
2681
  if(result)
    return result;

  DEBUGASSERT(done);

  return CURLE_OK;
}

static ssize_t sectransp_recv(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              char *buf,
                              size_t buffersize,
                              CURLcode *curlcode);

static CURLcode sectransp_shutdown(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   bool send_shutdown, bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct st_ssl_backend_data *backend =
    (struct st_ssl_backend_data *)connssl->backend;
  CURLcode result = CURLE_OK;
  ssize_t nread;
  char buf[1024];
  size_t i;

  DEBUGASSERT(backend);
  if(!backend->ssl_ctx || cf->shutdown) {
    *done = TRUE;
    goto out;
  }

  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  *done = FALSE;

  if(send_shutdown && !backend->sent_shutdown) {
    OSStatus err;

    CURL_TRC_CF(data, cf, "shutdown, send close notify");
    err = SSLClose(backend->ssl_ctx);
    switch(err) {
      case noErr:
        backend->sent_shutdown = TRUE;
        break;
      case errSSLWouldBlock:
        connssl->io_need = CURL_SSL_IO_NEED_SEND;
        result = CURLE_OK;
        goto out;
      default:
        CURL_TRC_CF(data, cf, "shutdown, error: %d", (int)err);
        result = CURLE_SEND_ERROR;
        goto out;
    }
  }

  for(i = 0; i < 10; ++i) {
    if(!backend->sent_shutdown) {
      nread = sectransp_recv(cf, data, buf, (int)sizeof(buf), &result);
    }
    else {
      /* We would like to read the close notify from the server using
       * secure transport, however SSLRead() no longer works after we
       * sent the notify from our side. So, we just read from the
       * underlying filter and hope it will end. */
      nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
    }
    CURL_TRC_CF(data, cf, "shutdown read -> %zd, %d", nread, result);
    if(nread <= 0)
      break;
  }

  if(nread > 0) {
    /* still data coming in? */
    connssl->io_need = CURL_SSL_IO_NEED_RECV;
  }
  else if(nread == 0) {
    /* We got the close notify alert and are done. */
    CURL_TRC_CF(data, cf, "shutdown done");
    *done = TRUE;
  }
  else if(result == CURLE_AGAIN) {
    connssl->io_need = CURL_SSL_IO_NEED_RECV;
    result = CURLE_OK;
  }
  else {
    DEBUGASSERT(result);
    CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
  }

out:
  cf->shutdown = (result || *done);
  return result;
}

static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct st_ssl_backend_data *backend =
    (struct st_ssl_backend_data *)connssl->backend;

  (void) data;

  DEBUGASSERT(backend);

  if(backend->ssl_ctx) {
    CURL_TRC_CF(data, cf, "close");

#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
    if(&SSLCreateContext)
      CFRelease(backend->ssl_ctx);
#if CURL_SUPPORT_MAC_10_8
    else
      (void)SSLDisposeContext(backend->ssl_ctx);
#endif  /* CURL_SUPPORT_MAC_10_8 */
#else
    (void)SSLDisposeContext(backend->ssl_ctx);
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
    backend->ssl_ctx = NULL;
  }
}
































































static size_t sectransp_version(char *buffer, size_t size)
{
  return msnprintf(buffer, size, "SecureTransport");
}

static bool sectransp_data_pending(struct Curl_cfilter *cf,
                                   const struct Curl_easy *data)
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
  else
    return false;
}

static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
                                 unsigned char *entropy, size_t length)
{
  /* arc4random_buf() isn't available on cats older than Lion, so let's
     do this manually for the benefit of the older cats. */
  size_t i;
  u_int32_t random_number = 0;

  (void)data;

  for(i = 0 ; i < length ; i++) {







|







2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
  else
    return false;
}

static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
                                 unsigned char *entropy, size_t length)
{
  /* arc4random_buf() is not available on cats older than Lion, so let's
     do this manually for the benefit of the older cats. */
  size_t i;
  u_int32_t random_number = 0;

  (void)data;

  for(i = 0 ; i < length ; i++) {
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
  (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
  return CURLE_OK;
}

static bool sectransp_false_start(void)
{
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
  if(SSLSetSessionOption)
    return TRUE;
#endif
  return FALSE;
}

static ssize_t sectransp_send(struct Curl_cfilter *cf,
                              struct Curl_easy *data,







|







2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
  (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
  return CURLE_OK;
}

static bool sectransp_false_start(void)
{
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
  if(&SSLSetSessionOption)
    return TRUE;
#endif
  return FALSE;
}

static ssize_t sectransp_send(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
  /* The SSLWrite() function works a little differently than expected. The
     fourth argument (processed) is currently documented in Apple's
     documentation as: "On return, the length, in bytes, of the data actually
     written."

     Now, one could interpret that as "written to the socket," but actually,
     it returns the amount of data that was written to a buffer internal to
     the SSLContextRef instead. So it's possible for SSLWrite() to return
     errSSLWouldBlock and a number of bytes "written" because those bytes were
     encrypted and written to a buffer, not to the socket.

     So if this happens, then we need to keep calling SSLWrite() over and
     over again with no new data until it quits returning errSSLWouldBlock. */

  /* Do we have buffered data to write from the last time we were called? */
  if(backend->ssl_write_buffered_length) {
    /* Write the buffered data: */
    err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed);
    switch(err) {
      case noErr:
        /* processed is always going to be 0 because we didn't write to
           the buffer, so return how much was written to the socket */
        processed = backend->ssl_write_buffered_length;
        backend->ssl_write_buffered_length = 0UL;
        break;
      case errSSLWouldBlock: /* argh, try again */
        *curlcode = CURLE_AGAIN;
        return -1L;
      default:
        failf(data, "SSLWrite() returned error %d", err);
        *curlcode = CURLE_SEND_ERROR;
        return -1L;
    }
  }
  else {
    /* We've got new data to write: */
    err = SSLWrite(backend->ssl_ctx, mem, len, &processed);
    if(err != noErr) {
      switch(err) {
        case errSSLWouldBlock:
          /* Data was buffered but not sent, we have to tell the caller
             to try sending again, and remember how much was buffered */
          backend->ssl_write_buffered_length = len;







|












|














|







2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
  /* The SSLWrite() function works a little differently than expected. The
     fourth argument (processed) is currently documented in Apple's
     documentation as: "On return, the length, in bytes, of the data actually
     written."

     Now, one could interpret that as "written to the socket," but actually,
     it returns the amount of data that was written to a buffer internal to
     the SSLContextRef instead. So it is possible for SSLWrite() to return
     errSSLWouldBlock and a number of bytes "written" because those bytes were
     encrypted and written to a buffer, not to the socket.

     So if this happens, then we need to keep calling SSLWrite() over and
     over again with no new data until it quits returning errSSLWouldBlock. */

  /* Do we have buffered data to write from the last time we were called? */
  if(backend->ssl_write_buffered_length) {
    /* Write the buffered data: */
    err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed);
    switch(err) {
      case noErr:
        /* processed is always going to be 0 because we did not write to
           the buffer, so return how much was written to the socket */
        processed = backend->ssl_write_buffered_length;
        backend->ssl_write_buffered_length = 0UL;
        break;
      case errSSLWouldBlock: /* argh, try again */
        *curlcode = CURLE_AGAIN;
        return -1L;
      default:
        failf(data, "SSLWrite() returned error %d", err);
        *curlcode = CURLE_SEND_ERROR;
        return -1L;
    }
  }
  else {
    /* We have got new data to write: */
    err = SSLWrite(backend->ssl_ctx, mem, len, &processed);
    if(err != noErr) {
      switch(err) {
        case errSSLWouldBlock:
          /* Data was buffered but not sent, we have to tell the caller
             to try sending again, and remember how much was buffered */
          backend->ssl_write_buffered_length = len;
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
           closure alert notice, read() is returning 0
         Either way, inform the caller that the server disconnected. */
      case errSSLClosedGraceful:
      case errSSLClosedNoNotify:
        *curlcode = CURLE_OK;
        return 0;

        /* The below is errSSLPeerAuthCompleted; it's not defined in
           Leopard's headers */
      case -9841:
        if((conn_config->CAfile || conn_config->ca_info_blob) &&
           conn_config->verifypeer) {
          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
                                        conn_config->ca_info_blob,
                                        backend->ssl_ctx);







|







2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
           closure alert notice, read() is returning 0
         Either way, inform the caller that the server disconnected. */
      case errSSLClosedGraceful:
      case errSSLClosedNoNotify:
        *curlcode = CURLE_OK;
        return 0;

        /* The below is errSSLPeerAuthCompleted; it is not defined in
           Leopard's headers */
      case -9841:
        if((conn_config->CAfile || conn_config->ca_info_blob) &&
           conn_config->verifypeer) {
          CURLcode result = verify_cert(cf, data, conn_config->CAfile,
                                        conn_config->ca_info_blob,
                                        backend->ssl_ctx);
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
  Curl_none_set_engine,               /* set_engine */
  Curl_none_set_engine_default,       /* set_engine_default */
  Curl_none_engines_list,             /* engines_list */
  sectransp_false_start,              /* false_start */
  sectransp_sha256sum,                /* sha256sum */
  NULL,                               /* associate_connection */
  NULL,                               /* disassociate_connection */
  NULL,                               /* free_multi_ssl_backend_data */
  sectransp_recv,                     /* recv decrypted data */
  sectransp_send,                     /* send data to encrypt */
};

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#ifdef __clang__
#pragma clang diagnostic pop
#endif

#endif /* USE_SECTRANSP */







<













2908
2909
2910
2911
2912
2913
2914

2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
  Curl_none_set_engine,               /* set_engine */
  Curl_none_set_engine_default,       /* set_engine_default */
  Curl_none_engines_list,             /* engines_list */
  sectransp_false_start,              /* false_start */
  sectransp_sha256sum,                /* sha256sum */
  NULL,                               /* associate_connection */
  NULL,                               /* disassociate_connection */

  sectransp_recv,                     /* recv decrypted data */
  sectransp_send,                     /* send data to encrypt */
};

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#ifdef __clang__
#pragma clang diagnostic pop
#endif

#endif /* USE_SECTRANSP */
Changes to jni/curl/lib/vtls/vtls.c.
64
65
66
67
68
69
70


71
72
73
74
75
76
77
#include "multiif.h"
#include "timeval.h"
#include "curl_md5.h"
#include "warnless.h"
#include "curl_base64.h"
#include "curl_printf.h"
#include "inet_pton.h"


#include "strdup.h"

/* The last #include files should be: */
#include "curl_memory.h"
#include "memdebug.h"









>
>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include "multiif.h"
#include "timeval.h"
#include "curl_md5.h"
#include "warnless.h"
#include "curl_base64.h"
#include "curl_printf.h"
#include "inet_pton.h"
#include "connect.h"
#include "select.h"
#include "strdup.h"

/* The last #include files should be: */
#include "curl_memory.h"
#include "memdebug.h"


99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

static CURLcode blobdup(struct curl_blob **dest,
                        struct curl_blob *src)
{
  DEBUGASSERT(dest);
  DEBUGASSERT(!*dest);
  if(src) {
    /* only if there's data to dupe! */
    struct curl_blob *d;
    d = malloc(sizeof(struct curl_blob) + src->len);
    if(!d)
      return CURLE_OUT_OF_MEMORY;
    d->len = src->len;
    /* Always duplicate because the connection may survive longer than the
       handle that passed in the blob. */







|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

static CURLcode blobdup(struct curl_blob **dest,
                        struct curl_blob *src)
{
  DEBUGASSERT(dest);
  DEBUGASSERT(!*dest);
  if(src) {
    /* only if there is data to dupe! */
    struct curl_blob *d;
    d = malloc(sizeof(struct curl_blob) + src->len);
    if(!d)
      return CURLE_OUT_OF_MEMORY;
    d->len = src->len;
    /* Always duplicate because the connection may survive longer than the
       handle that passed in the blob. */
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#ifdef USE_HTTP2
  if(httpwant >= CURL_HTTP_VERSION_2)
    return &ALPN_SPEC_H2_H11;
#else
  (void)httpwant;
#endif
  /* Use the ALPN protocol "http/1.1" for HTTP/1.x.
     Avoid "http/1.0" because some servers don't support it. */
  return &ALPN_SPEC_H11;
}
#endif /* USE_SSL */


void Curl_ssl_easy_config_init(struct Curl_easy *data)
{
  /*
   * libcurl 7.10 introduced SSL verification *by default*! This needs to be
   * switched off unless wanted.
   */
  data->set.ssl.primary.verifypeer = TRUE;
  data->set.ssl.primary.verifyhost = TRUE;
  data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */
#ifndef CURL_DISABLE_PROXY
  data->set.proxy_ssl = data->set.ssl;
#endif
}

static bool
match_ssl_primary_config(struct Curl_easy *data,







|













|







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#ifdef USE_HTTP2
  if(httpwant >= CURL_HTTP_VERSION_2)
    return &ALPN_SPEC_H2_H11;
#else
  (void)httpwant;
#endif
  /* Use the ALPN protocol "http/1.1" for HTTP/1.x.
     Avoid "http/1.0" because some servers do not support it. */
  return &ALPN_SPEC_H11;
}
#endif /* USE_SSL */


void Curl_ssl_easy_config_init(struct Curl_easy *data)
{
  /*
   * libcurl 7.10 introduced SSL verification *by default*! This needs to be
   * switched off unless wanted.
   */
  data->set.ssl.primary.verifypeer = TRUE;
  data->set.ssl.primary.verifyhost = TRUE;
  data->set.ssl.primary.cache_session = TRUE; /* caching by default */
#ifndef CURL_DISABLE_PROXY
  data->set.proxy_ssl = data->set.ssl;
#endif
}

static bool
match_ssl_primary_config(struct Curl_easy *data,
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
                                     struct ssl_primary_config *dest)
{
  dest->version = source->version;
  dest->version_max = source->version_max;
  dest->verifypeer = source->verifypeer;
  dest->verifyhost = source->verifyhost;
  dest->verifystatus = source->verifystatus;
  dest->sessionid = source->sessionid;
  dest->ssl_options = source->ssl_options;

  CLONE_BLOB(cert_blob);
  CLONE_BLOB(ca_info_blob);
  CLONE_BLOB(issuercert_blob);
  CLONE_STRING(CApath);
  CLONE_STRING(CAfile);







|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
                                     struct ssl_primary_config *dest)
{
  dest->version = source->version;
  dest->version_max = source->version_max;
  dest->verifypeer = source->verifypeer;
  dest->verifyhost = source->verifyhost;
  dest->verifystatus = source->verifystatus;
  dest->cache_session = source->cache_session;
  dest->ssl_options = source->ssl_options;

  CLONE_BLOB(cert_blob);
  CLONE_BLOB(ca_info_blob);
  CLONE_BLOB(issuercert_blob);
  CLONE_STRING(CApath);
  CLONE_STRING(CAfile);
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
    }
  }

  return TRUE;
}

static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
                                     const struct alpn_spec *alpn)
{
  struct ssl_connect_data *ctx;

  (void)data;
  ctx = calloc(1, sizeof(*ctx));
  if(!ctx)
    return NULL;







|







451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
    }
  }

  return TRUE;
}

static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
                                           const struct alpn_spec *alpn)
{
  struct ssl_connect_data *ctx;

  (void)data;
  ctx = calloc(1, sizeof(*ctx));
  if(!ctx)
    return NULL;
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
{
  if(SSLSESSION_SHARED(data))
    Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
}

/*
 * Check if there's a session ID for the given connection in the cache, and if
 * there's one suitable, it is provided. Returns TRUE when no entry matched.
 */
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
                           struct Curl_easy *data,
                           const struct ssl_peer *peer,
                           void **ssl_sessionid,
                           size_t *idsize) /* set 0 if unknown */
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  struct Curl_ssl_session *check;
  size_t i;
  long *general_age;
  bool no_match = TRUE;

  *ssl_sessionid = NULL;
  if(!ssl_config)
    return TRUE;

  DEBUGASSERT(ssl_config->primary.sessionid);

  if(!ssl_config->primary.sessionid || !data->state.session)
    /* session ID reuse is disabled or the session cache has not been
       setup */
    return TRUE;

  /* Lock if shared */
  if(SSLSESSION_SHARED(data))
    general_age = &data->share->sessionage;







|
|


















|

|







527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
{
  if(SSLSESSION_SHARED(data))
    Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
}

/*
 * Check if there is a session ID for the given connection in the cache, and if
 * there is one suitable, it is provided. Returns TRUE when no entry matched.
 */
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
                           struct Curl_easy *data,
                           const struct ssl_peer *peer,
                           void **ssl_sessionid,
                           size_t *idsize) /* set 0 if unknown */
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  struct Curl_ssl_session *check;
  size_t i;
  long *general_age;
  bool no_match = TRUE;

  *ssl_sessionid = NULL;
  if(!ssl_config)
    return TRUE;

  DEBUGASSERT(ssl_config->primary.cache_session);

  if(!ssl_config->primary.cache_session || !data->state.session)
    /* session ID reuse is disabled or the session cache has not been
       setup */
    return TRUE;

  /* Lock if shared */
  if(SSLSESSION_SHARED(data))
    general_age = &data->share->sessionage;
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
        *idsize = check->idsize;
      no_match = FALSE;
      break;
    }
  }

  DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
               no_match? "Didn't find": "Found",
               Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
               cf->conn->handler->scheme, peer->hostname, peer->port));
  return no_match;
}

/*
 * Kill a single session ID entry in the cache.







|







588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
        *idsize = check->idsize;
      no_match = FALSE;
      break;
    }
  }

  DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
               no_match? "Did not find": "Found",
               Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
               cf->conn->handler->scheme, peer->hostname, peer->port));
  return no_match;
}

/*
 * Kill a single session ID entry in the cache.
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659


660
661
662
663
664
665
666
667
668











669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
    if(check->sessionid == ssl_sessionid) {
      Curl_ssl_kill_session(check);
      break;
    }
  }
}

/*
 * Store session id in the session cache. The ID passed on to this function
 * must already have been extracted and allocated the proper way for the SSL
 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
 * later on.
 */
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               const struct ssl_peer *peer,
                               void *ssl_sessionid,
                               size_t idsize,
                               Curl_ssl_sessionid_dtor *sessionid_free_cb)
{
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  size_t i;
  struct Curl_ssl_session *store;
  long oldest_age;
  char *clone_host = NULL;
  char *clone_conn_to_host = NULL;
  int conn_to_port;
  long *general_age;


  CURLcode result = CURLE_OUT_OF_MEMORY;

  DEBUGASSERT(ssl_sessionid);
  DEBUGASSERT(sessionid_free_cb);

  if(!data->state.session) {
    sessionid_free_cb(ssl_sessionid, idsize);
    return CURLE_OK;
  }












  store = &data->state.session[0];
  oldest_age = data->state.session[0].age; /* zero if unused */
  DEBUGASSERT(ssl_config->primary.sessionid);
  (void)ssl_config;

  clone_host = strdup(peer->hostname);
  if(!clone_host)
    goto out;

  if(cf->conn->bits.conn_to_host) {
    clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
    if(!clone_conn_to_host)
      goto out;
  }

  if(cf->conn->bits.conn_to_port)
    conn_to_port = cf->conn->conn_to_port;
  else
    conn_to_port = -1;

  /* Now we should add the session ID and the host name to the cache, (remove
     the oldest if necessary) */

  /* If using shared SSL session, lock! */
  if(SSLSESSION_SHARED(data)) {
    general_age = &data->share->sessionage;
  }
  else {







<
<
<
<
<
<
|
|
|
|
|
|










>
>









>
>
>
>
>
>
>
>
>
>
>



|

















|







633
634
635
636
637
638
639






640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
    if(check->sessionid == ssl_sessionid) {
      Curl_ssl_kill_session(check);
      break;
    }
  }
}







CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                const struct ssl_peer *peer,
                                void *ssl_sessionid,
                                size_t idsize,
                                Curl_ssl_sessionid_dtor *sessionid_free_cb)
{
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  size_t i;
  struct Curl_ssl_session *store;
  long oldest_age;
  char *clone_host = NULL;
  char *clone_conn_to_host = NULL;
  int conn_to_port;
  long *general_age;
  void *old_sessionid;
  size_t old_size;
  CURLcode result = CURLE_OUT_OF_MEMORY;

  DEBUGASSERT(ssl_sessionid);
  DEBUGASSERT(sessionid_free_cb);

  if(!data->state.session) {
    sessionid_free_cb(ssl_sessionid, idsize);
    return CURLE_OK;
  }

  if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size)) {
    if((old_size == idsize) &&
       ((old_sessionid == ssl_sessionid) ||
        (idsize && !memcmp(old_sessionid, ssl_sessionid, idsize)))) {
      /* the very same */
      sessionid_free_cb(ssl_sessionid, idsize);
      return CURLE_OK;
    }
    Curl_ssl_delsessionid(data, old_sessionid);
  }

  store = &data->state.session[0];
  oldest_age = data->state.session[0].age; /* zero if unused */
  DEBUGASSERT(ssl_config->primary.cache_session);
  (void)ssl_config;

  clone_host = strdup(peer->hostname);
  if(!clone_host)
    goto out;

  if(cf->conn->bits.conn_to_host) {
    clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
    if(!clone_conn_to_host)
      goto out;
  }

  if(cf->conn->bits.conn_to_port)
    conn_to_port = cf->conn->conn_to_port;
  else
    conn_to_port = -1;

  /* Now we should add the session ID and the hostname to the cache, (remove
     the oldest if necessary) */

  /* If using shared SSL session, lock! */
  if(SSLSESSION_SHARED(data)) {
    general_age = &data->share->sessionage;
  }
  else {
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
    store->sessionid = NULL; /* let caller free sessionid */
    goto out;
  }
  store->sessionid = ssl_sessionid;
  store->idsize = idsize;
  store->sessionid_free = sessionid_free_cb;
  store->age = *general_age;    /* set current age */
  /* free it if there's one already present */
  free(store->name);
  free(store->conn_to_host);
  store->name = clone_host;               /* clone host name */
  clone_host = NULL;
  store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
  clone_conn_to_host = NULL;
  store->conn_to_port = conn_to_port; /* connect to port number */
  /* port number */
  store->remote_port = peer->port;
  store->scheme = cf->conn->handler->scheme;
  store->transport = peer->transport;








|


|

|







727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
    store->sessionid = NULL; /* let caller free sessionid */
    goto out;
  }
  store->sessionid = ssl_sessionid;
  store->idsize = idsize;
  store->sessionid_free = sessionid_free_cb;
  store->age = *general_age;    /* set current age */
  /* free it if there is one already present */
  free(store->name);
  free(store->conn_to_host);
  store->name = clone_host;               /* clone hostname */
  clone_host = NULL;
  store->conn_to_host = clone_conn_to_host; /* clone connect to hostname */
  clone_conn_to_host = NULL;
  store->conn_to_port = conn_to_port; /* connect to port number */
  /* port number */
  store->remote_port = peer->port;
  store->scheme = cf->conn->handler->scheme;
  store->transport = peer->transport;

749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782


783
784
785
786
787
788
789
790
791
792
  }
  CURL_TRC_CF(data, cf, "Added Session ID to cache for %s://%s:%d [%s]",
              store->scheme, store->name, store->remote_port,
              Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server");
  return CURLE_OK;
}

void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
{
  if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
    Curl_ssl->free_multi_ssl_backend_data(mbackend);
}

void Curl_ssl_close_all(struct Curl_easy *data)
{
  /* kill the session ID cache if not shared */
  if(data->state.session && !SSLSESSION_SHARED(data)) {
    size_t i;
    for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
      /* the single-killer function handles empty table slots */
      Curl_ssl_kill_session(&data->state.session[i]);

    /* free the cache data */
    Curl_safefree(data->state.session);
  }

  Curl_ssl->close_all(data);
}

void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
                              struct easy_pollset *ps)
{
  if(!cf->connected) {
    struct ssl_connect_data *connssl = cf->ctx;


    curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
    if(sock != CURL_SOCKET_BAD) {
      if(connssl->connecting_state == ssl_connect_2_writing) {
        Curl_pollset_set_out_only(data, ps, sock);
        CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%"
                    CURL_FORMAT_SOCKET_T, sock);
      }
      else {
        Curl_pollset_set_in_only(data, ps, sock);
        CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%"







<
<
<
<
<
<



















<
|
>
>


|







758
759
760
761
762
763
764






765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783

784
785
786
787
788
789
790
791
792
793
794
795
796
  }
  CURL_TRC_CF(data, cf, "Added Session ID to cache for %s://%s:%d [%s]",
              store->scheme, store->name, store->remote_port,
              Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server");
  return CURLE_OK;
}







void Curl_ssl_close_all(struct Curl_easy *data)
{
  /* kill the session ID cache if not shared */
  if(data->state.session && !SSLSESSION_SHARED(data)) {
    size_t i;
    for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
      /* the single-killer function handles empty table slots */
      Curl_ssl_kill_session(&data->state.session[i]);

    /* free the cache data */
    Curl_safefree(data->state.session);
  }

  Curl_ssl->close_all(data);
}

void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
                              struct easy_pollset *ps)
{

  struct ssl_connect_data *connssl = cf->ctx;

  if(connssl->io_need) {
    curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
    if(sock != CURL_SOCKET_BAD) {
      if(connssl->io_need & CURL_SSL_IO_NEED_SEND) {
        Curl_pollset_set_out_only(data, ps, sock);
        CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%"
                    CURL_FORMAT_SOCKET_T, sock);
      }
      else {
        Curl_pollset_set_in_only(data, ps, sock);
        CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%"
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
  FILE *fp;
  unsigned char *buf = NULL, *pem_ptr = NULL;
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
  (void)data;
#endif

  /* if a path wasn't specified, don't pin */
  if(!pinnedpubkey)
    return CURLE_OK;
  if(!pubkey || !pubkeylen)
    return result;

  /* only do this if pinnedpubkey starts with "sha256//", length 8 */
  if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {







|







1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  FILE *fp;
  unsigned char *buf = NULL, *pem_ptr = NULL;
  CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
  (void)data;
#endif

  /* if a path was not specified, do not pin */
  if(!pinnedpubkey)
    return CURLE_OK;
  if(!pubkey || !pubkeylen)
    return result;

  /* only do this if pinnedpubkey starts with "sha256//", length 8 */
  if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
    }
    /* point begin_pos to the copy, and start extracting keys */
    begin_pos = pinkeycopy;
    do {
      end_pos = strstr(begin_pos, ";sha256//");
      /*
       * if there is an end_pos, null terminate,
       * otherwise it'll go to the end of the original string
       */
      if(end_pos)
        end_pos[0] = '\0';

      /* compare base64 sha256 digests, 8 is the length of "sha256//" */
      if(encodedlen == strlen(begin_pos + 8) &&
         !memcmp(encoded, begin_pos + 8, encodedlen)) {







|







1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
    }
    /* point begin_pos to the copy, and start extracting keys */
    begin_pos = pinkeycopy;
    do {
      end_pos = strstr(begin_pos, ";sha256//");
      /*
       * if there is an end_pos, null terminate,
       * otherwise it will go to the end of the original string
       */
      if(end_pos)
        end_pos[0] = '\0';

      /* compare base64 sha256 digests, 8 is the length of "sha256//" */
      if(encodedlen == strlen(begin_pos + 8) &&
         !memcmp(encoded, begin_pos + 8, encodedlen)) {
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
    if(fseek(fp, 0, SEEK_SET))
      break;
    if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
      break;

    /*
     * if the size of our certificate is bigger than the file
     * size then it can't match
     */
    size = curlx_sotouz((curl_off_t) filesize);
    if(pubkeylen > size)
      break;

    /*
     * Allocate buffer for the pinned key
     * With 1 additional byte for null terminator in case of PEM key
     */
    buf = malloc(size + 1);
    if(!buf)
      break;

    /* Returns number of elements read, which should be 1 */
    if((int) fread(buf, size, 1, fp) != 1)
      break;

    /* If the sizes are the same, it can't be base64 encoded, must be der */
    if(pubkeylen == size) {
      if(!memcmp(pubkey, buf, pubkeylen))
        result = CURLE_OK;
      break;
    }

    /*
     * Otherwise we will assume it's PEM and try to decode it
     * after placing null terminator
     */
    buf[size] = '\0';
    pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
    /* if it wasn't read successfully, exit */
    if(pem_read)
      break;

    /*
     * if the size of our certificate doesn't match the size of
     * the decoded file, they can't be the same, otherwise compare
     */
    if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
      result = CURLE_OK;
  } while(0);

  Curl_safefree(buf);
  Curl_safefree(pem_ptr);







|

















|







|




|




|
|







1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
    if(fseek(fp, 0, SEEK_SET))
      break;
    if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
      break;

    /*
     * if the size of our certificate is bigger than the file
     * size then it cannot match
     */
    size = curlx_sotouz((curl_off_t) filesize);
    if(pubkeylen > size)
      break;

    /*
     * Allocate buffer for the pinned key
     * With 1 additional byte for null terminator in case of PEM key
     */
    buf = malloc(size + 1);
    if(!buf)
      break;

    /* Returns number of elements read, which should be 1 */
    if((int) fread(buf, size, 1, fp) != 1)
      break;

    /* If the sizes are the same, it cannot be base64 encoded, must be der */
    if(pubkeylen == size) {
      if(!memcmp(pubkey, buf, pubkeylen))
        result = CURLE_OK;
      break;
    }

    /*
     * Otherwise we will assume it is PEM and try to decode it
     * after placing null terminator
     */
    buf[size] = '\0';
    pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
    /* if it was not read successfully, exit */
    if(pem_read)
      break;

    /*
     * if the size of our certificate does not match the size of
     * the decoded file, they cannot be the same, otherwise compare
     */
    if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
      result = CURLE_OK;
  } while(0);

  Curl_safefree(buf);
  Curl_safefree(pem_ptr);
1169
1170
1171
1172
1173
1174
1175
1176
1177


1178
1179
1180




1181
1182
1183
1184
1185
1186
1187
1188
{
  return 1;
}

void Curl_none_cleanup(void)
{ }

int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
                       struct Curl_easy *data UNUSED_PARAM)


{
  (void)data;
  (void)cf;




  return 0;
}

int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  (void)cf;
  (void)data;
  return -1;







|
|
>
>



>
>
>
>
|







1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
{
  return 1;
}

void Curl_none_cleanup(void)
{ }

CURLcode Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
                            struct Curl_easy *data UNUSED_PARAM,
                            bool send_shutdown UNUSED_PARAM,
                            bool *done)
{
  (void)data;
  (void)cf;
  (void)send_shutdown;
  /* Every SSL backend should have a shutdown implementation. Until we
   * have implemented that, we put this fake in place. */
  *done = TRUE;
  return CURLE_OK;
}

int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  (void)cf;
  (void)data;
  return -1;
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361


1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384



1385
1386
1387
1388
1389
1390
1391
  Curl_none_set_engine,              /* set_engine */
  Curl_none_set_engine_default,      /* set_engine_default */
  Curl_none_engines_list,            /* engines_list */
  Curl_none_false_start,             /* false_start */
  NULL,                              /* sha256sum */
  NULL,                              /* associate_connection */
  NULL,                              /* disassociate_connection */
  NULL,                              /* free_multi_ssl_backend_data */
  multissl_recv_plain,               /* recv decrypted data */
  multissl_send_plain,               /* send data to encrypt */
};

const struct Curl_ssl *Curl_ssl =
#if defined(CURL_WITH_MULTI_SSL)
  &Curl_ssl_multi;
#elif defined(USE_WOLFSSL)
  &Curl_ssl_wolfssl;
#elif defined(USE_SECTRANSP)
  &Curl_ssl_sectransp;
#elif defined(USE_GNUTLS)
  &Curl_ssl_gnutls;
#elif defined(USE_MBEDTLS)
  &Curl_ssl_mbedtls;
#elif defined(USE_RUSTLS)
  &Curl_ssl_rustls;
#elif defined(USE_OPENSSL)
  &Curl_ssl_openssl;


#elif defined(USE_SCHANNEL)
  &Curl_ssl_schannel;
#elif defined(USE_BEARSSL)
  &Curl_ssl_bearssl;
#else
#error "Missing struct Curl_ssl for selected SSL backend"
#endif

static const struct Curl_ssl *available_backends[] = {
#if defined(USE_WOLFSSL)
  &Curl_ssl_wolfssl,
#endif
#if defined(USE_SECTRANSP)
  &Curl_ssl_sectransp,
#endif
#if defined(USE_GNUTLS)
  &Curl_ssl_gnutls,
#endif
#if defined(USE_MBEDTLS)
  &Curl_ssl_mbedtls,
#endif
#if defined(USE_OPENSSL)
  &Curl_ssl_openssl,



#endif
#if defined(USE_SCHANNEL)
  &Curl_ssl_schannel,
#endif
#if defined(USE_BEARSSL)
  &Curl_ssl_bearssl,
#endif







<









<
<








>
>












<
<
<








>
>
>







1345
1346
1347
1348
1349
1350
1351

1352
1353
1354
1355
1356
1357
1358
1359
1360


1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382



1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
  Curl_none_set_engine,              /* set_engine */
  Curl_none_set_engine_default,      /* set_engine_default */
  Curl_none_engines_list,            /* engines_list */
  Curl_none_false_start,             /* false_start */
  NULL,                              /* sha256sum */
  NULL,                              /* associate_connection */
  NULL,                              /* disassociate_connection */

  multissl_recv_plain,               /* recv decrypted data */
  multissl_send_plain,               /* send data to encrypt */
};

const struct Curl_ssl *Curl_ssl =
#if defined(CURL_WITH_MULTI_SSL)
  &Curl_ssl_multi;
#elif defined(USE_WOLFSSL)
  &Curl_ssl_wolfssl;


#elif defined(USE_GNUTLS)
  &Curl_ssl_gnutls;
#elif defined(USE_MBEDTLS)
  &Curl_ssl_mbedtls;
#elif defined(USE_RUSTLS)
  &Curl_ssl_rustls;
#elif defined(USE_OPENSSL)
  &Curl_ssl_openssl;
#elif defined(USE_SECTRANSP)
  &Curl_ssl_sectransp;
#elif defined(USE_SCHANNEL)
  &Curl_ssl_schannel;
#elif defined(USE_BEARSSL)
  &Curl_ssl_bearssl;
#else
#error "Missing struct Curl_ssl for selected SSL backend"
#endif

static const struct Curl_ssl *available_backends[] = {
#if defined(USE_WOLFSSL)
  &Curl_ssl_wolfssl,
#endif



#if defined(USE_GNUTLS)
  &Curl_ssl_gnutls,
#endif
#if defined(USE_MBEDTLS)
  &Curl_ssl_mbedtls,
#endif
#if defined(USE_OPENSSL)
  &Curl_ssl_openssl,
#endif
#if defined(USE_SECTRANSP)
  &Curl_ssl_sectransp,
#endif
#if defined(USE_SCHANNEL)
  &Curl_ssl_schannel,
#endif
#if defined(USE_BEARSSL)
  &Curl_ssl_bearssl,
#endif
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577

CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
                            int transport)
{
  const char *ehostname, *edispname;
  int eport;

  /* We need the hostname for SNI negotiation. Once handshaked, this
   * remains the SNI hostname for the TLS connection. But when the
   * connection is reused, the settings in cf->conn might change.
   * So we keep a copy of the hostname we use for SNI.
   */
#ifndef CURL_DISABLE_PROXY
  if(Curl_ssl_cf_is_proxy(cf)) {
    ehostname = cf->conn->http_proxy.host.name;
    edispname = cf->conn->http_proxy.host.dispname;
    eport = cf->conn->http_proxy.port;
  }







|
|
|
|







1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586

CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
                            int transport)
{
  const char *ehostname, *edispname;
  int eport;

  /* We need the hostname for SNI negotiation. Once handshaked, this remains
   * the SNI hostname for the TLS connection. When the connection is reused,
   * the settings in cf->conn might change. We keep a copy of the hostname we
   * use for SNI.
   */
#ifndef CURL_DISABLE_PROXY
  if(Curl_ssl_cf_is_proxy(cf)) {
    ehostname = cf->conn->http_proxy.host.name;
    edispname = cf->conn->http_proxy.host.dispname;
    eport = cf->conn->http_proxy.port;
  }
1746
1747
1748
1749
1750
1751
1752
1753



















1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
    *err = CURLE_OK;
  }
  CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
              nread, *err);
  CF_DATA_RESTORE(cf, save);
  return nread;
}




















static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   struct easy_pollset *ps)
{
  struct cf_call_data save;

  if(!cf->connected) {
    CF_DATA_SAVE(save, cf, data);
    Curl_ssl->adjust_pollset(cf, data, ps);
    CF_DATA_RESTORE(cf, save);
  }
}

static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
                             struct Curl_easy *data,
                             int event, int arg1, void *arg2)
{
  struct cf_call_data save;








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|
|



<
|
|
|
<







1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787

1788
1789
1790

1791
1792
1793
1794
1795
1796
1797
    *err = CURLE_OK;
  }
  CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
              nread, *err);
  CF_DATA_RESTORE(cf, save);
  return nread;
}

static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                bool *done)
{
  CURLcode result = CURLE_OK;

  *done = TRUE;
  if(!cf->shutdown) {
    struct cf_call_data save;

    CF_DATA_SAVE(save, cf, data);
    result = Curl_ssl->shut_down(cf, data, TRUE, done);
    CURL_TRC_CF(data, cf, "cf_shutdown -> %d, done=%d", result, *done);
    CF_DATA_RESTORE(cf, save);
    cf->shutdown = (result || *done);
  }
  return result;
}

static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  struct easy_pollset *ps)
{
  struct cf_call_data save;


  CF_DATA_SAVE(save, cf, data);
  Curl_ssl->adjust_pollset(cf, data, ps);
  CF_DATA_RESTORE(cf, save);

}

static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
                             struct Curl_easy *data,
                             int event, int arg1, void *arg2)
{
  struct cf_call_data save;
1847
1848
1849
1850
1851
1852
1853

1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873

1874
1875
1876
1877
1878
1879
1880
struct Curl_cftype Curl_cft_ssl = {
  "SSL",
  CF_TYPE_SSL,
  CURL_LOG_LVL_NONE,
  ssl_cf_destroy,
  ssl_cf_connect,
  ssl_cf_close,

  Curl_cf_def_get_host,
  ssl_cf_adjust_pollset,
  ssl_cf_data_pending,
  ssl_cf_send,
  ssl_cf_recv,
  ssl_cf_cntrl,
  cf_ssl_is_alive,
  Curl_cf_def_conn_keep_alive,
  ssl_cf_query,
};

#ifndef CURL_DISABLE_PROXY

struct Curl_cftype Curl_cft_ssl_proxy = {
  "SSL-PROXY",
  CF_TYPE_SSL|CF_TYPE_PROXY,
  CURL_LOG_LVL_NONE,
  ssl_cf_destroy,
  ssl_cf_connect,
  ssl_cf_close,

  Curl_cf_def_get_host,
  ssl_cf_adjust_pollset,
  ssl_cf_data_pending,
  ssl_cf_send,
  ssl_cf_recv,
  ssl_cf_cntrl,
  cf_ssl_is_alive,







>




















>







1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
struct Curl_cftype Curl_cft_ssl = {
  "SSL",
  CF_TYPE_SSL,
  CURL_LOG_LVL_NONE,
  ssl_cf_destroy,
  ssl_cf_connect,
  ssl_cf_close,
  ssl_cf_shutdown,
  Curl_cf_def_get_host,
  ssl_cf_adjust_pollset,
  ssl_cf_data_pending,
  ssl_cf_send,
  ssl_cf_recv,
  ssl_cf_cntrl,
  cf_ssl_is_alive,
  Curl_cf_def_conn_keep_alive,
  ssl_cf_query,
};

#ifndef CURL_DISABLE_PROXY

struct Curl_cftype Curl_cft_ssl_proxy = {
  "SSL-PROXY",
  CF_TYPE_SSL|CF_TYPE_PROXY,
  CURL_LOG_LVL_NONE,
  ssl_cf_destroy,
  ssl_cf_connect,
  ssl_cf_close,
  ssl_cf_shutdown,
  Curl_cf_def_get_host,
  ssl_cf_adjust_pollset,
  ssl_cf_data_pending,
  ssl_cf_send,
  ssl_cf_recv,
  ssl_cf_cntrl,
  cf_ssl_is_alive,
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
  if(!result)
    Curl_conn_cf_insert_after(cf_at, cf);
  return result;
}

#endif /* !CURL_DISABLE_PROXY */

bool Curl_ssl_supports(struct Curl_easy *data, int option)
{
  (void)data;
  return (Curl_ssl->supports & option)? TRUE : FALSE;
}

static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
{
  for(; cf; cf = cf->next) {
    if(cf->cft == &Curl_cft_ssl)
      return cf;







|


|







2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
  if(!result)
    Curl_conn_cf_insert_after(cf_at, cf);
  return result;
}

#endif /* !CURL_DISABLE_PROXY */

bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option)
{
  (void)data;
  return (Curl_ssl->supports & ssl_option)? TRUE : FALSE;
}

static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
{
  for(; cf; cf = cf->next) {
    if(cf->cft == &Curl_cft_ssl)
      return cf;
2016
2017
2018
2019
2020
2021
2022
2023





















































2024
2025
2026
2027
2028
2029
2030
2031
2032
2033



2034


2035
2036

2037
2038
2039
2040
2041
2042
2043
      CF_DATA_SAVE(save, cf, data);
      result = Curl_ssl->get_internals(cf->ctx, info);
      CF_DATA_RESTORE(cf, save);
    }
  }
  return result;
}






















































CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
                                 int sockindex)
{
  struct Curl_cfilter *cf, *head;
  CURLcode result = CURLE_OK;

  (void)data;
  head = data->conn? data->conn->cfilter[sockindex] : NULL;
  for(cf = head; cf; cf = cf->next) {
    if(cf->cft == &Curl_cft_ssl) {



      if(Curl_ssl->shut_down(cf, data))


        result = CURLE_SSL_SHUTDOWN_FAILED;
      Curl_conn_cf_discard_sub(head, cf, data, FALSE);

      break;
    }
  }
  return result;
}

bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|




<



>
>
>
|
>
>


>







2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110

2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
      CF_DATA_SAVE(save, cf, data);
      result = Curl_ssl->get_internals(cf->ctx, info);
      CF_DATA_RESTORE(cf, save);
    }
  }
  return result;
}

static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
                                       struct Curl_easy *data,
                                       bool send_shutdown, bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct cf_call_data save;
  CURLcode result = CURLE_OK;
  timediff_t timeout_ms;
  int what, loop = 10;

  if(cf->shutdown) {
    *done = TRUE;
    return CURLE_OK;
  }
  CF_DATA_SAVE(save, cf, data);

  *done = FALSE;
  while(!result && !*done && loop--) {
    timeout_ms = Curl_shutdown_timeleft(cf->conn, cf->sockindex, NULL);

    if(timeout_ms < 0) {
      /* no need to continue if time is already up */
      failf(data, "SSL shutdown timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = Curl_ssl->shut_down(cf, data, send_shutdown, done);
    if(result ||*done)
      goto out;

    if(connssl->io_need) {
      what = Curl_conn_cf_poll(cf, data, timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        result = CURLE_RECV_ERROR;
        goto out;
      }
      else if(0 == what) {
        /* timeout */
        failf(data, "SSL shutdown timeout");
        result = CURLE_OPERATION_TIMEDOUT;
        goto out;
      }
      /* socket is readable or writable */
    }
  }
out:
  CF_DATA_RESTORE(cf, save);
  cf->shutdown = (result || *done);
  return result;
}

CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
                                 int sockindex, bool send_shutdown)
{
  struct Curl_cfilter *cf, *head;
  CURLcode result = CURLE_OK;


  head = data->conn? data->conn->cfilter[sockindex] : NULL;
  for(cf = head; cf; cf = cf->next) {
    if(cf->cft == &Curl_cft_ssl) {
      bool done;
      CURL_TRC_CF(data, cf, "shutdown and remove SSL, start");
      Curl_shutdown_start(data, sockindex, NULL);
      result = vtls_shutdown_blocking(cf, data, send_shutdown, &done);
      Curl_shutdown_clear(data, sockindex);
      if(!result && !done) /* blocking failed? */
        result = CURLE_SSL_SHUTDOWN_FAILED;
      Curl_conn_cf_discard_sub(head, cf, data, FALSE);
      CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result);
      break;
    }
  }
  return result;
}

bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
Changes to jni/curl/lib/vtls/vtls.h.
34
35
36
37
38
39
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#define SSLSUPP_CERTINFO     (1<<1) /* supports CURLOPT_CERTINFO */
#define SSLSUPP_PINNEDPUBKEY (1<<2) /* supports CURLOPT_PINNEDPUBLICKEY */
#define SSLSUPP_SSL_CTX      (1<<3) /* supports CURLOPT_SSL_CTX */
#define SSLSUPP_HTTPS_PROXY  (1<<4) /* supports access via HTTPS proxies */
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
#define SSLSUPP_CAINFO_BLOB  (1<<6)
#define SSLSUPP_ECH          (1<<7)


#define ALPN_ACCEPTED "ALPN: server accepted "

#define VTLS_INFOF_NO_ALPN                                      \
  "ALPN: server did not agree on a protocol. Uses default."
#define VTLS_INFOF_ALPN_OFFER_1STR              \
  "ALPN: curl offers %s"
#define VTLS_INFOF_ALPN_ACCEPTED_1STR           \
  ALPN_ACCEPTED "%s"
#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR       \
  ALPN_ACCEPTED "%.*s"

/* Curl_multi SSL backend-specific data; declared differently by each SSL
   backend */
struct multi_ssl_backend_data;
struct Curl_cfilter;

CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
                                   const curl_ssl_backend ***avail);

#ifndef MAX_PINNED_PUBKEY_SIZE
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */







>














<







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
#define SSLSUPP_CERTINFO     (1<<1) /* supports CURLOPT_CERTINFO */
#define SSLSUPP_PINNEDPUBKEY (1<<2) /* supports CURLOPT_PINNEDPUBLICKEY */
#define SSLSUPP_SSL_CTX      (1<<3) /* supports CURLOPT_SSL_CTX */
#define SSLSUPP_HTTPS_PROXY  (1<<4) /* supports access via HTTPS proxies */
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
#define SSLSUPP_CAINFO_BLOB  (1<<6)
#define SSLSUPP_ECH          (1<<7)
#define SSLSUPP_CA_CACHE     (1<<8)

#define ALPN_ACCEPTED "ALPN: server accepted "

#define VTLS_INFOF_NO_ALPN                                      \
  "ALPN: server did not agree on a protocol. Uses default."
#define VTLS_INFOF_ALPN_OFFER_1STR              \
  "ALPN: curl offers %s"
#define VTLS_INFOF_ALPN_ACCEPTED_1STR           \
  ALPN_ACCEPTED "%s"
#define VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR       \
  ALPN_ACCEPTED "%.*s"

/* Curl_multi SSL backend-specific data; declared differently by each SSL
   backend */

struct Curl_cfilter;

CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
                                   const curl_ssl_backend ***avail);

#ifndef MAX_PINNED_PUBKEY_SIZE
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
                              const char *pinnedpubkey,
                              const unsigned char *pubkey, size_t pubkeylen);

bool Curl_ssl_cert_status_request(void);

bool Curl_ssl_false_start(struct Curl_easy *data);

void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend);

#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */

CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
                              struct connectdata *conn,
                              int sockindex);

CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
                                  struct Curl_easy *data);

CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
                                 int sockindex);

#ifndef CURL_DISABLE_PROXY
CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
                                        struct Curl_easy *data);
#endif /* !CURL_DISABLE_PROXY */

/**
 * True iff the underlying SSL implementation supports the option.
 * Option is one of the defined SSLSUPP_* values.
 * `data` maybe NULL for the features of the default implementation.
 */
bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option);

/**
 * Get the internal ssl instance (like OpenSSL's SSL*) from the filter
 * chain at `sockindex` of type specified by `info`.
 * For `n` == 0, the first active (top down) instance is returned.
 * 1 gives the second active, etc.
 * NULL is returned when no active SSL filter is present.







<
<










|











|







177
178
179
180
181
182
183


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
                              const char *pinnedpubkey,
                              const unsigned char *pubkey, size_t pubkeylen);

bool Curl_ssl_cert_status_request(void);

bool Curl_ssl_false_start(struct Curl_easy *data);



#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */

CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
                              struct connectdata *conn,
                              int sockindex);

CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
                                  struct Curl_easy *data);

CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
                                 int sockindex, bool send_shutdown);

#ifndef CURL_DISABLE_PROXY
CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
                                        struct Curl_easy *data);
#endif /* !CURL_DISABLE_PROXY */

/**
 * True iff the underlying SSL implementation supports the option.
 * Option is one of the defined SSLSUPP_* values.
 * `data` maybe NULL for the features of the default implementation.
 */
bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option);

/**
 * Get the internal ssl instance (like OpenSSL's SSL*) from the filter
 * chain at `sockindex` of type specified by `info`.
 * For `n` == 0, the first active (top down) instance is returned.
 * 1 gives the second active, etc.
 * NULL is returned when no active SSL filter is present.
248
249
250
251
252
253
254
255
256
257
258
259
260
#define Curl_ssl_kill_session(x) Curl_nop_stmt
#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
#define Curl_ssl_cert_status_request() FALSE
#define Curl_ssl_false_start(a) FALSE
#define Curl_ssl_get_internals(a,b,c,d) NULL
#define Curl_ssl_supports(a,b) FALSE
#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
#define Curl_ssl_cfilter_remove(a,b) CURLE_OK
#define Curl_ssl_cf_get_config(a,b) NULL
#define Curl_ssl_cf_get_primary_config(a) NULL
#endif

#endif /* HEADER_CURL_VTLS_H */







|





246
247
248
249
250
251
252
253
254
255
256
257
258
#define Curl_ssl_kill_session(x) Curl_nop_stmt
#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
#define Curl_ssl_cert_status_request() FALSE
#define Curl_ssl_false_start(a) FALSE
#define Curl_ssl_get_internals(a,b,c,d) NULL
#define Curl_ssl_supports(a,b) FALSE
#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
#define Curl_ssl_cfilter_remove(a,b,c) CURLE_OK
#define Curl_ssl_cf_get_config(a,b) NULL
#define Curl_ssl_cf_get_primary_config(a) NULL
#endif

#endif /* HEADER_CURL_VTLS_H */
Changes to jni/curl/lib/vtls/vtls_int.h.
59
60
61
62
63
64
65


















66
67
68
69
70
71
72
73
74
75



76
77
78
79
80
81
82
CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
                                const struct alpn_spec *spec);

CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  const unsigned char *proto,
                                  size_t proto_len);



















/* Information in each SSL cfilter context: cf->ctx */
struct ssl_connect_data {
  ssl_connection_state state;
  ssl_connect_state connecting_state;
  struct ssl_peer peer;
  const struct alpn_spec *alpn;     /* ALPN to use or NULL for none */
  void *backend;                    /* vtls backend specific props */
  struct cf_call_data call_data;    /* data handle used in current call */
  struct curltime handshake_done;   /* time when handshake finished */



  BIT(use_alpn);                    /* if ALPN shall be used in handshake */
  BIT(peer_closed);                 /* peer has closed connection */
};


#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf)  \







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



<
<





>
>
>







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86


87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
                                const struct alpn_spec *spec);

CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  const unsigned char *proto,
                                  size_t proto_len);

/* enum for the nonblocking SSL connection state machine */
typedef enum {
  ssl_connect_1,
  ssl_connect_2,
  ssl_connect_3,
  ssl_connect_done
} ssl_connect_state;

typedef enum {
  ssl_connection_none,
  ssl_connection_negotiating,
  ssl_connection_complete
} ssl_connection_state;

#define CURL_SSL_IO_NEED_NONE   (0)
#define CURL_SSL_IO_NEED_RECV   (1<<0)
#define CURL_SSL_IO_NEED_SEND   (1<<1)

/* Information in each SSL cfilter context: cf->ctx */
struct ssl_connect_data {


  struct ssl_peer peer;
  const struct alpn_spec *alpn;     /* ALPN to use or NULL for none */
  void *backend;                    /* vtls backend specific props */
  struct cf_call_data call_data;    /* data handle used in current call */
  struct curltime handshake_done;   /* time when handshake finished */
  ssl_connection_state state;
  ssl_connect_state connecting_state;
  int io_need;                      /* TLS signals special SEND/RECV needs */
  BIT(use_alpn);                    /* if ALPN shall be used in handshake */
  BIT(peer_closed);                 /* peer has closed connection */
};


#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf)  \
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
  size_t sizeof_ssl_backend_data;

  int (*init)(void);
  void (*cleanup)(void);

  size_t (*version)(char *buffer, size_t size);
  int (*check_cxn)(struct Curl_cfilter *cf, struct Curl_easy *data);
  int (*shut_down)(struct Curl_cfilter *cf,
                   struct Curl_easy *data);
  bool (*data_pending)(struct Curl_cfilter *cf,
                       const struct Curl_easy *data);

  /* return 0 if a find random is filled in */
  CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
                     size_t length);
  bool (*cert_status_request)(void);

  CURLcode (*connect_blocking)(struct Curl_cfilter *cf,
                               struct Curl_easy *data);
  CURLcode (*connect_nonblocking)(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  bool *done);

  /* During handshake, adjust the pollset to include the socket
   * for POLLOUT or POLLIN as needed.
   * Mandatory. */
  void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data,
                          struct easy_pollset *ps);
  void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
  void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
  void (*close_all)(struct Curl_easy *data);

  CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
  CURLcode (*set_engine_default)(struct Curl_easy *data);
  struct curl_slist *(*engines_list)(struct Curl_easy *data);

  bool (*false_start)(void);
  CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
                    unsigned char *sha256sum, size_t sha256sumlen);

  bool (*attach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
  void (*detach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);

  void (*free_multi_ssl_backend_data)(struct multi_ssl_backend_data *mbackend);

  ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
                        char *buf, size_t len, CURLcode *code);
  ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
                        const void *mem, size_t len, CURLcode *code);

};

extern const struct Curl_ssl *Curl_ssl;


int Curl_none_init(void);
void Curl_none_cleanup(void);
int Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data);

int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data);
CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
                          size_t length);
void Curl_none_close_all(struct Curl_easy *data);
void Curl_none_session_free(void *ptr);
bool Curl_none_data_pending(struct Curl_cfilter *cf,
                            const struct Curl_easy *data);







|
|














|
|
<

















<
<












|
>







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  size_t sizeof_ssl_backend_data;

  int (*init)(void);
  void (*cleanup)(void);

  size_t (*version)(char *buffer, size_t size);
  int (*check_cxn)(struct Curl_cfilter *cf, struct Curl_easy *data);
  CURLcode (*shut_down)(struct Curl_cfilter *cf, struct Curl_easy *data,
                        bool send_shutdown, bool *done);
  bool (*data_pending)(struct Curl_cfilter *cf,
                       const struct Curl_easy *data);

  /* return 0 if a find random is filled in */
  CURLcode (*random)(struct Curl_easy *data, unsigned char *entropy,
                     size_t length);
  bool (*cert_status_request)(void);

  CURLcode (*connect_blocking)(struct Curl_cfilter *cf,
                               struct Curl_easy *data);
  CURLcode (*connect_nonblocking)(struct Curl_cfilter *cf,
                                  struct Curl_easy *data,
                                  bool *done);

  /* During handshake/shutdown, adjust the pollset to include the socket
   * for POLLOUT or POLLIN as needed. Mandatory. */

  void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data,
                          struct easy_pollset *ps);
  void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
  void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
  void (*close_all)(struct Curl_easy *data);

  CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
  CURLcode (*set_engine_default)(struct Curl_easy *data);
  struct curl_slist *(*engines_list)(struct Curl_easy *data);

  bool (*false_start)(void);
  CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
                    unsigned char *sha256sum, size_t sha256sumlen);

  bool (*attach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
  void (*detach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);



  ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
                        char *buf, size_t len, CURLcode *code);
  ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
                        const void *mem, size_t len, CURLcode *code);

};

extern const struct Curl_ssl *Curl_ssl;


int Curl_none_init(void);
void Curl_none_cleanup(void);
CURLcode Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data,
                            bool send_shutdown, bool *done);
int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data);
CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
                          size_t length);
void Curl_none_close_all(struct Curl_easy *data);
void Curl_none_session_free(void *ptr);
bool Curl_none_data_pending(struct Curl_cfilter *cf,
                            const struct Curl_easy *data);
177
178
179
180
181
182
183
184


185



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
 * under sessionid mutex).
 */
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
                           struct Curl_easy *data,
                           const struct ssl_peer *peer,
                           void **ssl_sessionid,
                           size_t *idsize); /* set 0 if unknown */
/* add a new session ID


 * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).



 * Caller must ensure that it has properly shared ownership of this sessionid
 * object with cache (e.g. incrementing refcount on success)
 * Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb`
 * to destroy it in case of failure or later removal.
 */
CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               const struct ssl_peer *peer,
                               void *ssl_sessionid,
                               size_t idsize,
                               Curl_ssl_sessionid_dtor *sessionid_free_cb);

#include "openssl.h"        /* OpenSSL versions */
#include "gtls.h"           /* GnuTLS versions */
#include "wolfssl.h"        /* wolfSSL versions */
#include "schannel.h"       /* Schannel SSPI version */
#include "sectransp.h"      /* SecureTransport (Darwin) version */
#include "mbedtls.h"        /* mbedTLS versions */
#include "bearssl.h"        /* BearSSL versions */
#include "rustls.h"         /* rustls versions */

#endif /* USE_SSL */

#endif /* HEADER_CURL_VTLS_INT_H */







|
>
>

>
>
>


<
<

|
|
|
|
|
|













194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209


210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
 * under sessionid mutex).
 */
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
                           struct Curl_easy *data,
                           const struct ssl_peer *peer,
                           void **ssl_sessionid,
                           size_t *idsize); /* set 0 if unknown */

/* Set a TLS session ID for `peer`. Replaces an existing session ID if
 * not already the very same.
 * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
 * Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb`
 * to deallocate it. Is called in all outcomes, either right away or
 * later when the session cache is cleaned up.
 * Caller must ensure that it has properly shared ownership of this sessionid
 * object with cache (e.g. incrementing refcount on success)


 */
CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
                                struct Curl_easy *data,
                                const struct ssl_peer *peer,
                                void *sessionid,
                                size_t sessionid_size,
                                Curl_ssl_sessionid_dtor *sessionid_free_cb);

#include "openssl.h"        /* OpenSSL versions */
#include "gtls.h"           /* GnuTLS versions */
#include "wolfssl.h"        /* wolfSSL versions */
#include "schannel.h"       /* Schannel SSPI version */
#include "sectransp.h"      /* SecureTransport (Darwin) version */
#include "mbedtls.h"        /* mbedTLS versions */
#include "bearssl.h"        /* BearSSL versions */
#include "rustls.h"         /* rustls versions */

#endif /* USE_SSL */

#endif /* HEADER_CURL_VTLS_INT_H */
Changes to jni/curl/lib/vtls/wolfssl.c.
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
#define USE_BIO_CHAIN
#else
#undef USE_BIO_CHAIN
#endif

struct wolfssl_ssl_backend_data {
  WOLFSSL_CTX *ctx;
  WOLFSSL     *handle;
  CURLcode    io_result;   /* result of last BIO cfilter operation */
};

#ifdef OPENSSL_EXTRA
/*
 * Availability note:
 * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in
 * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
 * option is not set, then TLS 1.3 will not be logged.
 * For TLS 1.2 and before, we use wolfSSL_get_keys().
 * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
 * (--enable-opensslextra or --enable-all).
 */
#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
static int







<
<
<
<
<
<




|







95
96
97
98
99
100
101






102
103
104
105
106
107
108
109
110
111
112
113

#if defined(HAVE_WOLFSSL_FULL_BIO) && HAVE_WOLFSSL_FULL_BIO
#define USE_BIO_CHAIN
#else
#undef USE_BIO_CHAIN
#endif







#ifdef OPENSSL_EXTRA
/*
 * Availability note:
 * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in
 * wolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
 * option is not set, then TLS 1.3 will not be logged.
 * For TLS 1.2 and before, we use wolfSSL_get_keys().
 * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
 * (--enable-opensslextra or --enable-all).
 */
#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
static int
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
}

static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
                                    const char *buf, int blen)
{
  struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
  ssize_t nwritten;
  CURLcode result = CURLE_OK;

  DEBUGASSERT(data);
  nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
  backend->io_result = result;
  CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
              blen, nwritten, result);
  wolfSSL_BIO_clear_retry_flags(bio);
  if(nwritten < 0 && CURLE_AGAIN == result)
    BIO_set_retry_write(bio);
  return (int)nwritten;
}

static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
{
  struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
  ssize_t nread;
  CURLcode result = CURLE_OK;

  DEBUGASSERT(data);
  /* OpenSSL catches this case, so should we. */
  if(!buf)







|
|



















|
|







280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
}

static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
                                    const char *buf, int blen)
{
  struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
  ssize_t nwritten;
  CURLcode result = CURLE_OK;

  DEBUGASSERT(data);
  nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
  backend->io_result = result;
  CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
              blen, nwritten, result);
  wolfSSL_BIO_clear_retry_flags(bio);
  if(nwritten < 0 && CURLE_AGAIN == result)
    BIO_set_retry_write(bio);
  return (int)nwritten;
}

static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
{
  struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;
  struct Curl_easy *data = CF_DATA_CURRENT(cf);
  ssize_t nread;
  CURLcode result = CURLE_OK;

  DEBUGASSERT(data);
  /* OpenSSL catches this case, so should we. */
  if(!buf)
352
353
354
355
356
357
358






















































































































































































































































359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409

#else /* USE_BIO_CHAIN */

#define wolfssl_bio_cf_init_methods() Curl_nop_stmt
#define wolfssl_bio_cf_free_methods() Curl_nop_stmt

#endif /* !USE_BIO_CHAIN */























































































































































































































































/*
 * This function loads all the client/CA certificates and CRLs. Setup the TLS
 * layer and do all necessary magic.
 */
static CURLcode
wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  char *ciphers, *curves;
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
  const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  const char * const ssl_cafile =
    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
    (ca_info_blob ? NULL : conn_config->CAfile);
  const char * const ssl_capath = conn_config->CApath;
  WOLFSSL_METHOD* req_method = NULL;
#ifdef HAVE_LIBOQS
  word16 oqsAlg = 0;
  size_t idx = 0;
#endif
#ifdef HAVE_SNI
  bool sni = FALSE;
#define use_sni(x)  sni = (x)
#else
#define use_sni(x)  Curl_nop_stmt
#endif
  bool imported_native_ca = false;
  bool imported_ca_info_blob = false;

  DEBUGASSERT(backend);

  if(connssl->state == ssl_connection_complete)
    return CURLE_OK;

  if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
    failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
    return CURLE_SSL_CONNECT_ERROR;
  }

  /* check to see if we've been told to use an explicit SSL/TLS version */
  switch(conn_config->version) {
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1:
#if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
    /* minimum protocol version is set later after the CTX object is created */
    req_method = SSLv23_client_method();
#else







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










|
|

<

<
<
<
<











<
<











|







346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611

612




613
614
615
616
617
618
619
620
621
622
623


624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642

#else /* USE_BIO_CHAIN */

#define wolfssl_bio_cf_init_methods() Curl_nop_stmt
#define wolfssl_bio_cf_free_methods() Curl_nop_stmt

#endif /* !USE_BIO_CHAIN */

static CURLcode populate_x509_store(struct Curl_cfilter *cf,
                                    struct Curl_easy *data,
                                    X509_STORE *store,
                                    struct wolfssl_ctx *wssl)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
  const char * const ssl_cafile =
    /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
    (ca_info_blob ? NULL : conn_config->CAfile);
  const char * const ssl_capath = conn_config->CApath;
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  bool imported_native_ca = false;

#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
  /* load native CA certificates */
  if(ssl_config->native_ca_store) {
    if(wolfSSL_CTX_load_system_CA_certs(wssl->ctx) != WOLFSSL_SUCCESS) {
      infof(data, "error importing native CA store, continuing anyway");
    }
    else {
      imported_native_ca = true;
      infof(data, "successfully imported native CA store");
      wssl->x509_store_setup = TRUE;
    }
  }
#endif /* !NO_FILESYSTEM */

  /* load certificate blob */
  if(ca_info_blob) {
    if(wolfSSL_CTX_load_verify_buffer(wssl->ctx, ca_info_blob->data,
                                      (long)ca_info_blob->len,
                                      SSL_FILETYPE_PEM) != SSL_SUCCESS) {
      if(imported_native_ca) {
        infof(data, "error importing CA certificate blob, continuing anyway");
      }
      else {
        failf(data, "error importing CA certificate blob");
        return CURLE_SSL_CACERT_BADFILE;
      }
    }
    else {
      infof(data, "successfully imported CA certificate blob");
      wssl->x509_store_setup = TRUE;
    }
  }

#ifndef NO_FILESYSTEM
  /* load trusted cacert from file if not blob */

  CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
              ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
  if(!store)
    return CURLE_OUT_OF_MEMORY;

  if((ssl_cafile || ssl_capath) && (!wssl->x509_store_setup)) {
    int rc =
      wolfSSL_CTX_load_verify_locations_ex(wssl->ctx,
                                           ssl_cafile,
                                           ssl_capath,
                                           WOLFSSL_LOAD_FLAG_IGNORE_ERR);
    if(SSL_SUCCESS != rc) {
      if(conn_config->verifypeer) {
        /* Fail if we insist on successfully verifying the server. */
        failf(data, "error setting certificate verify locations:"
              " CAfile: %s CApath: %s",
              ssl_cafile ? ssl_cafile : "none",
              ssl_capath ? ssl_capath : "none");
        return CURLE_SSL_CACERT_BADFILE;
      }
      else {
        /* Just continue with a warning if no strict certificate
           verification is required. */
        infof(data, "error setting certificate verify locations,"
              " continuing anyway:");
      }
    }
    else {
      /* Everything is fine. */
      infof(data, "successfully set certificate verify locations:");
    }
    infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
    infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
    wssl->x509_store_setup = TRUE;
  }
#endif
  (void)store;
  return CURLE_OK;
}

/* key to use at `multi->proto_hash` */
#define MPROTO_WSSL_X509_KEY   "tls:wssl:x509:share"

struct wssl_x509_share {
  char *CAfile;         /* CAfile path used to generate X509 store */
  WOLFSSL_X509_STORE *store; /* cached X509 store or NULL if none */
  struct curltime time; /* when the cached store was created */
};

static void wssl_x509_share_free(void *key, size_t key_len, void *p)
{
  struct wssl_x509_share *share = p;
  DEBUGASSERT(key_len == (sizeof(MPROTO_WSSL_X509_KEY)-1));
  DEBUGASSERT(!memcmp(MPROTO_WSSL_X509_KEY, key, key_len));
  (void)key;
  (void)key_len;
  if(share->store) {
    wolfSSL_X509_STORE_free(share->store);
  }
  free(share->CAfile);
  free(share);
}

static bool
cached_x509_store_expired(const struct Curl_easy *data,
                          const struct wssl_x509_share *mb)
{
  const struct ssl_general_config *cfg = &data->set.general_ssl;
  struct curltime now = Curl_now();
  timediff_t elapsed_ms = Curl_timediff(now, mb->time);
  timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;

  if(timeout_ms < 0)
    return false;

  return elapsed_ms >= timeout_ms;
}

static bool
cached_x509_store_different(struct Curl_cfilter *cf,
                            const struct wssl_x509_share *mb)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  if(!mb->CAfile || !conn_config->CAfile)
    return mb->CAfile != conn_config->CAfile;

  return strcmp(mb->CAfile, conn_config->CAfile);
}

static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
                                         const struct Curl_easy *data)
{
  struct Curl_multi *multi = data->multi;
  struct wssl_x509_share *share;
  WOLFSSL_X509_STORE *store = NULL;

  DEBUGASSERT(multi);
  share = multi? Curl_hash_pick(&multi->proto_hash,
                                (void *)MPROTO_WSSL_X509_KEY,
                                sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
  if(share && share->store &&
     !cached_x509_store_expired(data, share) &&
     !cached_x509_store_different(cf, share)) {
    store = share->store;
  }

  return store;
}

static void set_cached_x509_store(struct Curl_cfilter *cf,
                                  const struct Curl_easy *data,
                                  X509_STORE *store)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct Curl_multi *multi = data->multi;
  struct wssl_x509_share *share;

  DEBUGASSERT(multi);
  if(!multi)
    return;
  share = Curl_hash_pick(&multi->proto_hash,
                         (void *)MPROTO_WSSL_X509_KEY,
                         sizeof(MPROTO_WSSL_X509_KEY)-1);

  if(!share) {
    share = calloc(1, sizeof(*share));
    if(!share)
      return;
    if(!Curl_hash_add2(&multi->proto_hash,
                       (void *)MPROTO_WSSL_X509_KEY,
                       sizeof(MPROTO_WSSL_X509_KEY)-1,
                       share, wssl_x509_share_free)) {
      free(share);
      return;
    }
  }

  if(wolfSSL_X509_STORE_up_ref(store)) {
    char *CAfile = NULL;

    if(conn_config->CAfile) {
      CAfile = strdup(conn_config->CAfile);
      if(!CAfile) {
        X509_STORE_free(store);
        return;
      }
    }

    if(share->store) {
      X509_STORE_free(share->store);
      free(share->CAfile);
    }

    share->time = Curl_now();
    share->store = store;
    share->CAfile = CAfile;
  }
}

CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
                                    struct Curl_easy *data,
                                    struct wolfssl_ctx *wssl)
{
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
  struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
  CURLcode result = CURLE_OK;
  WOLFSSL_X509_STORE *cached_store;
  bool cache_criteria_met;

  /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
     or no source is provided and we are falling back to OpenSSL's built-in
     default. */
  cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
    conn_config->verifypeer &&
    !conn_config->CApath &&
    !conn_config->ca_info_blob &&
    !ssl_config->primary.CRLfile &&
    !ssl_config->native_ca_store;

  cached_store = get_cached_x509_store(cf, data);
  if(cached_store && cache_criteria_met
     && wolfSSL_X509_STORE_up_ref(cached_store)) {
    wolfSSL_CTX_set_cert_store(wssl->ctx, cached_store);
  }
  else {
    X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);

    result = populate_x509_store(cf, data, store, wssl);
    if(result == CURLE_OK && cache_criteria_met) {
      set_cached_x509_store(cf, data, store);
    }
  }

  return result;
}

/*
 * This function loads all the client/CA certificates and CRLs. Setup the TLS
 * layer and do all necessary magic.
 */
static CURLcode
wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  char *ciphers, *curves;
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);

  const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);




  WOLFSSL_METHOD* req_method = NULL;
#ifdef HAVE_LIBOQS
  word16 oqsAlg = 0;
  size_t idx = 0;
#endif
#ifdef HAVE_SNI
  bool sni = FALSE;
#define use_sni(x)  sni = (x)
#else
#define use_sni(x)  Curl_nop_stmt
#endif



  DEBUGASSERT(backend);

  if(connssl->state == ssl_connection_complete)
    return CURLE_OK;

  if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
    failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
    return CURLE_SSL_CONNECT_ERROR;
  }

  /* check to see if we have been told to use an explicit SSL/TLS version */
  switch(conn_config->version) {
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1:
#if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
    /* minimum protocol version is set later after the CTX object is created */
    req_method = SSLv23_client_method();
#else
422
423
424
425
426
427
428

429
430
431
432
433
434
435
436
437
438
439
440
    failf(data, "wolfSSL does not support TLS 1.0");
    return CURLE_NOT_BUILT_IN;
#endif
  case CURL_SSLVERSION_TLSv1_1:
#ifndef NO_OLD_TLS
    req_method = TLSv1_1_client_method();
    use_sni(TRUE);

#else
    failf(data, "wolfSSL does not support TLS 1.1");
    return CURLE_NOT_BUILT_IN;
#endif
    break;
  case CURL_SSLVERSION_TLSv1_2:
#ifndef WOLFSSL_NO_TLS12
    req_method = TLSv1_2_client_method();
    use_sni(TRUE);
#else
    failf(data, "wolfSSL does not support TLS 1.2");
    return CURLE_NOT_BUILT_IN;







>




<







655
656
657
658
659
660
661
662
663
664
665
666

667
668
669
670
671
672
673
    failf(data, "wolfSSL does not support TLS 1.0");
    return CURLE_NOT_BUILT_IN;
#endif
  case CURL_SSLVERSION_TLSv1_1:
#ifndef NO_OLD_TLS
    req_method = TLSv1_1_client_method();
    use_sni(TRUE);
    break;
#else
    failf(data, "wolfSSL does not support TLS 1.1");
    return CURLE_NOT_BUILT_IN;
#endif

  case CURL_SSLVERSION_TLSv1_2:
#ifndef WOLFSSL_NO_TLS12
    req_method = TLSv1_2_client_method();
    use_sni(TRUE);
#else
    failf(data, "wolfSSL does not support TLS 1.2");
    return CURLE_NOT_BUILT_IN;
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
#endif
  default:
    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
    return CURLE_SSL_CONNECT_ERROR;
  }

  if(!req_method) {
    failf(data, "SSL: couldn't create a method");
    return CURLE_OUT_OF_MEMORY;
  }

  if(backend->ctx)
    wolfSSL_CTX_free(backend->ctx);
  backend->ctx = wolfSSL_CTX_new(req_method);

  if(!backend->ctx) {
    failf(data, "SSL: couldn't create a context");
    return CURLE_OUT_OF_MEMORY;
  }

  switch(conn_config->version) {
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1:
#if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
    /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
     * whatever minimum version of TLS was built in and at least TLS 1.0. For
     * later library versions that could change (eg TLS 1.0 built in but
     * defaults to TLS 1.1) so we have this short circuit evaluation to find
     * the minimum supported TLS version.
    */
    if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) &&
       (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) &&
       (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1)
#ifdef WOLFSSL_TLS13
       && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
#endif
      ) {
      failf(data, "SSL: couldn't set the minimum protocol version");
      return CURLE_SSL_CONNECT_ERROR;
    }
#endif
    FALLTHROUGH();
  default:
    break;
  }







|








|




















|







684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
#endif
  default:
    failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
    return CURLE_SSL_CONNECT_ERROR;
  }

  if(!req_method) {
    failf(data, "SSL: could not create a method");
    return CURLE_OUT_OF_MEMORY;
  }

  if(backend->ctx)
    wolfSSL_CTX_free(backend->ctx);
  backend->ctx = wolfSSL_CTX_new(req_method);

  if(!backend->ctx) {
    failf(data, "SSL: could not create a context");
    return CURLE_OUT_OF_MEMORY;
  }

  switch(conn_config->version) {
  case CURL_SSLVERSION_DEFAULT:
  case CURL_SSLVERSION_TLSv1:
#if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
    /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
     * whatever minimum version of TLS was built in and at least TLS 1.0. For
     * later library versions that could change (eg TLS 1.0 built in but
     * defaults to TLS 1.1) so we have this short circuit evaluation to find
     * the minimum supported TLS version.
    */
    if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) &&
       (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) &&
       (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1)
#ifdef WOLFSSL_TLS13
       && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
#endif
      ) {
      failf(data, "SSL: could not set the minimum protocol version");
      return CURLE_SSL_CONNECT_ERROR;
    }
#endif
    FALLTHROUGH();
  default:
    break;
  }
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593

594
595
596
597
598
599
600
      if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
        failf(data, "failed setting curves list: '%s'", curves);
        return CURLE_SSL_CIPHER;
      }
    }
  }

#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
  /* load native CA certificates */
  if(ssl_config->native_ca_store) {
    if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) {
      infof(data, "error importing native CA store, continuing anyway");
    }
    else {
      imported_native_ca = true;
      infof(data, "successfully imported native CA store");
    }
  }
#endif /* !NO_FILESYSTEM */

  /* load certificate blob */
  if(ca_info_blob) {
    if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data,
                                      ca_info_blob->len,
                                      SSL_FILETYPE_PEM) != SSL_SUCCESS) {
      if(imported_native_ca) {
        infof(data, "error importing CA certificate blob, continuing anyway");
      }
      else {
        failf(data, "error importing CA certificate blob");
        return CURLE_SSL_CACERT_BADFILE;
      }
    }
    else {
      imported_ca_info_blob = true;
      infof(data, "successfully imported CA certificate blob");
    }
  }

#ifndef NO_FILESYSTEM
  /* load trusted cacert from file if not blob */
  if(ssl_cafile || ssl_capath) {
    int rc =
      wolfSSL_CTX_load_verify_locations_ex(backend->ctx,
                                           ssl_cafile,
                                           ssl_capath,
                                           WOLFSSL_LOAD_FLAG_IGNORE_ERR);
    if(SSL_SUCCESS != rc) {
      if(conn_config->verifypeer && !imported_ca_info_blob &&
         !imported_native_ca) {
        /* Fail if we insist on successfully verifying the server. */
        failf(data, "error setting certificate verify locations:"
              " CAfile: %s CApath: %s",
              ssl_cafile ? ssl_cafile : "none",
              ssl_capath ? ssl_capath : "none");
        return CURLE_SSL_CACERT_BADFILE;
      }
      else {
        /* Just continue with a warning if no strict certificate
           verification is required. */
        infof(data, "error setting certificate verify locations,"
              " continuing anyway:");
      }
    }
    else {
      /* Everything is fine. */
      infof(data, "successfully set certificate verify locations:");
    }
    infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
    infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
  }

  /* Load the client certificate, and private key */
  if(ssl_config->primary.clientcert && ssl_config->key) {

    int file_type = do_file_type(ssl_config->cert_type);

    if(file_type == WOLFSSL_FILETYPE_PEM) {
      if(wolfSSL_CTX_use_certificate_chain_file(backend->ctx,
                                                ssl_config->primary.clientcert)
         != 1) {
        failf(data, "unable to use client certificate");







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

|
>







753
754
755
756
757
758
759
































760
































761
762
763
764
765
766
767
768
769
770
      if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
        failf(data, "failed setting curves list: '%s'", curves);
        return CURLE_SSL_CIPHER;
      }
    }
  }

































#ifndef NO_FILESYSTEM
































  /* Load the client certificate, and private key */
  if(ssl_config->primary.clientcert) {
    char *key_file = ssl_config->key;
    int file_type = do_file_type(ssl_config->cert_type);

    if(file_type == WOLFSSL_FILETYPE_PEM) {
      if(wolfSSL_CTX_use_certificate_chain_file(backend->ctx,
                                                ssl_config->primary.clientcert)
         != 1) {
        failf(data, "unable to use client certificate");
610
611
612
613
614
615
616



617

618
619
620
621
622
623
624
625
      }
    }
    else {
      failf(data, "unknown cert type");
      return CURLE_BAD_FUNCTION_ARGUMENT;
    }




    file_type = do_file_type(ssl_config->key_type);

    if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
                                       file_type) != 1) {
      failf(data, "unable to set private key");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
#endif /* !NO_FILESYSTEM */








>
>
>
|
>
|







780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
      }
    }
    else {
      failf(data, "unknown cert type");
      return CURLE_BAD_FUNCTION_ARGUMENT;
    }

    if(!key_file)
      key_file = ssl_config->primary.clientcert;
    else
      file_type = do_file_type(ssl_config->key_type);

    if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, key_file,
                                       file_type) != 1) {
      failf(data, "unable to set private key");
      return CURLE_SSL_CONNECT_ERROR;
    }
  }
#endif /* !NO_FILESYSTEM */

652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691

692
693
694
695
696
697
698
    if(result) {
      failf(data, "error signaled by ssl ctx callback");
      return result;
    }
  }
#ifdef NO_FILESYSTEM
  else if(conn_config->verifypeer) {
    failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
          " with \"no filesystem\". Either disable peer verification"
          " (insecure) or if you are building an application with libcurl you"
          " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif

  /* Let's make an SSL structure */
  if(backend->handle)
    wolfSSL_free(backend->handle);
  backend->handle = wolfSSL_new(backend->ctx);
  if(!backend->handle) {
    failf(data, "SSL: couldn't create a handle");
    return CURLE_OUT_OF_MEMORY;
  }

#ifdef HAVE_LIBOQS
  if(oqsAlg) {
    if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
      failf(data, "unable to use oqs KEM");
    }
  }
#endif

#ifdef HAVE_ALPN
  if(connssl->alpn) {
    struct alpn_proto_buf proto;
    CURLcode result;

    result = Curl_alpn_to_proto_str(&proto, connssl->alpn);
    if(result ||
       wolfSSL_UseALPN(backend->handle, (char *)proto.data, proto.len,

                       WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
      failf(data, "SSL: failed setting ALPN protocols");
      return CURLE_SSL_CONNECT_ERROR;
    }
    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
  }
#endif /* HAVE_ALPN */







|












|


















|
>







826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
    if(result) {
      failf(data, "error signaled by ssl ctx callback");
      return result;
    }
  }
#ifdef NO_FILESYSTEM
  else if(conn_config->verifypeer) {
    failf(data, "SSL: Certificates cannot be loaded because wolfSSL was built"
          " with \"no filesystem\". Either disable peer verification"
          " (insecure) or if you are building an application with libcurl you"
          " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif

  /* Let's make an SSL structure */
  if(backend->handle)
    wolfSSL_free(backend->handle);
  backend->handle = wolfSSL_new(backend->ctx);
  if(!backend->handle) {
    failf(data, "SSL: could not create a handle");
    return CURLE_OUT_OF_MEMORY;
  }

#ifdef HAVE_LIBOQS
  if(oqsAlg) {
    if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
      failf(data, "unable to use oqs KEM");
    }
  }
#endif

#ifdef HAVE_ALPN
  if(connssl->alpn) {
    struct alpn_proto_buf proto;
    CURLcode result;

    result = Curl_alpn_to_proto_str(&proto, connssl->alpn);
    if(result ||
       wolfSSL_UseALPN(backend->handle,
                       (char *)proto.data, (unsigned int)proto.len,
                       WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
      failf(data, "SSL: failed setting ALPN protocols");
      return CURLE_SSL_CONNECT_ERROR;
    }
    infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
  }
#endif /* HAVE_ALPN */
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
#ifdef HAVE_SECURE_RENEGOTIATION
  if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
    failf(data, "SSL: failed setting secure renegotiation");
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif /* HAVE_SECURE_RENEGOTIATION */

  /* Check if there's a cached ID we can/should use here! */
  if(ssl_config->primary.sessionid) {
    void *ssl_sessionid = NULL;

    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
                              &ssl_sessionid, NULL)) {
      /* we got a session id, use it! */
      if(!SSL_set_session(backend->handle, ssl_sessionid)) {
        Curl_ssl_delsessionid(data, ssl_sessionid);
        infof(data, "Can't use session ID, going on without");
      }
      else
        infof(data, "SSL reusing session ID");
    }
    Curl_ssl_sessionid_unlock(data);
  }

#ifdef USE_ECH
  if(ECH_ENABLED(data)) {
    int trying_ech_now = 0;

    if(data->set.str[STRING_ECH_PUBLIC]) {
      infof(data, "ECH: outername not (yet) supported with WolfSSL");
      return CURLE_SSL_CONNECT_ERROR;
    }
    if(data->set.tls_ech == CURLECH_GREASE) {
      infof(data, "ECH: GREASE'd ECH not yet supported for wolfSSL");
      return CURLE_SSL_CONNECT_ERROR;
    }
    if(data->set.tls_ech & CURLECH_CLA_CFG







|
|








|












|







886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
#ifdef HAVE_SECURE_RENEGOTIATION
  if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
    failf(data, "SSL: failed setting secure renegotiation");
    return CURLE_SSL_CONNECT_ERROR;
  }
#endif /* HAVE_SECURE_RENEGOTIATION */

  /* Check if there is a cached ID we can/should use here! */
  if(ssl_config->primary.cache_session) {
    void *ssl_sessionid = NULL;

    Curl_ssl_sessionid_lock(data);
    if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
                              &ssl_sessionid, NULL)) {
      /* we got a session id, use it! */
      if(!SSL_set_session(backend->handle, ssl_sessionid)) {
        Curl_ssl_delsessionid(data, ssl_sessionid);
        infof(data, "cannot use session ID, going on without");
      }
      else
        infof(data, "SSL reusing session ID");
    }
    Curl_ssl_sessionid_unlock(data);
  }

#ifdef USE_ECH
  if(ECH_ENABLED(data)) {
    int trying_ech_now = 0;

    if(data->set.str[STRING_ECH_PUBLIC]) {
      infof(data, "ECH: outername not (yet) supported with wolfSSL");
      return CURLE_SSL_CONNECT_ERROR;
    }
    if(data->set.tls_ech == CURLECH_GREASE) {
      infof(data, "ECH: GREASE'd ECH not yet supported for wolfSSL");
      return CURLE_SSL_CONNECT_ERROR;
    }
    if(data->set.tls_ech & CURLECH_CLA_CFG
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
        }
        Curl_resolv_unlock(data, dns);
      }
    }

    if(trying_ech_now
       && SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
      infof(data, "ECH: Can't force TLSv1.3 [ERROR]");
      return CURLE_SSL_CONNECT_ERROR;
    }

  }
#endif  /* USE_ECH */

#ifdef USE_BIO_CHAIN







|







973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
        }
        Curl_resolv_unlock(data, dns);
      }
    }

    if(trying_ech_now
       && SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
      infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
      return CURLE_SSL_CONNECT_ERROR;
    }

  }
#endif  /* USE_ECH */

#ifdef USE_BIO_CHAIN
829
830
831
832
833
834
835


















836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
  }
#endif /* !USE_BIO_CHAIN */

  connssl->connecting_state = ssl_connect_2;
  return CURLE_OK;
}




















static CURLcode
wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  int ret = -1;
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
#ifndef CURL_DISABLE_PROXY
  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
  const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






|
|







1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
  }
#endif /* !USE_BIO_CHAIN */

  connssl->connecting_state = ssl_connect_2;
  return CURLE_OK;
}


static char *wolfssl_strerror(unsigned long error, char *buf,
                              unsigned long size)
{
  DEBUGASSERT(size);
  *buf = '\0';

  wolfSSL_ERR_error_string_n(error, buf, size);

  if(!*buf) {
    const char *msg = error ? "Unknown error" : "No error";
    strncpy(buf, msg, size - 1);
    buf[size - 1] = '\0';
  }

  return buf;
}


static CURLcode
wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  int ret = -1;
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;
  struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
#ifndef CURL_DISABLE_PROXY
  const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
    data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
    data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#else
  const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
858
859
860
861
862
863
864
















865
866
867
868
869
870
871
  if(conn_config->verifyhost) {
    char *snihost = connssl->peer.sni?
                    connssl->peer.sni : connssl->peer.hostname;
    if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)
      return CURLE_SSL_CONNECT_ERROR;
  }

















  ret = wolfSSL_connect(backend->handle);

#ifdef OPENSSL_EXTRA
  if(Curl_tls_keylog_enabled()) {
    /* If key logging is enabled, wait for the handshake to complete and then
     * proceed with logging secrets (for TLS 1.2 or older).
     *







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
  if(conn_config->verifyhost) {
    char *snihost = connssl->peer.sni?
                    connssl->peer.sni : connssl->peer.hostname;
    if(wolfSSL_check_domain_name(backend->handle, snihost) == SSL_FAILURE)
      return CURLE_SSL_CONNECT_ERROR;
  }

  if(!backend->x509_store_setup) {
    /* After having send off the ClientHello, we prepare the x509
     * store to verify the coming certificate from the server */
    CURLcode result;
    struct wolfssl_ctx wssl;
    wssl.ctx = backend->ctx;
    wssl.handle = backend->handle;
    wssl.io_result = CURLE_OK;
    wssl.x509_store_setup = FALSE;
    result = Curl_wssl_setup_x509_store(cf, data, &wssl);
    if(result)
      return result;
    backend->x509_store_setup = wssl.x509_store_setup;
  }

  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  ret = wolfSSL_connect(backend->handle);

#ifdef OPENSSL_EXTRA
  if(Curl_tls_keylog_enabled()) {
    /* If key logging is enabled, wait for the handshake to complete and then
     * proceed with logging secrets (for TLS 1.2 or older).
     *
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
       * Ignored while the handshake is still in progress. */
      wolfSSL_FreeArrays(backend->handle);
    }
  }
#endif  /* OPENSSL_EXTRA */

  if(ret != 1) {
    char error_buffer[WOLFSSL_MAX_ERROR_SZ];
    int  detail = wolfSSL_get_error(backend->handle, ret);

    if(SSL_ERROR_WANT_READ == detail) {
      connssl->connecting_state = ssl_connect_2_reading;
      return CURLE_OK;
    }
    else if(SSL_ERROR_WANT_WRITE == detail) {
      connssl->connecting_state = ssl_connect_2_writing;
      return CURLE_OK;
    }
    /* There is no easy way to override only the CN matching.
     * This will enable the override of both mismatching SubjectAltNames
     * as also mismatching CN fields */
    else if(DOMAIN_NAME_MISMATCH == detail) {
#if 1







<
|


|



|







1094
1095
1096
1097
1098
1099
1100

1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
       * Ignored while the handshake is still in progress. */
      wolfSSL_FreeArrays(backend->handle);
    }
  }
#endif  /* OPENSSL_EXTRA */

  if(ret != 1) {

    int detail = wolfSSL_get_error(backend->handle, ret);

    if(SSL_ERROR_WANT_READ == detail) {
      connssl->io_need = CURL_SSL_IO_NEED_RECV;
      return CURLE_OK;
    }
    else if(SSL_ERROR_WANT_WRITE == detail) {
      connssl->io_need = CURL_SSL_IO_NEED_SEND;
      return CURLE_OK;
    }
    /* There is no easy way to override only the CN matching.
     * This will enable the override of both mismatching SubjectAltNames
     * as also mismatching CN fields */
    else if(DOMAIN_NAME_MISMATCH == detail) {
#if 1
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
#ifdef USE_ECH
    else if(-1 == detail) {
      /* try access a retry_config ECHConfigList for tracing */
      byte echConfigs[1000];
      word32 echConfigsLen = 1000;
      int rv = 0;

      /* this currently doesn't produce the retry_configs */
      rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
                                 &echConfigsLen);
      if(rv != WOLFSSL_SUCCESS) {
        infof(data, "Failed to get ECHConfigs");
      }
      else {
        char *b64str = NULL;







|







1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
#ifdef USE_ECH
    else if(-1 == detail) {
      /* try access a retry_config ECHConfigList for tracing */
      byte echConfigs[1000];
      word32 echConfigsLen = 1000;
      int rv = 0;

      /* this currently does not produce the retry_configs */
      rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
                                 &echConfigsLen);
      if(rv != WOLFSSL_SUCCESS) {
        infof(data, "Failed to get ECHConfigs");
      }
      else {
        char *b64str = NULL;
968
969
970
971
972
973
974

975

976
977
978
979
980
981
982
983
      }
    }
#endif
    else if(backend->io_result == CURLE_AGAIN) {
      return CURLE_OK;
    }
    else {

      failf(data, "SSL_connect failed with error %d: %s", detail,

            wolfSSL_ERR_error_string(detail, error_buffer));
      return CURLE_SSL_CONNECT_ERROR;
    }
  }

  if(pinnedpubkey) {
#ifdef KEEP_PEER_CERT
    X509 *x509;







>

>
|







1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
      }
    }
#endif
    else if(backend->io_result == CURLE_AGAIN) {
      return CURLE_OK;
    }
    else {
      char error_buffer[256];
      failf(data, "SSL_connect failed with error %d: %s", detail,
            wolfssl_strerror((unsigned long)detail, error_buffer,
                             sizeof(error_buffer)));
      return CURLE_SSL_CONNECT_ERROR;
    }
  }

  if(pinnedpubkey) {
#ifdef KEEP_PEER_CERT
    X509 *x509;
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104


static CURLcode
wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  CURLcode result = CURLE_OK;
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;
  const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);

  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
  DEBUGASSERT(backend);

  if(ssl_config->primary.sessionid) {
    /* wolfSSL_get1_session allocates memory that has to be freed. */
    WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);

    if(our_ssl_sessionid) {
      void *old_ssl_sessionid = NULL;
      bool incache;
      Curl_ssl_sessionid_lock(data);
      incache = !(Curl_ssl_getsessionid(cf, data, &connssl->peer,
                                        &old_ssl_sessionid, NULL));
      if(incache) {
        Curl_ssl_delsessionid(data, old_ssl_sessionid);
      }

      /* call takes ownership of `our_ssl_sessionid` */
      result = Curl_ssl_addsessionid(cf, data, &connssl->peer,
                                     our_ssl_sessionid, 0,
                                     wolfssl_session_free);
      Curl_ssl_sessionid_unlock(data);
      if(result) {
        failf(data, "failed to store ssl session");
        return result;
      }
    }
  }







|
|





|




<
<

<
<
<
<
<
<

|
|
|







1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294


1295






1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306


static CURLcode
wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  CURLcode result = CURLE_OK;
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;
  const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);

  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
  DEBUGASSERT(backend);

  if(ssl_config->primary.cache_session) {
    /* wolfSSL_get1_session allocates memory that has to be freed. */
    WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);

    if(our_ssl_sessionid) {


      Curl_ssl_sessionid_lock(data);






      /* call takes ownership of `our_ssl_sessionid` */
      result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
                                      our_ssl_sessionid, 0,
                                      wolfssl_session_free);
      Curl_ssl_sessionid_unlock(data);
      if(result) {
        failf(data, "failed to store ssl session");
        return result;
      }
    }
  }
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146


1147

1148
1149

1150
1151
1152
1153
1154
1155
1156






























































































1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
static ssize_t wolfssl_send(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            const void *mem,
                            size_t len,
                            CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;
  char error_buffer[WOLFSSL_MAX_ERROR_SZ];
  int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
  int rc;

  DEBUGASSERT(backend);

  wolfSSL_ERR_clear_error();

  rc = wolfSSL_write(backend->handle, mem, memlen);
  if(rc <= 0) {
    int err = wolfSSL_get_error(backend->handle, rc);

    switch(err) {
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
      /* there's data pending, re-invoke SSL_write() */
      CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
      *curlcode = CURLE_AGAIN;
      return -1;
    default:
      if(backend->io_result == CURLE_AGAIN) {
        CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
        *curlcode = CURLE_AGAIN;
        return -1;
      }
      CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err);


      failf(data, "SSL write: %s, errno %d",

            wolfSSL_ERR_error_string(err, error_buffer),
            SOCKERRNO);

      *curlcode = CURLE_SEND_ERROR;
      return -1;
    }
  }
  CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc);
  return rc;
}































































































static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;

  (void) data;

  DEBUGASSERT(backend);

  if(backend->handle) {
    char buf[32];
    /* Maybe the server has already sent a close notify alert.
       Read it to avoid an RST on the TCP connection. */
    (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf));
    if(!connssl->peer_closed)
      (void)wolfSSL_shutdown(backend->handle);
    wolfSSL_free(backend->handle);
    backend->handle = NULL;
  }
  if(backend->ctx) {
    wolfSSL_CTX_free(backend->ctx);
    backend->ctx = NULL;
  }
}

static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            char *buf, size_t blen,
                            CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;
  char error_buffer[WOLFSSL_MAX_ERROR_SZ];
  int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
  int nread;

  DEBUGASSERT(backend);

  wolfSSL_ERR_clear_error();
  *curlcode = CURLE_OK;







|
|
<














|










>
>
|
>
|
|
>







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|
|






<
<
<
<
<
<















|
|
<







1314
1315
1316
1317
1318
1319
1320
1321
1322

1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467






1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484

1485
1486
1487
1488
1489
1490
1491
static ssize_t wolfssl_send(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            const void *mem,
                            size_t len,
                            CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;

  int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
  int rc;

  DEBUGASSERT(backend);

  wolfSSL_ERR_clear_error();

  rc = wolfSSL_write(backend->handle, mem, memlen);
  if(rc <= 0) {
    int err = wolfSSL_get_error(backend->handle, rc);

    switch(err) {
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
      /* there is data pending, re-invoke SSL_write() */
      CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
      *curlcode = CURLE_AGAIN;
      return -1;
    default:
      if(backend->io_result == CURLE_AGAIN) {
        CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
        *curlcode = CURLE_AGAIN;
        return -1;
      }
      CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err);
      {
        char error_buffer[256];
        failf(data, "SSL write: %s, errno %d",
              wolfssl_strerror((unsigned long)err, error_buffer,
                               sizeof(error_buffer)),
              SOCKERRNO);
      }
      *curlcode = CURLE_SEND_ERROR;
      return -1;
    }
  }
  CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc);
  return rc;
}

static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 bool send_shutdown, bool *done)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *wctx = (struct wolfssl_ctx *)connssl->backend;
  CURLcode result = CURLE_OK;
  char buf[1024];
  int nread, err;

  DEBUGASSERT(wctx);
  if(!wctx->handle || cf->shutdown) {
    *done = TRUE;
    goto out;
  }

  connssl->io_need = CURL_SSL_IO_NEED_NONE;
  *done = FALSE;
  if(!(wolfSSL_get_shutdown(wctx->handle) & SSL_SENT_SHUTDOWN)) {
    /* We have not started the shutdown from our side yet. Check
     * if the server already sent us one. */
    ERR_clear_error();
    nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
    err = wolfSSL_get_error(wctx->handle, nread);
    if(!nread && err == SSL_ERROR_ZERO_RETURN) {
      bool input_pending;
      /* Yes, it did. */
      if(!send_shutdown) {
        CURL_TRC_CF(data, cf, "SSL shutdown received, not sending");
        *done = TRUE;
        goto out;
      }
      else if(!cf->next->cft->is_alive(cf->next, data, &input_pending)) {
        /* Server closed the connection after its closy notify. It
         * seems not interested to see our close notify, so do not
         * send it. We are done. */
        CURL_TRC_CF(data, cf, "peer closed connection");
        connssl->peer_closed = TRUE;
        *done = TRUE;
        goto out;
      }
    }
  }

  if(send_shutdown && wolfSSL_shutdown(wctx->handle) == 1) {
    CURL_TRC_CF(data, cf, "SSL shutdown finished");
    *done = TRUE;
    goto out;
  }
  else {
    size_t i;
    /* SSL should now have started the shutdown from our side. Since it
     * was not complete, we are lacking the close notify from the server. */
    for(i = 0; i < 10; ++i) {
      ERR_clear_error();
      nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
      if(nread <= 0)
        break;
    }
    err = wolfSSL_get_error(wctx->handle, nread);
    switch(err) {
    case SSL_ERROR_ZERO_RETURN: /* no more data */
      CURL_TRC_CF(data, cf, "SSL shutdown received");
      *done = TRUE;
      break;
    case SSL_ERROR_NONE: /* just did not get anything */
    case SSL_ERROR_WANT_READ:
      /* SSL has send its notify and now wants to read the reply
       * from the server. We are not really interested in that. */
      CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
      connssl->io_need = CURL_SSL_IO_NEED_RECV;
      break;
    case SSL_ERROR_WANT_WRITE:
      CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
      connssl->io_need = CURL_SSL_IO_NEED_SEND;
      break;
    default: {
      char error_buffer[256];
      int detail = wolfSSL_get_error(wctx->handle, err);
      CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)",
                  wolfssl_strerror((unsigned long)err, error_buffer,
                                   sizeof(error_buffer)),
                  detail);
      result = CURLE_RECV_ERROR;
      break;
    }
    }
  }

out:
  cf->shutdown = (result || *done);
  return result;
}

static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;

  (void) data;

  DEBUGASSERT(backend);

  if(backend->handle) {






    wolfSSL_free(backend->handle);
    backend->handle = NULL;
  }
  if(backend->ctx) {
    wolfSSL_CTX_free(backend->ctx);
    backend->ctx = NULL;
  }
}

static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            char *buf, size_t blen,
                            CURLcode *curlcode)
{
  struct ssl_connect_data *connssl = cf->ctx;
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;

  int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
  int nread;

  DEBUGASSERT(backend);

  wolfSSL_ERR_clear_error();
  *curlcode = CURLE_OK;
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223


1224


1225

1226
1227
1228
1229
1230
1231
1232
    case SSL_ERROR_ZERO_RETURN: /* no more data */
      CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
      *curlcode = CURLE_OK;
      return 0;
    case SSL_ERROR_NONE:
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
      /* there's data pending, re-invoke wolfSSL_read() */
      CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
      *curlcode = CURLE_AGAIN;
      return -1;
    default:
      if(backend->io_result == CURLE_AGAIN) {
        CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
        *curlcode = CURLE_AGAIN;
        return -1;
      }


      failf(data, "SSL read: %s, errno %d",


            wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO);

      *curlcode = CURLE_RECV_ERROR;
      return -1;
    }
  }
  CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread);
  return nread;
}







|









>
>
|
>
>
|
>







1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
    case SSL_ERROR_ZERO_RETURN: /* no more data */
      CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
      *curlcode = CURLE_OK;
      return 0;
    case SSL_ERROR_NONE:
    case SSL_ERROR_WANT_READ:
    case SSL_ERROR_WANT_WRITE:
      /* there is data pending, re-invoke wolfSSL_read() */
      CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
      *curlcode = CURLE_AGAIN;
      return -1;
    default:
      if(backend->io_result == CURLE_AGAIN) {
        CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
        *curlcode = CURLE_AGAIN;
        return -1;
      }
      {
        char error_buffer[256];
        failf(data, "SSL read: %s, errno %d",
              wolfssl_strerror((unsigned long)err, error_buffer,
                               sizeof(error_buffer)),
              SOCKERRNO);
      }
      *curlcode = CURLE_RECV_ERROR;
      return -1;
    }
  }
  CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread);
  return nread;
}
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
}


static bool wolfssl_data_pending(struct Curl_cfilter *cf,
                                 const struct Curl_easy *data)
{
  struct ssl_connect_data *ctx = cf->ctx;
  struct wolfssl_ssl_backend_data *backend;

  (void)data;
  DEBUGASSERT(ctx && ctx->backend);

  backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
  if(backend->handle)   /* SSL is in use */
    return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
  else
    return FALSE;
}


/*
 * This function is called to shut down the SSL layer but keep the
 * socket open (CCC - Clear Command Channel)
 */
static int wolfssl_shutdown(struct Curl_cfilter *cf,
                            struct Curl_easy *data)
{
  struct ssl_connect_data *ctx = cf->ctx;
  struct wolfssl_ssl_backend_data *backend;
  int retval = 0;

  (void)data;
  DEBUGASSERT(ctx && ctx->backend);

  backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
  if(backend->handle) {
    wolfSSL_ERR_clear_error();
    wolfSSL_free(backend->handle);
    backend->handle = NULL;
  }
  return retval;
}


static CURLcode
wolfssl_connect_common(struct Curl_cfilter *cf,
                       struct Curl_easy *data,
                       bool nonblocking,
                       bool *done)
{
  CURLcode result;
  struct ssl_connect_data *connssl = cf->ctx;
  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
  int what;

  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* Find out how much more time we're allowed */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = wolfssl_connect_step1(cf, data);
    if(result)
      return result;
  }

  while(ssl_connect_2 == connssl->connecting_state ||
        ssl_connect_2_reading == connssl->connecting_state ||
        ssl_connect_2_writing == connssl->connecting_state) {

    /* check allowed time left */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it's available. */
    if(connssl->connecting_state == ssl_connect_2_reading
       || connssl->connecting_state == ssl_connect_2_writing) {

      curl_socket_t writefd = ssl_connect_2_writing ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = ssl_connect_2_reading ==
        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking?0:timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;







|




|





<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



















|













|
<
<










|
|
<

|
|
|
|







1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579

























1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613


1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625

1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
}


static bool wolfssl_data_pending(struct Curl_cfilter *cf,
                                 const struct Curl_easy *data)
{
  struct ssl_connect_data *ctx = cf->ctx;
  struct wolfssl_ctx *backend;

  (void)data;
  DEBUGASSERT(ctx && ctx->backend);

  backend = (struct wolfssl_ctx *)ctx->backend;
  if(backend->handle)   /* SSL is in use */
    return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
  else
    return FALSE;
}


























static CURLcode
wolfssl_connect_common(struct Curl_cfilter *cf,
                       struct Curl_easy *data,
                       bool nonblocking,
                       bool *done)
{
  CURLcode result;
  struct ssl_connect_data *connssl = cf->ctx;
  curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
  int what;

  /* check if the connection has already been established */
  if(ssl_connection_complete == connssl->state) {
    *done = TRUE;
    return CURLE_OK;
  }

  if(ssl_connect_1 == connssl->connecting_state) {
    /* Find out how much more time we are allowed */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    result = wolfssl_connect_step1(cf, data);
    if(result)
      return result;
  }

  while(ssl_connect_2 == connssl->connecting_state) {



    /* check allowed time left */
    const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);

    if(timeout_ms < 0) {
      /* no need to continue if time already is up */
      failf(data, "SSL connection timeout");
      return CURLE_OPERATION_TIMEDOUT;
    }

    /* if ssl is expecting something, check if it is available. */
    if(connssl->io_need) {


      curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
                              sockfd:CURL_SOCKET_BAD;
      curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
                             sockfd:CURL_SOCKET_BAD;

      what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
                               nonblocking?0:timeout_ms);
      if(what < 0) {
        /* fatal error */
        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
        return CURLE_SSL_CONNECT_ERROR;
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
     * this connection is part of a multi handle and this loop would
     * execute again. This permits the owner of a multi handle to
     * abort a connection attempt before step2 has completed while
     * ensuring that a client using select() or epoll() will always
     * have a valid fdset to wait on.
     */
    result = wolfssl_connect_step2(cf, data);
    if(result || (nonblocking &&
                  (ssl_connect_2 == connssl->connecting_state ||
                   ssl_connect_2_reading == connssl->connecting_state ||
                   ssl_connect_2_writing == connssl->connecting_state)))
      return result;
  } /* repeat step2 until all transactions are done. */

  if(ssl_connect_3 == connssl->connecting_state) {
    result = wolfssl_connect_step3(cf, data);
    if(result)
      return result;







|
<
<
<







1654
1655
1656
1657
1658
1659
1660
1661



1662
1663
1664
1665
1666
1667
1668
     * this connection is part of a multi handle and this loop would
     * execute again. This permits the owner of a multi handle to
     * abort a connection attempt before step2 has completed while
     * ensuring that a client using select() or epoll() will always
     * have a valid fdset to wait on.
     */
    result = wolfssl_connect_step2(cf, data);
    if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))



      return result;
  } /* repeat step2 until all transactions are done. */

  if(ssl_connect_3 == connssl->connecting_state) {
    result = wolfssl_connect_step3(cf, data);
    if(result)
      return result;
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496

1497
1498
1499
1500
1501
1502
1503
1504
1505
  wc_Sha256Final(&SHA256pw, sha256sum);
  return CURLE_OK;
}

static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
                                   CURLINFO info UNUSED_PARAM)
{
  struct wolfssl_ssl_backend_data *backend =
    (struct wolfssl_ssl_backend_data *)connssl->backend;
  (void)info;
  DEBUGASSERT(backend);
  return backend->handle;
}

const struct Curl_ssl Curl_ssl_wolfssl = {
  { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */

#ifdef KEEP_PEER_CERT
  SSLSUPP_PINNEDPUBKEY |
#endif
#ifdef USE_BIO_CHAIN
  SSLSUPP_HTTPS_PROXY |
#endif
  SSLSUPP_CA_PATH |
  SSLSUPP_CAINFO_BLOB |
#ifdef USE_ECH
  SSLSUPP_ECH |
#endif
  SSLSUPP_SSL_CTX,


  sizeof(struct wolfssl_ssl_backend_data),

  wolfssl_init,                    /* init */
  wolfssl_cleanup,                 /* cleanup */
  wolfssl_version,                 /* version */
  Curl_none_check_cxn,             /* check_cxn */
  wolfssl_shutdown,                /* shutdown */
  wolfssl_data_pending,            /* data_pending */







|
|






|












|
>

|







1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
  wc_Sha256Final(&SHA256pw, sha256sum);
  return CURLE_OK;
}

static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
                                   CURLINFO info UNUSED_PARAM)
{
  struct wolfssl_ctx *backend =
    (struct wolfssl_ctx *)connssl->backend;
  (void)info;
  DEBUGASSERT(backend);
  return backend->handle;
}

const struct Curl_ssl Curl_ssl_wolfssl = {
  { CURLSSLBACKEND_WOLFSSL, "wolfssl" }, /* info */

#ifdef KEEP_PEER_CERT
  SSLSUPP_PINNEDPUBKEY |
#endif
#ifdef USE_BIO_CHAIN
  SSLSUPP_HTTPS_PROXY |
#endif
  SSLSUPP_CA_PATH |
  SSLSUPP_CAINFO_BLOB |
#ifdef USE_ECH
  SSLSUPP_ECH |
#endif
  SSLSUPP_SSL_CTX |
  SSLSUPP_CA_CACHE,

  sizeof(struct wolfssl_ctx),

  wolfssl_init,                    /* init */
  wolfssl_cleanup,                 /* cleanup */
  wolfssl_version,                 /* version */
  Curl_none_check_cxn,             /* check_cxn */
  wolfssl_shutdown,                /* shutdown */
  wolfssl_data_pending,            /* data_pending */
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
  Curl_none_set_engine,            /* set_engine */
  Curl_none_set_engine_default,    /* set_engine_default */
  Curl_none_engines_list,          /* engines_list */
  Curl_none_false_start,           /* false_start */
  wolfssl_sha256sum,               /* sha256sum */
  NULL,                            /* associate_connection */
  NULL,                            /* disassociate_connection */
  NULL,                            /* free_multi_ssl_backend_data */
  wolfssl_recv,                    /* recv decrypted data */
  wolfssl_send,                    /* send data to encrypt */
};

#endif







<





1781
1782
1783
1784
1785
1786
1787

1788
1789
1790
1791
1792
  Curl_none_set_engine,            /* set_engine */
  Curl_none_set_engine_default,    /* set_engine_default */
  Curl_none_engines_list,          /* engines_list */
  Curl_none_false_start,           /* false_start */
  wolfssl_sha256sum,               /* sha256sum */
  NULL,                            /* associate_connection */
  NULL,                            /* disassociate_connection */

  wolfssl_recv,                    /* recv decrypted data */
  wolfssl_send,                    /* send data to encrypt */
};

#endif
Changes to jni/curl/lib/vtls/wolfssl.h.
22
23
24
25
26
27
28






29
30
31











32
33
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curl_setup.h"

#ifdef USE_WOLFSSL







extern const struct Curl_ssl Curl_ssl_wolfssl;












#endif /* USE_WOLFSSL */
#endif /* HEADER_CURL_WOLFSSL_H */







>
>
>
>
>
>



>
>
>
>
>
>
>
>
>
>
>


22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curl_setup.h"

#ifdef USE_WOLFSSL
#include <wolfssl/version.h>
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>

#include "urldata.h"

extern const struct Curl_ssl Curl_ssl_wolfssl;

struct wolfssl_ctx {
  WOLFSSL_CTX *ctx;
  WOLFSSL     *handle;
  CURLcode    io_result;   /* result of last BIO cfilter operation */
  BIT(x509_store_setup);   /* x509 store has been set up */
};

CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
                                    struct Curl_easy *data,
                                    struct wolfssl_ctx *wssl);

#endif /* USE_WOLFSSL */
#endif /* HEADER_CURL_WOLFSSL_H */
Changes to jni/curl/lib/vtls/x509asn1.c.
21
22
23
24
25
26
27
28

29
30
31
32
33
34

35
36
37
38
39
40
41
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) ||      \
  defined(USE_SCHANNEL) || defined(USE_SECTRANSP)


#if defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
#define WANT_PARSEX509 /* uses Curl_parseX509() */
#endif

#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)

#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
#define WANT_PARSEX509 /* ... uses Curl_parseX509() */
#endif

#include <curl/curl.h>
#include "urldata.h"
#include "strcase.h"







|
>





|
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) ||      \
  defined(USE_SCHANNEL) || defined(USE_SECTRANSP) ||    \
  defined(USE_MBEDTLS)

#if defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
#define WANT_PARSEX509 /* uses Curl_parseX509() */
#endif

#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
  defined(USE_MBEDTLS)
#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
#define WANT_PARSEX509 /* ... uses Curl_parseX509() */
#endif

#include <curl/curl.h>
#include "urldata.h"
#include "strcase.h"
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121




122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* ASN.1 OID table entry. */
struct Curl_OID {
  const char *numoid;  /* Dotted-numeric OID. */
  const char *textoid; /* OID name. */
};

/* ASN.1 OIDs. */
static const char       cnOID[] = "2.5.4.3";    /* Common name. */
static const char       sanOID[] = "2.5.29.17"; /* Subject alternative name. */

static const struct Curl_OID OIDtable[] = {
  { "1.2.840.10040.4.1",        "dsa" },
  { "1.2.840.10040.4.3",        "dsa-with-sha1" },
  { "1.2.840.10045.2.1",        "ecPublicKey" },
  { "1.2.840.10045.3.0.1",      "c2pnb163v1" },
  { "1.2.840.10045.4.1",        "ecdsa-with-SHA1" },




  { "1.2.840.10046.2.1",        "dhpublicnumber" },
  { "1.2.840.113549.1.1.1",     "rsaEncryption" },
  { "1.2.840.113549.1.1.2",     "md2WithRSAEncryption" },
  { "1.2.840.113549.1.1.4",     "md5WithRSAEncryption" },
  { "1.2.840.113549.1.1.5",     "sha1WithRSAEncryption" },
  { "1.2.840.113549.1.1.10",    "RSASSA-PSS" },
  { "1.2.840.113549.1.1.14",    "sha224WithRSAEncryption" },
  { "1.2.840.113549.1.1.11",    "sha256WithRSAEncryption" },
  { "1.2.840.113549.1.1.12",    "sha384WithRSAEncryption" },
  { "1.2.840.113549.1.1.13",    "sha512WithRSAEncryption" },
  { "1.2.840.113549.2.2",       "md2" },
  { "1.2.840.113549.2.5",       "md5" },
  { "1.3.14.3.2.26",            "sha1" },
  { cnOID,                      "CN" },
  { "2.5.4.4",                  "SN" },
  { "2.5.4.5",                  "serialNumber" },
  { "2.5.4.6",                  "C" },
  { "2.5.4.7",                  "L" },
  { "2.5.4.8",                  "ST" },
  { "2.5.4.9",                  "streetAddress" },
  { "2.5.4.10",                 "O" },
  { "2.5.4.11",                 "OU" },
  { "2.5.4.12",                 "title" },
  { "2.5.4.13",                 "description" },
  { "2.5.4.17",                 "postalCode" },
  { "2.5.4.41",                 "name" },
  { "2.5.4.42",                 "givenName" },
  { "2.5.4.43",                 "initials" },
  { "2.5.4.44",                 "generationQualifier" },
  { "2.5.4.45",                 "X500UniqueIdentifier" },
  { "2.5.4.46",                 "dnQualifier" },
  { "2.5.4.65",                 "pseudonym" },
  { "1.2.840.113549.1.9.1",     "emailAddress" },
  { "2.5.4.72",                 "role" },
  { sanOID,                     "subjectAltName" },
  { "2.5.29.18",                "issuerAltName" },
  { "2.5.29.19",                "basicConstraints" },
  { "2.16.840.1.101.3.4.2.4",   "sha224" },
  { "2.16.840.1.101.3.4.2.1",   "sha256" },
  { "2.16.840.1.101.3.4.2.2",   "sha384" },
  { "2.16.840.1.101.3.4.2.3",   "sha512" },
  { "1.2.840.113549.1.9.2",     "unstructuredName" },







<
<
<






>
>
>
>













|




















|







108
109
110
111
112
113
114



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* ASN.1 OID table entry. */
struct Curl_OID {
  const char *numoid;  /* Dotted-numeric OID. */
  const char *textoid; /* OID name. */
};

/* ASN.1 OIDs. */



static const struct Curl_OID OIDtable[] = {
  { "1.2.840.10040.4.1",        "dsa" },
  { "1.2.840.10040.4.3",        "dsa-with-sha1" },
  { "1.2.840.10045.2.1",        "ecPublicKey" },
  { "1.2.840.10045.3.0.1",      "c2pnb163v1" },
  { "1.2.840.10045.4.1",        "ecdsa-with-SHA1" },
  { "1.2.840.10045.4.3.1",      "ecdsa-with-SHA224" },
  { "1.2.840.10045.4.3.2",      "ecdsa-with-SHA256" },
  { "1.2.840.10045.4.3.3",      "ecdsa-with-SHA384" },
  { "1.2.840.10045.4.3.4",      "ecdsa-with-SHA512" },
  { "1.2.840.10046.2.1",        "dhpublicnumber" },
  { "1.2.840.113549.1.1.1",     "rsaEncryption" },
  { "1.2.840.113549.1.1.2",     "md2WithRSAEncryption" },
  { "1.2.840.113549.1.1.4",     "md5WithRSAEncryption" },
  { "1.2.840.113549.1.1.5",     "sha1WithRSAEncryption" },
  { "1.2.840.113549.1.1.10",    "RSASSA-PSS" },
  { "1.2.840.113549.1.1.14",    "sha224WithRSAEncryption" },
  { "1.2.840.113549.1.1.11",    "sha256WithRSAEncryption" },
  { "1.2.840.113549.1.1.12",    "sha384WithRSAEncryption" },
  { "1.2.840.113549.1.1.13",    "sha512WithRSAEncryption" },
  { "1.2.840.113549.2.2",       "md2" },
  { "1.2.840.113549.2.5",       "md5" },
  { "1.3.14.3.2.26",            "sha1" },
  { "2.5.4.3",                  "CN" },
  { "2.5.4.4",                  "SN" },
  { "2.5.4.5",                  "serialNumber" },
  { "2.5.4.6",                  "C" },
  { "2.5.4.7",                  "L" },
  { "2.5.4.8",                  "ST" },
  { "2.5.4.9",                  "streetAddress" },
  { "2.5.4.10",                 "O" },
  { "2.5.4.11",                 "OU" },
  { "2.5.4.12",                 "title" },
  { "2.5.4.13",                 "description" },
  { "2.5.4.17",                 "postalCode" },
  { "2.5.4.41",                 "name" },
  { "2.5.4.42",                 "givenName" },
  { "2.5.4.43",                 "initials" },
  { "2.5.4.44",                 "generationQualifier" },
  { "2.5.4.45",                 "X500UniqueIdentifier" },
  { "2.5.4.46",                 "dnQualifier" },
  { "2.5.4.65",                 "pseudonym" },
  { "1.2.840.113549.1.9.1",     "emailAddress" },
  { "2.5.4.72",                 "role" },
  { "2.5.29.17",                "subjectAltName" },
  { "2.5.29.18",                "issuerAltName" },
  { "2.5.29.19",                "basicConstraints" },
  { "2.16.840.1.101.3.4.2.4",   "sha224" },
  { "2.16.840.1.101.3.4.2.1",   "sha256" },
  { "2.16.840.1.101.3.4.2.2",   "sha384" },
  { "2.16.840.1.101.3.4.2.3",   "sha512" },
  { "1.2.840.113549.1.9.2",     "unstructuredName" },
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
    /* Just copy. */
    if(inlength)
      result = Curl_dyn_addn(to, from, inlength);
  }
  else {
    while(!result && (from < end)) {
      char buf[4]; /* decode buffer */
      int charsize = 1;
      unsigned int wc = 0;

      switch(size) {
      case 4:
        wc = (wc << 8) | *(const unsigned char *) from++;
        wc = (wc << 8) | *(const unsigned char *) from++;
        FALLTHROUGH();
      case 2:
        wc = (wc << 8) | *(const unsigned char *) from++;
        FALLTHROUGH();
      default: /* case 1: */
        wc = (wc << 8) | *(const unsigned char *) from++;
      }
      if(wc >= 0x00000080) {
        if(wc >= 0x00000800) {
          if(wc >= 0x00010000) {
            if(wc >= 0x00200000) {
              free(buf);
              /* Invalid char. size for target encoding. */
              return CURLE_WEIRD_SERVER_REPLY;
            }
            buf[3] = (char) (0x80 | (wc & 0x3F));
            wc = (wc >> 6) | 0x00010000;
            charsize++;
          }







|

















<







371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395

396
397
398
399
400
401
402
    /* Just copy. */
    if(inlength)
      result = Curl_dyn_addn(to, from, inlength);
  }
  else {
    while(!result && (from < end)) {
      char buf[4]; /* decode buffer */
      size_t charsize = 1;
      unsigned int wc = 0;

      switch(size) {
      case 4:
        wc = (wc << 8) | *(const unsigned char *) from++;
        wc = (wc << 8) | *(const unsigned char *) from++;
        FALLTHROUGH();
      case 2:
        wc = (wc << 8) | *(const unsigned char *) from++;
        FALLTHROUGH();
      default: /* case 1: */
        wc = (wc << 8) | *(const unsigned char *) from++;
      }
      if(wc >= 0x00000080) {
        if(wc >= 0x00000800) {
          if(wc >= 0x00010000) {
            if(wc >= 0x00200000) {

              /* Invalid char. size for target encoding. */
              return CURLE_WEIRD_SERVER_REPLY;
            }
            buf[3] = (char) (0x80 | (wc & 0x3F));
            wc = (wc >> 6) | 0x00010000;
            charsize++;
          }
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
      result = encodeOID(&buf, beg, end);

      if(!result) {
        const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf));
        if(op)
          result = Curl_dyn_add(store, op->textoid);
        else
          result = CURLE_BAD_FUNCTION_ARGUMENT;
        Curl_dyn_free(&buf);
      }
    }
    else
      result = encodeOID(store, beg, end);
  }
  return result;







|







467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
      result = encodeOID(&buf, beg, end);

      if(!result) {
        const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf));
        if(op)
          result = Curl_dyn_add(store, op->textoid);
        else
          result = Curl_dyn_add(store, Curl_dyn_ptr(&buf));
        Curl_dyn_free(&buf);
      }
    }
    else
      result = encodeOID(store, beg, end);
  }
  return result;
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
 * Return error
 */
static CURLcode ASN1tostr(struct dynbuf *store,
                          struct Curl_asn1Element *elem, int type)
{
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
  if(elem->constructed)
    return CURLE_OK; /* No conversion of structured elements. */

  if(!type)
    type = elem->tag;   /* Type not forced: use element tag as type. */

  switch(type) {
  case CURL_ASN1_BOOLEAN:
    result = bool2str(store, elem->beg, elem->end);







|







596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
 * Return error
 */
static CURLcode ASN1tostr(struct dynbuf *store,
                          struct Curl_asn1Element *elem, int type)
{
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
  if(elem->constructed)
    return result; /* No conversion of structured elements. */

  if(!type)
    type = elem->tag;   /* Type not forced: use element tag as type. */

  switch(type) {
  case CURL_ASN1_BOOLEAN:
    result = bool2str(store, elem->beg, elem->end);
687
688
689
690
691
692
693





694
695
696
697
698
699
700
      }
      Curl_dyn_reset(&temp);
      result = ASN1tostr(&temp, &oid, 0);
      if(result)
        goto error;

      str = Curl_dyn_ptr(&temp);






      /* Encode delimiter.
         If attribute has a short uppercase name, delimiter is ", ". */
      for(p3 = str; ISUPPER(*p3); p3++)
        ;
      if(added) {
        if(p3 - str > 2)







>
>
>
>
>







689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
      }
      Curl_dyn_reset(&temp);
      result = ASN1tostr(&temp, &oid, 0);
      if(result)
        goto error;

      str = Curl_dyn_ptr(&temp);

      if(!str) {
        result = CURLE_BAD_FUNCTION_ARGUMENT;
        goto error;
      }

      /* Encode delimiter.
         If attribute has a short uppercase name, delimiter is ", ". */
      for(p3 = str; ISUPPER(*p3); p3++)
        ;
      if(added) {
        if(p3 - str > 2)
955
956
957
958
959
960
961
962

963
964
965
966
967
968
969
      infof(data, "   ECC Public Key (%zu bits)", len);
    if(data->set.ssl.certinfo) {
      char q[sizeof(len) * 8 / 3 + 1];
      (void)msnprintf(q, sizeof(q), "%zu", len);
      if(ssl_push_certinfo(data, certnum, "ECC Public Key", q))
        return 1;
    }
    return do_pubkey_field(data, certnum, "ecPublicKey", pubkey);

  }

  /* Get the public key (single element). */
  if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
    return 1;

  if(strcasecompare(algo, "rsaEncryption")) {







|
>







962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
      infof(data, "   ECC Public Key (%zu bits)", len);
    if(data->set.ssl.certinfo) {
      char q[sizeof(len) * 8 / 3 + 1];
      (void)msnprintf(q, sizeof(q), "%zu", len);
      if(ssl_push_certinfo(data, certnum, "ECC Public Key", q))
        return 1;
    }
    return do_pubkey_field(data, certnum, "ecPublicKey", pubkey) == CURLE_OK
      ? 0 : 1;
  }

  /* Get the public key (single element). */
  if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end))
    return 1;

  if(strcasecompare(algo, "rsaEncryption")) {
1219
1220
1221
1222
1223
1224
1225


1226
1227
1228
1229
1230
1231
1232
  }
  free(certptr);
  if(!result)
    if(data->set.ssl.certinfo)
      result = ssl_push_certinfo_dyn(data, certnum, "Cert", &out);

done:


  Curl_dyn_free(&out);
  return result;
}

#endif /* WANT_EXTRACT_CERTINFO */

#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */







>
>







1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
  }
  free(certptr);
  if(!result)
    if(data->set.ssl.certinfo)
      result = ssl_push_certinfo_dyn(data, certnum, "Cert", &out);

done:
  if(result)
    failf(data, "Failed extracting certificate chain");
  Curl_dyn_free(&out);
  return result;
}

#endif /* WANT_EXTRACT_CERTINFO */

#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
Changes to jni/curl/lib/vtls/x509asn1.h.
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
  defined(USE_SCHANNEL) || defined(USE_SECTRANSP)


#include "cfilters.h"
#include "urldata.h"

/*
 * Types.
 */







|
>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/

#include "curl_setup.h"

#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
  defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
  defined(USE_MBEDTLS)

#include "cfilters.h"
#include "urldata.h"

/*
 * Types.
 */
Changes to jni/curl/lib/ws.c.
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
}

static unsigned char ws_frame_flags2op(int flags)
{
  size_t i;
  for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) {
    if(WS_FRAMES[i].flags & flags)
      return WS_FRAMES[i].proto_opcode;
  }
  return 0;
}

static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data,
                        const char *msg)
{







|







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
}

static unsigned char ws_frame_flags2op(int flags)
{
  size_t i;
  for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) {
    if(WS_FRAMES[i].flags & flags)
      return (unsigned char)WS_FRAMES[i].proto_opcode;
  }
  return 0;
}

static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data,
                        const char *msg)
{
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  size_t inlen;

  while(Curl_bufq_peek(inraw, &inbuf, &inlen)) {
    if(dec->head_len == 0) {
      dec->head[0] = *inbuf;
      Curl_bufq_skip(inraw, 1);

      dec->frame_flags  = ws_frame_op2flags(dec->head[0]);
      if(!dec->frame_flags) {
        failf(data, "WS: unknown opcode: %x", dec->head[0]);
        ws_dec_reset(dec);
        return CURLE_RECV_ERROR;
      }
      dec->head_len = 1;
      /* ws_dec_info(dec, data, "seeing opcode"); */







|







167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  size_t inlen;

  while(Curl_bufq_peek(inraw, &inbuf, &inlen)) {
    if(dec->head_len == 0) {
      dec->head[0] = *inbuf;
      Curl_bufq_skip(inraw, 1);

      dec->frame_flags = ws_frame_op2flags(dec->head[0]);
      if(!dec->frame_flags) {
        failf(data, "WS: unknown opcode: %x", dec->head[0]);
        ws_dec_reset(dec);
        return CURLE_RECV_ERROR;
      }
      dec->head_len = 1;
      /* ws_dec_info(dec, data, "seeing opcode"); */
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
    /* trying to write a new frame before the previous one is finished */
    failf(data, "WS: starting new frame with %zd bytes from last one"
                "remaining to be sent", (ssize_t)enc->payload_remain);
    *err = CURLE_SEND_ERROR;
    return -1;
  }

  opcode = ws_frame_flags2op(flags);
  if(!opcode) {
    failf(data, "WS: provided flags not recognized '%x'", flags);
    *err = CURLE_SEND_ERROR;
    return -1;
  }

  if(!(flags & CURLWS_CONT)) {
    if(!enc->contfragment)
      /* not marked as continuing, this is the final fragment */
      firstbyte |= WSBIT_FIN | opcode;
    else
      /* marked as continuing, this is the final fragment; set CONT
         opcode and FIN bit */
      firstbyte |= WSBIT_FIN | WSBIT_OPCODE_CONT;

    enc->contfragment = FALSE;
  }
  else if(enc->contfragment) {
    /* the previous fragment was not a final one and this isn't either, keep a
       CONT opcode and no FIN bit */
    firstbyte |= WSBIT_OPCODE_CONT;
  }
  else {
    firstbyte = opcode;
    enc->contfragment = TRUE;
  }







|


















|







556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
    /* trying to write a new frame before the previous one is finished */
    failf(data, "WS: starting new frame with %zd bytes from last one"
                "remaining to be sent", (ssize_t)enc->payload_remain);
    *err = CURLE_SEND_ERROR;
    return -1;
  }

  opcode = ws_frame_flags2op((int)flags);
  if(!opcode) {
    failf(data, "WS: provided flags not recognized '%x'", flags);
    *err = CURLE_SEND_ERROR;
    return -1;
  }

  if(!(flags & CURLWS_CONT)) {
    if(!enc->contfragment)
      /* not marked as continuing, this is the final fragment */
      firstbyte |= WSBIT_FIN | opcode;
    else
      /* marked as continuing, this is the final fragment; set CONT
         opcode and FIN bit */
      firstbyte |= WSBIT_FIN | WSBIT_OPCODE_CONT;

    enc->contfragment = FALSE;
  }
  else if(enc->contfragment) {
    /* the previous fragment was not a final one and this is not either, keep a
       CONT opcode and no FIN bit */
    firstbyte |= WSBIT_OPCODE_CONT;
  }
  else {
    firstbyte = opcode;
    enc->contfragment = TRUE;
  }
Changes to jni/curl/lib/ws.h.
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

/* a client-side WS frame encoder, generating frame headers and
 * converting payloads, tracking remaining data in current frame */
struct ws_encoder {
  curl_off_t payload_len;  /* payload length of current frame */
  curl_off_t payload_remain;  /* remaining payload of current */
  unsigned int xori; /* xor index */
  unsigned char mask[4]; /* 32 bit mask for this connection */
  unsigned char firstbyte; /* first byte of frame we encode */
  bool contfragment; /* set TRUE if the previous fragment sent was not final */
};

/* A websocket connection with en- and decoder that treat frames
 * and keep track of boundaries. */
struct websocket {







|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

/* a client-side WS frame encoder, generating frame headers and
 * converting payloads, tracking remaining data in current frame */
struct ws_encoder {
  curl_off_t payload_len;  /* payload length of current frame */
  curl_off_t payload_remain;  /* remaining payload of current */
  unsigned int xori; /* xor index */
  unsigned char mask[4]; /* 32-bit mask for this connection */
  unsigned char firstbyte; /* first byte of frame we encode */
  bool contfragment; /* set TRUE if the previous fragment sent was not final */
};

/* A websocket connection with en- and decoder that treat frames
 * and keep track of boundaries. */
struct websocket {
Changes to jni/curl/libcurl.pc.in.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38


39
40
41
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################

# This should most probably benefit from getting a "Requires:" field added
# dynamically by configure.
#
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
supported_protocols="@SUPPORT_PROTOCOLS@"
supported_features="@SUPPORT_FEATURES@"

Name: libcurl
URL: https://curl.se/
Description: Library to transfer files with ftp, http, etc.
Version: @CURLVERSION@


Libs: -L${libdir} -lcurl @LIBCURL_NO_SHARED@
Libs.private: @LIBCURL_LIBS@
Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@







<
<
<











>
>



18
19
20
21
22
23
24



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################




prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
supported_protocols="@SUPPORT_PROTOCOLS@"
supported_features="@SUPPORT_FEATURES@"

Name: libcurl
URL: https://curl.se/
Description: Library to transfer files with ftp, http, etc.
Version: @CURLVERSION@
Requires: @LIBCURL_PC_REQUIRES@
Requires.private: @LIBCURL_PC_REQUIRES_PRIVATE@
Libs: -L${libdir} -lcurl @LIBCURL_NO_SHARED@
Libs.private: @LIBCURL_LIBS@
Cflags: -I${includedir} @CPPFLAG_CURL_STATICLIB@
Changes to jni/curl/ltmain.sh.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


PROGRAM=libtool
PACKAGE=libtool
VERSION="2.4.7 Debian-2.4.7-5"
package_revision=2.4.7


## ------ ##
## Usage. ##
## ------ ##








|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


PROGRAM=libtool
PACKAGE=libtool
VERSION="2.4.7 Debian-2.4.7-7~deb12u1"
package_revision=2.4.7


## ------ ##
## Usage. ##
## ------ ##

568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593


594
595

596
597
598
599
600
601
602
# less featureful shells.


# func_append VAR VALUE
# ---------------------
# Append VALUE onto the existing contents of VAR.

  # We should try to minimise forks, especially on Windows where they are
  # unreasonably slow, so skip the feature probes when bash or zsh are
  # being used:
  if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
    : ${_G_HAVE_ARITH_OP="yes"}
    : ${_G_HAVE_XSI_OPS="yes"}
    # The += operator was introduced in bash 3.1
    case $BASH_VERSION in
      [12].* | 3.0 | 3.0*) ;;
      *)
        : ${_G_HAVE_PLUSEQ_OP="yes"}
        ;;
    esac
  fi

  # _G_HAVE_PLUSEQ_OP
  # Can be empty, in which case the shell is probed, "yes" if += is
  # useable or anything else if it does not work.
  test -z "$_G_HAVE_PLUSEQ_OP" \


    && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
    && _G_HAVE_PLUSEQ_OP=yes


if test yes = "$_G_HAVE_PLUSEQ_OP"
then
  # This is an XSI compatible shell, allowing a faster implementation...
  eval 'func_append ()
  {
    $debug_cmd







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



|
>
>
|
|
>







568
569
570
571
572
573
574















575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
# less featureful shells.


# func_append VAR VALUE
# ---------------------
# Append VALUE onto the existing contents of VAR.
















  # _G_HAVE_PLUSEQ_OP
  # Can be empty, in which case the shell is probed, "yes" if += is
  # useable or anything else if it does not work.
  if test -z "$_G_HAVE_PLUSEQ_OP" &&  \
      __PLUSEQ_TEST="a" &&  \
      __PLUSEQ_TEST+=" b" 2>/dev/null &&  \
      test "a b" = "$__PLUSEQ_TEST"; then
    _G_HAVE_PLUSEQ_OP=yes
  fi

if test yes = "$_G_HAVE_PLUSEQ_OP"
then
  # This is an XSI compatible shell, allowing a faster implementation...
  eval 'func_append ()
  {
    $debug_cmd
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
include the following information:

       host-triplet:   $host
       shell:          $SHELL
       compiler:       $LTCC
       compiler flags: $LTCFLAGS
       linker:         $LD (gnu? $with_gnu_ld)
       version:        $progname $scriptversion Debian-2.4.7-5
       automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
       autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`

Report bugs to <bug-libtool@gnu.org>.
GNU libtool home page: <http://www.gnu.org/s/libtool/>.
General help using GNU software: <http://www.gnu.org/gethelp/>."
    exit 0







|







2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
include the following information:

       host-triplet:   $host
       shell:          $SHELL
       compiler:       $LTCC
       compiler flags: $LTCFLAGS
       linker:         $LD (gnu? $with_gnu_ld)
       version:        $progname $scriptversion Debian-2.4.7-7~deb12u1
       automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
       autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`

Report bugs to <bug-libtool@gnu.org>.
GNU libtool home page: <http://www.gnu.org/s/libtool/>.
General help using GNU software: <http://www.gnu.org/gethelp/>."
    exit 0
Changes to jni/curl/m4/curl-compilers.m4.
515
516
517
518
519
520
521

522
523
524
525
526
527
528
        #
      CLANG)
        #
        dnl Disable warnings for unused arguments, otherwise clang will
        dnl warn about compile-time arguments used during link-time, like
        dnl -O and -g and -pedantic.
        tmp_CFLAGS="$tmp_CFLAGS -Qunused-arguments"

        ;;
        #
      DEC_C)
        #
        dnl Select strict ANSI C compiler mode
        tmp_CFLAGS="$tmp_CFLAGS -std1"
        dnl Turn off optimizer ANSI C aliasing rules







>







515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
        #
      CLANG)
        #
        dnl Disable warnings for unused arguments, otherwise clang will
        dnl warn about compile-time arguments used during link-time, like
        dnl -O and -g and -pedantic.
        tmp_CFLAGS="$tmp_CFLAGS -Qunused-arguments"
        tmp_CFLAGS="$tmp_CFLAGS -Werror-implicit-function-declaration"
        ;;
        #
      DEC_C)
        #
        dnl Select strict ANSI C compiler mode
        tmp_CFLAGS="$tmp_CFLAGS -std1"
        dnl Turn off optimizer ANSI C aliasing rules
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
            CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [extra-semi-stmt])
          fi
          dnl clang 10 or later
          if test "$compiler_num" -ge "1000"; then
            tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough"  # we have silencing markup for clang 10.0 and above only
          fi
        fi
        dnl Disable pointer to bool conversion warnings since they cause
        dnl lib/securetransp.c cause several warnings for checks we want.
        dnl This option should be placed after -Wconversion.
        tmp_CFLAGS="$tmp_CFLAGS -Wno-pointer-bool-conversion"
        ;;
        #
      DEC_C)
        #
        if test "$want_warnings" = "yes"; then
          dnl Select a higher warning level than default level2
          tmp_CFLAGS="$tmp_CFLAGS -msg_enable level3"







<
<
<
<







894
895
896
897
898
899
900




901
902
903
904
905
906
907
            CURL_ADD_COMPILER_WARNINGS([tmp_CFLAGS], [extra-semi-stmt])
          fi
          dnl clang 10 or later
          if test "$compiler_num" -ge "1000"; then
            tmp_CFLAGS="$tmp_CFLAGS -Wimplicit-fallthrough"  # we have silencing markup for clang 10.0 and above only
          fi
        fi




        ;;
        #
      DEC_C)
        #
        if test "$want_warnings" = "yes"; then
          dnl Select a higher warning level than default level2
          tmp_CFLAGS="$tmp_CFLAGS -msg_enable level3"
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
      _sqz_result="$_sqz_result $_sqz_token"
    fi
  done
  eval [$]1=\$_sqz_result
  return 0
}
])


dnl CURL_CHECK_CURLDEBUG
dnl -------------------------------------------------
dnl Settings which depend on configure's curldebug given
dnl option, and other additional configure pre-requisites.
dnl Actually the curl debug memory tracking feature can
dnl only be used/enabled when libcurl is built as a static
dnl library or as a shared one on those systems on which
dnl shared libraries support undefined symbols.

AC_DEFUN([CURL_CHECK_CURLDEBUG], [
  AC_REQUIRE([XC_LIBTOOL])dnl
  AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl
  supports_curldebug="unknown"
  if test "$want_curldebug" = "yes"; then
    if test "x$enable_shared" != "xno" &&
      test "x$enable_shared" != "xyes"; then
      AC_MSG_WARN([unknown enable_shared setting.])
      supports_curldebug="no"
    fi
    if test "x$enable_static" != "xno" &&
      test "x$enable_static" != "xyes"; then
      AC_MSG_WARN([unknown enable_static setting.])
      supports_curldebug="no"
    fi
    if test "$supports_curldebug" != "no"; then
      if test "$enable_shared" = "yes" &&
        test "x$xc_lt_shlib_use_no_undefined" = 'xyes'; then
        supports_curldebug="no"
        AC_MSG_WARN([shared library does not support undefined symbols.])
      fi
    fi
  fi
  #
  if test "$want_curldebug" = "yes"; then
    AC_MSG_CHECKING([if curl debug memory tracking can be enabled])
    test "$supports_curldebug" = "no" || supports_curldebug="yes"
    AC_MSG_RESULT([$supports_curldebug])
    if test "$supports_curldebug" = "no"; then
      AC_MSG_WARN([cannot enable curl debug memory tracking.])
      want_curldebug="no"
    fi
  fi
])



dnl CURL_CHECK_COMPILER_HALT_ON_ERROR
dnl -------------------------------------------------
dnl Verifies if the compiler actually halts after the
dnl compilation phase without generating any object
dnl code file, when the source compiles with errors.







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1239
1240
1241
1242
1243
1244
1245














































1246
1247
1248
1249
1250
1251
1252
      _sqz_result="$_sqz_result $_sqz_token"
    fi
  done
  eval [$]1=\$_sqz_result
  return 0
}
])
















































dnl CURL_CHECK_COMPILER_HALT_ON_ERROR
dnl -------------------------------------------------
dnl Verifies if the compiler actually halts after the
dnl compilation phase without generating any object
dnl code file, when the source compiles with errors.
Changes to jni/curl/m4/curl-confopts.m4.
559
560
561
562
563
564
565

566
567
568
569
570
571
572
    ])

    if test "$want_ares" = "yes"; then
      dnl finally c-ares will be used
      AC_DEFINE(USE_ARES, 1, [Define to enable c-ares support])
      AC_DEFINE(CARES_NO_DEPRECATED, 1, [Ignore c-ares deprecation warnings])
      AC_SUBST([USE_ARES], [1])

      curl_res_msg="c-ares"
    fi
  fi
])

dnl CURL_CHECK_OPTION_NTLM_WB
dnl -------------------------------------------------







>







559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
    ])

    if test "$want_ares" = "yes"; then
      dnl finally c-ares will be used
      AC_DEFINE(USE_ARES, 1, [Define to enable c-ares support])
      AC_DEFINE(CARES_NO_DEPRECATED, 1, [Ignore c-ares deprecation warnings])
      AC_SUBST([USE_ARES], [1])
      LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE libcares"
      curl_res_msg="c-ares"
    fi
  fi
])

dnl CURL_CHECK_OPTION_NTLM_WB
dnl -------------------------------------------------
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
      curl_httpsrr_msg="no      (--enable-httpsrr)"
      AC_MSG_RESULT([no])
      ;;
    *)
      dnl --enable-httpsrr option used
      want_httpsrr="yes"
      curl_httpsrr_msg="enabled (--disable-httpsrr)"
      experimental="httpsrr"
      AC_MSG_RESULT([yes])
      ;;
  esac
])

dnl CURL_CHECK_OPTION_ECH
dnl -----------------------------------------------------







<







658
659
660
661
662
663
664

665
666
667
668
669
670
671
      curl_httpsrr_msg="no      (--enable-httpsrr)"
      AC_MSG_RESULT([no])
      ;;
    *)
      dnl --enable-httpsrr option used
      want_httpsrr="yes"
      curl_httpsrr_msg="enabled (--disable-httpsrr)"

      AC_MSG_RESULT([yes])
      ;;
  esac
])

dnl CURL_CHECK_OPTION_ECH
dnl -----------------------------------------------------
693
694
695
696
697
698
699
700
701
702
703
704
705
      curl_ech_msg="no      (--enable-ech)"
      AC_MSG_RESULT([no])
      ;;
    *)
      dnl --enable-ech option used
      want_ech="yes"
      curl_ech_msg="enabled (--disable-ech)"
      experimental="ech"
      AC_MSG_RESULT([yes])
      ;;
  esac
])
])







<





693
694
695
696
697
698
699

700
701
702
703
704
      curl_ech_msg="no      (--enable-ech)"
      AC_MSG_RESULT([no])
      ;;
    *)
      dnl --enable-ech option used
      want_ech="yes"
      curl_ech_msg="enabled (--disable-ech)"

      AC_MSG_RESULT([yes])
      ;;
  esac
])
])
Changes to jni/curl/m4/curl-functions.m4.
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
        AC_LANG_PROGRAM([[
        ]],[[
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
          return 0;
#elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
          return 0;
#else
          force compilation error
#endif
        ]])
      ],[
        tst_h_errno_sbs_issue_7="yes"
      ],[
        tst_h_errno_sbs_issue_7="no"
      ])







|







1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
        AC_LANG_PROGRAM([[
        ]],[[
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
          return 0;
#elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
          return 0;
#else
          #error force compilation error
#endif
        ]])
      ],[
        tst_h_errno_sbs_issue_7="yes"
      ],[
        tst_h_errno_sbs_issue_7="no"
      ])
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
    fi
  done
  if test $r -eq 0; then
    AC_MSG_ERROR([Failed to find size of $1])
  fi
  AC_MSG_RESULT($r)
  dnl lowercase and underscore instead of space
  tname=$(echo "ac_cv_sizeof_$1" | tr A-Z a-z | tr " " "_")
  eval "$tname=$r"

  AC_DEFINE_UNQUOTED(TYPE, [$r], [Size of $1 in number of bytes])

])







|





5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
    fi
  done
  if test $r -eq 0; then
    AC_MSG_ERROR([Failed to find size of $1])
  fi
  AC_MSG_RESULT($r)
  dnl lowercase and underscore instead of space
  tname=`echo "ac_cv_sizeof_$1" | tr A-Z a-z | tr " " "_"`
  eval "$tname=$r"

  AC_DEFINE_UNQUOTED(TYPE, [$r], [Size of $1 in number of bytes])

])
Changes to jni/curl/m4/curl-gnutls.m4.
122
123
124
125
126
127
128

129
130
131
132
133
134
135
          dnl due to this
          if test "x$cross_compiling" != "xyes"; then
            CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$gtlslib"
            export CURL_LIBRARY_PATH
            AC_MSG_NOTICE([Added $gtlslib to CURL_LIBRARY_PATH])
          fi
        fi

      fi

    fi

  fi dnl GNUTLS not disabled

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"







>







122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
          dnl due to this
          if test "x$cross_compiling" != "xyes"; then
            CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$gtlslib"
            export CURL_LIBRARY_PATH
            AC_MSG_NOTICE([Added $gtlslib to CURL_LIBRARY_PATH])
          fi
        fi
        LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE gnutls"
      fi

    fi

  fi dnl GNUTLS not disabled

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
Changes to jni/curl/m4/curl-mbedtls.m4.
97
98
99
100
101
102
103

104
105
106
107
108
109
110
        dnl due to this
        if test "x$cross_compiling" != "xyes"; then
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$mbedtlslib"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $mbedtlslib to CURL_LIBRARY_PATH])
        fi
      fi

    fi

  fi dnl mbedTLS not disabled

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi








>







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
        dnl due to this
        if test "x$cross_compiling" != "xyes"; then
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$mbedtlslib"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $mbedtlslib to CURL_LIBRARY_PATH])
        fi
      fi
      LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE mbedtls"
    fi

  fi dnl mbedTLS not disabled

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi

Changes to jni/curl/m4/curl-openssl.m4.
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
        AC_MSG_RESULT([yes])
        ssl_msg="AWS-LC"
        OPENSSL_IS_BORINGSSL=1
    ],[
        AC_MSG_RESULT([no])
    ])

    AC_MSG_CHECKING([for libressl])
    AC_COMPILE_IFELSE([
      AC_LANG_PROGRAM([[
#include <openssl/opensslv.h>
      ]],[[
        int dummy = LIBRESSL_VERSION_NUMBER;
      ]])
    ],[
      AC_MSG_RESULT([yes])
      AC_DEFINE_UNQUOTED(HAVE_LIBRESSL, 1,
        [Define to 1 if using libressl.])
      ssl_msg="libressl"
    ],[
      AC_MSG_RESULT([no])
    ])

    AC_MSG_CHECKING([for OpenSSL >= v3])
    AC_COMPILE_IFELSE([
      AC_LANG_PROGRAM([[







|









|
|







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
        AC_MSG_RESULT([yes])
        ssl_msg="AWS-LC"
        OPENSSL_IS_BORINGSSL=1
    ],[
        AC_MSG_RESULT([no])
    ])

    AC_MSG_CHECKING([for LibreSSL])
    AC_COMPILE_IFELSE([
      AC_LANG_PROGRAM([[
#include <openssl/opensslv.h>
      ]],[[
        int dummy = LIBRESSL_VERSION_NUMBER;
      ]])
    ],[
      AC_MSG_RESULT([yes])
      AC_DEFINE_UNQUOTED(HAVE_LIBRESSL, 1,
        [Define to 1 if using LibreSSL.])
      ssl_msg="LibreSSL"
    ],[
      AC_MSG_RESULT([no])
    ])

    AC_MSG_CHECKING([for OpenSSL >= v3])
    AC_COMPILE_IFELSE([
      AC_LANG_PROGRAM([[
347
348
349
350
351
352
353

354
355
356
357
358
359
360
       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_OPENSSL"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $LIB_OPENSSL to CURL_LIBRARY_PATH])
       fi
    fi
    check_for_ca_bundle=1

  fi

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi

if test X"$OPT_OPENSSL" != Xno &&
  test "$OPENSSL_ENABLED" != "1"; then







>







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
       if test "x$cross_compiling" != "xyes"; then
         CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_OPENSSL"
         export CURL_LIBRARY_PATH
         AC_MSG_NOTICE([Added $LIB_OPENSSL to CURL_LIBRARY_PATH])
       fi
    fi
    check_for_ca_bundle=1
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE openssl"
  fi

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi

if test X"$OPT_OPENSSL" != Xno &&
  test "$OPENSSL_ENABLED" != "1"; then
424
425
426
427
428
429
430
431
432
433
434
435



436
437
438
439
440
441
442
443
444
445
446
])
fi

dnl ---
dnl We may use OpenSSL QUIC.
dnl ---
if test "$OPENSSL_ENABLED" = "1"; then
  AC_MSG_CHECKING([for QUIC support in OpenSSL])
  AC_LINK_IFELSE([
    AC_LANG_PROGRAM([[
#include <openssl/ssl.h>
    ]],[[



      OSSL_QUIC_client_method();
    ]])
  ],[
    AC_MSG_RESULT([yes])
    AC_DEFINE(HAVE_OPENSSL_QUIC, 1, [if you have the functions OSSL_QUIC_client_method])
    AC_SUBST(HAVE_OPENSSL_QUIC, [1])
  ],[
    AC_MSG_RESULT([no])
  ])
fi
])







|




>
>
>











425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
])
fi

dnl ---
dnl We may use OpenSSL QUIC.
dnl ---
if test "$OPENSSL_ENABLED" = "1"; then
  AC_MSG_CHECKING([for QUIC support and OpenSSL >= 3.3])
  AC_LINK_IFELSE([
    AC_LANG_PROGRAM([[
#include <openssl/ssl.h>
    ]],[[
      #if (OPENSSL_VERSION_NUMBER < 0x30300000L)
      #error need at least version 3.3.0
      #endif
      OSSL_QUIC_client_method();
    ]])
  ],[
    AC_MSG_RESULT([yes])
    AC_DEFINE(HAVE_OPENSSL_QUIC, 1, [if you have the functions OSSL_QUIC_client_method])
    AC_SUBST(HAVE_OPENSSL_QUIC, [1])
  ],[
    AC_MSG_RESULT([no])
  ])
fi
])
Changes to jni/curl/m4/curl-reentrant.m4.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    AC_COMPILE_IFELSE([
      AC_LANG_PROGRAM([[
#include <errno.h>
      ]],[[
#ifdef errno
        int dummy=1;
#else
        force compilation error
#endif
      ]])
    ],[
      tmp_errno="errno_macro_defined"
    ],[
      AC_COMPILE_IFELSE([
        AC_LANG_PROGRAM([[
#define _REENTRANT
#include <errno.h>
        ]],[[
#ifdef errno
          int dummy=1;
#else
          force compilation error
#endif
        ]])
      ],[
        tmp_errno="errno_macro_needs_reentrant"
        tmp_need_reentrant="yes"
      ])
    ])







|













|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    AC_COMPILE_IFELSE([
      AC_LANG_PROGRAM([[
#include <errno.h>
      ]],[[
#ifdef errno
        int dummy=1;
#else
        #error force compilation error
#endif
      ]])
    ],[
      tmp_errno="errno_macro_defined"
    ],[
      AC_COMPILE_IFELSE([
        AC_LANG_PROGRAM([[
#define _REENTRANT
#include <errno.h>
        ]],[[
#ifdef errno
          int dummy=1;
#else
          #error force compilation error
#endif
        ]])
      ],[
        tmp_errno="errno_macro_needs_reentrant"
        tmp_need_reentrant="yes"
      ])
    ])
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  AC_MSG_CHECKING([if _REENTRANT is already defined])
  AC_COMPILE_IFELSE([
    AC_LANG_PROGRAM([[
    ]],[[
#ifdef _REENTRANT
      int dummy=1;
#else
      force compilation error
#endif
    ]])
  ],[
    AC_MSG_RESULT([yes])
    tmp_reentrant_initially_defined="yes"
  ],[
    AC_MSG_RESULT([no])







|







409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  AC_MSG_CHECKING([if _REENTRANT is already defined])
  AC_COMPILE_IFELSE([
    AC_LANG_PROGRAM([[
    ]],[[
#ifdef _REENTRANT
      int dummy=1;
#else
      #error force compilation error
#endif
    ]])
  ],[
    AC_MSG_RESULT([yes])
    tmp_reentrant_initially_defined="yes"
  ],[
    AC_MSG_RESULT([no])
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  AC_MSG_CHECKING([if _THREAD_SAFE is already defined])
  AC_COMPILE_IFELSE([
    AC_LANG_PROGRAM([[
    ]],[[
#ifdef _THREAD_SAFE
      int dummy=1;
#else
      force compilation error
#endif
    ]])
  ],[
    AC_MSG_RESULT([yes])
    tmp_thread_safe_initially_defined="yes"
  ],[
    AC_MSG_RESULT([no])







|







469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
  AC_MSG_CHECKING([if _THREAD_SAFE is already defined])
  AC_COMPILE_IFELSE([
    AC_LANG_PROGRAM([[
    ]],[[
#ifdef _THREAD_SAFE
      int dummy=1;
#else
      #error force compilation error
#endif
    ]])
  ],[
    AC_MSG_RESULT([yes])
    tmp_thread_safe_initially_defined="yes"
  ],[
    AC_MSG_RESULT([no])
Changes to jni/curl/m4/curl-rustls.m4.
168
169
170
171
172
173
174

175
176
177
178
179
180
181
      dnl fail due to this
      if test "x$cross_compiling" != "xyes"; then
        CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_RUSTLS"
        export CURL_LIBRARY_PATH
        AC_MSG_NOTICE([Added $LIB_RUSTLS to CURL_LIBRARY_PATH])
      fi
    fi

  fi

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"

  if test X"$OPT_RUSTLS" != Xno &&
    test "$RUSTLS_ENABLED" != "1"; then
    AC_MSG_NOTICE([OPT_RUSTLS: $OPT_RUSTLS])







>







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
      dnl fail due to this
      if test "x$cross_compiling" != "xyes"; then
        CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$LIB_RUSTLS"
        export CURL_LIBRARY_PATH
        AC_MSG_NOTICE([Added $LIB_RUSTLS to CURL_LIBRARY_PATH])
      fi
    fi
    LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE rustls"
  fi

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"

  if test X"$OPT_RUSTLS" != Xno &&
    test "$RUSTLS_ENABLED" != "1"; then
    AC_MSG_NOTICE([OPT_RUSTLS: $OPT_RUSTLS])
Changes to jni/curl/m4/curl-sysconfig.m4.
24
25
26
27
28
29
30

31
32
33
34
35
36
37

AC_DEFUN([CURL_DARWIN_SYSTEMCONFIGURATION], [
AC_MSG_CHECKING([whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks])
case $host_os in
  darwin*)
    AC_COMPILE_IFELSE([
      AC_LANG_PROGRAM([[

#include <TargetConditionals.h>
      ]],[[
#if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
      return 0;
#else
#error Not macOS
#endif







>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

AC_DEFUN([CURL_DARWIN_SYSTEMCONFIGURATION], [
AC_MSG_CHECKING([whether to link macOS CoreFoundation, CoreServices, and SystemConfiguration frameworks])
case $host_os in
  darwin*)
    AC_COMPILE_IFELSE([
      AC_LANG_PROGRAM([[
#include <sys/types.h>
#include <TargetConditionals.h>
      ]],[[
#if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
      return 0;
#else
#error Not macOS
#endif
Changes to jni/curl/m4/curl-wolfssl.m4.
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
      my_ac_save_LIBS="$LIBS"
      LIBS="$addlib $LIBS"
      AC_MSG_NOTICE([Add $addlib to LIBS])

      AC_MSG_CHECKING([for wolfSSL_Init in -lwolfssl])
      AC_LINK_IFELSE([
        AC_LANG_PROGRAM([[
/* These aren't needed for detection and confuse WolfSSL.
   They are set up properly later if it is detected.  */
#undef SIZEOF_LONG
#undef SIZEOF_LONG_LONG
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
        ]],[[
          return wolfSSL_Init();
        ]])
      ],[
         AC_MSG_RESULT(yes)
         AC_DEFINE(USE_WOLFSSL, 1, [if wolfSSL is enabled])
         AC_SUBST(USE_WOLFSSL, [1])
         WOLFSSL_ENABLED=1
         USE_WOLFSSL="yes"
         ssl_msg="WolfSSL"
         QUIC_ENABLED=yes
         test wolfssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes
       ],
       [
         AC_MSG_RESULT(no)
         CPPFLAGS=$_cppflags
         LDFLAGS=$_ldflags







|














|







87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
      my_ac_save_LIBS="$LIBS"
      LIBS="$addlib $LIBS"
      AC_MSG_NOTICE([Add $addlib to LIBS])

      AC_MSG_CHECKING([for wolfSSL_Init in -lwolfssl])
      AC_LINK_IFELSE([
        AC_LANG_PROGRAM([[
/* These are not needed for detection and confuse wolfSSL.
   They are set up properly later if it is detected.  */
#undef SIZEOF_LONG
#undef SIZEOF_LONG_LONG
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
        ]],[[
          return wolfSSL_Init();
        ]])
      ],[
         AC_MSG_RESULT(yes)
         AC_DEFINE(USE_WOLFSSL, 1, [if wolfSSL is enabled])
         AC_SUBST(USE_WOLFSSL, [1])
         WOLFSSL_ENABLED=1
         USE_WOLFSSL="yes"
         ssl_msg="wolfSSL"
         QUIC_ENABLED=yes
         test wolfssl != "$DEFAULT_SSL_BACKEND" || VALID_DEFAULT_SSL_BACKEND=yes
       ],
       [
         AC_MSG_RESULT(no)
         CPPFLAGS=$_cppflags
         LDFLAGS=$_ldflags
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
      check_for_ca_bundle=1

      dnl wolfssl/ctaocrypt/types.h needs SIZEOF_LONG_LONG defined!
      CURL_SIZEOF(long long)

      LIBS="$addlib -lm $LIBS"

      dnl WolfSSL needs configure --enable-opensslextra to have *get_peer*
      dnl DES* is needed for NTLM support and lives in the OpenSSL compatibility
      dnl layer
      AC_CHECK_FUNCS(wolfSSL_get_peer_certificate \
                     wolfSSL_UseALPN )

      dnl if this symbol is present, we want the include path to include the
      dnl OpenSSL API root as well







|







124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
      check_for_ca_bundle=1

      dnl wolfssl/ctaocrypt/types.h needs SIZEOF_LONG_LONG defined!
      CURL_SIZEOF(long long)

      LIBS="$addlib -lm $LIBS"

      dnl wolfSSL needs configure --enable-opensslextra to have *get_peer*
      dnl DES* is needed for NTLM support and lives in the OpenSSL compatibility
      dnl layer
      AC_CHECK_FUNCS(wolfSSL_get_peer_certificate \
                     wolfSSL_UseALPN )

      dnl if this symbol is present, we want the include path to include the
      dnl OpenSSL API root as well
160
161
162
163
164
165
166

167
168
169
170
171
172
173
174
175
176
        dnl due to this
        if test "x$cross_compiling" != "xyes"; then
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$wolfssllibpath"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $wolfssllibpath to CURL_LIBRARY_PATH])
        fi
      fi

    else
        AC_MSG_ERROR([--with-wolfssl but wolfSSL was not found or doesn't work])
    fi

  fi dnl wolfSSL not disabled

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi

])







>










160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
        dnl due to this
        if test "x$cross_compiling" != "xyes"; then
          CURL_LIBRARY_PATH="$CURL_LIBRARY_PATH:$wolfssllibpath"
          export CURL_LIBRARY_PATH
          AC_MSG_NOTICE([Added $wolfssllibpath to CURL_LIBRARY_PATH])
        fi
      fi
      LIBCURL_PC_REQUIRES_PRIVATE="$LIBCURL_PC_REQUIRES_PRIVATE wolfssl"
    else
        AC_MSG_ERROR([--with-wolfssl but wolfSSL was not found or doesn't work])
    fi

  fi dnl wolfSSL not disabled

  test -z "$ssl_msg" || ssl_backends="${ssl_backends:+$ssl_backends, }$ssl_msg"
fi

])
Changes to jni/curl/packages/Makefile.in.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







105
106
107
108
109
110
111

112
113
114
115
116
117
118
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
287
288
289
290
291
292
293


294
295
296
297
298
299
300
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
Changes to jni/curl/packages/OS400/curl.inc.in.
439
440
441
442
443
444
445
446


447


448
449
450
451
452
453
454
     d                 c                   X'00000100'
     d CURLU_GUESS_SCHEME...
     d                 c                   X'00000200'
     d CURLU_NO_AUTHORITY...
     d                 c                   X'00000400'
     d CURLU_ALLOW_SPACE...
     d                 c                   X'00000800'
     d CURLU_PUNYCODE...


     d                 c                   X'00001000'


      *
     d CURLOT_FLAG_ALIAS...
     d                 c                   X'00000001'
      *
     d CURLH_HEADER    c                   X'00000001'
     d CURLH_TRAILER   c                   X'00000002'
     d CURLH_CONNECT   c                   X'00000004'







|
>
>
|
>
>







439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
     d                 c                   X'00000100'
     d CURLU_GUESS_SCHEME...
     d                 c                   X'00000200'
     d CURLU_NO_AUTHORITY...
     d                 c                   X'00000400'
     d CURLU_ALLOW_SPACE...
     d                 c                   X'00000800'
     d CURLU_PUNYCODE  c                   X'00001000'
     d CURLU_PUNY2IDN  c                   X'00002000'
     d CURLU_GET_EMPTY...
     d                 c                   X'00004000'
     d CURLU_NO_GUESS_SCHEME...
     d                 c                   X'00008000'
      *
     d CURLOT_FLAG_ALIAS...
     d                 c                   X'00000001'
      *
     d CURLH_HEADER    c                   X'00000001'
     d CURLH_TRAILER   c                   X'00000002'
     d CURLH_CONNECT   c                   X'00000004'
1662
1663
1664
1665
1666
1667
1668


1669
1670
1671
1672
1673
1674
1675
     d  CURLOPT_QUICK_EXIT...
     d                 c                   00322
     d  CURLOPT_HAPROXY_CLIENT_IP...
     d                 c                   10323
     d  CURLOPT_SERVER_RESPONSE_TIMEOUT_MS...
     d                 c                   00324
     d  CURLOPT_ECH    c                   10325


      *
      /if not defined(CURL_NO_OLDIES)
     d  CURLOPT_FILE   c                   10001
     d  CURLOPT_INFILE...
     d                 c                   10009
     d  CURLOPT_SSLKEYPASSWD...
     d                 c                   10026







>
>







1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
     d  CURLOPT_QUICK_EXIT...
     d                 c                   00322
     d  CURLOPT_HAPROXY_CLIENT_IP...
     d                 c                   10323
     d  CURLOPT_SERVER_RESPONSE_TIMEOUT_MS...
     d                 c                   00324
     d  CURLOPT_ECH    c                   10325
     d  CURLOPT_TCP_KEEPCNT...
     d                 c                   00326
      *
      /if not defined(CURL_NO_OLDIES)
     d  CURLOPT_FILE   c                   10001
     d  CURLOPT_INFILE...
     d                 c                   10009
     d  CURLOPT_SSLKEYPASSWD...
     d                 c                   10026
jni/curl/packages/OS400/initscript.sh became executable.
jni/curl/packages/OS400/make-include.sh became executable.
jni/curl/packages/OS400/make-lib.sh became executable.
jni/curl/packages/OS400/make-src.sh became executable.
jni/curl/packages/OS400/make-tests.sh became executable.
jni/curl/packages/OS400/makefile.sh became executable.
Changes to jni/curl/packages/vms/Makefile.in.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







105
106
107
108
109
110
111

112
113
114
115
116
117
118
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
229
230
231
232
233
234
235


236
237
238
239
240
241
242
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
Changes to jni/curl/packages/vms/compare_curl_source.com.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$!     3. Keep a copy directory up to date.  The third is needed by
$!        me because VMS Backup can create a saveset of files from a
$!        NFS mounted volume.
$!
$! First the files in the original source directory which is assumed to be
$! under source code control are compared with the copy directory.
$!
$! Then the files are are only in the copy directory are listed.
$!
$! The result will five diagnostics about of files:
$!    1. Files that are not generation 1.
$!    2. Files missing in the copy directory.
$!    3. Files in the copy directory not in the source directory.
$!    4. Files different from the source directory.
$!    5. Files that VMS DIFF can not process.
$!
$! This needs to be run on an ODS-5 volume.







|

|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$!     3. Keep a copy directory up to date.  The third is needed by
$!        me because VMS Backup can create a saveset of files from a
$!        NFS mounted volume.
$!
$! First the files in the original source directory which is assumed to be
$! under source code control are compared with the copy directory.
$!
$! Only files present in the copy directory are listed.
$!
$! Diagnostics are displayed about the files:
$!    1. Files that are not generation 1.
$!    2. Files missing in the copy directory.
$!    3. Files in the copy directory not in the source directory.
$!    4. Files different from the source directory.
$!    5. Files that VMS DIFF can not process.
$!
$! This needs to be run on an ODS-5 volume.
Changes to jni/curl/packages/vms/config_h.com.
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
$if p1 .nes. ""
$then
$   cfile = p1
$else
$   cfile = f$search("sys$disk:[]config.h.in")
$   if cfile .eqs. ""
$   then
$	cfile = f$search("sys$disk:[]config.h_in")
$	if cfile .eqs. ""
$	then
$	    cfile = f$search("sys$disk:[]configh.in")
$	    if cfile .eqs. ""
$	    then
$		cfile = f$search("sys$disk:[]config__2eh.in")
$		if cfile .eqs. ""
$		then
$		    cfile = f$search("sys$disk:[]config.h__2ein")
$		endif
$	    endif
$	endif
$   endif
$endif
$if f$trnlnm("PRJ_INCLUDE") .nes. ""
$then
$   cfile = f$search("PRJ_INCLUDE:config.h.in")
$   if cfile .eqs. ""
$   then
$	cfile = f$search("PRJ_INCLUDE:config.h_in")
$	if cfile .eqs. ""
$	then
$	    cfile = f$search("PRJ_INCLUDE:config__2eh.in")
$	    if cfile .eqs. ""
$	    then
$		cfile = f$search("PRJ_INCLUDE:config__2eh.in")
$		if cfile .eqs. ""
$		then
$		    cfile = f$search("PRJ_INCLUDE:config.h__2ein")
$		endif
$	    endif
$	endif
$    endif
$endif
$if cfile .eqs. ""
$then
$   write sys$output "Can not find sys$disk:config.h.in"
$   line_out = "Looked for config.h.in, config.h_in, configh.in, "
$   line_out = line_out + "config__2eh.in, config.h__2ein"
$   write/symbol sys$output line_out
$   if f$trnlnm("PRJ_INCLUDE") .nes. ""
$   then
$	write sys$output "Also looked in PRJ_INCLUDE: for these files."
$   endif
$!
$   write tf ""
$   write tf -
	"   /* Could not find sys$disk:config.h.in                           */"
$   write tf -
	"  /*  Looked also for config.h_in, configh.in, config__2eh.in,     */"
$   write tf -
	" /*   config.h__2ein						   */"
$   if f$trnlnm("PRJ_INCLUDE") .nes. ""
$   then
$	write tf -
	" /* Also looked in PRJ_INCLUDE: for these files.		  */"
$   endif
$   write tf -
	"/*--------------------------------------------------------------*/
$   write tf ""
$   goto write_tail
$endif
$!
$!
$! Locate the DECC libraries in use
$!-----------------------------------







|
|
|
|
|
|
|
|
|
|
|
|
|







|
|
|
|
|
|
|
|
|
|
|
|
|










|




|

|

|


|
|


|







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
$if p1 .nes. ""
$then
$   cfile = p1
$else
$   cfile = f$search("sys$disk:[]config.h.in")
$   if cfile .eqs. ""
$   then
$       cfile = f$search("sys$disk:[]config.h_in")
$       if cfile .eqs. ""
$       then
$           cfile = f$search("sys$disk:[]configh.in")
$           if cfile .eqs. ""
$           then
$               cfile = f$search("sys$disk:[]config__2eh.in")
$               if cfile .eqs. ""
$               then
$                   cfile = f$search("sys$disk:[]config.h__2ein")
$               endif
$           endif
$       endif
$   endif
$endif
$if f$trnlnm("PRJ_INCLUDE") .nes. ""
$then
$   cfile = f$search("PRJ_INCLUDE:config.h.in")
$   if cfile .eqs. ""
$   then
$       cfile = f$search("PRJ_INCLUDE:config.h_in")
$       if cfile .eqs. ""
$       then
$           cfile = f$search("PRJ_INCLUDE:config__2eh.in")
$           if cfile .eqs. ""
$           then
$               cfile = f$search("PRJ_INCLUDE:config__2eh.in")
$               if cfile .eqs. ""
$               then
$                   cfile = f$search("PRJ_INCLUDE:config.h__2ein")
$               endif
$           endif
$       endif
$    endif
$endif
$if cfile .eqs. ""
$then
$   write sys$output "Can not find sys$disk:config.h.in"
$   line_out = "Looked for config.h.in, config.h_in, configh.in, "
$   line_out = line_out + "config__2eh.in, config.h__2ein"
$   write/symbol sys$output line_out
$   if f$trnlnm("PRJ_INCLUDE") .nes. ""
$   then
$       write sys$output "Also looked in PRJ_INCLUDE: for these files."
$   endif
$!
$   write tf ""
$   write tf -
        "   /* Could not find sys$disk:config.h.in                           */"
$   write tf -
        "  /*  Looked also for config.h_in, configh.in, config__2eh.in,     */"
$   write tf -
        " /*   config.h__2ein                                              */"
$   if f$trnlnm("PRJ_INCLUDE") .nes. ""
$   then
$       write tf -
        " /* Also looked in PRJ_INCLUDE: for these files.                 */"
$   endif
$   write tf -
        "/*--------------------------------------------------------------*/
$   write tf ""
$   goto write_tail
$endif
$!
$!
$! Locate the DECC libraries in use
$!-----------------------------------
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
$   read/end=cfgh_in_loop1_end inf line_in
$   xline = f$edit(line_in,"TRIM,COMPRESS")
$!
$!  Blank line handling
$!---------------------
$   if xline .eqs. ""
$   then
$	write tf ""
$	goto cfgh_in_loop1
$   endif
$   xlen = f$length(xline)
$   key = f$extract(0,2,xline)
$!
$!  deal with comments by copying exactly
$!-----------------------------------------
$   if (do_comment .eq. 1) .or. (key .eqs. "/*")
$   then
$	do_comment = 1
$	write tf line_in
$	key = f$extract(xlen - 2, 2, xline)
$	if key .eqs. "*/" then do_comment = 0
$	goto cfgh_in_loop1
$   endif
$!
$!  Some quick parsing
$!----------------------
$   keyif = f$extract(0,3,xline)
$   key1 = f$element(0," ",xline)
$   key2 = f$element(1," ",xline)







|
|








|
|
|
|
|







240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
$   read/end=cfgh_in_loop1_end inf line_in
$   xline = f$edit(line_in,"TRIM,COMPRESS")
$!
$!  Blank line handling
$!---------------------
$   if xline .eqs. ""
$   then
$       write tf ""
$       goto cfgh_in_loop1
$   endif
$   xlen = f$length(xline)
$   key = f$extract(0,2,xline)
$!
$!  deal with comments by copying exactly
$!-----------------------------------------
$   if (do_comment .eq. 1) .or. (key .eqs. "/*")
$   then
$       do_comment = 1
$       write tf line_in
$       key = f$extract(xlen - 2, 2, xline)
$       if key .eqs. "*/" then do_comment = 0
$       goto cfgh_in_loop1
$   endif
$!
$!  Some quick parsing
$!----------------------
$   keyif = f$extract(0,3,xline)
$   key1 = f$element(0," ",xline)
$   key2 = f$element(1," ",xline)
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999

1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110

1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
$!
$!write sys$output "xline = ''xline'"
$!
$!  Comment out this section of the ifblock
$!-----------------------------------------
$   if if_block .ge. 3
$   then
$	write tf "/* ", xline, " */"
$	if keyif .eqs. "#en" then if_block = 0
$	goto cfgh_in_loop1
$   endif
$!
$!  Handle the end of an ifblock
$!-------------------------------
$   if keyif .eqs. "#en"
$   then
$	write tf xline
$	if_block = 0
$	goto cfgh_in_loop1
$   endif
$!
$   if key1 .eqs. "#ifndef"
$   then
$!	Manual check for _ALL_SOURCE on AIX error
$!-----------------------------------------------
$	if key2 .eqs. "_ALL_SOURCE"
$	then
$	   write tf "/* ", xline, " */"
$!
$!	   Ignore the rest of the block
$!--------------------------------------
$	   if_block = 3
$	   goto cfgh_in_loop1
$	endif
$   endif
$!
$!
$!  Default action for an #if/#else/#endif
$!------------------------------------------
$   if keyif .eqs. "#if" .or. keyif .eqs. "#el"
$   then
$	if_block = 1
$	write tf xline
$	goto cfgh_in_loop1
$   endif
$!
$!
$!  Process "normal?" stuff
$!---------------------------
$   if key1 .eqs. "#undef"
$   then
$	key2c = f$element(2, "_", key2)
$	if (key2c .eqs. "_") .or. (key2c .eqs. "H") then key2c = ""
$	key2d = f$element(3, "_", key2)
$	if (key2d .eqs. "_") .or. (key2d .eqs. "H") then key2d = ""
$	key2e = f$element(4, "_", key2)
$	if (key2e .eqs. "_") .or. (key2e .eqs. "H") then key2e = ""
$	if key2d .eqs. "T"
$	then
$	    if key2e .eqs. "TYPE"
$	    then
$		key2_h = "_T"
$		key2d = ""
$	    endif
$	endif
$!
$	double_under = 0
$!
$!	Process FCNTL directives
$!-------------------------------------
$	if (key2b .eqs. "FCNTL") .and. (key2c .eqs. "O") .and. -
	   (key2d .eqs. "NONBLOCK")
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Process GETADDRINFO directives
$!-------------------------------------
$	if key2 .eqs. "GETADDRINFO_THREADSAFE"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Process IOCTL directives
$!-------------------------------------
$	if (key2b .eqs. "IOCTL") .and. (key2c .nes. "")
$	then
$	    if (key2c .eqs. "FIONBIO") .or. (key2c .eqs. "SIOCGIFADDR")
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' 1"
$		write tf "#endif"
$		goto cfgh_in_loop1

$	    endif
$	endif
$!
$!
$!	Manual check for LL on
$!-----------------------------------------------
$	if key2 .eqs. "LL"
$	then
$	   write tf "#ifndef __VAX
$	   write tf "#define HAVE_''key2' 1"
$	   write tf "#endif"
$	   goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "bool_t"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' short"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "bits16_t"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' short"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "u_bits16_t"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' unsigned short"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "bits32_t"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' int"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "u_bits32_t"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' unsigned int"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "intmax_t"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#ifdef __VAX"
$	    write tf "#define ''key2' long"
$	    write tf "#else"
$	    write tf "#define ''key2' long long"
$	    write tf "#endif"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "uintmax_t"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#ifdef __VAX"
$	    write tf "#define ''key2' unsigned long"
$	    write tf "#else"
$	    write tf "#define ''key2' unsigned long long"
$	    write tf "#endif"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "socklen_t"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' int"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "GETGROUPS_T"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' gid_t"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_SYS_SIGLIST"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 0"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_SYS_ERRLIST"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_STRUCT_DIRENT_D_INO"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_STRUCT_TIMEVAL"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	! The header files have this information, however
$!      ! The ioctl() call only works on sockets.
$!	if key2 .eqs. "FIONREAD_IN_SYS_IOCTL"
$!	then
$!	    write tf "#ifndef ''key2'"
$!	    write tf "#define ''key2' 1"
$!	    write tf "#endif"
$!	    goto cfgh_in_loop1
$!	endif
$!
$!	! The header files have this information, however
$!      ! The ioctl() call only works on sockets.
$!	if key2 .eqs. "GWINSZ_IN_SYS_IOCTL"
$!	then
$!	    write tf "#ifndef ''key2'"
$!	    write tf "#define ''key2' 1"
$!	    write tf "#endif"
$!	    goto cfgh_in_loop1
$!	endif
$!
$!	! The header files have this information, however
$!      ! The ioctl() call only works on sockets.
$!	if key2 .eqs. "STRUCT_WINSIZE_IN_SYS_IOCTL"
$!	then
$!	    write tf "#ifndef ''key2'"
$!	    write tf "#define ''key2' 0"
$!	    write tf "#endif"
$!	    goto cfgh_in_loop1
$!	endif
$!
$	if key2 .eqs. "HAVE_STRUCT_TM_TM_ZONE"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_TM_ZONE"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_TIMEVAL"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "WEXITSTATUS_OFFSET"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 2"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_GETPW_DECLS"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_CONFSTR"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_PRINTF"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_SBRK"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_STRSIGNAL"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 0"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2a .eqs. "HAVE_DECL_STRTOLD"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 0"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_STRTOIMAX"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 0"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_STRTOL"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_STRTOLL"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_STRTOUL"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_STRTOULL"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_STRTOUMAX"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 0"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "GETPGRP_VOID"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "NAMED_PIPES_MISSING"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "OPENDIR_NOT_ROBUST"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "PGRP_PIPE"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "CAN_REDEFINE_GETENV"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_PRINTF_A_FORMAT"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "CTYPE_NON_ASCII"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_LANGINFO_CODESET"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 0"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!      This wants execve() to do this automagically to pass.
$!	if key2 .eqs. "HAVE_HASH_BANG_EXEC"
$!	then
$!	    write tf "#ifndef ''key2'"
$!	    write tf "#define ''key2' 1"
$!	    write tf "#endif"
$!	    goto cfgh_in_loop1
$!	endif
$!
$	if key2 .eqs. "ICONV_CONST"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2'"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "VOID_SIGHANDLER"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_POSIX_SIGNALS"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "UNUSABLE_RT_SIGNALS"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2a .eqs. "HAVE_DECL_FPURGE"
$	then
$	    write tf "#ifndef ''key2a'"
$	    write tf "#define ''key2a' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_DECL_SETREGID"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "HAVE_POSIX_SIGSETJMP"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2b .eqs. "RAND" .and. key2c .nes. "" .and. key2d .eqs. ""
$	then
$	    if (key2c .eqs. "EGD") .or. -
	       (key2c .eqs. "STATUS") .or. -
	       (key2c .eqs. "SCREEN")
$	    then
$		if f$search("''ssl_header_dir'rand.h") .nes. ""
$		then
$		    write tf "#ifndef ''key2'"
$		    write tf "#define ''key2' 1"
$		    write tf "#endif"
$		else
$		    write tf "/* #undef ''key2' */"
$		endif
$	    endif
$	endif
$!
$	if key2 .eqs. "STRCOLL_BROKEN"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$	if key2 .eqs. "DUP_BROKEN"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#define ''key2' 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	This is for a test that getcwd(0,0) works.
$!	It does not on VMS.
$!--------------------------
$	if key2 .eqs. "GETCWD_BROKEN"
$	then
$	    write sys$output ""
$	    write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being tested for!"
$		   write sys$output -
 "-CONFIG_H-I-GETCWD, GETCWD(0,0) does not work on VMS."
$		   write sys$output -
 "-CONFIG_H-I-GETCWD2, Work around hack probably required."
$		   write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$		    if update_config_vms
$		    then
$			open/append tfcv sys$disk:[]config_vms.h
$			write tfcv ""
$			write tfcv -
		"/* Check config.h for use of ''key2' settings */"
$			write tfcv ""
$			close tfcv
$		    endif
$
$	    goto cfgh_in_loop1
$	endif
$!
$	if (key2a .eqs. "HAVE") .or. (key2a .eqs. "STAT") .or. -
	   (key2 .eqs. "USE_IPV6") .or. (key2b .eqs. "LDAP")
$	then
$!
$!	    Process extra underscores
$!------------------------------------
$	    if f$locate("HAVE___", key2) .lt. key2_len
$	    then
$		key2b = "__" + key2d
$		key2d = ""
$		double_under = 1
$	    else
$		if f$locate("HAVE__", key2) .lt. key2_len
$		then
$		    key2b = "_" + key2c
$		    key2c = ""
$		    double_under = 1
$		endif
$	    endif
$!
$	    if (key2_h .eqs. "_H") .or. (key2 .eqs. "USE_IPV6") .or. -
	       (key2b .eqs. "LDAP")
$	    then
$!
$!		Looking for a header file
$!---------------------------------------
$		headf = key2b
$		if key2c .nes. "" then headf = headf + "_" + key2c
$		if key2d .nes. "" then headf = headf + "_" + key2d
$!
$!		   (key2b .eqs. "READLINE")
$!
$!		Some special parsing
$!------------------------------------------
$		if (key2b .eqs. "SYS") .or. (key2b .eqs. "ARPA") .or. -
		   (key2b .eqs. "NET") .or. (key2b .eqs. "NETINET")
$		then
$		    if key2c .nes. ""
$		    then
$			headf = key2c
$			if key2d .nes. "" then headf = key2c + "_" + key2d
$		    endif
$		endif
$!
$!		And of course what's life with out some special cases
$!--------------------------------------------------------------------
$		if key2 .eqs. "USE_IPV6"
$		then
$		    headf = "in6"
$		endif
$!
$		if key2b .eqs. "LDAP"
$		then
$		    if (key2 .eqs. "HAVE_LDAP_SSL") .or. -
		       (key2 .eqs. "HAVE_LDAP_URL_PARSE")
$		    then
$			headf = "ldap"
$		    endif
$		endif
$!
$!
$		if key2b .eqs. "FILE"
$		then
$		   write sys$output ""
$		   write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!"
$		   write sys$output -
 "-CONFIG_H-I-FILE_OLD, file.h will not be configured as is obsolete!"
$		   write sys$output -
 "-CONFIG_H_I-FCNTL_NEW, "Expecting fcntl.h to be configured instead!"
$		   write sys$output -
 "-CONFIG_H_I-FCNTL_CHK, "Unable to verify at this time!"
$		   write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$!
$		    if update_config_vms
$		    then
$			open/append tfcv sys$disk:[]config_vms.h
$			write tfcv ""
$			write tfcv -
		"/* Check config.h for use of fcntl.h instead of file.h */"
$			write tfcv ""
$			close tfcv
$		    endif
$		endif
$!
$!		Now look it up in the DEC C RTL
$!---------------------------------------------
$		define/user sys$output nl:
$		define/user sys$error nl:
$		search/output=nl: 'dchfile' |'headf'|/exact
$		if '$severity' .eq. 1
$		then
$		    if key64 then write tf "#ifndef __VAX"
$		    write tf "#ifndef ''key2'"
$		    write tf "#define ''key2' 1"
$if p2 .nes. "" then write sys$output "''dchfile' - #define ''key2' 1"
$		    write tf "#endif"
$		    if key64 then write tf "#endif"
$set nover
$		    goto cfgh_in_loop1
$		endif
$!
$!
$!		Now look it up in the DEC C STARLET_C
$!---------------------------------------------
$		define/user sys$output nl:
$		define/user sys$error nl:
$		search/output=nl: 'starhfile' |'headf'|/exact
$		if '$severity' .eq. 1
$		then
$		    if key64 then write tf "#ifndef __VAX"
$		    write tf "#ifndef ''key2'"
$		    write tf "#define ''key2' 1"
$if p2 .nes. "" then write sys$output "''starfile' - #define ''key2' 1"
$		    write tf "#endif"
$		    if key64 then write tf "#endif"
$set nover
$		    goto cfgh_in_loop1
$		endif
$!
$!		Now look for OPENSSL headers
$!---------------------------------------------------------
$		if key2b .eqs. "OPENSSL"
$		then
$		    headf = headf - "OPENSSL_"
$		    header = f$search("''ssl_header_dir'''headf'.h")
$		    if header .nes. ""
$		    then
$			write tf "#ifndef ''key2'"
$			write tf "#define ''key2' 1"
$			write tf "#endif"
$set nover
$			goto cfgh_in_loop1
$		    endif
$		endif
$!
$!		Now look for Kerberos
$!------------------------------------------------------------
$		if key2b .eqs. "GSSAPI"
$		then
$		    header_dir = "sys$sysroot:[kerberos.include]"
$		    headf = headf - "GSSAPI_"
$		    header = f$search("''header_dir'''headf'.h")
$		    if header .nes. ""
$		    then
$			write tf "#ifndef ''key2'"
$			write tf "#define ''key2' 1"
$			write tf "#endif"
$set nover
$			goto cfgh_in_loop1

$		    endif
$		endif
$!
$set nover
$	    else
$!
$!		Looking for a routine or a symbol
$!------------------------------------------------
$		if key2c .eqs. "MACRO"
$		then
$		    if (key2b .eqs. "FILE") .or. (key2b .eqs. "DATE") -
			.or. (key2b .eqs. "LINE") .or. (key2b .eqs. "TIME")
$		    then
$			write tf "#ifndef HAVE_''key2b'"
$			write tf "#define HAVE_''key2b' 1"
$			write tf "#endif"
$		    endif
$		    goto cfgh_in_loop1
$		endif
$!
$!		Special false tests
$!-------------------------------------
$		if double_under
$		then
$		    if key2b .eqs. "_FCNTL" .or. key2b .eqs. "__FCNTL"
$		    then
$			write tf "/* #undef HAVE_''key2b' */"
$			goto cfgh_in_loop1
$		    endif
$!
$		    if key2b .eqs. "_STAT" .or. key2b .eqs. "__STAT"
$		    then
$			write tf "/* #undef HAVE_''key2b' */"
$			goto cfgh_in_loop1
$		    endif
$!
$		    if key2b .eqs. "_READ" .or. key2b .eqs. "__READ"
$		    then
$			write tf "/* #undef HAVE_''key2b' */"
$			goto cfgh_in_loop1
$		    endif
$		endif
$!
$		keysym = key2b
$		if key2c .nes. "" then keysym = keysym + "_" + key2c
$		if key2d .nes. "" then keysym = keysym + "_" + key2d
$		if key2e .nes. "" then keysym = keysym + "_" + key2e
$!
$!
$!		Stat structure members
$!-------------------------------------
$		if key2b .eqs. "STRUCT"
$		then
$		    if key2c .eqs. "STAT" .and (key2d .nes. "")
$		    then
$			key2b = key2b + "_" + key2c + "_" + key2d
$			key2c = key2e
$			key2d = ""
$			key2e = ""
$		    endif
$		endif
$		if (key2b .eqs. "ST") .or. (key2b .eqs. "STRUCT_STAT_ST")
$		then
$		    keysym = "ST" + "_" + key2c
$		    keysym = f$edit(keysym,"LOWERCASE")
$		endif
$		if key2a .eqs. "STAT"
$		then
$		    if (f$locate("STATVFS", key2b) .eq. 0) .and. key2c .eqs. ""
$		    then
$			keysym = f$edit(key2b, "LOWERCASE")
$		    endif
$!$		    if (key2b .eqs. "STATVFS" .or. key2b .eqs. "STATFS2" -
$!			.or. key2b .eqs. "STATFS3") .and. key2c .nes. ""
$!
$		    if (key2b .eqs. "STATVFS") .and. key2c .nes. ""
$		    then
$!			Should really verify that the structure
$!			named by key2b actually exists first.
$!------------------------------------------------------------
$!
$!			Statvfs structure members
$!-------------------------------------------------
$			keysym = "f_" + f$edit(key2c,"LOWERCASE")
$		    endif
$		endif
$!
$!		UTMPX structure members
$!--------------------------------------
$		if key2b .eqs. "UT" .and. key2c .eqs. "UT"
$		then
$		    keysym = "ut_" + f$edit(key2d,"LOWERCASE")
$		endif
$!
$		if f$locate("MMAP",key2) .lt. key2_len
$		then
$		   write sys$output ""
$		   write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!"
$		   write sys$output -
 "-CONFIG_H-I-MMAP, MMAP operations only work on STREAM and BINARY files!"
$		   write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$		    if update_config_vms
$		    then
$			open/append tfcv sys$disk:[]config_vms.h
$			write tfcv ""
$			write tfcv -
		"/* Check config.h for use of ''key2' settings */"
$			write tfcv ""
$			close tfcv

$		    endif
$		endif
$!
$!
$		if keysym .eqs. "CRYPT"
$		then
$		   write sys$output ""
$		   write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!"
$		   write sys$output -
 "-CONFIG_H-I-CRYPT, CRYPT operations on the VMS SYSUAF may not work!"
$		   write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$		    if update_config_vms
$		    then
$			open/append tfcv sys$disk:[]config_vms.h
$			write tfcv ""
$			write tfcv -
		"/* Check config.h for use of ''keysym' */"
$			write tfcv ""
$			close tfcv
$		    endif
$		endif
$!
$!
$		if keysym .eqs. "EXECL"
$		then
$		   write sys$output ""
$		   write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!"
$		   write sys$output -
 "-CONFIG_H-I-EXCEL, EXECL configured, Will probably not work."
$		   write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$		    if update_config_vms
$		    then
$			open/append tfcv sys$disk:[]config_vms.h
$			write tfcv ""
$			write tfcv -
		"/* Check config.h for use of ''keysym' */"
$			write tfcv ""
$			close tfcv
$		    endif
$		endif
$!
$!
$!		Process if cpp supports ANSI-C stringizing '#' operator
$!-----------------------------------------------------------------------
$		if keysym .eqs. "STRINGIZE"
$		then
$		    write tf "#ifndef HAVE_STRINGIZE"
$		    write tf "#define HAVE_STRINGSIZE 1"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$		if keysym .eqs. "VOLATILE"
$		then
$		    write tf "#ifndef HAVE_VOLATILE"
$		    write tf "#define HAVE_VOLATILE 1"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$		if keysym .eqs. "ALLOCA"
$		then
$		    write tf "#ifndef HAVE_ALLOCA"
$		    write tf "#define HAVE_ALLOCA 1"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$		if keysym .eqs. "ERRNO_DECL"
$		then
$		    write tf "#ifndef HAVE_ERRNO_DECL"
$		    write tf "#define HAVE_ERRNO_DECL 1"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$		if keysym .eqs. "LONGLONG"
$		then
$		    write tf "#ifndef __VAX"
$		    write tf "#pragma message disable longlongtype"
$		    write tf "#ifndef HAVE_LONGLONG"
$		    write tf "#define HAVE_LONGLONG 1"
$		    write tf "#endif"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$!		May need to test compiler version
$!-----------------------------------------------
$		if keysym .eqs. "LONG_LONG"
$		then
$		    write tf "#ifndef __VAX"
$		    write tf "#pragma message disable longlongtype"
$		    write tf "#ifndef HAVE_LONG_LONG"
$		    write tf "#define HAVE_LONG_LONG 1"
$		    write tf "#endif"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$!		May need to test compiler version
$!-----------------------------------------------
$		if keysym .eqs. "UNSIGNED_LONG_LONG"
$		then
$		    write tf "#ifndef __VAX"
$		    write tf "#pragma message disable longlongtype"
$		    write tf "#ifndef HAVE_UNSIGNED_LONG_LONG"
$		    write tf "#define HAVE_UNSIGNED_LONG_LONG 1"
$		    write tf "#endif"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$!		May need to test compiler version
$!-----------------------------------------------
$		if keysym .eqs. "UNSIGNED_LONG_LONG_INT"
$		then
$		    write tf "#ifndef __VAX"
$		    write tf "#pragma message disable longlongtype"
$		    write tf "#ifndef HAVE_UNSIGNED_LONG_LONG_INT"
$		    write tf "#define HAVE_UNSIGNED_LONG_LONG_INT 1"
$		    write tf "#endif"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$!		May need to test compiler version
$!-----------------------------------------------
$		if keysym .eqs. "LONG_DOUBLE"
$		then
$		    write tf "#ifndef __VAX"
$		    write tf "#pragma message disable longlongtype"
$		    write tf "#ifndef HAVE_LONG_DOUBLE"
$		    write tf "#define HAVE_LONG_DOUBLE 1"
$		    write tf "#endif"
$		    write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$		if keysym .eqs. "FCNTL_LOCK"
$		then
$		    write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!
$		   write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$		    goto cfgh_in_loop1
$		endif
$!
$!
$!		These libraries are provided by the DEC C RTL
$!-------------------------------------------------------------
$		if keysym .eqs. "LIBINET" .or. keysym .eqs. "LIBSOCKET"
$		then
$		    write tf "#ifndef HAVE_''keysym'"
$		    write tf "#define HAVE_''keysym' 1"
$if p2 .nes. "" then write sys$output "''decc_shr' #define ''keysym' 1"
$		    write tf "#endif
$		    goto cfgh_in_loop1
$		endif
$!
$		if keysym .eqs. "HERRNO" then keysym = "h_errno"
$		if keysym .eqs. "UTIMBUF" then keysym = "utimbuf"
$		if key2c .eqs. "STRUCT"
$		then
$		    keysym = f$edit(key2d,"LOWERCASE")
$		else
$		    if key2_h .eqs. "_T"
$		    then
$			if key2_t .eqs. "_TYPE"
$			then
$			    keysym = f$extract(0, key2_len - 5, key2) - "HAVE_"
$			endif
$			keysym = f$edit(keysym,"LOWERCASE")
$		    endif
$		endif
$!
$!		Check the DEC C RTL shared image first
$!------------------------------------------------------
$		if f$search(tfile1) .nes. "" then delete 'tfile1';*
$		define/user sys$output nl:
$		define/user sys$error nl:
$		search/format=nonull/out='tfile1' 'decc_shr' 'keysym'
$		if '$severity' .eq. 1
$		then
$!
$!		    Not documented, but from observation
$!------------------------------------------------------
$		    define/user sys$output nl:
$		    define/user sys$error nl:
$		    if arch_type .eq. 3
$		    then
$			keyterm = "''keysym'<SOH>"
$		    else
$			if arch_type .eq. 2
$			then
$			    keyterm = "''keysym'<BS>"
$			else
$			    keyterm = "''keysym'<STX>"
$			endif
$		    endif
$		    search/out=nl: 'tfile1' -
   "$''keyterm'","$g''keyterm'","$__utc_''keyterm'",-
   "$__utctz_''keyterm'","$__bsd44_''keyterm'","$bsd_''keyterm'",-
   "$''keysym'decc$","$G''keysym'decc$","$GX''keyterm'"
$		    severity = '$severity'
$!
$!
$!		    Of course the 64 bit stuff is different
$!---------------------------------------------------------
$		    if severity .ne. 1 .and. key64
$		    then
$			define/user sys$output nl:
$		        define/user sys$error nl:
$			search/out=nl: 'tfile1' "$_''keyterm'"
$!			search/out 'tfile1' "$_''keyterm'"
$			severity = '$severity'
$		    endif
$!
$!		    Unix compatibility routines
$!---------------------------------------------
$		    if severity .ne. 1
$		    then
$			define/user sys$output nl:
$			define/user sys$error nl:
$			search/out=nl: 'tfile1' -
    "$__unix_''keyterm'","$__vms_''keyterm'","$_posix_''keyterm'"
$			severity = '$severity'
$		    endif
$!
$!		    Show the result of the search
$!------------------------------------------------
$		    if 'severity' .eq. 1
$		    then
$			if key64 then write tf "#ifndef __VAX"
$			write tf "#ifndef ''key2'"
$			write tf "#define ''key2' 1"
$if p2 .nes. "" then write sys$output "''decc_shr' #define ''key2' 1"
$			write tf "#endif"
$			if key64 then write tf "#endif"
$			goto cfgh_in_loop1
$		    endif
$		endif
$		if f$search(tfile1) .nes. "" then delete 'tfile1';*
$!
$!		Check the DECC Header files next
$!----------------------------------------------
$		define/user sys$output nl:
$		define/user sys$error nl:
$		search/out=nl: 'decc_rtldef' -
		    "''keysym';", "''keysym'[", "struct ''keysym'"/exact
$		severity = '$severity'
$		if severity .eq. 1
$		then
$		    if key64 then write tf "#ifndef __VAX"
$		    write tf "#ifndef ''key2'"
$		    write tf "#define ''key2' 1"
$if p2 .nes. "" then write sys$output "''decc_rtldef' #define ''key2' 1"
$		    write tf "#endif"
$		    if key64 then write tf "#endif"
$		    goto cfgh_in_loop1
$		endif
$!
$!		Check kerberos
$!--------------------------------------------
$		if f$search("SYS$SYSROOT:[kerberos]include.dir") .nes. ""
$		then
$		    test_mit = "SYS$SYSROOT:[kerberos.include]gssapi_krb5.h"
$		    if (key2 .eqs. "HAVE_GSSAPI")
$		    then
$			write tf "#ifndef ''key2'"
$			write tf "#define ''key2' 1"
$			write tf "#endif"
$			goto cfgh_in_loop1
$		    endif
$		endif
$!
$	    endif
$	    write tf "/* ", xline, " */"
$	    goto cfgh_in_loop1
$	endif
$!
$!
$!	Process SIZEOF directives found in SAMBA and others
$!----------------------------------------------------------
$	if key2a .eqs. "SIZEOF"
$	then
$	    if key2b .eqs. "INO" .and. key2_h .eqs. "_T"
$	    then
$		write tf "#ifndef SIZEOF_INO_T"
$		write tf "#if !__USING_STD_STAT
$		write tf "#define SIZEOF_INO_T 6"
$		write tf "#else
$		write tf "#define SIZEOF_INO_T 8"
$		write tf "#endif
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "INTMAX" .and. key2_h .eqs. "_T"
$	    then
$		write tf "#ifndef SIZEOF_INTMAX_T"
$		write tf "#ifdef __VAX"
$		write tf "#define SIZEOF_INTMAX_T 4"
$		write tf "#else"
$		write tf "#define SIZEOF_INTMAX_T 8"
$		write tf "#endif"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "OFF" .and. key2_h .eqs. "_T"
$	    then
$		write tf "#ifndef SIZEOF_OFF_T"
$		write tf "#if __USE_OFF64_T"
$		write tf "#define SIZEOF_OFF_T 8"
$		write tf "#else"
$		write tf "#define SIZEOF_OFF_T 4"
$		write tf "#endif"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "CHAR" .and. key2_h .eqs. "_P"
$	    then
$		write tf "#ifndef SIZEOF_CHAR_P"
$		write tf "#if __INITIAL_POINTER_SIZE == 64"
$		write tf "#define SIZEOF_CHAR_P 8"
$		write tf "#else"
$		write tf "#define SIZEOF_CHAR_P 4"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "VOIDP"
$	    then
$		write tf "#ifndef SIZEOF_VOIDP"
$		write tf "#if __INITIAL_POINTER_SIZE == 64"
$		write tf "#define SIZEOF_VOIDP 8"
$		write tf "#else"
$		write tf "#define SIZEOF_VOIDP 4"
$		write tf "#endif"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "INT"
$	    then
$		write tf "#ifndef SIZEOF_INT"
$		write tf "#define SIZEOF_INT 4"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "SIZE" .and. key2_h .eqs. "_T"
$	    then
$		write tf "#ifndef SIZEOF_SIZE_T"
$		write tf "#define SIZEOF_SIZE_T 4"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "TIME" .and. key2_h .eqs. "_T"
$	    then
$		write tf "#ifndef SIZEOF_TIME_T"
$		write tf "#define SIZEOF_TIME_T 4"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "DOUBLE"
$	    then
$		write tf "#ifndef SIZEOF_DOUBLE"
$		write tf "#define SIZEOF_DOUBLE 8"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2b .eqs. "LONG"
$	    then
$		if key2c .eqs. ""
$		then
$		    write tf "#ifndef SIZEOF_LONG"
$		    write tf "#define SIZEOF_LONG 4"
$		    write tf "#endif"
$		else
$		    write tf "#ifndef SIZEOF_LONG_LONG"
$		    write tf "#ifndef __VAX"
$		    write tf "#define SIZEOF_LONG_LONG 8"
$		    write tf "#endif"
$		    write tf "#endif"
$		endif
$		goto cfgh_in_loop1
$	    endif
$	    write tf "/* ", xline, " */"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Process NEED directives
$!-------------------------------
$	if key2a .eqs. "NEED"
$	then
$	    if key2b .eqs. "STRINGS" .and. key2_h .eqs. "_H"
$	    then
$		write tf "#ifndef NEED_STRINGS_H"
$		write tf "#define NEED_STRINGS_H 1"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    write tf "/* ", xline, " */"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Process GETHOSTNAME directives
$!-------------------------------------
$	if key2 .eqs. "GETHOSTNAME_TYPE_ARG2"
$	then
$	    write tf "#ifndef ''key2'"
$	    write tf "#ifdef _DECC_V4_SOURCE"
$	    write tf "#define ''key2' int"
$	    write tf "#else"
$	    write tf "#define ''key2' size_t"
$	    write tf "#endif"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Process GETNAMEINFO directives
$!-------------------------------------
$	if key2a .eqs. "GETNAMEINFO"
$	then
$	    if key2 .eqs. "GETNAMEINFO_QUAL_ARG1"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' const"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "GETNAMEINFO_TYPE_ARG1"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' struct sockaddr *"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "GETNAMEINFO_TYPE_ARG2"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' size_t"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "GETNAMEINFO_TYPE_ARG46"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' size_t"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "GETNAMEINFO_TYPE_ARG7"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' int"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	endif
$!
$!	Process RECV directives
$!-------------------------------------
$	if key2a .eqs. "RECV"
$	then
$	    if key2 .eqs. "RECV_TYPE_ARG1"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' int"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "RECV_TYPE_ARG2"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' void *"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "RECV_TYPE_ARG3"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' size_t"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "RECV_TYPE_ARG4"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' int"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "RECV_TYPE_RETV"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' int"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	endif
$!
$!	Process SEND directives
$!-------------------------------------
$	if key2a .eqs. "SEND"
$	then
$	    if key2 .eqs. "SEND_QUAL_ARG2"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' const"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "SEND_TYPE_ARG1"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' int"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "SEND_TYPE_ARG2"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' void *"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "SEND_TYPE_ARG3"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' size_t"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "SEND_TYPE_ARG4"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' int"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	    if key2 .eqs. "SEND_TYPE_RETV"
$	    then
$		write tf "#ifndef ''key2'"
$		write tf "#define ''key2' int"
$		write tf "#endif"
$		goto cfgh_in_loop1
$	    endif
$	endif
$!
$!
$!	Process STATFS directives
$!-------------------------------
$!	if key2a .eqs. "STATFS"
$!	then
$!	    write tf "/* ", xline, " */"
$!	    goto cfgh_in_loop1
$!	endif
$!
$!	Process inline directive
$!------------------------------
$	if key2 .eqs. "inline"
$	then
$	    write tf "#ifndef inline"
$	    write tf "#define inline __inline"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Process restrict directive
$!--------------------------------
$	if key2 .eqs. "restrict"
$	then
$	    write tf "#ifndef restrict"
$	    write tf "#define restrict __restrict"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Process STDC_HEADERS (SAMBA!)
$!---------------------------
$	if key2 .eqs. "STDC_HEADERS"
$	then
$	    write tf "#ifndef STDC_HEADERS"
$	    write tf "#define STDC_HEADERS 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Process PROTOTYPES directive
$!-------------------------------------
$	if key2 .eqs. "PROTOTYPES"
$	then
$	    write tf "#ifndef PROTOTYPES"
$	    write tf "#define PROTOTYPES 1"
$	    write tf "#endif"
$	    goto cfgh_in_loop1
$	endif
$!
$!	Special for SEEKDIR_RETURNS_VOID
$!---------------------------------------
$	if key2 .eqs. "SEEKDIR_RETURNS_VOID"
$	then
$	    write tf "#ifndef SEEKDIR_RETURNS_VOID"
$	    write tf "#define SEEKDIR_RETURNS_VOID 1"
$	    write tf "#endif"
$	endif
$!
$!	Unknown - See if CONFIGURE can give a clue for this
$!----------------------------------------------------------
$	pflag = 0
$	set_flag = 0
$!	gproj_name = proj_name - "_VMS" - "-VMS"
$	if f$search(tfile1) .nes. "" then delete 'tfile1';*
$	define/user sys$output nl:
$	define/user sys$error nl:
$!	if f$locate("FILE", key2) .lt. key2_len then pflag = 1
$!	if f$locate("DIR", key2) .eq. key2_len - 3 then pflag = 1
$!	if f$locate("PATH", key2) .eq. key2_len - 4 then pflag = 1
$!
$	search/out='tfile1' 'configure_script' "''key2'="/exact
$	search_sev = '$severity'
$	if 'search_sev' .eq. 1
$	then
$	    open/read/err=unknown_cf_rd_error sf 'tfile1'
$search_file_rd_loop:
$	    read/end=unknown_cf_rd_err sf line_in
$	    line_in = f$edit(line_in, "TRIM")
$	    skey1 = f$element(0,"=",line_in)
$	    if skey1 .eqs. key2
$	    then
$		skey2 = f$element(1,"=",line_in)
$		skey2a = f$extract(0,2,skey2)
$!
$!
$!		We can not handle assignment to shell symbols.
$!		For now skip them.
$!------------------------------------------------------------
$		if f$locate("$", skey2) .lt. f$length(skey2)
$		then
$		    write tf "/* ", xline, " */"
$		    set_flag = 1
$		    goto found_in_configure
$		endif
$!
$!		Keep these two cases separate to make it easier to add
$!		more future intelligence to this routine
$!----------------------------------------------------------------------
$		if skey2a .eqs. """`"
$		then
$!		    if pflag .eq. 1
$!		    then
$!			write tf "#ifndef ''key2'"
$!			write tf "#define ",key2," """,gproj_name,"_",key2,""""
$!			write tf "#endif"
$!		    else
$!			Ignore this for now
$!------------------------------------------
$			write tf "/* ", xline, " */"
$!		    endif
$		    set_flag = 1
$		    goto found_in_configure
$		endif
$		if skey2a .eqs. """$"
$		then
$!		    if pflag .eq. 1
$!		    then
$!			write tf "#ifndef ''key2'"
$!			write tf "#define ",key2," """,gproj_name,"_",key2,""""
$!			write tf "#endif"
$!		    else
$!			Ignore this for now
$!-------------------------------------------
$			write tf "/* ", xline, " */"
$!		    endif
$		    set_flag = 1
$		    goto found_in_configure
$		endif
$!
$!		Remove multiple layers of quotes if present
$!----------------------------------------------------------
$		if f$extract(0, 1, skey2) .eqs. "'"
$		then
$		    skey2 = skey2 - "'" - "'" - "'" - "'"
$		endif
$		if f$extract(0, 1, skey2) .eqs. """"
$		then
$		    skey2 = skey2 - """" - """" - """" - """"
$		endif
$		write tf "#ifndef ''key2'"
$		if skey2 .eqs. ""
$		then
$		    write tf "#define ",key2
$		else
$!		    Only quote non-numbers
$!----------------------------------------
$		    if f$string(skey2+0) .eqs. skey2
$		    then
$			write tf "#define ",key2," ",skey2
$		    else
$			write tf "#define ",key2," """,skey2,""""
$		    endif
$		endif
$		write tf "#endif"
$		set_flag = 1
$	    else
$		goto search_file_rd_loop
$!		if pflag .eq. 1
$!		then
$!		    write tf "#ifndef ''key2'"
$!		    write tf "#define ",key2," """,gproj_name,"_",key2,""""
$!		    write tf "#endif"
$!		    set_flag = 1
$!		endif
$	    endif
$found_in_configure:
$unknown_cf_rd_err:
$	    if f$trnlnm("sf","lnm$process",,"SUPERVISOR") .nes. ""
$	    then
$		close sf
$	    endif
$	    if f$search(tfile1) .nes. "" then delete 'tfile1';*
$	    if set_flag .eq. 1 then goto cfgh_in_loop1
$	endif
$   endif
$!
$!
$!
$!  If it falls through everything else, comment it out
$!-----------------------------------------------------
$   write tf "/* ", xline, " */"







|
|
|






|
|
|




|

|
|
|

|

|
|
|







|
|
|







|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|

|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
>
|
<


|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|


|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|

|
|
|
|

|

|

|

|
|
|
|
|
|
|
|
|

|
|

|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|

|

|
|
|

|

|

|
|
|
|
|
|
|
|
|

|

|
|
|
|

|
|
|
|
|
|
|
|


|
|
|
|

|

|

|

|


|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|

|
|

|
|


|

|
|
|
|
|
|
|
|

|
|

|
|

|

|
|
|
|
|
|
|
|
|

|
|
|

|

|
|
|
|
|
|
|
|
|
|

|
>
|
<


|

|

|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|
|
|
|
|

|
|
|
|
|
|

|
|
|
|


|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|


|

|
|
|

|

|
|
|
|

|
|
|
|

|

|

|
|
|
|
|
|
|
|
>
|
<


|
|
|
|

|

|

|
|
|
|
|
|
|
|
|
|


|
|
|
|

|

|

|
|
|
|
|
|
|
|
|
|


|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|

|
|
|

|

|
|


|

|
|
|
|

|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|



|


|

|
|
|
|
|
|
|
|

|

|
|
|
|
|

|
|

|

|
|
|
|
|

|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|

|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|


|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|

|
|
|
|
|

|

|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|

|
|
|
|
|
|
|

|

|
|
|
|
|
|

|

|
|
|
|
|
|
|
|
|

|
|
|
|
|

|
|
|
|
|
|
|


|
|

|
|
|
|
|
|

|
|

|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|

|

|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001

1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112

1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
$!
$!write sys$output "xline = ''xline'"
$!
$!  Comment out this section of the ifblock
$!-----------------------------------------
$   if if_block .ge. 3
$   then
$       write tf "/* ", xline, " */"
$       if keyif .eqs. "#en" then if_block = 0
$       goto cfgh_in_loop1
$   endif
$!
$!  Handle the end of an ifblock
$!-------------------------------
$   if keyif .eqs. "#en"
$   then
$       write tf xline
$       if_block = 0
$       goto cfgh_in_loop1
$   endif
$!
$   if key1 .eqs. "#ifndef"
$   then
$!      Manual check for _ALL_SOURCE on AIX error
$!-----------------------------------------------
$       if key2 .eqs. "_ALL_SOURCE"
$       then
$          write tf "/* ", xline, " */"
$!
$!         Ignore the rest of the block
$!--------------------------------------
$          if_block = 3
$          goto cfgh_in_loop1
$       endif
$   endif
$!
$!
$!  Default action for an #if/#else/#endif
$!------------------------------------------
$   if keyif .eqs. "#if" .or. keyif .eqs. "#el"
$   then
$       if_block = 1
$       write tf xline
$       goto cfgh_in_loop1
$   endif
$!
$!
$!  Process "normal?" stuff
$!---------------------------
$   if key1 .eqs. "#undef"
$   then
$       key2c = f$element(2, "_", key2)
$       if (key2c .eqs. "_") .or. (key2c .eqs. "H") then key2c = ""
$       key2d = f$element(3, "_", key2)
$       if (key2d .eqs. "_") .or. (key2d .eqs. "H") then key2d = ""
$       key2e = f$element(4, "_", key2)
$       if (key2e .eqs. "_") .or. (key2e .eqs. "H") then key2e = ""
$       if key2d .eqs. "T"
$       then
$           if key2e .eqs. "TYPE"
$           then
$               key2_h = "_T"
$               key2d = ""
$           endif
$       endif
$!
$       double_under = 0
$!
$!      Process FCNTL directives
$!-------------------------------------
$       if (key2b .eqs. "FCNTL") .and. (key2c .eqs. "O") .and. -
           (key2d .eqs. "NONBLOCK")
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      Process GETADDRINFO directives
$!-------------------------------------
$       if key2 .eqs. "GETADDRINFO_THREADSAFE"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      Process IOCTL directives
$!-------------------------------------
$       if (key2b .eqs. "IOCTL") .and. (key2c .nes. "")
$       then
$           if (key2c .eqs. "FIONBIO") .or. (key2c .eqs. "SIOCGIFADDR")
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' 1"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$       endif

$!
$!
$!      Manual check for LL on
$!-----------------------------------------------
$       if key2 .eqs. "LL"
$       then
$          write tf "#ifndef __VAX
$          write tf "#define HAVE_''key2' 1"
$          write tf "#endif"
$          goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "bool_t"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' short"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "bits16_t"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' short"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "u_bits16_t"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' unsigned short"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "bits32_t"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' int"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "u_bits32_t"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' unsigned int"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "intmax_t"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#ifdef __VAX"
$           write tf "#define ''key2' long"
$           write tf "#else"
$           write tf "#define ''key2' long long"
$           write tf "#endif"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "uintmax_t"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#ifdef __VAX"
$           write tf "#define ''key2' unsigned long"
$           write tf "#else"
$           write tf "#define ''key2' unsigned long long"
$           write tf "#endif"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "socklen_t"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' int"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "GETGROUPS_T"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' gid_t"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_SYS_SIGLIST"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 0"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_SYS_ERRLIST"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_STRUCT_DIRENT_D_INO"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_STRUCT_TIMEVAL"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      ! The header files have this information, however
$!      ! The ioctl() call only works on sockets.
$!      if key2 .eqs. "FIONREAD_IN_SYS_IOCTL"
$!      then
$!          write tf "#ifndef ''key2'"
$!          write tf "#define ''key2' 1"
$!          write tf "#endif"
$!          goto cfgh_in_loop1
$!      endif
$!
$!      ! The header files have this information, however
$!      ! The ioctl() call only works on sockets.
$!      if key2 .eqs. "GWINSZ_IN_SYS_IOCTL"
$!      then
$!          write tf "#ifndef ''key2'"
$!          write tf "#define ''key2' 1"
$!          write tf "#endif"
$!          goto cfgh_in_loop1
$!      endif
$!
$!      ! The header files have this information, however
$!      ! The ioctl() call only works on sockets.
$!      if key2 .eqs. "STRUCT_WINSIZE_IN_SYS_IOCTL"
$!      then
$!          write tf "#ifndef ''key2'"
$!          write tf "#define ''key2' 0"
$!          write tf "#endif"
$!          goto cfgh_in_loop1
$!      endif
$!
$       if key2 .eqs. "HAVE_STRUCT_TM_TM_ZONE"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_TM_ZONE"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_TIMEVAL"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "WEXITSTATUS_OFFSET"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 2"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_GETPW_DECLS"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_CONFSTR"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_PRINTF"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_SBRK"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_STRSIGNAL"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 0"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2a .eqs. "HAVE_DECL_STRTOLD"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 0"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_STRTOIMAX"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 0"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_STRTOL"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_STRTOLL"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_STRTOUL"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_STRTOULL"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_STRTOUMAX"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 0"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "GETPGRP_VOID"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "NAMED_PIPES_MISSING"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "OPENDIR_NOT_ROBUST"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "PGRP_PIPE"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "CAN_REDEFINE_GETENV"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_PRINTF_A_FORMAT"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "CTYPE_NON_ASCII"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_LANGINFO_CODESET"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 0"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      This wants execve() to do this automagically to pass.
$!      if key2 .eqs. "HAVE_HASH_BANG_EXEC"
$!      then
$!          write tf "#ifndef ''key2'"
$!          write tf "#define ''key2' 1"
$!          write tf "#endif"
$!          goto cfgh_in_loop1
$!      endif
$!
$       if key2 .eqs. "ICONV_CONST"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2'"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "VOID_SIGHANDLER"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_POSIX_SIGNALS"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "UNUSABLE_RT_SIGNALS"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2a .eqs. "HAVE_DECL_FPURGE"
$       then
$           write tf "#ifndef ''key2a'"
$           write tf "#define ''key2a' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_DECL_SETREGID"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "HAVE_POSIX_SIGSETJMP"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2b .eqs. "RAND" .and. key2c .nes. "" .and. key2d .eqs. ""
$       then
$           if (key2c .eqs. "EGD") .or. -
               (key2c .eqs. "STATUS") .or. -
               (key2c .eqs. "SCREEN")
$           then
$               if f$search("''ssl_header_dir'rand.h") .nes. ""
$               then
$                   write tf "#ifndef ''key2'"
$                   write tf "#define ''key2' 1"
$                   write tf "#endif"
$               else
$                   write tf "/* #undef ''key2' */"
$               endif
$           endif
$       endif
$!
$       if key2 .eqs. "STRCOLL_BROKEN"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$       if key2 .eqs. "DUP_BROKEN"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#define ''key2' 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      This is for a test that getcwd(0,0) works.
$!      It does not on VMS.
$!--------------------------
$       if key2 .eqs. "GETCWD_BROKEN"
$       then
$           write sys$output ""
$           write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being tested for!"
$                  write sys$output -
 "-CONFIG_H-I-GETCWD, GETCWD(0,0) does not work on VMS."
$                  write sys$output -
 "-CONFIG_H-I-GETCWD2, Work around hack probably required."
$                  write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$                   if update_config_vms
$                   then
$                       open/append tfcv sys$disk:[]config_vms.h
$                       write tfcv ""
$                       write tfcv -
                "/* Check config.h for use of ''key2' settings */"
$                       write tfcv ""
$                       close tfcv
$                   endif
$
$           goto cfgh_in_loop1
$       endif
$!
$       if (key2a .eqs. "HAVE") .or. (key2a .eqs. "STAT") .or. -
           (key2 .eqs. "USE_IPV6") .or. (key2b .eqs. "LDAP")
$       then
$!
$!          Process extra underscores
$!------------------------------------
$           if f$locate("HAVE___", key2) .lt. key2_len
$           then
$               key2b = "__" + key2d
$               key2d = ""
$               double_under = 1
$           else
$               if f$locate("HAVE__", key2) .lt. key2_len
$               then
$                   key2b = "_" + key2c
$                   key2c = ""
$                   double_under = 1
$               endif
$           endif
$!
$           if (key2_h .eqs. "_H") .or. (key2 .eqs. "USE_IPV6") .or. -
               (key2b .eqs. "LDAP")
$           then
$!
$!              Looking for a header file
$!---------------------------------------
$               headf = key2b
$               if key2c .nes. "" then headf = headf + "_" + key2c
$               if key2d .nes. "" then headf = headf + "_" + key2d
$!
$!                 (key2b .eqs. "READLINE")
$!
$!              Some special parsing
$!------------------------------------------
$               if (key2b .eqs. "SYS") .or. (key2b .eqs. "ARPA") .or. -
                   (key2b .eqs. "NET") .or. (key2b .eqs. "NETINET")
$               then
$                   if key2c .nes. ""
$                   then
$                       headf = key2c
$                       if key2d .nes. "" then headf = key2c + "_" + key2d
$                   endif
$               endif
$!
$!              And of course what's life with out some special cases
$!--------------------------------------------------------------------
$               if key2 .eqs. "USE_IPV6"
$               then
$                   headf = "in6"
$               endif
$!
$               if key2b .eqs. "LDAP"
$               then
$                   if (key2 .eqs. "HAVE_LDAP_SSL") .or. -
                       (key2 .eqs. "HAVE_LDAP_URL_PARSE")
$                   then
$                       headf = "ldap"
$                   endif
$               endif
$!
$!
$               if key2b .eqs. "FILE"
$               then
$                  write sys$output ""
$                  write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!"
$                  write sys$output -
 "-CONFIG_H-I-FILE_OLD, file.h will not be configured as is obsolete!"
$                  write sys$output -
 "-CONFIG_H_I-FCNTL_NEW, "Expecting fcntl.h to be configured instead!"
$                  write sys$output -
 "-CONFIG_H_I-FCNTL_CHK, "Unable to verify at this time!"
$                  write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$!
$                   if update_config_vms
$                   then
$                       open/append tfcv sys$disk:[]config_vms.h
$                       write tfcv ""
$                       write tfcv -
                "/* Check config.h for use of fcntl.h instead of file.h */"
$                       write tfcv ""
$                       close tfcv
$                   endif
$               endif
$!
$!              Now look it up in the DEC C RTL
$!---------------------------------------------
$               define/user sys$output nl:
$               define/user sys$error nl:
$               search/output=nl: 'dchfile' |'headf'|/exact
$               if '$severity' .eq. 1
$               then
$                   if key64 then write tf "#ifndef __VAX"
$                   write tf "#ifndef ''key2'"
$                   write tf "#define ''key2' 1"
$if p2 .nes. "" then write sys$output "''dchfile' - #define ''key2' 1"
$                   write tf "#endif"
$                   if key64 then write tf "#endif"
$set nover
$                   goto cfgh_in_loop1
$               endif
$!
$!
$!              Now look it up in the DEC C STARLET_C
$!---------------------------------------------
$               define/user sys$output nl:
$               define/user sys$error nl:
$               search/output=nl: 'starhfile' |'headf'|/exact
$               if '$severity' .eq. 1
$               then
$                   if key64 then write tf "#ifndef __VAX"
$                   write tf "#ifndef ''key2'"
$                   write tf "#define ''key2' 1"
$if p2 .nes. "" then write sys$output "''starfile' - #define ''key2' 1"
$                   write tf "#endif"
$                   if key64 then write tf "#endif"
$set nover
$                   goto cfgh_in_loop1
$               endif
$!
$!              Now look for OPENSSL headers
$!---------------------------------------------------------
$               if key2b .eqs. "OPENSSL"
$               then
$                   headf = headf - "OPENSSL_"
$                   header = f$search("''ssl_header_dir'''headf'.h")
$                   if header .nes. ""
$                   then
$                       write tf "#ifndef ''key2'"
$                       write tf "#define ''key2' 1"
$                       write tf "#endif"
$set nover
$                       goto cfgh_in_loop1
$                   endif
$               endif
$!
$!              Now look for Kerberos
$!------------------------------------------------------------
$               if key2b .eqs. "GSSAPI"
$               then
$                   header_dir = "sys$sysroot:[kerberos.include]"
$                   headf = headf - "GSSAPI_"
$                   header = f$search("''header_dir'''headf'.h")
$                   if header .nes. ""
$                   then
$                       write tf "#ifndef ''key2'"
$                       write tf "#define ''key2' 1"
$                       write tf "#endif"
$set nover
$                       goto cfgh_in_loop1
$                   endif
$               endif

$!
$set nover
$           else
$!
$!              Looking for a routine or a symbol
$!------------------------------------------------
$               if key2c .eqs. "MACRO"
$               then
$                   if (key2b .eqs. "FILE") .or. (key2b .eqs. "DATE") -
                        .or. (key2b .eqs. "LINE") .or. (key2b .eqs. "TIME")
$                   then
$                       write tf "#ifndef HAVE_''key2b'"
$                       write tf "#define HAVE_''key2b' 1"
$                       write tf "#endif"
$                   endif
$                   goto cfgh_in_loop1
$               endif
$!
$!              Special false tests
$!-------------------------------------
$               if double_under
$               then
$                   if key2b .eqs. "_FCNTL" .or. key2b .eqs. "__FCNTL"
$                   then
$                       write tf "/* #undef HAVE_''key2b' */"
$                       goto cfgh_in_loop1
$                   endif
$!
$                   if key2b .eqs. "_STAT" .or. key2b .eqs. "__STAT"
$                   then
$                       write tf "/* #undef HAVE_''key2b' */"
$                       goto cfgh_in_loop1
$                   endif
$!
$                   if key2b .eqs. "_READ" .or. key2b .eqs. "__READ"
$                   then
$                       write tf "/* #undef HAVE_''key2b' */"
$                       goto cfgh_in_loop1
$                   endif
$               endif
$!
$               keysym = key2b
$               if key2c .nes. "" then keysym = keysym + "_" + key2c
$               if key2d .nes. "" then keysym = keysym + "_" + key2d
$               if key2e .nes. "" then keysym = keysym + "_" + key2e
$!
$!
$!              Stat structure members
$!-------------------------------------
$               if key2b .eqs. "STRUCT"
$               then
$                   if key2c .eqs. "STAT" .and (key2d .nes. "")
$                   then
$                       key2b = key2b + "_" + key2c + "_" + key2d
$                       key2c = key2e
$                       key2d = ""
$                       key2e = ""
$                   endif
$               endif
$               if (key2b .eqs. "ST") .or. (key2b .eqs. "STRUCT_STAT_ST")
$               then
$                   keysym = "ST" + "_" + key2c
$                   keysym = f$edit(keysym,"LOWERCASE")
$               endif
$               if key2a .eqs. "STAT"
$               then
$                   if (f$locate("STATVFS", key2b) .eq. 0) .and. key2c .eqs. ""
$                   then
$                       keysym = f$edit(key2b, "LOWERCASE")
$                   endif
$!$                 if (key2b .eqs. "STATVFS" .or. key2b .eqs. "STATFS2" -
$!                      .or. key2b .eqs. "STATFS3") .and. key2c .nes. ""
$!
$                   if (key2b .eqs. "STATVFS") .and. key2c .nes. ""
$                   then
$!                      Should really verify that the structure
$!                      named by key2b actually exists first.
$!------------------------------------------------------------
$!
$!                      Statvfs structure members
$!-------------------------------------------------
$                       keysym = "f_" + f$edit(key2c,"LOWERCASE")
$                   endif
$               endif
$!
$!              UTMPX structure members
$!--------------------------------------
$               if key2b .eqs. "UT" .and. key2c .eqs. "UT"
$               then
$                   keysym = "ut_" + f$edit(key2d,"LOWERCASE")
$               endif
$!
$               if f$locate("MMAP",key2) .lt. key2_len
$               then
$                  write sys$output ""
$                  write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!"
$                  write sys$output -
 "-CONFIG_H-I-MMAP, MMAP operations only work on STREAM and BINARY files!"
$                  write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$                   if update_config_vms
$                   then
$                       open/append tfcv sys$disk:[]config_vms.h
$                       write tfcv ""
$                       write tfcv -
                "/* Check config.h for use of ''key2' settings */"
$                       write tfcv ""
$                       close tfcv
$                   endif
$               endif

$!
$!
$               if keysym .eqs. "CRYPT"
$               then
$                  write sys$output ""
$                  write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!"
$                  write sys$output -
 "-CONFIG_H-I-CRYPT, CRYPT operations on the VMS SYSUAF may not work!"
$                  write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$                   if update_config_vms
$                   then
$                       open/append tfcv sys$disk:[]config_vms.h
$                       write tfcv ""
$                       write tfcv -
                "/* Check config.h for use of ''keysym' */"
$                       write tfcv ""
$                       close tfcv
$                   endif
$               endif
$!
$!
$               if keysym .eqs. "EXECL"
$               then
$                  write sys$output ""
$                  write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!"
$                  write sys$output -
 "-CONFIG_H-I-EXCEL, EXECL configured, Will probably not work."
$                  write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$                   if update_config_vms
$                   then
$                       open/append tfcv sys$disk:[]config_vms.h
$                       write tfcv ""
$                       write tfcv -
                "/* Check config.h for use of ''keysym' */"
$                       write tfcv ""
$                       close tfcv
$                   endif
$               endif
$!
$!
$!              Process if cpp supports ANSI-C stringizing '#' operator
$!-----------------------------------------------------------------------
$               if keysym .eqs. "STRINGIZE"
$               then
$                   write tf "#ifndef HAVE_STRINGIZE"
$                   write tf "#define HAVE_STRINGSIZE 1"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$               if keysym .eqs. "VOLATILE"
$               then
$                   write tf "#ifndef HAVE_VOLATILE"
$                   write tf "#define HAVE_VOLATILE 1"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$               if keysym .eqs. "ALLOCA"
$               then
$                   write tf "#ifndef HAVE_ALLOCA"
$                   write tf "#define HAVE_ALLOCA 1"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$               if keysym .eqs. "ERRNO_DECL"
$               then
$                   write tf "#ifndef HAVE_ERRNO_DECL"
$                   write tf "#define HAVE_ERRNO_DECL 1"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$               if keysym .eqs. "LONGLONG"
$               then
$                   write tf "#ifndef __VAX"
$                   write tf "#pragma message disable longlongtype"
$                   write tf "#ifndef HAVE_LONGLONG"
$                   write tf "#define HAVE_LONGLONG 1"
$                   write tf "#endif"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$!              May need to test compiler version
$!-----------------------------------------------
$               if keysym .eqs. "LONG_LONG"
$               then
$                   write tf "#ifndef __VAX"
$                   write tf "#pragma message disable longlongtype"
$                   write tf "#ifndef HAVE_LONG_LONG"
$                   write tf "#define HAVE_LONG_LONG 1"
$                   write tf "#endif"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$!              May need to test compiler version
$!-----------------------------------------------
$               if keysym .eqs. "UNSIGNED_LONG_LONG"
$               then
$                   write tf "#ifndef __VAX"
$                   write tf "#pragma message disable longlongtype"
$                   write tf "#ifndef HAVE_UNSIGNED_LONG_LONG"
$                   write tf "#define HAVE_UNSIGNED_LONG_LONG 1"
$                   write tf "#endif"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$!              May need to test compiler version
$!-----------------------------------------------
$               if keysym .eqs. "UNSIGNED_LONG_LONG_INT"
$               then
$                   write tf "#ifndef __VAX"
$                   write tf "#pragma message disable longlongtype"
$                   write tf "#ifndef HAVE_UNSIGNED_LONG_LONG_INT"
$                   write tf "#define HAVE_UNSIGNED_LONG_LONG_INT 1"
$                   write tf "#endif"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$!              May need to test compiler version
$!-----------------------------------------------
$               if keysym .eqs. "LONG_DOUBLE"
$               then
$                   write tf "#ifndef __VAX"
$                   write tf "#pragma message disable longlongtype"
$                   write tf "#ifndef HAVE_LONG_DOUBLE"
$                   write tf "#define HAVE_LONG_DOUBLE 1"
$                   write tf "#endif"
$                   write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$               if keysym .eqs. "FCNTL_LOCK"
$               then
$                   write sys$output -
  "%CONFIG_H-I-NONPORT, ''key2' being asked for!
$                  write sys$output -
 "-CONFIG_H-I-REVIEW, Manual Code review required!"
$                   goto cfgh_in_loop1
$               endif
$!
$!
$!              These libraries are provided by the DEC C RTL
$!-------------------------------------------------------------
$               if keysym .eqs. "LIBINET" .or. keysym .eqs. "LIBSOCKET"
$               then
$                   write tf "#ifndef HAVE_''keysym'"
$                   write tf "#define HAVE_''keysym' 1"
$if p2 .nes. "" then write sys$output "''decc_shr' #define ''keysym' 1"
$                   write tf "#endif
$                   goto cfgh_in_loop1
$               endif
$!
$               if keysym .eqs. "HERRNO" then keysym = "h_errno"
$               if keysym .eqs. "UTIMBUF" then keysym = "utimbuf"
$               if key2c .eqs. "STRUCT"
$               then
$                   keysym = f$edit(key2d,"LOWERCASE")
$               else
$                   if key2_h .eqs. "_T"
$                   then
$                       if key2_t .eqs. "_TYPE"
$                       then
$                           keysym = f$extract(0, key2_len - 5, key2) - "HAVE_"
$                       endif
$                       keysym = f$edit(keysym,"LOWERCASE")
$                   endif
$               endif
$!
$!              Check the DEC C RTL shared image first
$!------------------------------------------------------
$               if f$search(tfile1) .nes. "" then delete 'tfile1';*
$               define/user sys$output nl:
$               define/user sys$error nl:
$               search/format=nonull/out='tfile1' 'decc_shr' 'keysym'
$               if '$severity' .eq. 1
$               then
$!
$!                  Not documented, but from observation
$!------------------------------------------------------
$                   define/user sys$output nl:
$                   define/user sys$error nl:
$                   if arch_type .eq. 3
$                   then
$                       keyterm = "''keysym'<SOH>"
$                   else
$                       if arch_type .eq. 2
$                       then
$                           keyterm = "''keysym'<BS>"
$                       else
$                           keyterm = "''keysym'<STX>"
$                       endif
$                   endif
$                   search/out=nl: 'tfile1' -
   "$''keyterm'","$g''keyterm'","$__utc_''keyterm'",-
   "$__utctz_''keyterm'","$__bsd44_''keyterm'","$bsd_''keyterm'",-
   "$''keysym'decc$","$G''keysym'decc$","$GX''keyterm'"
$                   severity = '$severity'
$!
$!
$!                  Of course the 64 bit stuff is different
$!---------------------------------------------------------
$                   if severity .ne. 1 .and. key64
$                   then
$                       define/user sys$output nl:
$                       define/user sys$error nl:
$                       search/out=nl: 'tfile1' "$_''keyterm'"
$!                      search/out 'tfile1' "$_''keyterm'"
$                       severity = '$severity'
$                   endif
$!
$!                  Unix compatibility routines
$!---------------------------------------------
$                   if severity .ne. 1
$                   then
$                       define/user sys$output nl:
$                       define/user sys$error nl:
$                       search/out=nl: 'tfile1' -
    "$__unix_''keyterm'","$__vms_''keyterm'","$_posix_''keyterm'"
$                       severity = '$severity'
$                   endif
$!
$!                  Show the result of the search
$!------------------------------------------------
$                   if 'severity' .eq. 1
$                   then
$                       if key64 then write tf "#ifndef __VAX"
$                       write tf "#ifndef ''key2'"
$                       write tf "#define ''key2' 1"
$if p2 .nes. "" then write sys$output "''decc_shr' #define ''key2' 1"
$                       write tf "#endif"
$                       if key64 then write tf "#endif"
$                       goto cfgh_in_loop1
$                   endif
$               endif
$               if f$search(tfile1) .nes. "" then delete 'tfile1';*
$!
$!              Check the DECC Header files next
$!----------------------------------------------
$               define/user sys$output nl:
$               define/user sys$error nl:
$               search/out=nl: 'decc_rtldef' -
                    "''keysym';", "''keysym'[", "struct ''keysym'"/exact
$               severity = '$severity'
$               if severity .eq. 1
$               then
$                   if key64 then write tf "#ifndef __VAX"
$                   write tf "#ifndef ''key2'"
$                   write tf "#define ''key2' 1"
$if p2 .nes. "" then write sys$output "''decc_rtldef' #define ''key2' 1"
$                   write tf "#endif"
$                   if key64 then write tf "#endif"
$                   goto cfgh_in_loop1
$               endif
$!
$!              Check kerberos
$!--------------------------------------------
$               if f$search("SYS$SYSROOT:[kerberos]include.dir") .nes. ""
$               then
$                   test_mit = "SYS$SYSROOT:[kerberos.include]gssapi_krb5.h"
$                   if (key2 .eqs. "HAVE_GSSAPI")
$                   then
$                       write tf "#ifndef ''key2'"
$                       write tf "#define ''key2' 1"
$                       write tf "#endif"
$                       goto cfgh_in_loop1
$                   endif
$               endif
$!
$           endif
$           write tf "/* ", xline, " */"
$           goto cfgh_in_loop1
$       endif
$!
$!
$!      Process SIZEOF directives found in SAMBA and others
$!----------------------------------------------------------
$       if key2a .eqs. "SIZEOF"
$       then
$           if key2b .eqs. "INO" .and. key2_h .eqs. "_T"
$           then
$               write tf "#ifndef SIZEOF_INO_T"
$               write tf "#if !__USING_STD_STAT
$               write tf "#define SIZEOF_INO_T 6"
$               write tf "#else
$               write tf "#define SIZEOF_INO_T 8"
$               write tf "#endif
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "INTMAX" .and. key2_h .eqs. "_T"
$           then
$               write tf "#ifndef SIZEOF_INTMAX_T"
$               write tf "#ifdef __VAX"
$               write tf "#define SIZEOF_INTMAX_T 4"
$               write tf "#else"
$               write tf "#define SIZEOF_INTMAX_T 8"
$               write tf "#endif"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "OFF" .and. key2_h .eqs. "_T"
$           then
$               write tf "#ifndef SIZEOF_OFF_T"
$               write tf "#if __USE_OFF64_T"
$               write tf "#define SIZEOF_OFF_T 8"
$               write tf "#else"
$               write tf "#define SIZEOF_OFF_T 4"
$               write tf "#endif"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "CHAR" .and. key2_h .eqs. "_P"
$           then
$               write tf "#ifndef SIZEOF_CHAR_P"
$               write tf "#if __INITIAL_POINTER_SIZE == 64"
$               write tf "#define SIZEOF_CHAR_P 8"
$               write tf "#else"
$               write tf "#define SIZEOF_CHAR_P 4"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "VOIDP"
$           then
$               write tf "#ifndef SIZEOF_VOIDP"
$               write tf "#if __INITIAL_POINTER_SIZE == 64"
$               write tf "#define SIZEOF_VOIDP 8"
$               write tf "#else"
$               write tf "#define SIZEOF_VOIDP 4"
$               write tf "#endif"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "INT"
$           then
$               write tf "#ifndef SIZEOF_INT"
$               write tf "#define SIZEOF_INT 4"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "SIZE" .and. key2_h .eqs. "_T"
$           then
$               write tf "#ifndef SIZEOF_SIZE_T"
$               write tf "#define SIZEOF_SIZE_T 4"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "TIME" .and. key2_h .eqs. "_T"
$           then
$               write tf "#ifndef SIZEOF_TIME_T"
$               write tf "#define SIZEOF_TIME_T 4"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "DOUBLE"
$           then
$               write tf "#ifndef SIZEOF_DOUBLE"
$               write tf "#define SIZEOF_DOUBLE 8"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2b .eqs. "LONG"
$           then
$               if key2c .eqs. ""
$               then
$                   write tf "#ifndef SIZEOF_LONG"
$                   write tf "#define SIZEOF_LONG 4"
$                   write tf "#endif"
$               else
$                   write tf "#ifndef SIZEOF_LONG_LONG"
$                   write tf "#ifndef __VAX"
$                   write tf "#define SIZEOF_LONG_LONG 8"
$                   write tf "#endif"
$                   write tf "#endif"
$               endif
$               goto cfgh_in_loop1
$           endif
$           write tf "/* ", xline, " */"
$           goto cfgh_in_loop1
$       endif
$!
$!      Process NEED directives
$!-------------------------------
$       if key2a .eqs. "NEED"
$       then
$           if key2b .eqs. "STRINGS" .and. key2_h .eqs. "_H"
$           then
$               write tf "#ifndef NEED_STRINGS_H"
$               write tf "#define NEED_STRINGS_H 1"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           write tf "/* ", xline, " */"
$           goto cfgh_in_loop1
$       endif
$!
$!      Process GETHOSTNAME directives
$!-------------------------------------
$       if key2 .eqs. "GETHOSTNAME_TYPE_ARG2"
$       then
$           write tf "#ifndef ''key2'"
$           write tf "#ifdef _DECC_V4_SOURCE"
$           write tf "#define ''key2' int"
$           write tf "#else"
$           write tf "#define ''key2' size_t"
$           write tf "#endif"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      Process GETNAMEINFO directives
$!-------------------------------------
$       if key2a .eqs. "GETNAMEINFO"
$       then
$           if key2 .eqs. "GETNAMEINFO_QUAL_ARG1"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' const"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "GETNAMEINFO_TYPE_ARG1"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' struct sockaddr *"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "GETNAMEINFO_TYPE_ARG2"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' size_t"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "GETNAMEINFO_TYPE_ARG46"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' size_t"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "GETNAMEINFO_TYPE_ARG7"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' int"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$       endif
$!
$!      Process RECV directives
$!-------------------------------------
$       if key2a .eqs. "RECV"
$       then
$           if key2 .eqs. "RECV_TYPE_ARG1"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' int"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "RECV_TYPE_ARG2"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' void *"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "RECV_TYPE_ARG3"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' size_t"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "RECV_TYPE_ARG4"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' int"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "RECV_TYPE_RETV"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' int"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$       endif
$!
$!      Process SEND directives
$!-------------------------------------
$       if key2a .eqs. "SEND"
$       then
$           if key2 .eqs. "SEND_QUAL_ARG2"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' const"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "SEND_TYPE_ARG1"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' int"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "SEND_TYPE_ARG2"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' void *"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "SEND_TYPE_ARG3"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' size_t"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "SEND_TYPE_ARG4"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' int"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$           if key2 .eqs. "SEND_TYPE_RETV"
$           then
$               write tf "#ifndef ''key2'"
$               write tf "#define ''key2' int"
$               write tf "#endif"
$               goto cfgh_in_loop1
$           endif
$       endif
$!
$!
$!      Process STATFS directives
$!-------------------------------
$!      if key2a .eqs. "STATFS"
$!      then
$!          write tf "/* ", xline, " */"
$!          goto cfgh_in_loop1
$!      endif
$!
$!      Process inline directive
$!------------------------------
$       if key2 .eqs. "inline"
$       then
$           write tf "#ifndef inline"
$           write tf "#define inline __inline"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      Process restrict directive
$!--------------------------------
$       if key2 .eqs. "restrict"
$       then
$           write tf "#ifndef restrict"
$           write tf "#define restrict __restrict"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      Process STDC_HEADERS (SAMBA!)
$!---------------------------
$       if key2 .eqs. "STDC_HEADERS"
$       then
$           write tf "#ifndef STDC_HEADERS"
$           write tf "#define STDC_HEADERS 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      Process PROTOTYPES directive
$!-------------------------------------
$       if key2 .eqs. "PROTOTYPES"
$       then
$           write tf "#ifndef PROTOTYPES"
$           write tf "#define PROTOTYPES 1"
$           write tf "#endif"
$           goto cfgh_in_loop1
$       endif
$!
$!      Special for SEEKDIR_RETURNS_VOID
$!---------------------------------------
$       if key2 .eqs. "SEEKDIR_RETURNS_VOID"
$       then
$           write tf "#ifndef SEEKDIR_RETURNS_VOID"
$           write tf "#define SEEKDIR_RETURNS_VOID 1"
$           write tf "#endif"
$       endif
$!
$!      Unknown - See if CONFIGURE can give a clue for this
$!----------------------------------------------------------
$       pflag = 0
$       set_flag = 0
$!      gproj_name = proj_name - "_VMS" - "-VMS"
$       if f$search(tfile1) .nes. "" then delete 'tfile1';*
$       define/user sys$output nl:
$       define/user sys$error nl:
$!      if f$locate("FILE", key2) .lt. key2_len then pflag = 1
$!      if f$locate("DIR", key2) .eq. key2_len - 3 then pflag = 1
$!      if f$locate("PATH", key2) .eq. key2_len - 4 then pflag = 1
$!
$       search/out='tfile1' 'configure_script' "''key2'="/exact
$       search_sev = '$severity'
$       if 'search_sev' .eq. 1
$       then
$           open/read/err=unknown_cf_rd_error sf 'tfile1'
$search_file_rd_loop:
$           read/end=unknown_cf_rd_err sf line_in
$           line_in = f$edit(line_in, "TRIM")
$           skey1 = f$element(0,"=",line_in)
$           if skey1 .eqs. key2
$           then
$               skey2 = f$element(1,"=",line_in)
$               skey2a = f$extract(0,2,skey2)
$!
$!
$!              We can not handle assignment to shell symbols.
$!              For now skip them.
$!------------------------------------------------------------
$               if f$locate("$", skey2) .lt. f$length(skey2)
$               then
$                   write tf "/* ", xline, " */"
$                   set_flag = 1
$                   goto found_in_configure
$               endif
$!
$!              Keep these two cases separate to make it easier to add
$!              more future intelligence to this routine
$!----------------------------------------------------------------------
$               if skey2a .eqs. """`"
$               then
$!                  if pflag .eq. 1
$!                  then
$!                      write tf "#ifndef ''key2'"
$!                      write tf "#define ",key2," """,gproj_name,"_",key2,""""
$!                      write tf "#endif"
$!                  else
$!                      Ignore this for now
$!------------------------------------------
$                       write tf "/* ", xline, " */"
$!                  endif
$                   set_flag = 1
$                   goto found_in_configure
$               endif
$               if skey2a .eqs. """$"
$               then
$!                  if pflag .eq. 1
$!                  then
$!                      write tf "#ifndef ''key2'"
$!                      write tf "#define ",key2," """,gproj_name,"_",key2,""""
$!                      write tf "#endif"
$!                  else
$!                      Ignore this for now
$!-------------------------------------------
$                       write tf "/* ", xline, " */"
$!                  endif
$                   set_flag = 1
$                   goto found_in_configure
$               endif
$!
$!              Remove multiple layers of quotes if present
$!----------------------------------------------------------
$               if f$extract(0, 1, skey2) .eqs. "'"
$               then
$                   skey2 = skey2 - "'" - "'" - "'" - "'"
$               endif
$               if f$extract(0, 1, skey2) .eqs. """"
$               then
$                   skey2 = skey2 - """" - """" - """" - """"
$               endif
$               write tf "#ifndef ''key2'"
$               if skey2 .eqs. ""
$               then
$                   write tf "#define ",key2
$               else
$!                  Only quote non-numbers
$!----------------------------------------
$                   if f$string(skey2+0) .eqs. skey2
$                   then
$                       write tf "#define ",key2," ",skey2
$                   else
$                       write tf "#define ",key2," """,skey2,""""
$                   endif
$               endif
$               write tf "#endif"
$               set_flag = 1
$           else
$               goto search_file_rd_loop
$!              if pflag .eq. 1
$!              then
$!                  write tf "#ifndef ''key2'"
$!                  write tf "#define ",key2," """,gproj_name,"_",key2,""""
$!                  write tf "#endif"
$!                  set_flag = 1
$!              endif
$           endif
$found_in_configure:
$unknown_cf_rd_err:
$           if f$trnlnm("sf","lnm$process",,"SUPERVISOR") .nes. ""
$           then
$               close sf
$           endif
$           if f$search(tfile1) .nes. "" then delete 'tfile1';*
$           if set_flag .eq. 1 then goto cfgh_in_loop1
$       endif
$   endif
$!
$!
$!
$!  If it falls through everything else, comment it out
$!-----------------------------------------------------
$   write tf "/* ", xline, " */"
Changes to jni/curl/packages/vms/curlmsg.msg.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
! CURLE_ ones in include/curl.h.  The Message Utility manual states
! "The combined length of the prefix and the message symbol name cannot
! exceed 31 characters."  With a prefix of five that leaves us with 26
! for the message name.
!
! If you update this file also update curlmsg_vms.h so that they are in sync
!
.TITLE		CURLMSG Message files
.FACILITY	CURL,1793	/PREFIX=CURL_
.BASE		1
.SEVERITY	SUCCESS
OK		<normal successful completion>

.SEVERITY	ERROR
UNSUPPORTED_PROTOCOL	<unsupported protocol>
FAILED_INIT		<failed init>
URL_MALFORMAT		<URL malformat>
OBSOLETE4		<obsolete error code>
COULDNT_RESOLVE_PROXY	<could not resolve proxy>
COULDNT_RESOLVE_HOST	<could not resolve host>
COULDNT_CONNECT		<could not connect>
WEIRD_SERVER_REPLY	<weird server reply>
FTP_ACCESS_DENIED	<FTP access denied>
OBSOLETE10		<obsolete error code>
FTP_WEIRD_PASS_REPLY	<FTP weird PASS reply>
OBSOLETE12		<obsolete error code>
FTP_WEIRD_PASV_REPLY	<FTP weird PASV reply>
FTP_WEIRD_227_FORMAT	<FTP weird 227 format>
FTP_CANT_GET_HOST	<FTP can not get host>
OBSOLETE16		<obsolete error code>
FTP_COULDNT_SET_TYPE	<FTP could not set type>
PARTIAL_FILE		<partial file>
FTP_COULDNT_RETR_FILE	<FTP could not RETR file>
OBSOLETE20		<obsolete error code>
QUOTE_ERROR		<quote command error>
HTTP_RETURNED_ERROR	<HTTP returned error>
WRITE_ERROR		<write error>
OBSOLETE24    		<obsolete error code>
UPLOAD_FAILED		<failed upload command>
READ_ERROR		<read error, could not open/read file>
OUT_OF_MEMORY		<out of memory>
OPERATION_TIMEOUTED	<operation timed out, timeout time was reached>
OBSOLETE29		<obsolete error code>
FTP_PORT_FAILED		<FTP PORT operation failed>
FTP_COULDNT_USE_REST	<FTP REST command failed>
OBSOLETE32		<obsolete error code>
RANGE_ERROR		<RANGE command error>
HTTP_POST_ERROR		<HTTP POST error>
SSL_CONNECT_ERROR	<SSL connect error>
BAD_DOWNLOAD_RESUME	<bad download resume>
FILE_COULDNT_READ_FILE	<FILE could not read file>
LDAP_CANNOT_BIND	<LDAP cannot bind>
LDAP_SEARCH_FAILED	<LDAP search failed>
OBSOLETE40		<obsolete error code>
FUNCTION_NOT_FOUND	<function not found>
ABORTED_BY_CALLBACK	<aborted by callback>
BAD_FUNCTION_ARGUMENT	<bad function argument>
OBSOLETE44		<obsolete error code>
INTERFACE_FAILED	<CURLOPT_INTERFACE failed>
OBSOLETE46		<obsolete error code>
TOO_MANY_REDIRECTS	<too many redirects>
UNKNOWN_TELNET_OPTION	<unknown TELNET option>
TELNET_OPTION_SYNTAX	<malformed TELNET option syntax>
OBSOLETE50		<obsolete error code>
PEER_FAILED_VERIF	<peer certificate or fingerprint failed>
GOT_NOTHING		<got nothing>
SSL_ENGINE_NOTFOUND	<SSL crypto engine not found>
SSL_ENGINE_SETFAILED	<SSL can not set SSL crypto engine as default>
SEND_ERROR		<SEND error, failure sending network data>
RECV_ERROR		<RECV error, failure receiving network data>
OBSOLETE57  		<obsolete error code>
SSL_CERTPROBLEM		<SSL problem with the local certificate>
SSL_CIPHER              <SSL CIPHER, could not use specified cipher>
SSL_CACERT		<SSL CACERT, problem with the CA cert (path?)>
BAD_CONTENT_ENCODING	<unrecognized transfer encoding>
LDAP_INVALID_URL	<LDAP invalid url>
FILESIZE_EXCEEDED	<maximum file size exceeded>
USE_SSL_FAILED		<requested FTP SSL level failed>
SEND_FAIL_REWIND	<sending data requires a rewind that failed>
SSL_ENGINE_INITFAILED	<failed to initialise ENGINE>
LOGIN_DENIED		<user or password not accepted. failed to login>
TFTP_NOTFOUND		<file not found on server>
TFTP_PERM		<permission problem on server>
REMOTE_DISK_FULL	<out of disk space on server>
TFTP_ILLEGAL		<illegal TFTP operation>
TFTP_UNKNOWNID		<unknown transfer ID>
REMOTE_FILE_EXISTS	<file already exists>
TFTP_NOSUCHUSER		<no such user>
CONV_FAILED		<conversion failed>
CONV_REQD		<caller must register conversion callbacks>
SSL_CACERT_BADFILE	<could not load CACERT file>
REMOTE_FILE_NOT_FOUND	<remote file not found>
SSH			<unspecified error from the SSH layer>
SSL_SHUTDOWN_FAILED	<failed to shut down the SSL connection>
AGAIN			<socket not ready, wait and try again>
SSL_CRL_BADFILE		<could not load CRL file, missing or wrong format>
SSL_ISSUER_ERROR	<issuer check failed>
CURL_LAST		<CURLMSG.MSG is out of sync with the source code>

.END







|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
! CURLE_ ones in include/curl.h.  The Message Utility manual states
! "The combined length of the prefix and the message symbol name cannot
! exceed 31 characters."  With a prefix of five that leaves us with 26
! for the message name.
!
! If you update this file also update curlmsg_vms.h so that they are in sync
!
.TITLE          CURLMSG Message files
.FACILITY       CURL,1793       /PREFIX=CURL_
.BASE           1
.SEVERITY       SUCCESS
OK              <normal successful completion>

.SEVERITY       ERROR
UNSUPPORTED_PROTOCOL    <unsupported protocol>
FAILED_INIT             <failed init>
URL_MALFORMAT           <URL malformat>
OBSOLETE4               <obsolete error code>
COULDNT_RESOLVE_PROXY   <could not resolve proxy>
COULDNT_RESOLVE_HOST    <could not resolve host>
COULDNT_CONNECT         <could not connect>
WEIRD_SERVER_REPLY      <weird server reply>
FTP_ACCESS_DENIED       <FTP access denied>
OBSOLETE10              <obsolete error code>
FTP_WEIRD_PASS_REPLY    <FTP weird PASS reply>
OBSOLETE12              <obsolete error code>
FTP_WEIRD_PASV_REPLY    <FTP weird PASV reply>
FTP_WEIRD_227_FORMAT    <FTP weird 227 format>
FTP_CANT_GET_HOST       <FTP can not get host>
OBSOLETE16              <obsolete error code>
FTP_COULDNT_SET_TYPE    <FTP could not set type>
PARTIAL_FILE            <partial file>
FTP_COULDNT_RETR_FILE   <FTP could not RETR file>
OBSOLETE20              <obsolete error code>
QUOTE_ERROR             <quote command error>
HTTP_RETURNED_ERROR     <HTTP returned error>
WRITE_ERROR             <write error>
OBSOLETE24              <obsolete error code>
UPLOAD_FAILED           <failed upload command>
READ_ERROR              <read error, could not open/read file>
OUT_OF_MEMORY           <out of memory>
OPERATION_TIMEOUTED     <operation timed out, timeout time was reached>
OBSOLETE29              <obsolete error code>
FTP_PORT_FAILED         <FTP PORT operation failed>
FTP_COULDNT_USE_REST    <FTP REST command failed>
OBSOLETE32              <obsolete error code>
RANGE_ERROR             <RANGE command error>
HTTP_POST_ERROR         <HTTP POST error>
SSL_CONNECT_ERROR       <SSL connect error>
BAD_DOWNLOAD_RESUME     <bad download resume>
FILE_COULDNT_READ_FILE  <FILE could not read file>
LDAP_CANNOT_BIND        <LDAP cannot bind>
LDAP_SEARCH_FAILED      <LDAP search failed>
OBSOLETE40              <obsolete error code>
FUNCTION_NOT_FOUND      <function not found>
ABORTED_BY_CALLBACK     <aborted by callback>
BAD_FUNCTION_ARGUMENT   <bad function argument>
OBSOLETE44              <obsolete error code>
INTERFACE_FAILED        <CURLOPT_INTERFACE failed>
OBSOLETE46              <obsolete error code>
TOO_MANY_REDIRECTS      <too many redirects>
UNKNOWN_TELNET_OPTION   <unknown TELNET option>
TELNET_OPTION_SYNTAX    <malformed TELNET option syntax>
OBSOLETE50              <obsolete error code>
PEER_FAILED_VERIF       <peer certificate or fingerprint failed>
GOT_NOTHING             <got nothing>
SSL_ENGINE_NOTFOUND     <SSL crypto engine not found>
SSL_ENGINE_SETFAILED    <SSL can not set SSL crypto engine as default>
SEND_ERROR              <SEND error, failure sending network data>
RECV_ERROR              <RECV error, failure receiving network data>
OBSOLETE57              <obsolete error code>
SSL_CERTPROBLEM         <SSL problem with the local certificate>
SSL_CIPHER              <SSL CIPHER, could not use specified cipher>
SSL_CACERT              <SSL CACERT, problem with the CA cert (path?)>
BAD_CONTENT_ENCODING    <unrecognized transfer encoding>
LDAP_INVALID_URL        <LDAP invalid url>
FILESIZE_EXCEEDED       <maximum file size exceeded>
USE_SSL_FAILED          <requested FTP SSL level failed>
SEND_FAIL_REWIND        <sending data requires a rewind that failed>
SSL_ENGINE_INITFAILED   <failed to initialise ENGINE>
LOGIN_DENIED            <user or password not accepted. failed to login>
TFTP_NOTFOUND           <file not found on server>
TFTP_PERM               <permission problem on server>
REMOTE_DISK_FULL        <out of disk space on server>
TFTP_ILLEGAL            <illegal TFTP operation>
TFTP_UNKNOWNID          <unknown transfer ID>
REMOTE_FILE_EXISTS      <file already exists>
TFTP_NOSUCHUSER         <no such user>
CONV_FAILED             <conversion failed>
CONV_REQD               <caller must register conversion callbacks>
SSL_CACERT_BADFILE      <could not load CACERT file>
REMOTE_FILE_NOT_FOUND   <remote file not found>
SSH                     <unspecified error from the SSH layer>
SSL_SHUTDOWN_FAILED     <failed to shut down the SSL connection>
AGAIN                   <socket not ready, wait and try again>
SSL_CRL_BADFILE         <could not load CRL file, missing or wrong format>
SSL_ISSUER_ERROR        <issuer check failed>
CURL_LAST               <CURLMSG.MSG is out of sync with the source code>

.END
Changes to jni/curl/packages/vms/curlmsg_vms.h.
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#define   SEV_SUCCESS   1
#define   SEV_ERROR     2
#define   SEV_INFO      3
#define   SEV_FATAL     4
*/

static const long vms_cond[] =
	{
	CURL_OK,
	CURL_UNSUPPORTED_PROTOCOL,
	CURL_FAILED_INIT,
	CURL_URL_MALFORMAT,
	CURL_OBSOLETE4,
	CURL_COULDNT_RESOLVE_PROXY,
	CURL_COULDNT_RESOLVE_HOST,
	CURL_COULDNT_CONNECT,
	CURL_WEIRD_SERVER_REPLY,
	CURL_FTP_ACCESS_DENIED,
	CURL_OBSOLETE10,
	CURL_FTP_WEIRD_PASS_REPLY,
	CURL_OBSOLETE12,
	CURL_FTP_WEIRD_PASV_REPLY,
	CURL_FTP_WEIRD_227_FORMAT,
	CURL_FTP_CANT_GET_HOST,
	CURL_OBSOLETE16,
	CURL_FTP_COULDNT_SET_TYPE,
	CURL_PARTIAL_FILE,
	CURL_FTP_COULDNT_RETR_FILE,
	CURL_OBSOLETE20,
	CURL_QUOTE_ERROR,
	CURL_HTTP_RETURNED_ERROR,
	CURL_WRITE_ERROR,
	CURL_OBSOLETE24,
	CURL_UPLOAD_FAILED,
	CURL_READ_ERROR,
	CURL_OUT_OF_MEMORY,
	CURL_OPERATION_TIMEOUTED,
	CURL_OBSOLETE29,
	CURL_FTP_PORT_FAILED,
	CURL_FTP_COULDNT_USE_REST,
	CURL_OBSOLETE32,
	CURL_RANGE_ERROR,
	CURL_HTTP_POST_ERROR,
	CURL_SSL_CONNECT_ERROR,
	CURL_BAD_DOWNLOAD_RESUME,
	CURL_FILE_COULDNT_READ_FILE,
	CURL_LDAP_CANNOT_BIND,
	CURL_LDAP_SEARCH_FAILED,
	CURL_OBSOLETE40,
	CURL_FUNCTION_NOT_FOUND,
	CURL_ABORTED_BY_CALLBACK,
	CURL_BAD_FUNCTION_ARGUMENT,
	CURL_OBSOLETE44,
	CURL_INTERFACE_FAILED,
	CURL_OBSOLETE46,
	CURL_TOO_MANY_REDIRECTS,
	CURL_UNKNOWN_TELNET_OPTION,
	CURL_TELNET_OPTION_SYNTAX,
	CURL_OBSOLETE50,
	CURL_PEER_FAILED_VERIF,
	CURL_GOT_NOTHING,
	CURL_SSL_ENGINE_NOTFOUND,
	CURL_SSL_ENGINE_SETFAILED,
	CURL_SEND_ERROR,
	CURL_RECV_ERROR,
	CURL_OBSOLETE57,
	CURL_SSL_CERTPROBLEM,
	CURL_SSL_CIPHER,
	CURL_SSL_CACERT,
	CURL_BAD_CONTENT_ENCODING,
	CURL_LDAP_INVALID_URL,
	CURL_FILESIZE_EXCEEDED,
	CURL_USE_SSL_FAILED,
	CURL_SEND_FAIL_REWIND,
	CURL_SSL_ENGINE_INITFAILED,
	CURL_LOGIN_DENIED,
	CURL_TFTP_NOTFOUND,
	CURL_TFTP_PERM,
	CURL_REMOTE_DISK_FULL,
	CURL_TFTP_ILLEGAL,
	CURL_TFTP_UNKNOWNID,
	CURL_REMOTE_FILE_EXISTS,
	CURL_TFTP_NOSUCHUSER,
	CURL_CONV_FAILED,
	CURL_CONV_REQD,
	CURL_SSL_CACERT_BADFILE,
	CURL_REMOTE_FILE_NOT_FOUND,
	CURL_SSH,
	CURL_SSL_SHUTDOWN_FAILED,
	CURL_AGAIN,
	CURLE_SSL_CRL_BADFILE,
	CURLE_SSL_ISSUER_ERROR,
	CURL_CURL_LAST
	};

#endif /* HEADER_CURLMSG_VMS_H */







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#define   SEV_SUCCESS   1
#define   SEV_ERROR     2
#define   SEV_INFO      3
#define   SEV_FATAL     4
*/

static const long vms_cond[] =
{
  CURL_OK,
  CURL_UNSUPPORTED_PROTOCOL,
  CURL_FAILED_INIT,
  CURL_URL_MALFORMAT,
  CURL_OBSOLETE4,
  CURL_COULDNT_RESOLVE_PROXY,
  CURL_COULDNT_RESOLVE_HOST,
  CURL_COULDNT_CONNECT,
  CURL_WEIRD_SERVER_REPLY,
  CURL_FTP_ACCESS_DENIED,
  CURL_OBSOLETE10,
  CURL_FTP_WEIRD_PASS_REPLY,
  CURL_OBSOLETE12,
  CURL_FTP_WEIRD_PASV_REPLY,
  CURL_FTP_WEIRD_227_FORMAT,
  CURL_FTP_CANT_GET_HOST,
  CURL_OBSOLETE16,
  CURL_FTP_COULDNT_SET_TYPE,
  CURL_PARTIAL_FILE,
  CURL_FTP_COULDNT_RETR_FILE,
  CURL_OBSOLETE20,
  CURL_QUOTE_ERROR,
  CURL_HTTP_RETURNED_ERROR,
  CURL_WRITE_ERROR,
  CURL_OBSOLETE24,
  CURL_UPLOAD_FAILED,
  CURL_READ_ERROR,
  CURL_OUT_OF_MEMORY,
  CURL_OPERATION_TIMEOUTED,
  CURL_OBSOLETE29,
  CURL_FTP_PORT_FAILED,
  CURL_FTP_COULDNT_USE_REST,
  CURL_OBSOLETE32,
  CURL_RANGE_ERROR,
  CURL_HTTP_POST_ERROR,
  CURL_SSL_CONNECT_ERROR,
  CURL_BAD_DOWNLOAD_RESUME,
  CURL_FILE_COULDNT_READ_FILE,
  CURL_LDAP_CANNOT_BIND,
  CURL_LDAP_SEARCH_FAILED,
  CURL_OBSOLETE40,
  CURL_FUNCTION_NOT_FOUND,
  CURL_ABORTED_BY_CALLBACK,
  CURL_BAD_FUNCTION_ARGUMENT,
  CURL_OBSOLETE44,
  CURL_INTERFACE_FAILED,
  CURL_OBSOLETE46,
  CURL_TOO_MANY_REDIRECTS,
  CURL_UNKNOWN_TELNET_OPTION,
  CURL_TELNET_OPTION_SYNTAX,
  CURL_OBSOLETE50,
  CURL_PEER_FAILED_VERIF,
  CURL_GOT_NOTHING,
  CURL_SSL_ENGINE_NOTFOUND,
  CURL_SSL_ENGINE_SETFAILED,
  CURL_SEND_ERROR,
  CURL_RECV_ERROR,
  CURL_OBSOLETE57,
  CURL_SSL_CERTPROBLEM,
  CURL_SSL_CIPHER,
  CURL_SSL_CACERT,
  CURL_BAD_CONTENT_ENCODING,
  CURL_LDAP_INVALID_URL,
  CURL_FILESIZE_EXCEEDED,
  CURL_USE_SSL_FAILED,
  CURL_SEND_FAIL_REWIND,
  CURL_SSL_ENGINE_INITFAILED,
  CURL_LOGIN_DENIED,
  CURL_TFTP_NOTFOUND,
  CURL_TFTP_PERM,
  CURL_REMOTE_DISK_FULL,
  CURL_TFTP_ILLEGAL,
  CURL_TFTP_UNKNOWNID,
  CURL_REMOTE_FILE_EXISTS,
  CURL_TFTP_NOSUCHUSER,
  CURL_CONV_FAILED,
  CURL_CONV_REQD,
  CURL_SSL_CACERT_BADFILE,
  CURL_REMOTE_FILE_NOT_FOUND,
  CURL_SSH,
  CURL_SSL_SHUTDOWN_FAILED,
  CURL_AGAIN,
  CURLE_SSL_CRL_BADFILE,
  CURLE_SSL_ISSUER_ERROR,
  CURL_CURL_LAST
};

#endif /* HEADER_CURLMSG_VMS_H */
Changes to jni/curl/packages/vms/generate_config_vms_h_curl.com.
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
$if .not. nossl
$then
$!
$!  ssl$* logicals means HP ssl is present
$!----------------------------------------
$   if f$trnlnm("ssl$root") .nes. ""
$   then
$	nohpssl = 0
$	hpssl = 1
$   endif
$!
$!  HP defines OPENSSL as SSL$INCLUDE as a convenience for linking.
$!  As it is a violation of VMS standards for this to be provided,
$!  some sites may have removed it, but if present, assume that
$!  it indicates which OpenSSL to use.
$!------------------------------------
$   openssl_lnm = f$trnlnm("OPENSSL")
$   if (openssl_lnm .nes. "SYS$INCLUDE")
$   then
$!	Non HP SSL is installed, default to use it.
$	nohpssl = 1
$	hpssl = 0
$   endif
$!
$!  Now check to see if hpssl has been specifically disabled
$!----------------------------------------------------------
$   if f$locate(",nohpssl,", args_lower) .lt. args_len
$   then
$	nohpssl = 1
$	hpssl = 0
$   endif
$!
$!  Finally check to see if hp ssl has been specifically included.
$!----------------------------------------------------------------
$   if f$locate(",nohpssl,", args_lower) .lt. args_len
$   then
$	nohpssl = 1
$	hpssl = 0
$   endif
$endif
$!
$! Did someone port LIBIDN in the GNV compatible way?
$!------------------------------------------------------
$if f$trnlnm("GNV$LIBIDNSHR") .nes. ""
$then
$   write sys$output "NOTICE:  A LIBIDN port has been detected."
$   write sys$output " This port of curl for VMS has not been tested with it."
$   if f$locate(",libidn,", args_lower) .lt. args_len
$   then
$	libidn = 1
$   endif
$   if .not. libidn
$   then
$	write sys$output " LIBIDN support is not enabled."
$	write sys$output "Run with the ""libidn"" parameter to attempt to use."
$   else
$	write sys$output " Untested LIBIDN support requested."
$   endif
$endif
$!
$! Did someone port LIBSSH2 in the GNV compatible way?
$!------------------------------------------------------
$if f$trnlnm("GNV$LIBSSH2SHR") .nes. ""
$then
$   write sys$output "NOTICE:  A LIBSSH2 port has been detected."
$   write sys$output " This port of curl for VMS has not been tested with it."
$   if f$locate(",libssh2,", args_lower) .lt. args_len
$   then
$	libssh2 = 1
$   endif
$   if .not. libssh2
$   then
$	write sys$output " LIBSSH2 support is not enabled."
$	write sys$output "Run with the ""libssh2"" parameter to attempt to use."
$   else
$	write sys$output " Untested LIBSSH2 support requested."
$   endif
$endif
$!
$! LDAP suppressed?
$if f$locate(",noldap,", args_lower) .lt. args_len
$then
$   noldap = 1
$endif
$if f$search("SYS$SHARE:LDAP$SHR.EXE") .eqs. ""
$then
$   noldap = 1
$endif
$!
$if f$locate(",nokerberos,", args_lower) .lt. args_len then nokerberos = 1
$if .not. nokerberos
$then
$!  If kerberos is installed: sys$share:gss$rtl.exe exists.
$   if f$search("sys$shsare:gss$rtl.exe") .eqs. ""
$   then
$	nokerberos = 1
$   endif
$endif
$!
$!
$! Is GNV compatible LIBZ present?
$!------------------------------------------------------
$if f$trnlnm("GNV$LIBZSHR") .nes. ""
$then
$   if f$locate(",nozlib,", args_lower) .lt. args_len
$   then
$	nozlib = 1
$   endif
$!   if .not. nozlib
$!   then
$!	write sys$output " GNV$LIBZSHR support is enabled."
$!   else
$!	write sys$output " GNV$LIBZSHR support is disabled by nozlib."
$!   endif
$else
$   nozlib = 1
$endif
$!
$!
$! Start the configuration file.







|
|










|
|
|






|
|






|
|











|



|
|

|











|



|
|

|



















|










|



|

|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
$if .not. nossl
$then
$!
$!  ssl$* logicals means HP ssl is present
$!----------------------------------------
$   if f$trnlnm("ssl$root") .nes. ""
$   then
$       nohpssl = 0
$       hpssl = 1
$   endif
$!
$!  HP defines OPENSSL as SSL$INCLUDE as a convenience for linking.
$!  As it is a violation of VMS standards for this to be provided,
$!  some sites may have removed it, but if present, assume that
$!  it indicates which OpenSSL to use.
$!------------------------------------
$   openssl_lnm = f$trnlnm("OPENSSL")
$   if (openssl_lnm .nes. "SYS$INCLUDE")
$   then
$!      Non HP SSL is installed, default to use it.
$       nohpssl = 1
$       hpssl = 0
$   endif
$!
$!  Now check to see if hpssl has been specifically disabled
$!----------------------------------------------------------
$   if f$locate(",nohpssl,", args_lower) .lt. args_len
$   then
$       nohpssl = 1
$       hpssl = 0
$   endif
$!
$!  Finally check to see if hp ssl has been specifically included.
$!----------------------------------------------------------------
$   if f$locate(",nohpssl,", args_lower) .lt. args_len
$   then
$       nohpssl = 1
$       hpssl = 0
$   endif
$endif
$!
$! Did someone port LIBIDN in the GNV compatible way?
$!------------------------------------------------------
$if f$trnlnm("GNV$LIBIDNSHR") .nes. ""
$then
$   write sys$output "NOTICE:  A LIBIDN port has been detected."
$   write sys$output " This port of curl for VMS has not been tested with it."
$   if f$locate(",libidn,", args_lower) .lt. args_len
$   then
$       libidn = 1
$   endif
$   if .not. libidn
$   then
$       write sys$output " LIBIDN support is not enabled."
$       write sys$output "Run with the ""libidn"" parameter to attempt to use."
$   else
$       write sys$output " Untested LIBIDN support requested."
$   endif
$endif
$!
$! Did someone port LIBSSH2 in the GNV compatible way?
$!------------------------------------------------------
$if f$trnlnm("GNV$LIBSSH2SHR") .nes. ""
$then
$   write sys$output "NOTICE:  A LIBSSH2 port has been detected."
$   write sys$output " This port of curl for VMS has not been tested with it."
$   if f$locate(",libssh2,", args_lower) .lt. args_len
$   then
$       libssh2 = 1
$   endif
$   if .not. libssh2
$   then
$       write sys$output " LIBSSH2 support is not enabled."
$       write sys$output "Run with the ""libssh2"" parameter to attempt to use."
$   else
$       write sys$output " Untested LIBSSH2 support requested."
$   endif
$endif
$!
$! LDAP suppressed?
$if f$locate(",noldap,", args_lower) .lt. args_len
$then
$   noldap = 1
$endif
$if f$search("SYS$SHARE:LDAP$SHR.EXE") .eqs. ""
$then
$   noldap = 1
$endif
$!
$if f$locate(",nokerberos,", args_lower) .lt. args_len then nokerberos = 1
$if .not. nokerberos
$then
$!  If kerberos is installed: sys$share:gss$rtl.exe exists.
$   if f$search("sys$shsare:gss$rtl.exe") .eqs. ""
$   then
$       nokerberos = 1
$   endif
$endif
$!
$!
$! Is GNV compatible LIBZ present?
$!------------------------------------------------------
$if f$trnlnm("GNV$LIBZSHR") .nes. ""
$then
$   if f$locate(",nozlib,", args_lower) .lt. args_len
$   then
$       nozlib = 1
$   endif
$!   if .not. nozlib
$!   then
$!      write sys$output " GNV$LIBZSHR support is enabled."
$!   else
$!      write sys$output " GNV$LIBZSHR support is disabled by nozlib."
$!   endif
$else
$   nozlib = 1
$endif
$!
$!
$! Start the configuration file.
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
$if .not. noldap
$then
$   write cvh "#ifdef CURL_DISABLE_LDAP"
$   write cvh "#undef CURL_DISABLE_LDAP"
$   write cvh "#endif"
$   if .not. nossl
$   then
$	write cvh "#ifdef CURL_DISABLE_LDAPS"
$	write cvh "#undef CURL_DISABLE_LDAPS"
$	write cvh "#endif"
$   endif
$endif
$write cvh "#ifdef CURL_DISABLE_LIBCURL_OPTION"
$write cvh "#undef CURL_DISABLE_LIBCURL_OPTION"
$write cvh "#endif"
$write cvh "#ifndef __VAX"
$write cvh "#ifdef CURL_DISABLE_NTLM"







|
|
|







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
$if .not. noldap
$then
$   write cvh "#ifdef CURL_DISABLE_LDAP"
$   write cvh "#undef CURL_DISABLE_LDAP"
$   write cvh "#endif"
$   if .not. nossl
$   then
$       write cvh "#ifdef CURL_DISABLE_LDAPS"
$       write cvh "#undef CURL_DISABLE_LDAPS"
$       write cvh "#endif"
$   endif
$endif
$write cvh "#ifdef CURL_DISABLE_LIBCURL_OPTION"
$write cvh "#undef CURL_DISABLE_LIBCURL_OPTION"
$write cvh "#endif"
$write cvh "#ifndef __VAX"
$write cvh "#ifdef CURL_DISABLE_NTLM"
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
$       then
$           write cvh "#define VMS_OLD_SSL 1"
$       endif
$   endif
$endif
$!
$!
$! LibIDN not ported to VMS at this time.
$! This is for international domain name support.
$! Allow explicit experimentation.
$if libidn
$then
$   write cvh "#define HAVE_IDNA_STRERROR 1"
$   write cvh "#define HAVE_IDNA_FREE 1"
$   write cvh "#define HAVE_IDNA_FREE_H 1"
$   write cvh "#define HAVE_LIBIDN 1"
$else
$   write cvh "#ifdef HAVE_LIBIDN"
$   write cvh "#undef HAVE_LIBIDN"
$   write cvh "#endif"
$endif
$!
$!
$! LibSSH2 not ported to VMS at this time.
$! Allow explicit experimentation.
$if libssh2
$then
$   write cvh "#define HAVE_LIBSSH2_EXIT 1"
$   write cvh "#define HAVE_LIBSSH2_INIT 1"
$   write cvh "#define HAVE_LIBSSH2_SCP_SEND64 1"
$   write cvh "#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1"







|















|







390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
$       then
$           write cvh "#define VMS_OLD_SSL 1"
$       endif
$   endif
$endif
$!
$!
$! libidn not ported to VMS at this time.
$! This is for international domain name support.
$! Allow explicit experimentation.
$if libidn
$then
$   write cvh "#define HAVE_IDNA_STRERROR 1"
$   write cvh "#define HAVE_IDNA_FREE 1"
$   write cvh "#define HAVE_IDNA_FREE_H 1"
$   write cvh "#define HAVE_LIBIDN 1"
$else
$   write cvh "#ifdef HAVE_LIBIDN"
$   write cvh "#undef HAVE_LIBIDN"
$   write cvh "#endif"
$endif
$!
$!
$! libssh2 not ported to VMS at this time.
$! Allow explicit experimentation.
$if libssh2
$then
$   write cvh "#define HAVE_LIBSSH2_EXIT 1"
$   write cvh "#define HAVE_LIBSSH2_INIT 1"
$   write cvh "#define HAVE_LIBSSH2_SCP_SEND64 1"
$   write cvh "#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1"
Changes to jni/curl/packages/vms/gnv_link_curl.com.
396
397
398
399
400
401
402

403
404
405
406
407
408
409
$   then
$       define/user gnv$libcurl 'gnv_libcurl_share'
$       link'ldebug'/exe=[.src]curl.exe/dsf=[.src]curl.dsf -
           [.src]curl-tool_main.o, [.src]curl-tool_binmode.o, -
           [.src]curl-tool_bname.o, [.src]curl-tool_cb_dbg.o, -
           [.src]curl-tool_cb_hdr.o, [.src]curl-tool_cb_prg.o, -
           [.src]curl-tool_cb_rea.o, [.src]curl-tool_cb_see.o, -

           [.src]curl-tool_cb_wrt.o, [.src]curl-tool_cfgable.o, -
           [.src]curl-tool_convert.o, [.src]curl-tool_dirhie.o, -
           [.src]curl-tool_doswin.o, [.src]curl-tool_easysrc.o, -
           [.src]curl-tool_formparse.o, [.src]curl-tool_getparam.o, -
           [.src]curl-tool_getpass.o, [.src]curl-tool_help.o, -
           [.src]curl-tool_helpers.o, [.src]curl-tool_homedir.o, -
           [.src]curl-tool_hugehelp.o, [.src]curl-tool_libinfo.o, -







>







396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
$   then
$       define/user gnv$libcurl 'gnv_libcurl_share'
$       link'ldebug'/exe=[.src]curl.exe/dsf=[.src]curl.dsf -
           [.src]curl-tool_main.o, [.src]curl-tool_binmode.o, -
           [.src]curl-tool_bname.o, [.src]curl-tool_cb_dbg.o, -
           [.src]curl-tool_cb_hdr.o, [.src]curl-tool_cb_prg.o, -
           [.src]curl-tool_cb_rea.o, [.src]curl-tool_cb_see.o, -
           [.src]curl-tool_cb_soc.o, -
           [.src]curl-tool_cb_wrt.o, [.src]curl-tool_cfgable.o, -
           [.src]curl-tool_convert.o, [.src]curl-tool_dirhie.o, -
           [.src]curl-tool_doswin.o, [.src]curl-tool_easysrc.o, -
           [.src]curl-tool_formparse.o, [.src]curl-tool_getparam.o, -
           [.src]curl-tool_getpass.o, [.src]curl-tool_help.o, -
           [.src]curl-tool_helpers.o, [.src]curl-tool_homedir.o, -
           [.src]curl-tool_hugehelp.o, [.src]curl-tool_libinfo.o, -
Changes to jni/curl/packages/vms/readme.
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
pcsi_product_gnv_curl.com
                        This generates the PCSI kit after the libcurl
                        shared image has been made.

readme.                 This file.

report_openssl_version.c
                        Program to check that the openssl version is new
                        enough for building a shared libcurl image.

setup_gnv_curl_build.com
                        This procedure sets up symbols and logical names
                        for a GNV build environment and also copies some
                        helper files.








|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
pcsi_product_gnv_curl.com
                        This generates the PCSI kit after the libcurl
                        shared image has been made.

readme.                 This file.

report_openssl_version.c
                        Program to check that the OpenSSL version is new
                        enough for building a shared libcurl image.

setup_gnv_curl_build.com
                        This procedure sets up symbols and logical names
                        for a GNV build environment and also copies some
                        helper files.

Changes to jni/curl/packages/vms/report_openssl_version.c.
1
2
3
4
5
6
7
8
9
10
/* File: report_openssl_version.c
 *
 * This file dynamically loads the openssl shared image to report the
 * version string.
 *
 * It will optionally place that version string in a DCL symbol.
 *
 * Usage:  report_openssl_version <shared_image> [<dcl_symbol>]
 *
 * Copyright (C) John Malmberg


|







1
2
3
4
5
6
7
8
9
10
/* File: report_openssl_version.c
 *
 * This file dynamically loads the OpenSSL shared image to report the
 * version string.
 *
 * It will optionally place that version string in a DCL symbol.
 *
 * Usage:  report_openssl_version <shared_image> [<dcl_symbol>]
 *
 * Copyright (C) John Malmberg
Changes to jni/curl/projects/README.md.
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

For example, if you are using Visual Studio 2010 then you should be able to
use `VC10\curl-all.sln` to build curl and libcurl.

## Running DLL based configurations

If you are a developer and plan to run the curl tool from Visual Studio with
any third-party libraries (such as OpenSSL, wolfSSL or LibSSH2) then you will
need to add the search path of these DLLs to the configuration's PATH
environment. To do that:

 1. Open the 'curl-all.sln' or 'curl.sln' solutions
 2. Right-click on the 'curl' project and select Properties
 3. Navigate to 'Configuration Properties > Debugging > Environment'
 4. Add `PATH='Path to DLL';C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem`

... where 'Path to DLL` is the configuration specific path. For example the
following configurations in Visual Studio 2010 might be:

DLL Debug - DLL OpenSSL (Win32):

    PATH=..\..\..\..\..\openssl\build\Win32\VC10\DLL Debug;C:\Windows\system32;
    C:\Windows;C:\Windows\System32\Wbem

DLL Debug - DLL OpenSSL (x64):

    PATH=..\..\..\..\..\openssl\build\Win64\VC10\DLL Debug;C:\Windows\system32;
    C:\Windows;C:\Windows\System32\Wbem

DLL Debug - DLL wolfSSL (Win32):

    PATH=..\..\..\..\..\wolfssl\build\Win32\VC10\DLL Debug;C:\Windows\system32;
    C:\Windows;C:\Windows\System32\Wbem

DLL Debug - DLL wolfSSL (x64):

    PATH=..\..\..\..\..\wolfssl\build\Win64\VC10\DLL Debug;C:\Windows\system32;
    C:\Windows;C:\Windows\System32\Wbem

If you are using a configuration that uses multiple third-party library DLLs
(such as DLL Debug - DLL OpenSSL - DLL LibSSH2) then 'Path to DLL' will need
to contain the path to both of these.

## Notes

The following keywords have been used in the directory hierarchy:

 - `<platform>`      - The platform (For example: Windows)







|






|






|




|




|




|



|







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

For example, if you are using Visual Studio 2010 then you should be able to
use `VC10\curl-all.sln` to build curl and libcurl.

## Running DLL based configurations

If you are a developer and plan to run the curl tool from Visual Studio with
any third-party libraries (such as OpenSSL, wolfSSL or libssh2) then you will
need to add the search path of these DLLs to the configuration's PATH
environment. To do that:

 1. Open the 'curl-all.sln' or 'curl.sln' solutions
 2. Right-click on the 'curl' project and select Properties
 3. Navigate to 'Configuration Properties > Debugging > Environment'
 4. Add `PATH='Path to DLL';C:\Windows\System32;C:\Windows;C:\Windows\System32\Wbem`

... where 'Path to DLL` is the configuration specific path. For example the
following configurations in Visual Studio 2010 might be:

DLL Debug - DLL OpenSSL (Win32):

    PATH=..\..\..\..\..\openssl\build\Win32\VC10\DLL Debug;C:\Windows\System32;
    C:\Windows;C:\Windows\System32\Wbem

DLL Debug - DLL OpenSSL (x64):

    PATH=..\..\..\..\..\openssl\build\Win64\VC10\DLL Debug;C:\Windows\System32;
    C:\Windows;C:\Windows\System32\Wbem

DLL Debug - DLL wolfSSL (Win32):

    PATH=..\..\..\..\..\wolfssl\build\Win32\VC10\DLL Debug;C:\Windows\System32;
    C:\Windows;C:\Windows\System32\Wbem

DLL Debug - DLL wolfSSL (x64):

    PATH=..\..\..\..\..\wolfssl\build\Win64\VC10\DLL Debug;C:\Windows\System32;
    C:\Windows;C:\Windows\System32\Wbem

If you are using a configuration that uses multiple third-party library DLLs
(such as DLL Debug - DLL OpenSSL - DLL libssh2) then 'Path to DLL' will need
to contain the path to both of these.

## Notes

The following keywords have been used in the directory hierarchy:

 - `<platform>`      - The platform (For example: Windows)
Changes to jni/curl/projects/build-openssl.bat.
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  ) else (
    call "%ABS_VC_PATH%\vcvarsall" %VCVARS_PLATFORM%
  )

  echo.

  cd /d "%START_DIR%" || (echo Error: Failed cd start & exit /B 1)
  rem Save the full path of the openssl source dir
  set "SOURCE_PATH=%CD%"

  rem Set temporary paths for building and installing OpenSSL. If a temporary
  rem path is not the same as the source path then it is *removed* after the
  rem installation is completed.
  rem
  rem For legacy OpenSSL the temporary build path must be the source path.







|







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  ) else (
    call "%ABS_VC_PATH%\vcvarsall" %VCVARS_PLATFORM%
  )

  echo.

  cd /d "%START_DIR%" || (echo Error: Failed cd start & exit /B 1)
  rem Save the full path of the OpenSSL source dir
  set "SOURCE_PATH=%CD%"

  rem Set temporary paths for building and installing OpenSSL. If a temporary
  rem path is not the same as the source path then it is *removed* after the
  rem installation is completed.
  rem
  rem For legacy OpenSSL the temporary build path must be the source path.
Changes to jni/curl/scripts/Makefile.in.
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







129
130
131
132
133
134
135

136
137
138
139
140
141
142
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
253
254
255
256
257
258
259


260
261
262
263
264
265
266
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
Changes to jni/curl/scripts/cd2nroff.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#
# SPDX-License-Identifier: curl
#
###########################################################################

=begin comment

Converts a curldown file to nroff (man page).

=end comment
=cut

use strict;
use warnings;








|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#
# SPDX-License-Identifier: curl
#
###########################################################################

=begin comment

Converts a curldown file to nroff (manpage).

=end comment
=cut

use strict;
use warnings;

99
100
101
102
103
104
105
106
107
108
109

110
111
112

113








114
115
116
117
118
119
120
sub outprotocols {
    my (@p) = @_;
    my $comma = 0;
    my @o;
    push @o, ".SH PROTOCOLS\n";

    if($p[0] eq "TLS") {
        push @o, "All TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc.";
    }
    else {
        my @s = sort @p;

        for my $e (sort @s) {
            push @o, sprintf "%s$e",
                $comma ? (($e eq $s[-1]) ? " and " : ", "): "";

            $comma = 1;








        }
    }
    push @o, "\n";
    return @o;
}

sub outtls {







|



>

|
|
>

>
>
>
>
>
>
>
>







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
sub outprotocols {
    my (@p) = @_;
    my $comma = 0;
    my @o;
    push @o, ".SH PROTOCOLS\n";

    if($p[0] eq "TLS") {
        push @o, "This functionality affects all TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc.";
    }
    else {
        my @s = sort @p;
        push @o, "This functionality affects ";
        for my $e (sort @s) {
            push @o, sprintf "%s%s",
                $comma ? (($e eq $s[-1]) ? " and " : ", "): "",
                lc($e);
            $comma = 1;
        }
        if($#s == 0) {
            if($s[0] eq "All") {
                push @o, " supported protocols";
            }
            else {
                push @o, " only";
            }
        }
    }
    push @o, "\n";
    return @o;
}

sub outtls {
193
194
195
196
197
198
199

200
201
202
203
204
205
206
    my $errors = 0;
    my $fh;
    my $line;
    my $list;
    my $tlslist;
    my $section;
    my $source;

    my $spdx;
    my $start = 0;
    my $title;

    if(defined($f)) {
        if(!open($fh, "<:crlf", "$f")) {
            print STDERR "cd2nroff failed to open '$f' for reading: $!\n";







>







203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
    my $errors = 0;
    my $fh;
    my $line;
    my $list;
    my $tlslist;
    my $section;
    my $source;
    my $addedin;
    my $spdx;
    my $start = 0;
    my $title;

    if(defined($f)) {
        if(!open($fh, "<:crlf", "$f")) {
            print STDERR "cd2nroff failed to open '$f' for reading: $!\n";
242
243
244
245
246
247
248








249
250
251
252
253
254
255
            $list = 1; # 1 for see-also
        }
        elsif(/^Protocol:/i) {
            $list = 2; # 2 for protocol
        }
        elsif(/^TLS-backend:/i) {
            $list = 3; # 3 for TLS backend








        }
        elsif(/^ +- (.*)/i) {
            # the only lists we support are see-also and protocol
            if($list == 1) {
                push @seealso, $1;
            }
            elsif($list == 2) {







>
>
>
>
>
>
>
>







253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
            $list = 1; # 1 for see-also
        }
        elsif(/^Protocol:/i) {
            $list = 2; # 2 for protocol
        }
        elsif(/^TLS-backend:/i) {
            $list = 3; # 3 for TLS backend
        }
        elsif(/^Added-in: *(.*)/i) {
            $addedin=$1;
            if(($addedin !~ /^[0-9.]+[0-9]\z/) &&
               ($addedin ne "n/a")) {
                print STDERR "$f:$line:1:ERROR: invalid version number in Added-in line: $addedin\n";
                return 2;
            }
        }
        elsif(/^ +- (.*)/i) {
            # the only lists we support are see-also and protocol
            if($list == 1) {
                push @seealso, $1;
            }
            elsif($list == 2) {
270
271
272
273
274
275
276
277
278
279
280
281








282
283
284
285
286
287
288
        elsif(/^SPDX-License-Identifier: (.*)/i) {
            $spdx=$1;
        }
        # REUSE-IgnoreEnd
        elsif(/^---/) {
            # end of the header section
            if(!$title) {
                print STDERR "ERROR: no 'Title:' in $f\n";
                return 1;
            }
            if(!$section) {
                print STDERR "ERROR: no 'Section:' in $f\n";








                return 2;
            }
            if(!$seealso[0]) {
                print STDERR "$f:$line:1:ERROR: no 'See-also:' present\n";
                return 2;
            }
            if(!$copyright) {







|



|
>
>
>
>
>
>
>
>







289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
        elsif(/^SPDX-License-Identifier: (.*)/i) {
            $spdx=$1;
        }
        # REUSE-IgnoreEnd
        elsif(/^---/) {
            # end of the header section
            if(!$title) {
                print STDERR "$f:$line:1:ERROR: no 'Title:' in $f\n";
                return 1;
            }
            if(!$section) {
                print STDERR "$f:$line:1:ERROR: no 'Section:' in $f\n";
                return 2;
            }
            if(!$source) {
                print STDERR "$f:$line:1:ERROR: no 'Source:' in $f\n";
                return 2;
            }
            if(!$addedin) {
                print STDERR "$f:$line:1:ERROR: no 'Added-in:' in $f\n";
                return 2;
            }
            if(!$seealso[0]) {
                print STDERR "$f:$line:1:ERROR: no 'See-also:' present\n";
                return 2;
            }
            if(!$copyright) {
322
323
324
325
326
327
328
329

330
331
332
333
334
335
336
                    }
                }
            }
            last;
        }
        else {
            chomp;
            print STDERR "WARN: unrecognized line in $f, ignoring:\n:'$_';"

        }
    }

    if(!$start) {
        print STDERR "$f:$line:1:ERROR: no header present\n";
        return 2;
    }







|
>







349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
                    }
                }
            }
            last;
        }
        else {
            chomp;
            print STDERR "$f:$line:1:ERROR: unrecognized header keyword: '$_'\n";
            $errors++;
        }
    }

    if(!$start) {
        print STDERR "$f:$line:1:ERROR: no header present\n";
        return 2;
    }
383
384
385
386
387
388
389
390

391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414





415
416
417
418
419
420
421
422
423



424
425
426
427
428
429











430
431
432
433
434
435
436

        # **bold**
        $d =~ s/\*\*(\S.*?)\*\*/\\fB$1\\fP/g;
        # *italics*
        $d =~ s/\*(\S.*?)\*/\\fI$1\\fP/g;

        if($d =~ /[^\\][\<\>]/) {
            print STDERR "$f:$line:1:WARN: un-escaped < or > used\n";

        }
        # convert backslash-'<' or '> to just the second character
        $d =~ s/\\([<>])/$1/g;

        # mentions of curl symbols with man pages use italics by default
        $d =~ s/((lib|)curl([^ ]*\(3\)))/\\fI$1\\fP/gi;

        # backticked becomes italics
        $d =~ s/\`(.*?)\`/\\fI$1\\fP/g;

        if(/^## (.*)/) {
            my $word = $1;
            # if there are enclosing quotes, remove them first
            $word =~ s/[\"\'\`](.*)[\"\'\`]\z/$1/;

            # enclose in double quotes if there is a space present
            if($word =~ / /) {
                push @desc, ".IP \"$word\"\n";
            }
            else {
                push @desc, ".IP $word\n";
            }
            $header = 1;
        }





        elsif(/^# (.*)/) {
            my $word = $1;
            # if there are enclosing quotes, remove them first
            $word =~ s/[\"\'](.*)[\"\']\z/$1/;

            if($word eq "PROTOCOLS") {
                print STDERR "$f:$line:1:WARN: PROTOCOLS section in source file\n";
            }
            elsif($word eq "EXAMPLE") {



                # insert the generated PROTOCOLS section before EXAMPLE
                push @desc, outprotocols(@proto);

                if($proto[0] eq "TLS") {
                    push @desc, outtls(@tls);
                }











            }
            push @desc, ".SH $word\n";
            $header = 1;
        }
        elsif(/^~~~c/) {
            # start of a code section, not indented
            $quote = 1;







|
>




|



















>
>
>
>
>








|
>
>
>
|





>
>
>
>
>
>
>
>
>
>
>







411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484

        # **bold**
        $d =~ s/\*\*(\S.*?)\*\*/\\fB$1\\fP/g;
        # *italics*
        $d =~ s/\*(\S.*?)\*/\\fI$1\\fP/g;

        if($d =~ /[^\\][\<\>]/) {
            print STDERR "$f:$line:1:ERROR: un-escaped < or > used\n";
            $errors++;
        }
        # convert backslash-'<' or '> to just the second character
        $d =~ s/\\([<>])/$1/g;

        # mentions of curl symbols with manpages use italics by default
        $d =~ s/((lib|)curl([^ ]*\(3\)))/\\fI$1\\fP/gi;

        # backticked becomes italics
        $d =~ s/\`(.*?)\`/\\fI$1\\fP/g;

        if(/^## (.*)/) {
            my $word = $1;
            # if there are enclosing quotes, remove them first
            $word =~ s/[\"\'\`](.*)[\"\'\`]\z/$1/;

            # enclose in double quotes if there is a space present
            if($word =~ / /) {
                push @desc, ".IP \"$word\"\n";
            }
            else {
                push @desc, ".IP $word\n";
            }
            $header = 1;
        }
        elsif(/^##/) {
            # end of IP sequence
            push @desc, ".PP\n";
            $header = 1;
        }
        elsif(/^# (.*)/) {
            my $word = $1;
            # if there are enclosing quotes, remove them first
            $word =~ s/[\"\'](.*)[\"\']\z/$1/;

            if($word eq "PROTOCOLS") {
                print STDERR "$f:$line:1:WARN: PROTOCOLS section in source file\n";
            }
            elsif($word eq "AVAILABILITY") {
                print STDERR "$f:$line:1:WARN: AVAILABILITY section in source file\n";
            }
            elsif($word eq "%PROTOCOLS%") {
                # insert the generated PROTOCOLS section
                push @desc, outprotocols(@proto);

                if($proto[0] eq "TLS") {
                    push @desc, outtls(@tls);
                }
                $header = 1;
                next;
            }
            elsif($word eq "%AVAILABILITY%") {
                if($addedin ne "n/a") {
                    # insert the generated AVAILABILITY section
                    push @desc, ".SH AVAILABILITY\n";
                    push @desc, "Added in curl $addedin\n";
                }
                $header = 1;
                next;
            }
            push @desc, ".SH $word\n";
            $header = 1;
        }
        elsif(/^~~~c/) {
            # start of a code section, not indented
            $quote = 1;
jni/curl/scripts/firefox-db2pem.sh became executable.
Changes to jni/curl/scripts/managen.
55
56
57
58
59
60
61


62
63
64
65
66
67
68
69
    @ts = localtime;
}
my $date = strftime "%Y-%m-%d", @ts;
my $year = strftime "%Y", @ts;
my $version = "unknown";
my $globals;



# get the long name version, return the man page string
sub manpageify {
    my ($k)=@_;
    my $l;
    my $trail;
    # the matching pattern might include a trailing dot that cannot be part of
    # the option name
    if($k =~ s/\.$//) {







>
>
|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    @ts = localtime;
}
my $date = strftime "%Y-%m-%d", @ts;
my $year = strftime "%Y", @ts;
my $version = "unknown";
my $globals;

my $indent = 4;

# get the long name version, return the manpage string
sub manpageify {
    my ($k)=@_;
    my $l;
    my $trail;
    # the matching pattern might include a trailing dot that cannot be part of
    # the option name
    if($k =~ s/\.$//) {
81
82
83
84
85
86
87
88






89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
        # only long
        $l = "\\fI\\-\\-$klong\\fP$trail";
    }
    return $l;
}


my $colwidth=78; # max number of columns







sub justline {
    my ($lvl, @line) = @_;
    my $w = -1;
    my $spaces = -1;
    my $width = $colwidth - ($lvl * 4);
    for(@line) {
        $w += length($_);
        $w++;
        $spaces++;
    }
    my $inject = $width - $w;
    my $ratio = 0; # stay at zero if no spaces at all
    if($spaces) {
        $ratio = $inject / $spaces;
    }
    my $spare = 0;
    print ' ' x ($lvl * 4);
    my $prev;
    for(@line) {
        while($spare >= 0.90) {
            print " ";
            $spare--;
        }
        printf "%s%s", $prev?" ":"", $_;
        $prev = 1;
        $spare += $ratio;
    }
    print "\n";
}

sub lastline {
    my ($lvl, @line) = @_;
    print ' ' x ($lvl * 4);
    my $prev = 0;
    for(@line) {
        printf "%s%s", $prev?" ":"", $_;
        $prev = 1;
    }
    print "\n";
}

sub outputpara {
    my ($lvl, $f) = @_;
    $f =~ s/\n/ /g;

    my $w = 0;
    my @words = split(/  */, $f);
    my $width = $colwidth - ($lvl * 4);

    my @line;
    for my $e (@words) {
        my $l = length($e);
        my $spaces = scalar(@line);
        if(($w + $l + $spaces) >= $width) {
            justline($lvl, @line);







|
>
>
>
>
>
>





|











|















|














|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
        # only long
        $l = "\\fI\\-\\-$klong\\fP$trail";
    }
    return $l;
}


my $colwidth=79; # max number of columns

sub prefixline {
    my ($num) = @_;
    print "\t" x ($num/8);
    print ' ' x ($num%8);
}

sub justline {
    my ($lvl, @line) = @_;
    my $w = -1;
    my $spaces = -1;
    my $width = $colwidth - ($lvl * $indent);
    for(@line) {
        $w += length($_);
        $w++;
        $spaces++;
    }
    my $inject = $width - $w;
    my $ratio = 0; # stay at zero if no spaces at all
    if($spaces) {
        $ratio = $inject / $spaces;
    }
    my $spare = 0;
    prefixline($lvl * $indent);
    my $prev;
    for(@line) {
        while($spare >= 0.90) {
            print " ";
            $spare--;
        }
        printf "%s%s", $prev?" ":"", $_;
        $prev = 1;
        $spare += $ratio;
    }
    print "\n";
}

sub lastline {
    my ($lvl, @line) = @_;
    prefixline($lvl * $indent);
    my $prev = 0;
    for(@line) {
        printf "%s%s", $prev?" ":"", $_;
        $prev = 1;
    }
    print "\n";
}

sub outputpara {
    my ($lvl, $f) = @_;
    $f =~ s/\n/ /g;

    my $w = 0;
    my @words = split(/  */, $f);
    my $width = $colwidth - ($lvl * $indent);

    my @line;
    for my $e (@words) {
        my $l = length($e);
        my $spaces = scalar(@line);
        if(($w + $l + $spaces) >= $width) {
            justline($lvl, @line);
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
    my $a = 999999;
    if($version =~ /^(\d+)\.(\d+)\.(\d+)/) {
        $a = $1 * 1000 + $2 * 10 + $3;
    }
    elsif($version =~ /^(\d+)\.(\d+)/) {
        $a = $1 * 1000 + $2 * 10;
    }
    if($a < 7500) {
        # we consider everything before 7.50.0 to be too old to mention
        # specific changes for
        return 1;
    }
    return 0;
}

sub added {







|
|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
    my $a = 999999;
    if($version =~ /^(\d+)\.(\d+)\.(\d+)/) {
        $a = $1 * 1000 + $2 * 10 + $3;
    }
    elsif($version =~ /^(\d+)\.(\d+)/) {
        $a = $1 * 1000 + $2 * 10;
    }
    if($a < 7600) {
        # we consider everything before 7.60.0 to be too old to mention
        # specific changes for
        return 1;
    }
    return 0;
}

sub added {
264
265
266
267
268
269
270

271
272
273
274
275

276
277
278
279
280
281
282
    my @desc;
    my $tablemode = 0;
    my $header = 0;
    # if $top is TRUE, it means a top-level page and not a command line option
    my $top = ($line == 1);
    my $quote;
    my $level;

    $start = 0;

    while(<$fh>) {
        my $d = $_;
        $line++;

        if($d =~ /^\.(SH|BR|IP|B)/) {
            print STDERR "$f:$line:1:ERROR: nroff instruction in input: \".$1\"\n";
            return 4;
        }
        if(/^ *<!--/) {
            # skip comments
            next;







>





>







272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
    my @desc;
    my $tablemode = 0;
    my $header = 0;
    # if $top is TRUE, it means a top-level page and not a command line option
    my $top = ($line == 1);
    my $quote;
    my $level;
    my $finalblank;
    $start = 0;

    while(<$fh>) {
        my $d = $_;
        $line++;
        $finalblank = ($d eq "\n");
        if($d =~ /^\.(SH|BR|IP|B)/) {
            print STDERR "$f:$line:1:ERROR: nroff instruction in input: \".$1\"\n";
            return 4;
        }
        if(/^ *<!--/) {
            # skip comments
            next;
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
        }
        elsif(/^## (.*)/) {
            my $word = $1;
            # if there are enclosing quotes, remove them first
            $word =~ s/[\"\'](.*)[\"\']\z/$1/;

            # remove backticks from headers
            $words =~ s/\`//g;

            # if there is a space, it needs quotes for man page
            if(($word =~ / /) && $manpage) {
                $word = "\"$word\"";
            }
            $level = 1;
            if($top == 1) {
                push @desc, ".IP $word\n" if($manpage);
                push @desc, "\n" if(!$manpage);







|

|







313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
        }
        elsif(/^## (.*)/) {
            my $word = $1;
            # if there are enclosing quotes, remove them first
            $word =~ s/[\"\'](.*)[\"\']\z/$1/;

            # remove backticks from headers
            $word =~ s/\`//g;

            # if there is a space, it needs quotes for manpage
            if(($word =~ / /) && $manpage) {
                $word = "\"$word\"";
            }
            $level = 1;
            if($top == 1) {
                push @desc, ".IP $word\n" if($manpage);
                push @desc, "\n" if(!$manpage);
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
        elsif(/^##/) {
            if($top == 1) {
                print STDERR "$f:$line:1:ERROR: ## empty header top-level mode\n";
                exit 3;
            }
            if($tablemode) {
                # end of table
                push @desc, ".RE\n.IP\n";
                $tablemode = 0;
            }
            $header = 1;
            next;
        }
        elsif(/^\.(IP|RS|RE)/) {
            my ($cmd) = ($1);







|







344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
        elsif(/^##/) {
            if($top == 1) {
                print STDERR "$f:$line:1:ERROR: ## empty header top-level mode\n";
                exit 3;
            }
            if($tablemode) {
                # end of table
                push @desc, ".RE\n.IP\n" if($manpage);
                $tablemode = 0;
            }
            $header = 1;
            next;
        }
        elsif(/^\.(IP|RS|RE)/) {
            my ($cmd) = ($1);
371
372
373
374
375
376
377








378
379
380
381

382
383
384
385
386
387
388
        $d =~ s/`%DATE`/$date/g;
        $d =~ s/`%VERSION`/$version/g;
        $d =~ s/`%GLOBALS`/$globals/g;

        # convert backticks to double quotes
        $d =~ s/\`/\"/g;









        if($d =~ /\(Added in ([0-9.]+)\)/i) {
            my $ver = $1;
            if(too_old($ver)) {
                $d =~ s/ *\(Added in $ver\)//gi;

            }
        }

        if(!$quote) {
            if($d =~ /^(.*)  /) {
                printf STDERR "$f:$line:%d:ERROR: 2 spaces detected\n",
                    length($1);







>
>
>
>
>
>
>
>




>







381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
        $d =~ s/`%DATE`/$date/g;
        $d =~ s/`%VERSION`/$version/g;
        $d =~ s/`%GLOBALS`/$globals/g;

        # convert backticks to double quotes
        $d =~ s/\`/\"/g;

        if($d =~ /\(added in(.*)/i) {
            if(length($1) < 2) {
                print STDERR "$f:$line:1:ERROR: broken up added-in line:\n";
                print STDERR "$f:$line:1:ERROR: $d";
                return 3;
            }
        }
      again:
        if($d =~ /\(Added in ([0-9.]+)\)/i) {
            my $ver = $1;
            if(too_old($ver)) {
                $d =~ s/ *\(Added in $ver\)//gi;
                goto again;
            }
        }

        if(!$quote) {
            if($d =~ /^(.*)  /) {
                printf STDERR "$f:$line:%d:ERROR: 2 spaces detected\n",
                    length($1);
427
428
429
430
431
432
433








434
435
436
437
438
439
440
        $blankline = 0;
        push @desc, $d if($manpage);
        my $qstr = $quote ? "q": "";
        push @desc, "[".(1 + $level)."$qstr]$d" if(!$manpage);
        $header = 0;

    }








    if($tablemode) {
        # end of table
        push @desc, ".RE\n.IP\n" if($manpage);
    }
    return @desc;
}








>
>
>
>
>
>
>
>







446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
        $blankline = 0;
        push @desc, $d if($manpage);
        my $qstr = $quote ? "q": "";
        push @desc, "[".(1 + $level)."$qstr]$d" if(!$manpage);
        $header = 0;

    }
    if($finalblank) {
        print STDERR "$f:$line:1:ERROR: trailing blank line\n";
        exit 3;
    }
    if($quote) {
        # don't leave the quote "hanging"
        push @desc, ".fi\n" if($manpage);
    }
    if($tablemode) {
        # end of table
        push @desc, ".RE\n.IP\n" if($manpage);
    }
    return @desc;
}

636
637
638
639
640
641
642




643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
    if($experimental) {
        push @leading, "**WARNING**: this option is experimental. Do not use in production.\n\n";
    }

    my $pre = $manpage ? "\n": "[1]";

    if($scope) {




        if($scope eq "global") {
            push @desc, "\n" if(!$manpage);
            push @desc, "${pre}This option is global and does not need to be specified for each use of --next.\n";
        }
        else {
            print STDERR "$f:$line:1:ERROR: unrecognized scope: '$scope'\n";
            return 2;
        }
    }

    printdesc($manpage, 2, (@leading, @desc));
    undef @desc;

    my @extra;
    if($multi eq "single") {
        push @extra, "${pre}If --$long is provided several times, the last set ".
            "value is used.\n";
    }
    elsif($multi eq "append") {
        push @extra, "${pre}--$long can be used several times in a command line\n";







>
>
>
>










<
<
<







663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683



684
685
686
687
688
689
690
    if($experimental) {
        push @leading, "**WARNING**: this option is experimental. Do not use in production.\n\n";
    }

    my $pre = $manpage ? "\n": "[1]";

    if($scope) {
        if($category !~ /global/) {
            print STDERR "$f:$line:1:ERROR: global scope option does not have global category\n";
            return 2;
        }
        if($scope eq "global") {
            push @desc, "\n" if(!$manpage);
            push @desc, "${pre}This option is global and does not need to be specified for each use of --next.\n";
        }
        else {
            print STDERR "$f:$line:1:ERROR: unrecognized scope: '$scope'\n";
            return 2;
        }
    }




    my @extra;
    if($multi eq "single") {
        push @extra, "${pre}If --$long is provided several times, the last set ".
            "value is used.\n";
    }
    elsif($multi eq "append") {
        push @extra, "${pre}--$long can be used several times in a command line\n";
677
678
679
680
681
682
683





684
685
686
687
688
689

690
691
692
693
694
695
696
    elsif($multi eq "mutex") {
        push @extra,
            "${pre}Providing --$long multiple times has no extra effect.\n";
    }
    elsif($multi eq "custom") {
        ; # left for the text to describe
    }





    else {
        print STDERR "$f:$line:1:ERROR: unrecognized Multi: '$multi'\n";
        return 2;
    }

    printdesc($manpage, 2, @extra);


    my @foot;

    my $mstr;
    my $and = 0;
    my $num = scalar(@seealso);
    if($num > 2) {







>
>
>
>
>





|
>







705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
    elsif($multi eq "mutex") {
        push @extra,
            "${pre}Providing --$long multiple times has no extra effect.\n";
    }
    elsif($multi eq "custom") {
        ; # left for the text to describe
    }
    elsif($multi eq "per-URL") {
        push @extra,
            "${pre}--$long is associated with a single URL. Use it once per URL ".
            "when you use several URLs in a command line.\n";
    }
    else {
        print STDERR "$f:$line:1:ERROR: unrecognized Multi: '$multi'\n";
        return 2;
    }

    printdesc($manpage, 2, (@leading, @desc, @extra));
    undef @desc;

    my @foot;

    my $mstr;
    my $and = 0;
    my $num = scalar(@seealso);
    if($num > 2) {
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722


723
724
725
726
727




728

729
730
731
732
733
734
735
736
737
738
        my $sep = " and";
        if($and && ($i < $and)) {
            $sep = ",";
        }
        $mstr .= sprintf "%s$l", $mstr?"$sep ":"";
        $i++;
    }
    push @foot, seealso($standalone, $mstr);

    if($requires) {
        my $l = $manpage ? manpageify($long) : "--$long";
        push @foot, "$l requires that the underlying libcurl".
            " was built to support $requires. ";
    }
    if($mutexed) {
        my @m=split(/ /, $mutexed);
        my $mstr;


        for my $k (@m) {
            if(!$helplong{$k}) {
                print STDERR "WARN: $f mutexes a non-existing option: $k\n";
            }
            my $l = $manpage ? manpageify($k) : "--$k";




            $mstr .= sprintf "%s$l", $mstr?" and ":"";

        }
        push @foot, overrides($standalone,
                              "This option is mutually exclusive to $mstr. ");
    }
    if($examples[0]) {
        my $s ="";
        $s="s" if($examples[1]);
        if($manpage) {
            print "\nExample$s:\n";
            print ".nf\n";







<



|
|




>
>





>
>
>
>
|
>


|







740
741
742
743
744
745
746

747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
        my $sep = " and";
        if($and && ($i < $and)) {
            $sep = ",";
        }
        $mstr .= sprintf "%s$l", $mstr?"$sep ":"";
        $i++;
    }


    if($requires) {
        my $l = $manpage ? manpageify($long) : "--$long";
        push @foot, "$l requires that libcurl".
            " is built to support $requires.\n";
    }
    if($mutexed) {
        my @m=split(/ /, $mutexed);
        my $mstr;
        my $num = scalar(@m);
        my $count;
        for my $k (@m) {
            if(!$helplong{$k}) {
                print STDERR "WARN: $f mutexes a non-existing option: $k\n";
            }
            my $l = $manpage ? manpageify($k) : "--$k";
            my $sep = ", ";
            if($count == ($num -1)) {
                $sep = " and ";
            }
            $mstr .= sprintf "%s$l", $mstr?$sep:"";
            $count++;
        }
        push @foot, overrides($standalone,
                              "This option is mutually exclusive with $mstr.\n");
    }
    if($examples[0]) {
        my $s ="";
        $s="s" if($examples[1]);
        if($manpage) {
            print "\nExample$s:\n";
            print ".nf\n";
753
754
755
756
757
758
759

760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785

786

787
788
789
790
791
792
793
794
795
796
797
798
799
800





801
802
803
804
805
806
807
            }
            printdesc($manpage, 2, @ex);
        }
    }
    if($added) {
        push @foot, added($standalone, $added);
    }

    if($foot[0]) {
        print "\n";
        my $f = join("", @foot);
        if($manpage) {
            $f =~ s/ +\z//; # remove trailing space
            print "$f\n";
        }
        else {
            printdesc($manpage, 2, "[1]$f");
        }
    }
    return 0;
}

sub getshortlong {
    my ($dir, $f)=@_;
    $f =~ s/^.*\///;
    open(F, "<:crlf", "$dir/$f") ||
        die "could not find $dir/$f";
    my $short;
    my $long;
    my $help;
    my $arg;
    my $protocols;
    my $category;
    my $start = 0;

    while(<F>) {

        if(!$start) {
            if(/^---/) {
                $start = 1;
            }
            next;
        }
        if(/^Short: (.)/i) {
            $short=$1;
        }
        elsif(/^Long: (.*)/i) {
            $long=$1;
        }
        elsif(/^Help: (.*)/i) {
            $help=$1;





        }
        elsif(/^Arg: (.*)/i) {
            $arg=$1;
        }
        elsif(/^Protocols: (.*)/i) {
            $protocols=$1;
        }







>
|
|
|
|
|
|
|
|
|
<
















>

>














>
>
>
>
>







793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809

810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
            }
            printdesc($manpage, 2, @ex);
        }
    }
    if($added) {
        push @foot, added($standalone, $added);
    }
    push @foot, seealso($standalone, $mstr);

    print "\n";
    my $f = join("", @foot);
    if($manpage) {
        $f =~ s/ +\z//; # remove trailing space
        print "$f\n";
    }
    else {
        printdesc($manpage, 2, "[1]$f");

    }
    return 0;
}

sub getshortlong {
    my ($dir, $f)=@_;
    $f =~ s/^.*\///;
    open(F, "<:crlf", "$dir/$f") ||
        die "could not find $dir/$f";
    my $short;
    my $long;
    my $help;
    my $arg;
    my $protocols;
    my $category;
    my $start = 0;
    my $line = 0;
    while(<F>) {
        $line++;
        if(!$start) {
            if(/^---/) {
                $start = 1;
            }
            next;
        }
        if(/^Short: (.)/i) {
            $short=$1;
        }
        elsif(/^Long: (.*)/i) {
            $long=$1;
        }
        elsif(/^Help: (.*)/i) {
            $help=$1;
            my $len = length($help);
            if($len >= 49) {
                printf STDERR "$f:$line:1:WARN: oversized help text: %d characters\n",
                    $len;
            }
        }
        elsif(/^Arg: (.*)/i) {
            $arg=$1;
        }
        elsif(/^Protocols: (.*)/i) {
            $protocols=$1;
        }
838
839
840
841
842
843
844















845



846
847
848
849
850
851
852
    open($fh, "<:crlf", "$dir/$f") ||
        die "could not find $dir/$f";
    my @d = render($manpage, $fh, $f, 1);
    close($fh);
    printdesc($manpage, 0, @d);
}
















sub listhelp {



    print <<HEAD
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \\| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \\___|\\___/|_| \\_\\_____|







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>







885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
    open($fh, "<:crlf", "$dir/$f") ||
        die "could not find $dir/$f";
    my @d = render($manpage, $fh, $f, 1);
    close($fh);
    printdesc($manpage, 0, @d);
}


sub sourcecategories {
    my ($dir) = @_;
    my %cats;
    open(H, "<$dir/../../src/tool_help.h") ||
        die "can't find the header file";
    while(<H>) {
        if(/^\#define CURLHELP_([A-Z0-9]*)/) {
            $cats{lc($1)}++;
        }
    }
    close(H);
    return %cats;
}

sub listhelp {
    my ($dir) = @_;
    my %cats = sourcecategories($dir);

    print <<HEAD
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \\| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \\___|\\___/|_| \\_\\_____|
891
892
893
894
895
896
897






898
899
900
901
902
903
904
        if(defined($short) && $long) {
            $opt = "-$short, --$long";
        }
        elsif($long && !$short) {
            $opt = "    --$long";
        }
        for my $i (0 .. $#categories) {






            $bitmask .= 'CURLHELP_' . uc $categories[$i];
            # If not last element, append |
            if($i < $#categories) {
                $bitmask .= ' | ';
            }
        }
        $bitmask =~ s/(?=.{76}).{1,76}\|/$&\n  /g;







>
>
>
>
>
>







956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
        if(defined($short) && $long) {
            $opt = "-$short, --$long";
        }
        elsif($long && !$short) {
            $opt = "    --$long";
        }
        for my $i (0 .. $#categories) {
            if(!$cats{ $categories[$i] }) {
                printf STDERR "$f.md:ERROR: Unknown category '%s'\n",
                    $categories[$i];
                exit 3;
            }

            $bitmask .= 'CURLHELP_' . uc $categories[$i];
            # If not last element, append |
            if($i < $#categories) {
                $bitmask .= ' | ';
            }
        }
        $bitmask =~ s/(?=.{76}).{1,76}\|/$&\n  /g;
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943

944
945
946
947
948
949
950
951
        }
        elsif(length($desc) > 78) {
            print STDERR "WARN: the --$long description is too long\n";
        }
        print $line;
    }
    print <<FOOT
  { NULL, NULL, CURLHELP_HIDDEN }
};
FOOT
        ;
}

sub listcats {
    my %allcats;
    foreach my $f (sort keys %helplong) {
        my @categories = split ' ', $catlong{$f};
        foreach (@categories) {
            $allcats{$_} = undef;
        }
    }
    my @categories;
    foreach my $key (keys %allcats) {
        push @categories, $key;
    }
    @categories = sort @categories;
    unshift @categories, 'hidden';
    for my $i (0..$#categories) {

        print '#define ' . 'CURLHELP_' . uc($categories[$i]) . ' ' . "1u << " . $i . "u\n";
    }
}

sub listglobals {
    my ($dir, @files) = @_;
    my @globalopts;








|


















<

>
|







987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012

1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
        }
        elsif(length($desc) > 78) {
            print STDERR "WARN: the --$long description is too long\n";
        }
        print $line;
    }
    print <<FOOT
  { NULL, NULL, 0 }
};
FOOT
        ;
}

sub listcats {
    my %allcats;
    foreach my $f (sort keys %helplong) {
        my @categories = split ' ', $catlong{$f};
        foreach (@categories) {
            $allcats{$_} = undef;
        }
    }
    my @categories;
    foreach my $key (keys %allcats) {
        push @categories, $key;
    }
    @categories = sort @categories;

    for my $i (0..$#categories) {
        printf("#define CURLHELP_%-10s (%s)\n",
               uc($categories[$i]), "1u << ${i}u");
    }
}

sub listglobals {
    my ($dir, @files) = @_;
    my @globalopts;

1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
.\\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\\" * KIND, either express or implied.
.\\" *
.\\" * SPDX-License-Identifier: curl
.\\" *
.\\" **************************************************************************
.\\"
.\\" DO NOT EDIT. Generated by the curl project managen man page generator.
.\\"
.TH curl 1 "$date" "curl $version" "curl Manual"
HEADER
        if ($manpage);

    while(<$fh>) {
        my $f = $_;







|







1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
.\\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\\" * KIND, either express or implied.
.\\" *
.\\" * SPDX-License-Identifier: curl
.\\" *
.\\" **************************************************************************
.\\"
.\\" DO NOT EDIT. Generated by the curl project managen manpage generator.
.\\"
.TH curl 1 "$date" "curl $version" "curl Manual"
HEADER
        if ($manpage);

    while(<$fh>) {
        my $f = $_;
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
    }
    elsif($f eq "ascii") {
        listglobals($dir, @s);
        mainpage($dir, 0, @s);
        return;
    }
    elsif($f eq "listhelp") {
        listhelp();
        return;
    }
    elsif($f eq "single") {
        showonly($s[0]);
        return;
    }
    elsif($f eq "protos") {







|







1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
    }
    elsif($f eq "ascii") {
        listglobals($dir, @s);
        mainpage($dir, 0, @s);
        return;
    }
    elsif($f eq "listhelp") {
        listhelp($dir);
        return;
    }
    elsif($f eq "single") {
        showonly($s[0]);
        return;
    }
    elsif($f eq "protos") {
Changes to jni/curl/scripts/mk-ca-bundle.pl.
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
    die "The URL for '$opt_d' is not HTTPS. Use -k to override (insecure).\n";
  }
}
else {
  $url = $opt_d;
}

my $curl = `curl -V`;

if ($opt_i) {
  print ("=" x 78 . "\n");
  print "Script Version                   : $version\n";
  print "Perl Version                     : $]\n";
  print "Operating System Name            : $^O\n";
  print "Getopt::Std.pm Version           : ${Getopt::Std::VERSION}\n";
  print "Encode::Encoding.pm Version      : ${Encode::Encoding::VERSION}\n";







<
<







132
133
134
135
136
137
138


139
140
141
142
143
144
145
    die "The URL for '$opt_d' is not HTTPS. Use -k to override (insecure).\n";
  }
}
else {
  $url = $opt_d;
}



if ($opt_i) {
  print ("=" x 78 . "\n");
  print "Script Version                   : $version\n";
  print "Perl Version                     : $]\n";
  print "Operating System Name            : $^O\n";
  print "Getopt::Std.pm Version           : ${Getopt::Std::VERSION}\n";
  print "Encode::Encoding.pm Version      : ${Encode::Encoding::VERSION}\n";
310
311
312
313
314
315
316

317
318
319
320
321
322
323
report "SHA256 of old file: $oldhash";

if(!$opt_n) {
  report "Downloading $txt ...";

  # If we have an HTTPS URL then use curl
  if($url =~ /^https:\/\//i) {

    if($curl) {
      if($curl =~ /^Protocols:.* https( |$)/m) {
        report "Get certdata with curl!";
        my $proto = !$opt_k ? "--proto =https" : "";
        my $quiet = $opt_q ? "-s" : "";
        my @out = `curl -w %{response_code} $proto $quiet -o "$txt" "$url"`;
        if(!$? && @out && $out[0] == 200) {







>







308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
report "SHA256 of old file: $oldhash";

if(!$opt_n) {
  report "Downloading $txt ...";

  # If we have an HTTPS URL then use curl
  if($url =~ /^https:\/\//i) {
    my $curl = `curl -V`;
    if($curl) {
      if($curl =~ /^Protocols:.* https( |$)/m) {
        report "Get certdata with curl!";
        my $proto = !$opt_k ? "--proto =https" : "";
        my $quiet = $opt_q ? "-s" : "";
        my @out = `curl -w %{response_code} $proto $quiet -o "$txt" "$url"`;
        if(!$? && @out && $out[0] == 200) {
Changes to jni/curl/src/CMakeLists.txt.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

add_executable(
  ${PROJECT_NAME}::${EXE_NAME}
  ALIAS ${EXE_NAME}
  )

add_library(
  curltool # special libcurltool library just for unittests
  STATIC
  EXCLUDE_FROM_ALL
  ${CURL_CFILES} ${CURLTOOL_LIBCURL_CFILES} ${CURL_HFILES}
)
target_compile_definitions(curltool PUBLIC UNITTESTS CURL_STATICLIB)
target_link_libraries(curltool PRIVATE ${CURL_LIBS})








|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

add_executable(
  ${PROJECT_NAME}::${EXE_NAME}
  ALIAS ${EXE_NAME}
  )

add_library(
  curltool  # special libcurltool library just for unittests
  STATIC
  EXCLUDE_FROM_ALL
  ${CURL_CFILES} ${CURLTOOL_LIBCURL_CFILES} ${CURL_HFILES}
)
target_compile_definitions(curltool PUBLIC UNITTESTS CURL_STATICLIB)
target_link_libraries(curltool PRIVATE ${CURL_LIBS})

100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
endif()

source_group("curlX source files" FILES ${CURLX_CFILES})
source_group("curl source files" FILES ${CURL_CFILES})
source_group("curl header files" FILES ${CURL_HFILES})

include_directories(
  ${CURL_SOURCE_DIR}/lib        # To be able to reach "curl_setup_once.h"
  ${CURL_BINARY_DIR}/lib        # To be able to reach "curl_config.h"
  ${CURL_BINARY_DIR}/include    # To be able to reach "curl/curl.h"
  # This is needed as tool_hugehelp.c is generated in the binary dir
  ${CURL_SOURCE_DIR}/src        # To be able to reach "tool_hugehelp.h"
  )

#Build curl executable
target_link_libraries(${EXE_NAME} ${LIB_SELECTED_FOR_EXE} ${CURL_LIBS})

################################################################################

#SET_TARGET_PROPERTIES(${EXE_NAME} ARCHIVE_OUTPUT_DIRECTORY "blah blah blah")
#SET_TARGET_PROPERTIES(${EXE_NAME} RUNTIME_OUTPUT_DIRECTORY "blah blah blah")
#SET_TARGET_PROPERTIES(${EXE_NAME} LIBRARY_OUTPUT_DIRECTORY "blah blah blah")

#INCLUDE(ModuleInstall OPTIONAL)

install(TARGETS ${EXE_NAME} EXPORT ${TARGETS_EXPORT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
export(TARGETS ${EXE_NAME}
       FILE ${PROJECT_BINARY_DIR}/curl-target.cmake
       NAMESPACE ${PROJECT_NAME}::
)







|
|
|

|


|




|
|
|

|






100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
endif()

source_group("curlX source files" FILES ${CURLX_CFILES})
source_group("curl source files" FILES ${CURL_CFILES})
source_group("curl header files" FILES ${CURL_HFILES})

include_directories(
  ${CURL_SOURCE_DIR}/lib      # for "curl_setup_once.h"
  ${CURL_BINARY_DIR}/lib      # for "curl_config.h"
  ${CURL_BINARY_DIR}/include  # for "curl/curl.h"
  # This is needed as tool_hugehelp.c is generated in the binary dir
  ${CURL_SOURCE_DIR}/src      # for "tool_hugehelp.h"
  )

# Build curl executable
target_link_libraries(${EXE_NAME} ${LIB_SELECTED_FOR_EXE} ${CURL_LIBS})

################################################################################

#set_target_properties(${EXE_NAME} ARCHIVE_OUTPUT_DIRECTORY "blah blah blah")
#set_target_properties(${EXE_NAME} RUNTIME_OUTPUT_DIRECTORY "blah blah blah")
#set_target_properties(${EXE_NAME} LIBRARY_OUTPUT_DIRECTORY "blah blah blah")

#include(ModuleInstall OPTIONAL)

install(TARGETS ${EXE_NAME} EXPORT ${TARGETS_EXPORT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
export(TARGETS ${EXE_NAME}
       FILE ${PROJECT_BINARY_DIR}/curl-target.cmake
       NAMESPACE ${PROJECT_NAME}::
)
Changes to jni/curl/src/Makefile.am.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
              -I$(top_builddir)/lib          \
              -I$(top_builddir)/src          \
              -I$(top_srcdir)/lib            \
              -I$(top_srcdir)/src

bin_PROGRAMS = curl

if BUILD_DOCS
SUBDIRS = ../docs
endif

if USE_CPPFLAG_CURL_STATICLIB
AM_CPPFLAGS += -DCURL_STATICLIB
endif
AM_CPPFLAGS += -DBUILDING_CURL

include Makefile.inc








<
<
<
<







41
42
43
44
45
46
47




48
49
50
51
52
53
54
              -I$(top_builddir)/lib          \
              -I$(top_builddir)/src          \
              -I$(top_srcdir)/lib            \
              -I$(top_srcdir)/src

bin_PROGRAMS = curl





if USE_CPPFLAG_CURL_STATICLIB
AM_CPPFLAGS += -DCURL_STATICLIB
endif
AM_CPPFLAGS += -DBUILDING_CURL

include Makefile.inc

141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

# ignore tool_hugehelp.c since it is generated source code and it plays
# by slightly different rules!
checksrc:
	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \
	-W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch])

if CURLDEBUG
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif

# disable the tests that are mostly causing false positives
TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference








|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

# ignore tool_hugehelp.c since it is generated source code and it plays
# by slightly different rules!
checksrc:
	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \
	-W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch])

if DEBUGBUILD
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif

# disable the tests that are mostly causing false positives
TIDYFLAGS=-checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference

Changes to jni/curl/src/Makefile.in.
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/lib/curl_config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
LTLIBRARIES = $(noinst_LTLIBRARIES)
libcurltool_la_LIBADD =
am__libcurltool_la_SOURCES_DIST = slist_wc.c tool_binmode.c \
	tool_bname.c tool_cb_dbg.c tool_cb_hdr.c tool_cb_prg.c \
	tool_cb_rea.c tool_cb_see.c tool_cb_wrt.c tool_cfgable.c \
	tool_dirhie.c tool_doswin.c tool_easysrc.c tool_filetime.c \
	tool_findfile.c tool_formparse.c tool_getparam.c \
	tool_getpass.c tool_help.c tool_helpers.c tool_hugehelp.c \
	tool_ipfs.c tool_libinfo.c tool_listhelp.c tool_main.c \
	tool_msgs.c tool_operate.c tool_operhlp.c tool_paramhlp.c \
	tool_parsecfg.c tool_progress.c tool_setopt.c tool_sleep.c \
	tool_stderr.c tool_strdup.c tool_urlglob.c tool_util.c \
	tool_vms.c tool_writeout.c tool_writeout_json.c tool_xattr.c \
	var.c ../lib/base64.c ../lib/curl_multibyte.c ../lib/dynbuf.c \
	../lib/nonblock.c ../lib/strtoofft.c ../lib/timediff.c \
	../lib/version_win32.c ../lib/warnless.c slist_wc.h \
	tool_binmode.h tool_bname.h tool_cb_dbg.h tool_cb_hdr.h \
	tool_cb_prg.h tool_cb_rea.h tool_cb_see.h tool_cb_wrt.h \

	tool_cfgable.h tool_dirhie.h tool_doswin.h tool_easysrc.h \
	tool_filetime.h tool_findfile.h tool_formparse.h \
	tool_getparam.h tool_getpass.h tool_help.h tool_helpers.h \
	tool_hugehelp.h tool_ipfs.h tool_libinfo.h tool_main.h \
	tool_msgs.h tool_operate.h tool_operhlp.h tool_paramhlp.h \
	tool_parsecfg.h tool_progress.h tool_sdecls.h tool_setopt.h \
	tool_setup.h tool_sleep.h tool_stderr.h tool_strdup.h \
	tool_urlglob.h tool_util.h tool_version.h tool_vms.h \
	tool_writeout.h tool_writeout_json.h tool_xattr.h var.h
am__objects_1 = libcurltool_la-slist_wc.lo \
	libcurltool_la-tool_binmode.lo libcurltool_la-tool_bname.lo \
	libcurltool_la-tool_cb_dbg.lo libcurltool_la-tool_cb_hdr.lo \
	libcurltool_la-tool_cb_prg.lo libcurltool_la-tool_cb_rea.lo \
	libcurltool_la-tool_cb_see.lo libcurltool_la-tool_cb_wrt.lo \
	libcurltool_la-tool_cfgable.lo libcurltool_la-tool_dirhie.lo \
	libcurltool_la-tool_doswin.lo libcurltool_la-tool_easysrc.lo \
	libcurltool_la-tool_filetime.lo \
	libcurltool_la-tool_findfile.lo \
	libcurltool_la-tool_formparse.lo \
	libcurltool_la-tool_getparam.lo libcurltool_la-tool_getpass.lo \
	libcurltool_la-tool_help.lo libcurltool_la-tool_helpers.lo \
	libcurltool_la-tool_hugehelp.lo libcurltool_la-tool_ipfs.lo \
	libcurltool_la-tool_libinfo.lo libcurltool_la-tool_listhelp.lo \
	libcurltool_la-tool_main.lo libcurltool_la-tool_msgs.lo \







<
















|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
|
|



|
|
|
|







141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/lib/curl_config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
LTLIBRARIES = $(noinst_LTLIBRARIES)
libcurltool_la_LIBADD =
am__libcurltool_la_SOURCES_DIST = slist_wc.c terminal.c tool_binmode.c \
	tool_bname.c tool_cb_dbg.c tool_cb_hdr.c tool_cb_prg.c \
	tool_cb_rea.c tool_cb_see.c tool_cb_soc.c tool_cb_wrt.c \
	tool_cfgable.c tool_dirhie.c tool_doswin.c tool_easysrc.c \
	tool_filetime.c tool_findfile.c tool_formparse.c \
	tool_getparam.c tool_getpass.c tool_help.c tool_helpers.c \
	tool_hugehelp.c tool_ipfs.c tool_libinfo.c tool_listhelp.c \
	tool_main.c tool_msgs.c tool_operate.c tool_operhlp.c \
	tool_paramhlp.c tool_parsecfg.c tool_progress.c tool_setopt.c \
	tool_sleep.c tool_stderr.c tool_strdup.c tool_urlglob.c \
	tool_util.c tool_vms.c tool_writeout.c tool_writeout_json.c \
	tool_xattr.c var.c ../lib/base64.c ../lib/curl_multibyte.c \
	../lib/dynbuf.c ../lib/nonblock.c ../lib/strtoofft.c \
	../lib/timediff.c ../lib/version_win32.c ../lib/warnless.c \
	slist_wc.h terminal.h tool_binmode.h tool_bname.h \
	tool_cb_dbg.h tool_cb_hdr.h tool_cb_prg.h tool_cb_rea.h \
	tool_cb_see.h tool_cb_soc.h tool_cb_wrt.h tool_cfgable.h \
	tool_dirhie.h tool_doswin.h tool_easysrc.h tool_filetime.h \
	tool_findfile.h tool_formparse.h tool_getparam.h \
	tool_getpass.h tool_help.h tool_helpers.h tool_hugehelp.h \
	tool_ipfs.h tool_libinfo.h tool_main.h tool_msgs.h \
	tool_operate.h tool_operhlp.h tool_paramhlp.h tool_parsecfg.h \
	tool_progress.h tool_sdecls.h tool_setopt.h tool_setup.h \
	tool_sleep.h tool_stderr.h tool_strdup.h tool_urlglob.h \
	tool_util.h tool_version.h tool_vms.h tool_writeout.h \
	tool_writeout_json.h tool_xattr.h var.h
am__objects_1 = libcurltool_la-slist_wc.lo libcurltool_la-terminal.lo \
	libcurltool_la-tool_binmode.lo libcurltool_la-tool_bname.lo \
	libcurltool_la-tool_cb_dbg.lo libcurltool_la-tool_cb_hdr.lo \
	libcurltool_la-tool_cb_prg.lo libcurltool_la-tool_cb_rea.lo \
	libcurltool_la-tool_cb_see.lo libcurltool_la-tool_cb_soc.lo \
	libcurltool_la-tool_cb_wrt.lo libcurltool_la-tool_cfgable.lo \
	libcurltool_la-tool_dirhie.lo libcurltool_la-tool_doswin.lo \
	libcurltool_la-tool_easysrc.lo libcurltool_la-tool_filetime.lo \
	libcurltool_la-tool_findfile.lo \
	libcurltool_la-tool_formparse.lo \
	libcurltool_la-tool_getparam.lo libcurltool_la-tool_getpass.lo \
	libcurltool_la-tool_help.lo libcurltool_la-tool_helpers.lo \
	libcurltool_la-tool_hugehelp.lo libcurltool_la-tool_ipfs.lo \
	libcurltool_la-tool_libinfo.lo libcurltool_la-tool_listhelp.lo \
	libcurltool_la-tool_main.lo libcurltool_la-tool_msgs.lo \
230
231
232
233
234
235
236
237
238

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254

255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
am__v_lt_0 = --silent
am__v_lt_1 = 
libcurltool_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
	$(libcurltool_la_CFLAGS) $(CFLAGS) $(libcurltool_la_LDFLAGS) \
	$(LDFLAGS) -o $@
@BUILD_UNITTESTS_TRUE@am_libcurltool_la_rpath =
am__curl_SOURCES_DIST = slist_wc.c tool_binmode.c tool_bname.c \
	tool_cb_dbg.c tool_cb_hdr.c tool_cb_prg.c tool_cb_rea.c \

	tool_cb_see.c tool_cb_wrt.c tool_cfgable.c tool_dirhie.c \
	tool_doswin.c tool_easysrc.c tool_filetime.c tool_findfile.c \
	tool_formparse.c tool_getparam.c tool_getpass.c tool_help.c \
	tool_helpers.c tool_hugehelp.c tool_ipfs.c tool_libinfo.c \
	tool_listhelp.c tool_main.c tool_msgs.c tool_operate.c \
	tool_operhlp.c tool_paramhlp.c tool_parsecfg.c tool_progress.c \
	tool_setopt.c tool_sleep.c tool_stderr.c tool_strdup.c \
	tool_urlglob.c tool_util.c tool_vms.c tool_writeout.c \
	tool_writeout_json.c tool_xattr.c var.c ../lib/base64.c \
	../lib/curl_multibyte.c ../lib/dynbuf.c ../lib/nonblock.c \
	../lib/strtoofft.c ../lib/timediff.c ../lib/version_win32.c \
	../lib/warnless.c slist_wc.h tool_binmode.h tool_bname.h \
	tool_cb_dbg.h tool_cb_hdr.h tool_cb_prg.h tool_cb_rea.h \
	tool_cb_see.h tool_cb_wrt.h tool_cfgable.h tool_dirhie.h \
	tool_doswin.h tool_easysrc.h tool_filetime.h tool_findfile.h \
	tool_formparse.h tool_getparam.h tool_getpass.h tool_help.h \

	tool_helpers.h tool_hugehelp.h tool_ipfs.h tool_libinfo.h \
	tool_main.h tool_msgs.h tool_operate.h tool_operhlp.h \
	tool_paramhlp.h tool_parsecfg.h tool_progress.h tool_sdecls.h \
	tool_setopt.h tool_setup.h tool_sleep.h tool_stderr.h \
	tool_strdup.h tool_urlglob.h tool_util.h tool_version.h \
	tool_vms.h tool_writeout.h tool_writeout_json.h tool_xattr.h \
	var.h curl.rc
am__objects_5 = slist_wc.$(OBJEXT) tool_binmode.$(OBJEXT) \

	tool_bname.$(OBJEXT) tool_cb_dbg.$(OBJEXT) \
	tool_cb_hdr.$(OBJEXT) tool_cb_prg.$(OBJEXT) \
	tool_cb_rea.$(OBJEXT) tool_cb_see.$(OBJEXT) \
	tool_cb_wrt.$(OBJEXT) tool_cfgable.$(OBJEXT) \
	tool_dirhie.$(OBJEXT) tool_doswin.$(OBJEXT) \
	tool_easysrc.$(OBJEXT) tool_filetime.$(OBJEXT) \
	tool_findfile.$(OBJEXT) tool_formparse.$(OBJEXT) \
	tool_getparam.$(OBJEXT) tool_getpass.$(OBJEXT) \
	tool_help.$(OBJEXT) tool_helpers.$(OBJEXT) \
	tool_hugehelp.$(OBJEXT) tool_ipfs.$(OBJEXT) \







|
|
>
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
>
|
|
|
|
|
|
<
|
>
|
|
|







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
273
274
am__v_lt_0 = --silent
am__v_lt_1 = 
libcurltool_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
	$(libcurltool_la_CFLAGS) $(CFLAGS) $(libcurltool_la_LDFLAGS) \
	$(LDFLAGS) -o $@
@BUILD_UNITTESTS_TRUE@am_libcurltool_la_rpath =
am__curl_SOURCES_DIST = slist_wc.c terminal.c tool_binmode.c \
	tool_bname.c tool_cb_dbg.c tool_cb_hdr.c tool_cb_prg.c \
	tool_cb_rea.c tool_cb_see.c tool_cb_soc.c tool_cb_wrt.c \
	tool_cfgable.c tool_dirhie.c tool_doswin.c tool_easysrc.c \
	tool_filetime.c tool_findfile.c tool_formparse.c \
	tool_getparam.c tool_getpass.c tool_help.c tool_helpers.c \
	tool_hugehelp.c tool_ipfs.c tool_libinfo.c tool_listhelp.c \
	tool_main.c tool_msgs.c tool_operate.c tool_operhlp.c \
	tool_paramhlp.c tool_parsecfg.c tool_progress.c tool_setopt.c \
	tool_sleep.c tool_stderr.c tool_strdup.c tool_urlglob.c \
	tool_util.c tool_vms.c tool_writeout.c tool_writeout_json.c \
	tool_xattr.c var.c ../lib/base64.c ../lib/curl_multibyte.c \
	../lib/dynbuf.c ../lib/nonblock.c ../lib/strtoofft.c \
	../lib/timediff.c ../lib/version_win32.c ../lib/warnless.c \
	slist_wc.h terminal.h tool_binmode.h tool_bname.h \
	tool_cb_dbg.h tool_cb_hdr.h tool_cb_prg.h tool_cb_rea.h \
	tool_cb_see.h tool_cb_soc.h tool_cb_wrt.h tool_cfgable.h \
	tool_dirhie.h tool_doswin.h tool_easysrc.h tool_filetime.h \
	tool_findfile.h tool_formparse.h tool_getparam.h \
	tool_getpass.h tool_help.h tool_helpers.h tool_hugehelp.h \
	tool_ipfs.h tool_libinfo.h tool_main.h tool_msgs.h \
	tool_operate.h tool_operhlp.h tool_paramhlp.h tool_parsecfg.h \
	tool_progress.h tool_sdecls.h tool_setopt.h tool_setup.h \
	tool_sleep.h tool_stderr.h tool_strdup.h tool_urlglob.h \
	tool_util.h tool_version.h tool_vms.h tool_writeout.h \
	tool_writeout_json.h tool_xattr.h var.h curl.rc

am__objects_5 = slist_wc.$(OBJEXT) terminal.$(OBJEXT) \
	tool_binmode.$(OBJEXT) tool_bname.$(OBJEXT) \
	tool_cb_dbg.$(OBJEXT) tool_cb_hdr.$(OBJEXT) \
	tool_cb_prg.$(OBJEXT) tool_cb_rea.$(OBJEXT) \
	tool_cb_see.$(OBJEXT) tool_cb_soc.$(OBJEXT) \
	tool_cb_wrt.$(OBJEXT) tool_cfgable.$(OBJEXT) \
	tool_dirhie.$(OBJEXT) tool_doswin.$(OBJEXT) \
	tool_easysrc.$(OBJEXT) tool_filetime.$(OBJEXT) \
	tool_findfile.$(OBJEXT) tool_formparse.$(OBJEXT) \
	tool_getparam.$(OBJEXT) tool_getpass.$(OBJEXT) \
	tool_help.$(OBJEXT) tool_helpers.$(OBJEXT) \
	tool_hugehelp.$(OBJEXT) tool_ipfs.$(OBJEXT) \
321
322
323
324
325
326
327

328
329
330
331
332
333
334

335
336
337
338
339
340
341
	../lib/$(DEPDIR)/libcurltool_la-timediff.Plo \
	../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo \
	../lib/$(DEPDIR)/libcurltool_la-warnless.Plo \
	../lib/$(DEPDIR)/nonblock.Po ../lib/$(DEPDIR)/strtoofft.Po \
	../lib/$(DEPDIR)/timediff.Po ../lib/$(DEPDIR)/version_win32.Po \
	../lib/$(DEPDIR)/warnless.Po \
	./$(DEPDIR)/libcurltool_la-slist_wc.Plo \

	./$(DEPDIR)/libcurltool_la-tool_binmode.Plo \
	./$(DEPDIR)/libcurltool_la-tool_bname.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo \

	./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo \
	./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo \
	./$(DEPDIR)/libcurltool_la-tool_doswin.Plo \
	./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo \
	./$(DEPDIR)/libcurltool_la-tool_filetime.Plo \
	./$(DEPDIR)/libcurltool_la-tool_findfile.Plo \







>







>







323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
	../lib/$(DEPDIR)/libcurltool_la-timediff.Plo \
	../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo \
	../lib/$(DEPDIR)/libcurltool_la-warnless.Plo \
	../lib/$(DEPDIR)/nonblock.Po ../lib/$(DEPDIR)/strtoofft.Po \
	../lib/$(DEPDIR)/timediff.Po ../lib/$(DEPDIR)/version_win32.Po \
	../lib/$(DEPDIR)/warnless.Po \
	./$(DEPDIR)/libcurltool_la-slist_wc.Plo \
	./$(DEPDIR)/libcurltool_la-terminal.Plo \
	./$(DEPDIR)/libcurltool_la-tool_binmode.Plo \
	./$(DEPDIR)/libcurltool_la-tool_bname.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_soc.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo \
	./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo \
	./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo \
	./$(DEPDIR)/libcurltool_la-tool_doswin.Plo \
	./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo \
	./$(DEPDIR)/libcurltool_la-tool_filetime.Plo \
	./$(DEPDIR)/libcurltool_la-tool_findfile.Plo \
362
363
364
365
366
367
368

369
370
371
372
373
374
375
376
377
378
379
	./$(DEPDIR)/libcurltool_la-tool_urlglob.Plo \
	./$(DEPDIR)/libcurltool_la-tool_util.Plo \
	./$(DEPDIR)/libcurltool_la-tool_vms.Plo \
	./$(DEPDIR)/libcurltool_la-tool_writeout.Plo \
	./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo \
	./$(DEPDIR)/libcurltool_la-tool_xattr.Plo \
	./$(DEPDIR)/libcurltool_la-var.Plo ./$(DEPDIR)/slist_wc.Po \

	./$(DEPDIR)/tool_binmode.Po ./$(DEPDIR)/tool_bname.Po \
	./$(DEPDIR)/tool_cb_dbg.Po ./$(DEPDIR)/tool_cb_hdr.Po \
	./$(DEPDIR)/tool_cb_prg.Po ./$(DEPDIR)/tool_cb_rea.Po \
	./$(DEPDIR)/tool_cb_see.Po ./$(DEPDIR)/tool_cb_wrt.Po \
	./$(DEPDIR)/tool_cfgable.Po ./$(DEPDIR)/tool_dirhie.Po \
	./$(DEPDIR)/tool_doswin.Po ./$(DEPDIR)/tool_easysrc.Po \
	./$(DEPDIR)/tool_filetime.Po ./$(DEPDIR)/tool_findfile.Po \
	./$(DEPDIR)/tool_formparse.Po ./$(DEPDIR)/tool_getparam.Po \
	./$(DEPDIR)/tool_getpass.Po ./$(DEPDIR)/tool_help.Po \
	./$(DEPDIR)/tool_helpers.Po ./$(DEPDIR)/tool_hugehelp.Po \
	./$(DEPDIR)/tool_ipfs.Po ./$(DEPDIR)/tool_libinfo.Po \







>
|
|
|
|







366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
	./$(DEPDIR)/libcurltool_la-tool_urlglob.Plo \
	./$(DEPDIR)/libcurltool_la-tool_util.Plo \
	./$(DEPDIR)/libcurltool_la-tool_vms.Plo \
	./$(DEPDIR)/libcurltool_la-tool_writeout.Plo \
	./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo \
	./$(DEPDIR)/libcurltool_la-tool_xattr.Plo \
	./$(DEPDIR)/libcurltool_la-var.Plo ./$(DEPDIR)/slist_wc.Po \
	./$(DEPDIR)/terminal.Po ./$(DEPDIR)/tool_binmode.Po \
	./$(DEPDIR)/tool_bname.Po ./$(DEPDIR)/tool_cb_dbg.Po \
	./$(DEPDIR)/tool_cb_hdr.Po ./$(DEPDIR)/tool_cb_prg.Po \
	./$(DEPDIR)/tool_cb_rea.Po ./$(DEPDIR)/tool_cb_see.Po \
	./$(DEPDIR)/tool_cb_soc.Po ./$(DEPDIR)/tool_cb_wrt.Po \
	./$(DEPDIR)/tool_cfgable.Po ./$(DEPDIR)/tool_dirhie.Po \
	./$(DEPDIR)/tool_doswin.Po ./$(DEPDIR)/tool_easysrc.Po \
	./$(DEPDIR)/tool_filetime.Po ./$(DEPDIR)/tool_findfile.Po \
	./$(DEPDIR)/tool_formparse.Po ./$(DEPDIR)/tool_getparam.Po \
	./$(DEPDIR)/tool_getpass.Po ./$(DEPDIR)/tool_help.Po \
	./$(DEPDIR)/tool_helpers.Po ./$(DEPDIR)/tool_hugehelp.Po \
	./$(DEPDIR)/tool_ipfs.Po ./$(DEPDIR)/tool_libinfo.Po \
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo "  CCLD    " $@;
am__v_CCLD_1 = 
SOURCES = $(libcurltool_la_SOURCES) $(curl_SOURCES)
DIST_SOURCES = $(am__libcurltool_la_SOURCES_DIST) \
	$(am__curl_SOURCES_DIST)
RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
	ctags-recursive dvi-recursive html-recursive info-recursive \
	install-data-recursive install-dvi-recursive \
	install-exec-recursive install-html-recursive \
	install-info-recursive install-pdf-recursive \
	install-ps-recursive install-recursive installcheck-recursive \
	installdirs-recursive pdf-recursive ps-recursive \
	tags-recursive uninstall-recursive
am__can_run_installinfo = \
  case $$AM_UPDATE_INFO_DIR in \
    n|no|NO) false;; \
    *) (install-info --version) >/dev/null 2>&1;; \
  esac
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
  distclean-recursive maintainer-clean-recursive
am__recursive_targets = \
  $(RECURSIVE_TARGETS) \
  $(RECURSIVE_CLEAN_TARGETS) \
  $(am__extra_recursive_targets)
AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
	distdir distdir-am
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates.  Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
  BEGIN { nonempty = 0; } \
  { items[$$0] = 1; nonempty = 1; } \
  END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique.  This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
  list='$(am__tagged_files)'; \
  unique=`for i in $$list; do \
    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
  done | $(am__uniquify_input)`
DIST_SUBDIRS = ../docs
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc \
	$(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
  dir0=`pwd`; \
  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
  sed_rest='s,^[^/]*/*,,'; \
  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
  sed_butlast='s,/*[^/]*$$,,'; \
  while test -n "$$dir1"; do \
    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
    if test "$$first" != "."; then \
      if test "$$first" = ".."; then \
        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
      else \
        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
        if test "$$first2" = "$$first"; then \
          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
        else \
          dir2="../$$dir2"; \
        fi; \
        dir0="$$dir0"/"$$first"; \
      fi; \
    fi; \
    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
  done; \
  reldir="$$dir2"
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APACHECTL = @APACHECTL@
APXS = @APXS@
AR = @AR@
AR_FLAGS = @AR_FLAGS@







<
<
<
<
<
<
<
<





<
<
<
<
<
<
<
<

















<



<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







410
411
412
413
414
415
416








417
418
419
420
421








422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438

439
440
441

























442
443
444
445
446
447
448
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo "  CCLD    " $@;
am__v_CCLD_1 = 
SOURCES = $(libcurltool_la_SOURCES) $(curl_SOURCES)
DIST_SOURCES = $(am__libcurltool_la_SOURCES_DIST) \
	$(am__curl_SOURCES_DIST)








am__can_run_installinfo = \
  case $$AM_UPDATE_INFO_DIR in \
    n|no|NO) false;; \
    *) (install-info --version) >/dev/null 2>&1;; \
  esac








am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates.  Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
  BEGIN { nonempty = 0; } \
  { items[$$0] = 1; nonempty = 1; } \
  END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique.  This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
  list='$(am__tagged_files)'; \
  unique=`for i in $$list; do \
    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
  done | $(am__uniquify_input)`

am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc \
	$(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)

























ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
APACHECTL = @APACHECTL@
APXS = @APXS@
AR = @AR@
AR_FLAGS = @AR_FLAGS@
563
564
565
566
567
568
569


570
571
572
573
574
575
576
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@







>
>







526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
# $(top_builddir)/src is for curl's generated src/curl_config.h file
# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files
# $(top_srcdir)/src is for curl's src/tool_setup.h and "curl-private" files
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/lib \
	-I$(top_builddir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/src \
	$(am__append_1) -DBUILDING_CURL
@BUILD_DOCS_TRUE@SUBDIRS = ../docs

# libcurl sources to include in curltool lib we use for test binaries
CURLTOOL_LIBCURL_CFILES = \
  ../lib/base64.c \
  ../lib/dynbuf.c


# libcurl has sources that provide functions named curlx_* that aren't part of
# the official API, but we reuse the code here to avoid duplication.
CURLX_CFILES = \
  ../lib/base64.c \
  ../lib/curl_multibyte.c \
  ../lib/dynbuf.c \
  ../lib/nonblock.c \
  ../lib/strtoofft.c \







<







|







704
705
706
707
708
709
710

711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
# $(top_builddir)/src is for curl's generated src/curl_config.h file
# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files
# $(top_srcdir)/src is for curl's src/tool_setup.h and "curl-private" files
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/lib \
	-I$(top_builddir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/src \
	$(am__append_1) -DBUILDING_CURL


# libcurl sources to include in curltool lib we use for test binaries
CURLTOOL_LIBCURL_CFILES = \
  ../lib/base64.c \
  ../lib/dynbuf.c


# libcurl has sources that provide functions named curlx_* that are not part of
# the official API, but we reuse the code here to avoid duplication.
CURLX_CFILES = \
  ../lib/base64.c \
  ../lib/curl_multibyte.c \
  ../lib/dynbuf.c \
  ../lib/nonblock.c \
  ../lib/strtoofft.c \
772
773
774
775
776
777
778

779
780
781
782
783
784
785

786
787
788
789
790
791
792
  ../lib/strtoofft.h \
  ../lib/timediff.h \
  ../lib/version_win32.h \
  ../lib/warnless.h

CURL_CFILES = \
  slist_wc.c \

  tool_binmode.c \
  tool_bname.c \
  tool_cb_dbg.c \
  tool_cb_hdr.c \
  tool_cb_prg.c \
  tool_cb_rea.c \
  tool_cb_see.c \

  tool_cb_wrt.c \
  tool_cfgable.c \
  tool_dirhie.c \
  tool_doswin.c \
  tool_easysrc.c \
  tool_filetime.c \
  tool_findfile.c \







>







>







736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
  ../lib/strtoofft.h \
  ../lib/timediff.h \
  ../lib/version_win32.h \
  ../lib/warnless.h

CURL_CFILES = \
  slist_wc.c \
  terminal.c \
  tool_binmode.c \
  tool_bname.c \
  tool_cb_dbg.c \
  tool_cb_hdr.c \
  tool_cb_prg.c \
  tool_cb_rea.c \
  tool_cb_see.c \
  tool_cb_soc.c \
  tool_cb_wrt.c \
  tool_cfgable.c \
  tool_dirhie.c \
  tool_doswin.c \
  tool_easysrc.c \
  tool_filetime.c \
  tool_findfile.c \
816
817
818
819
820
821
822

823
824
825
826
827
828
829

830
831
832
833
834
835
836
  tool_writeout.c \
  tool_writeout_json.c \
  tool_xattr.c \
  var.c

CURL_HFILES = \
  slist_wc.h \

  tool_binmode.h \
  tool_bname.h \
  tool_cb_dbg.h \
  tool_cb_hdr.h \
  tool_cb_prg.h \
  tool_cb_rea.h \
  tool_cb_see.h \

  tool_cb_wrt.h \
  tool_cfgable.h \
  tool_dirhie.h \
  tool_doswin.h \
  tool_easysrc.h \
  tool_filetime.h \
  tool_findfile.h \







>







>







782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
  tool_writeout.c \
  tool_writeout_json.c \
  tool_xattr.c \
  var.c

CURL_HFILES = \
  slist_wc.h \
  terminal.h \
  tool_binmode.h \
  tool_bname.h \
  tool_cb_dbg.h \
  tool_cb_hdr.h \
  tool_cb_prg.h \
  tool_cb_rea.h \
  tool_cb_see.h \
  tool_cb_soc.h \
  tool_cb_wrt.h \
  tool_cfgable.h \
  tool_dirhie.h \
  tool_doswin.h \
  tool_easysrc.h \
  tool_filetime.h \
  tool_findfile.h \
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
CS_0 = @echo "  RUN     " $@;
CS_1 = 
CS_ = $(CS_0)

# disable the tests that are mostly causing false positives
TIDYFLAGS = -checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference
TIDY := clang-tidy
all: all-recursive

.SUFFIXES:
.SUFFIXES: .c .lo .o .obj .rc
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.inc $(am__configure_deps)
	@for dep in $?; do \
	  case '$(am__configure_deps)' in \
	    *$$dep*) \







|







871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
CS_0 = @echo "  RUN     " $@;
CS_1 = 
CS_ = $(CS_0)

# disable the tests that are mostly causing false positives
TIDYFLAGS = -checks=-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-valist.Uninitialized,-clang-analyzer-core.NonNullParamChecker,-clang-analyzer-core.NullDereference
TIDY := clang-tidy
all: all-am

.SUFFIXES:
.SUFFIXES: .c .lo .o .obj .rc
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.inc $(am__configure_deps)
	@for dep in $?; do \
	  case '$(am__configure_deps)' in \
	    *$$dep*) \
1068
1069
1070
1071
1072
1073
1074

1075
1076
1077
1078
1079
1080
1081

1082
1083
1084
1085
1086
1087
1088
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-warnless.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/nonblock.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/strtoofft.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/timediff.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/version_win32.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/warnless.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-slist_wc.Plo@am__quote@ # am--include-marker

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_binmode.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_bname.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo@am__quote@ # am--include-marker

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_doswin.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_filetime.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_findfile.Plo@am__quote@ # am--include-marker







>







>







1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/libcurltool_la-warnless.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/nonblock.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/strtoofft.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/timediff.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/version_win32.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../lib/$(DEPDIR)/warnless.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-slist_wc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-terminal.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_binmode.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_bname.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_soc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_doswin.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_filetime.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_findfile.Plo@am__quote@ # am--include-marker
1110
1111
1112
1113
1114
1115
1116

1117
1118
1119
1120
1121
1122
1123

1124
1125
1126
1127
1128
1129
1130
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_vms.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_writeout.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_xattr.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-var.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slist_wc.Po@am__quote@ # am--include-marker

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_binmode.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_bname.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_dbg.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_hdr.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_prg.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_rea.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_see.Po@am__quote@ # am--include-marker

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_wrt.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cfgable.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_dirhie.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_doswin.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_easysrc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_filetime.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_findfile.Po@am__quote@ # am--include-marker







>







>







1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_util.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_vms.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_writeout.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-tool_xattr.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurltool_la-var.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slist_wc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/terminal.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_binmode.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_bname.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_dbg.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_hdr.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_prg.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_rea.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_see.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_soc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cb_wrt.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_cfgable.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_dirhie.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_doswin.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_easysrc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_filetime.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool_findfile.Po@am__quote@ # am--include-marker
1189
1190
1191
1192
1193
1194
1195







1196
1197
1198
1199
1200
1201
1202
libcurltool_la-slist_wc.lo: slist_wc.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-slist_wc.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-slist_wc.Tpo -c -o libcurltool_la-slist_wc.lo `test -f 'slist_wc.c' || echo '$(srcdir)/'`slist_wc.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-slist_wc.Tpo $(DEPDIR)/libcurltool_la-slist_wc.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='slist_wc.c' object='libcurltool_la-slist_wc.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-slist_wc.lo `test -f 'slist_wc.c' || echo '$(srcdir)/'`slist_wc.c








libcurltool_la-tool_binmode.lo: tool_binmode.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_binmode.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_binmode.Tpo -c -o libcurltool_la-tool_binmode.lo `test -f 'tool_binmode.c' || echo '$(srcdir)/'`tool_binmode.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_binmode.Tpo $(DEPDIR)/libcurltool_la-tool_binmode.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tool_binmode.c' object='libcurltool_la-tool_binmode.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_binmode.lo `test -f 'tool_binmode.c' || echo '$(srcdir)/'`tool_binmode.c








>
>
>
>
>
>
>







1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
libcurltool_la-slist_wc.lo: slist_wc.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-slist_wc.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-slist_wc.Tpo -c -o libcurltool_la-slist_wc.lo `test -f 'slist_wc.c' || echo '$(srcdir)/'`slist_wc.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-slist_wc.Tpo $(DEPDIR)/libcurltool_la-slist_wc.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='slist_wc.c' object='libcurltool_la-slist_wc.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-slist_wc.lo `test -f 'slist_wc.c' || echo '$(srcdir)/'`slist_wc.c

libcurltool_la-terminal.lo: terminal.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-terminal.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-terminal.Tpo -c -o libcurltool_la-terminal.lo `test -f 'terminal.c' || echo '$(srcdir)/'`terminal.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-terminal.Tpo $(DEPDIR)/libcurltool_la-terminal.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='terminal.c' object='libcurltool_la-terminal.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-terminal.lo `test -f 'terminal.c' || echo '$(srcdir)/'`terminal.c

libcurltool_la-tool_binmode.lo: tool_binmode.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_binmode.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_binmode.Tpo -c -o libcurltool_la-tool_binmode.lo `test -f 'tool_binmode.c' || echo '$(srcdir)/'`tool_binmode.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_binmode.Tpo $(DEPDIR)/libcurltool_la-tool_binmode.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tool_binmode.c' object='libcurltool_la-tool_binmode.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_binmode.lo `test -f 'tool_binmode.c' || echo '$(srcdir)/'`tool_binmode.c

1238
1239
1240
1241
1242
1243
1244







1245
1246
1247
1248
1249
1250
1251
libcurltool_la-tool_cb_see.lo: tool_cb_see.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_see.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_see.Tpo -c -o libcurltool_la-tool_cb_see.lo `test -f 'tool_cb_see.c' || echo '$(srcdir)/'`tool_cb_see.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_see.Tpo $(DEPDIR)/libcurltool_la-tool_cb_see.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tool_cb_see.c' object='libcurltool_la-tool_cb_see.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_see.lo `test -f 'tool_cb_see.c' || echo '$(srcdir)/'`tool_cb_see.c








libcurltool_la-tool_cb_wrt.lo: tool_cb_wrt.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_wrt.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_wrt.Tpo -c -o libcurltool_la-tool_cb_wrt.lo `test -f 'tool_cb_wrt.c' || echo '$(srcdir)/'`tool_cb_wrt.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_wrt.Tpo $(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tool_cb_wrt.c' object='libcurltool_la-tool_cb_wrt.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_wrt.lo `test -f 'tool_cb_wrt.c' || echo '$(srcdir)/'`tool_cb_wrt.c








>
>
>
>
>
>
>







1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
libcurltool_la-tool_cb_see.lo: tool_cb_see.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_see.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_see.Tpo -c -o libcurltool_la-tool_cb_see.lo `test -f 'tool_cb_see.c' || echo '$(srcdir)/'`tool_cb_see.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_see.Tpo $(DEPDIR)/libcurltool_la-tool_cb_see.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tool_cb_see.c' object='libcurltool_la-tool_cb_see.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_see.lo `test -f 'tool_cb_see.c' || echo '$(srcdir)/'`tool_cb_see.c

libcurltool_la-tool_cb_soc.lo: tool_cb_soc.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_soc.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_soc.Tpo -c -o libcurltool_la-tool_cb_soc.lo `test -f 'tool_cb_soc.c' || echo '$(srcdir)/'`tool_cb_soc.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_soc.Tpo $(DEPDIR)/libcurltool_la-tool_cb_soc.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tool_cb_soc.c' object='libcurltool_la-tool_cb_soc.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_soc.lo `test -f 'tool_cb_soc.c' || echo '$(srcdir)/'`tool_cb_soc.c

libcurltool_la-tool_cb_wrt.lo: tool_cb_wrt.c
@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -MT libcurltool_la-tool_cb_wrt.lo -MD -MP -MF $(DEPDIR)/libcurltool_la-tool_cb_wrt.Tpo -c -o libcurltool_la-tool_cb_wrt.lo `test -f 'tool_cb_wrt.c' || echo '$(srcdir)/'`tool_cb_wrt.c
@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libcurltool_la-tool_cb_wrt.Tpo $(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tool_cb_wrt.c' object='libcurltool_la-tool_cb_wrt.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurltool_la_CPPFLAGS) $(CPPFLAGS) $(libcurltool_la_CFLAGS) $(CFLAGS) -c -o libcurltool_la-tool_cb_wrt.lo `test -f 'tool_cb_wrt.c' || echo '$(srcdir)/'`tool_cb_wrt.c

1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
mostlyclean-libtool:
	-rm -f *.lo

clean-libtool:
	-rm -rf .libs _libs
	-rm -rf ../lib/.libs ../lib/_libs

# This directory's subdirectories are mostly independent; you can cd
# into them and run 'make' without going through this Makefile.
# To change the values of 'make' variables: instead of editing Makefiles,
# (1) if the variable is set in 'config.status', edit 'config.status'
#     (which will cause the Makefiles to be regenerated when you run 'make');
# (2) otherwise, pass the desired values on the 'make' command line.
$(am__recursive_targets):
	@fail=; \
	if $(am__make_keepgoing); then \
	  failcom='fail=yes'; \
	else \
	  failcom='exit 1'; \
	fi; \
	dot_seen=no; \
	target=`echo $@ | sed s/-recursive//`; \
	case "$@" in \
	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
	  *) list='$(SUBDIRS)' ;; \
	esac; \
	for subdir in $$list; do \
	  echo "Making $$target in $$subdir"; \
	  if test "$$subdir" = "."; then \
	    dot_seen=yes; \
	    local_target="$$target-am"; \
	  else \
	    local_target="$$target"; \
	  fi; \
	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
	  || eval $$failcom; \
	done; \
	if test "$$dot_seen" = "no"; then \
	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
	fi; test -z "$$fail"

ID: $(am__tagged_files)
	$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-recursive
TAGS: tags

tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
	set x; \
	here=`pwd`; \
	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
	  include_option=--etags-include; \
	  empty_fix=.; \
	else \
	  include_option=--include; \
	  empty_fix=; \
	fi; \
	list='$(SUBDIRS)'; for subdir in $$list; do \
	  if test "$$subdir" = .; then :; else \
	    test ! -f $$subdir/TAGS || \
	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
	  fi; \
	done; \
	$(am__define_uniq_tagged_files); \
	shift; \
	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
	  test -n "$$unique" || unique=$$empty_fix; \
	  if test $$# -gt 0; then \
	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
	      "$$@" $$unique; \
	  else \
	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
	      $$unique; \
	  fi; \
	fi
ctags: ctags-recursive

CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
	$(am__define_uniq_tagged_files); \
	test -z "$(CTAGS_ARGS)$$unique" \
	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
	     $$unique

GTAGS:
	here=`$(am__cd) $(top_builddir) && pwd` \
	  && $(am__cd) $(top_srcdir) \
	  && gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-recursive

cscopelist-am: $(am__tagged_files)
	list='$(am__tagged_files)'; \
	case "$(srcdir)" in \
	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
	  *) sdir=$(subdir)/$(srcdir) ;; \
	esac; \







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


|





<
<
<
<
<
<
<
<
<
<
<
<
<












|












|







1525
1526
1527
1528
1529
1530
1531


































1532
1533
1534
1535
1536
1537
1538
1539













1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
mostlyclean-libtool:
	-rm -f *.lo

clean-libtool:
	-rm -rf .libs _libs
	-rm -rf ../lib/.libs ../lib/_libs



































ID: $(am__tagged_files)
	$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags

tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
	set x; \
	here=`pwd`; \













	$(am__define_uniq_tagged_files); \
	shift; \
	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
	  test -n "$$unique" || unique=$$empty_fix; \
	  if test $$# -gt 0; then \
	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
	      "$$@" $$unique; \
	  else \
	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
	      $$unique; \
	  fi; \
	fi
ctags: ctags-am

CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
	$(am__define_uniq_tagged_files); \
	test -z "$(CTAGS_ARGS)$$unique" \
	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
	     $$unique

GTAGS:
	here=`$(am__cd) $(top_builddir) && pwd` \
	  && $(am__cd) $(top_srcdir) \
	  && gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am

cscopelist-am: $(am__tagged_files)
	list='$(am__tagged_files)'; \
	case "$(srcdir)" in \
	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
	  *) sdir=$(subdir)/$(srcdir) ;; \
	esac; \
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
	  else \
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
	  if test "$$subdir" = .; then :; else \
	    $(am__make_dryrun) \
	      || test -d "$(distdir)/$$subdir" \
	      || $(MKDIR_P) "$(distdir)/$$subdir" \
	      || exit 1; \
	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
	    $(am__relativize); \
	    new_distdir=$$reldir; \
	    dir1=$$subdir; dir2="$(top_distdir)"; \
	    $(am__relativize); \
	    new_top_distdir=$$reldir; \
	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
	    ($(am__cd) $$subdir && \
	      $(MAKE) $(AM_MAKEFLAGS) \
	        top_distdir="$$new_top_distdir" \
	        distdir="$$new_distdir" \
		am__remove_distdir=: \
		am__skip_length_check=: \
		am__skip_mode_fix=: \
	        distdir) \
	      || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-recursive
@CURLDEBUG_FALSE@all-local:
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) all-local
installdirs: installdirs-recursive
installdirs-am:
	for dir in "$(DESTDIR)$(bindir)"; do \
	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
	done
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive

install-am: all-am
	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am

installcheck: installcheck-recursive
install-strip:
	if test -z '$(STRIP)'; then \
	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
	      install; \
	else \
	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

|
|

<
|



|
|
|
|




|







1609
1610
1611
1612
1613
1614
1615

























1616
1617
1618
1619

1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
	  else \
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done

























check-am: all-am
check: check-am
@DEBUGBUILD_FALSE@all-local:
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) all-local

installdirs:
	for dir in "$(DESTDIR)$(bindir)"; do \
	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
	done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am

install-am: all-am
	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am

installcheck: installcheck-am
install-strip:
	if test -z '$(STRIP)'; then \
	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
	      install; \
	else \
	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766

1767
1768
1769
1770
1771
1772
1773

1774
1775
1776
1777
1778
1779
1780
	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
	-rm -f ../lib/$(DEPDIR)/$(am__dirstamp)
	-rm -f ../lib/$(am__dirstamp)

maintainer-clean-generic:
	@echo "This command is intended for maintainers to use"
	@echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive

clean-am: clean-binPROGRAMS clean-generic clean-libtool \
	clean-noinstLTLIBRARIES mostlyclean-am

distclean: distclean-recursive
		-rm -f ../lib/$(DEPDIR)/base64.Po
	-rm -f ../lib/$(DEPDIR)/curl_multibyte.Po
	-rm -f ../lib/$(DEPDIR)/dynbuf.Po
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-base64.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-timediff.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-warnless.Plo
	-rm -f ../lib/$(DEPDIR)/nonblock.Po
	-rm -f ../lib/$(DEPDIR)/strtoofft.Po
	-rm -f ../lib/$(DEPDIR)/timediff.Po
	-rm -f ../lib/$(DEPDIR)/version_win32.Po
	-rm -f ../lib/$(DEPDIR)/warnless.Po
	-rm -f ./$(DEPDIR)/libcurltool_la-slist_wc.Plo

	-rm -f ./$(DEPDIR)/libcurltool_la-tool_binmode.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_bname.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo

	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_doswin.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_filetime.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_findfile.Plo







|




|

















>







>







1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
	-rm -f ../lib/$(DEPDIR)/$(am__dirstamp)
	-rm -f ../lib/$(am__dirstamp)

maintainer-clean-generic:
	@echo "This command is intended for maintainers to use"
	@echo "it deletes files that may require special tools to rebuild."
clean: clean-am

clean-am: clean-binPROGRAMS clean-generic clean-libtool \
	clean-noinstLTLIBRARIES mostlyclean-am

distclean: distclean-am
		-rm -f ../lib/$(DEPDIR)/base64.Po
	-rm -f ../lib/$(DEPDIR)/curl_multibyte.Po
	-rm -f ../lib/$(DEPDIR)/dynbuf.Po
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-base64.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-timediff.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-warnless.Plo
	-rm -f ../lib/$(DEPDIR)/nonblock.Po
	-rm -f ../lib/$(DEPDIR)/strtoofft.Po
	-rm -f ../lib/$(DEPDIR)/timediff.Po
	-rm -f ../lib/$(DEPDIR)/version_win32.Po
	-rm -f ../lib/$(DEPDIR)/warnless.Po
	-rm -f ./$(DEPDIR)/libcurltool_la-slist_wc.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-terminal.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_binmode.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_bname.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_soc.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_doswin.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_filetime.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_findfile.Plo
1802
1803
1804
1805
1806
1807
1808

1809
1810
1811
1812
1813
1814
1815

1816
1817
1818
1819
1820
1821
1822
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_util.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_vms.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_xattr.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-var.Plo
	-rm -f ./$(DEPDIR)/slist_wc.Po

	-rm -f ./$(DEPDIR)/tool_binmode.Po
	-rm -f ./$(DEPDIR)/tool_bname.Po
	-rm -f ./$(DEPDIR)/tool_cb_dbg.Po
	-rm -f ./$(DEPDIR)/tool_cb_hdr.Po
	-rm -f ./$(DEPDIR)/tool_cb_prg.Po
	-rm -f ./$(DEPDIR)/tool_cb_rea.Po
	-rm -f ./$(DEPDIR)/tool_cb_see.Po

	-rm -f ./$(DEPDIR)/tool_cb_wrt.Po
	-rm -f ./$(DEPDIR)/tool_cfgable.Po
	-rm -f ./$(DEPDIR)/tool_dirhie.Po
	-rm -f ./$(DEPDIR)/tool_doswin.Po
	-rm -f ./$(DEPDIR)/tool_easysrc.Po
	-rm -f ./$(DEPDIR)/tool_filetime.Po
	-rm -f ./$(DEPDIR)/tool_findfile.Po







>







>







1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_util.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_vms.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_xattr.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-var.Plo
	-rm -f ./$(DEPDIR)/slist_wc.Po
	-rm -f ./$(DEPDIR)/terminal.Po
	-rm -f ./$(DEPDIR)/tool_binmode.Po
	-rm -f ./$(DEPDIR)/tool_bname.Po
	-rm -f ./$(DEPDIR)/tool_cb_dbg.Po
	-rm -f ./$(DEPDIR)/tool_cb_hdr.Po
	-rm -f ./$(DEPDIR)/tool_cb_prg.Po
	-rm -f ./$(DEPDIR)/tool_cb_rea.Po
	-rm -f ./$(DEPDIR)/tool_cb_see.Po
	-rm -f ./$(DEPDIR)/tool_cb_soc.Po
	-rm -f ./$(DEPDIR)/tool_cb_wrt.Po
	-rm -f ./$(DEPDIR)/tool_cfgable.Po
	-rm -f ./$(DEPDIR)/tool_dirhie.Po
	-rm -f ./$(DEPDIR)/tool_doswin.Po
	-rm -f ./$(DEPDIR)/tool_easysrc.Po
	-rm -f ./$(DEPDIR)/tool_filetime.Po
	-rm -f ./$(DEPDIR)/tool_findfile.Po
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911

1912
1913
1914
1915
1916
1917
1918

1919
1920
1921
1922
1923
1924
1925
	-rm -f ./$(DEPDIR)/tool_writeout_json.Po
	-rm -f ./$(DEPDIR)/tool_xattr.Po
	-rm -f ./$(DEPDIR)/var.Po
	-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
	distclean-tags

dvi: dvi-recursive

dvi-am:

html: html-recursive

html-am:

info: info-recursive

info-am:

install-data-am:

install-dvi: install-dvi-recursive

install-dvi-am:

install-exec-am: install-binPROGRAMS

install-html: install-html-recursive

install-html-am:

install-info: install-info-recursive

install-info-am:

install-man:

install-pdf: install-pdf-recursive

install-pdf-am:

install-ps: install-ps-recursive

install-ps-am:

installcheck-am:

maintainer-clean: maintainer-clean-recursive
		-rm -f ../lib/$(DEPDIR)/base64.Po
	-rm -f ../lib/$(DEPDIR)/curl_multibyte.Po
	-rm -f ../lib/$(DEPDIR)/dynbuf.Po
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-base64.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-timediff.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-warnless.Plo
	-rm -f ../lib/$(DEPDIR)/nonblock.Po
	-rm -f ../lib/$(DEPDIR)/strtoofft.Po
	-rm -f ../lib/$(DEPDIR)/timediff.Po
	-rm -f ../lib/$(DEPDIR)/version_win32.Po
	-rm -f ../lib/$(DEPDIR)/warnless.Po
	-rm -f ./$(DEPDIR)/libcurltool_la-slist_wc.Plo

	-rm -f ./$(DEPDIR)/libcurltool_la-tool_binmode.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_bname.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo

	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_doswin.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_filetime.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_findfile.Plo







|



|



|





|





|



|





|



|





|

















>







>







1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
	-rm -f ./$(DEPDIR)/tool_writeout_json.Po
	-rm -f ./$(DEPDIR)/tool_xattr.Po
	-rm -f ./$(DEPDIR)/var.Po
	-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
	distclean-tags

dvi: dvi-am

dvi-am:

html: html-am

html-am:

info: info-am

info-am:

install-data-am:

install-dvi: install-dvi-am

install-dvi-am:

install-exec-am: install-binPROGRAMS

install-html: install-html-am

install-html-am:

install-info: install-info-am

install-info-am:

install-man:

install-pdf: install-pdf-am

install-pdf-am:

install-ps: install-ps-am

install-ps-am:

installcheck-am:

maintainer-clean: maintainer-clean-am
		-rm -f ../lib/$(DEPDIR)/base64.Po
	-rm -f ../lib/$(DEPDIR)/curl_multibyte.Po
	-rm -f ../lib/$(DEPDIR)/dynbuf.Po
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-base64.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-curl_multibyte.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-dynbuf.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-nonblock.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-strtoofft.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-timediff.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-version_win32.Plo
	-rm -f ../lib/$(DEPDIR)/libcurltool_la-warnless.Plo
	-rm -f ../lib/$(DEPDIR)/nonblock.Po
	-rm -f ../lib/$(DEPDIR)/strtoofft.Po
	-rm -f ../lib/$(DEPDIR)/timediff.Po
	-rm -f ../lib/$(DEPDIR)/version_win32.Po
	-rm -f ../lib/$(DEPDIR)/warnless.Po
	-rm -f ./$(DEPDIR)/libcurltool_la-slist_wc.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-terminal.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_binmode.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_bname.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_dbg.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_hdr.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_prg.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_rea.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_see.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_soc.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cb_wrt.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_cfgable.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_dirhie.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_doswin.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_easysrc.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_filetime.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_findfile.Plo
1947
1948
1949
1950
1951
1952
1953

1954
1955
1956
1957
1958
1959
1960

1961
1962
1963
1964
1965
1966
1967
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_util.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_vms.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_xattr.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-var.Plo
	-rm -f ./$(DEPDIR)/slist_wc.Po

	-rm -f ./$(DEPDIR)/tool_binmode.Po
	-rm -f ./$(DEPDIR)/tool_bname.Po
	-rm -f ./$(DEPDIR)/tool_cb_dbg.Po
	-rm -f ./$(DEPDIR)/tool_cb_hdr.Po
	-rm -f ./$(DEPDIR)/tool_cb_prg.Po
	-rm -f ./$(DEPDIR)/tool_cb_rea.Po
	-rm -f ./$(DEPDIR)/tool_cb_see.Po

	-rm -f ./$(DEPDIR)/tool_cb_wrt.Po
	-rm -f ./$(DEPDIR)/tool_cfgable.Po
	-rm -f ./$(DEPDIR)/tool_dirhie.Po
	-rm -f ./$(DEPDIR)/tool_doswin.Po
	-rm -f ./$(DEPDIR)/tool_easysrc.Po
	-rm -f ./$(DEPDIR)/tool_filetime.Po
	-rm -f ./$(DEPDIR)/tool_findfile.Po







>







>







1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_util.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_vms.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_writeout_json.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-tool_xattr.Plo
	-rm -f ./$(DEPDIR)/libcurltool_la-var.Plo
	-rm -f ./$(DEPDIR)/slist_wc.Po
	-rm -f ./$(DEPDIR)/terminal.Po
	-rm -f ./$(DEPDIR)/tool_binmode.Po
	-rm -f ./$(DEPDIR)/tool_bname.Po
	-rm -f ./$(DEPDIR)/tool_cb_dbg.Po
	-rm -f ./$(DEPDIR)/tool_cb_hdr.Po
	-rm -f ./$(DEPDIR)/tool_cb_prg.Po
	-rm -f ./$(DEPDIR)/tool_cb_rea.Po
	-rm -f ./$(DEPDIR)/tool_cb_see.Po
	-rm -f ./$(DEPDIR)/tool_cb_soc.Po
	-rm -f ./$(DEPDIR)/tool_cb_wrt.Po
	-rm -f ./$(DEPDIR)/tool_cfgable.Po
	-rm -f ./$(DEPDIR)/tool_dirhie.Po
	-rm -f ./$(DEPDIR)/tool_doswin.Po
	-rm -f ./$(DEPDIR)/tool_easysrc.Po
	-rm -f ./$(DEPDIR)/tool_filetime.Po
	-rm -f ./$(DEPDIR)/tool_findfile.Po
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021

2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
	-rm -f ./$(DEPDIR)/tool_writeout.Po
	-rm -f ./$(DEPDIR)/tool_writeout_json.Po
	-rm -f ./$(DEPDIR)/tool_xattr.Po
	-rm -f ./$(DEPDIR)/var.Po
	-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic

mostlyclean: mostlyclean-recursive

mostlyclean-am: mostlyclean-compile mostlyclean-generic \
	mostlyclean-libtool

pdf: pdf-recursive

pdf-am:

ps: ps-recursive

ps-am:

uninstall-am: uninstall-binPROGRAMS

.MAKE: $(am__recursive_targets) install-am install-strip

.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \
	am--depfiles check check-am clean clean-binPROGRAMS \
	clean-generic clean-libtool clean-noinstLTLIBRARIES \
	cscopelist-am ctags ctags-am distclean distclean-compile \
	distclean-generic distclean-libtool distclean-tags distdir dvi \
	dvi-am html html-am info info-am install install-am \
	install-binPROGRAMS install-data install-data-am install-dvi \

	install-dvi-am install-exec install-exec-am install-html \
	install-html-am install-info install-info-am install-man \
	install-pdf install-pdf-am install-ps install-ps-am \
	install-strip installcheck installcheck-am installdirs \
	installdirs-am maintainer-clean maintainer-clean-generic \
	mostlyclean mostlyclean-compile mostlyclean-generic \
	mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
	uninstall-am uninstall-binPROGRAMS

.PRECIOUS: Makefile


# remove targets if the command fails
.DELETE_ON_ERROR:
@HAVE_WINDRES_TRUE@$(CURL_RCFILES): tool_version.h







|




|



|





|

|
|
<
|
|
|
|
>
|
|
|
|
<
|
|
|







1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937

1938
1939
1940
1941
1942
1943
1944
1945
1946

1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
	-rm -f ./$(DEPDIR)/tool_writeout.Po
	-rm -f ./$(DEPDIR)/tool_writeout_json.Po
	-rm -f ./$(DEPDIR)/tool_xattr.Po
	-rm -f ./$(DEPDIR)/var.Po
	-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic

mostlyclean: mostlyclean-am

mostlyclean-am: mostlyclean-compile mostlyclean-generic \
	mostlyclean-libtool

pdf: pdf-am

pdf-am:

ps: ps-am

ps-am:

uninstall-am: uninstall-binPROGRAMS

.MAKE: install-am install-strip

.PHONY: CTAGS GTAGS TAGS all all-am all-local am--depfiles check \
	check-am clean clean-binPROGRAMS clean-generic clean-libtool \

	clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \
	distclean-compile distclean-generic distclean-libtool \
	distclean-tags distdir dvi dvi-am html html-am info info-am \
	install install-am install-binPROGRAMS install-data \
	install-data-am install-dvi install-dvi-am install-exec \
	install-exec-am install-html install-html-am install-info \
	install-info-am install-man install-pdf install-pdf-am \
	install-ps install-ps-am install-strip installcheck \
	installcheck-am installdirs maintainer-clean \

	maintainer-clean-generic mostlyclean mostlyclean-compile \
	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
	tags tags-am uninstall uninstall-am uninstall-binPROGRAMS

.PRECIOUS: Makefile


# remove targets if the command fails
.DELETE_ON_ERROR:
@HAVE_WINDRES_TRUE@$(CURL_RCFILES): tool_version.h
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
# ignore tool_hugehelp.c since it is generated source code and it plays
# by slightly different rules!
checksrc:
	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \
	-W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch])

# for debug builds, we scan the sources on all regular make invokes
@CURLDEBUG_TRUE@all-local: checksrc

tidy:
	$(TIDY) $(CURL_CFILES) $(TIDYFLAGS) -- $(curl_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H

listhelp:
	(cd $(top_srcdir)/docs/cmdline-opts && make listhelp)

@HAVE_WINDRES_TRUE@.rc.o:
@HAVE_WINDRES_TRUE@	$(RC) -I$(top_srcdir)/include -DCURL_EMBED_MANIFEST $(RCFLAGS) -i $< -o $@

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:







|













1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
# ignore tool_hugehelp.c since it is generated source code and it plays
# by slightly different rules!
checksrc:
	$(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \
	-W$(srcdir)/tool_hugehelp.c $(srcdir)/*.[ch])

# for debug builds, we scan the sources on all regular make invokes
@DEBUGBUILD_TRUE@all-local: checksrc

tidy:
	$(TIDY) $(CURL_CFILES) $(TIDYFLAGS) -- $(curl_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H

listhelp:
	(cd $(top_srcdir)/docs/cmdline-opts && make listhelp)

@HAVE_WINDRES_TRUE@.rc.o:
@HAVE_WINDRES_TRUE@	$(RC) -I$(top_srcdir)/include -DCURL_EMBED_MANIFEST $(RCFLAGS) -i $< -o $@

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
Changes to jni/curl/src/Makefile.inc.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# CSOURCES = $(CSRC1) $(CSRC2)

# libcurl sources to include in curltool lib we use for test binaries
CURLTOOL_LIBCURL_CFILES = \
  ../lib/base64.c \
  ../lib/dynbuf.c

# libcurl has sources that provide functions named curlx_* that aren't part of
# the official API, but we reuse the code here to avoid duplication.
CURLX_CFILES = \
  ../lib/base64.c \
  ../lib/curl_multibyte.c \
  ../lib/dynbuf.c \
  ../lib/nonblock.c \
  ../lib/strtoofft.c \







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# CSOURCES = $(CSRC1) $(CSRC2)

# libcurl sources to include in curltool lib we use for test binaries
CURLTOOL_LIBCURL_CFILES = \
  ../lib/base64.c \
  ../lib/dynbuf.c

# libcurl has sources that provide functions named curlx_* that are not part of
# the official API, but we reuse the code here to avoid duplication.
CURLX_CFILES = \
  ../lib/base64.c \
  ../lib/curl_multibyte.c \
  ../lib/dynbuf.c \
  ../lib/nonblock.c \
  ../lib/strtoofft.c \
55
56
57
58
59
60
61

62
63
64
65
66
67
68

69
70
71
72
73
74
75
  ../lib/strtoofft.h \
  ../lib/timediff.h \
  ../lib/version_win32.h \
  ../lib/warnless.h

CURL_CFILES = \
  slist_wc.c \

  tool_binmode.c \
  tool_bname.c \
  tool_cb_dbg.c \
  tool_cb_hdr.c \
  tool_cb_prg.c \
  tool_cb_rea.c \
  tool_cb_see.c \

  tool_cb_wrt.c \
  tool_cfgable.c \
  tool_dirhie.c \
  tool_doswin.c \
  tool_easysrc.c \
  tool_filetime.c \
  tool_findfile.c \







>







>







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  ../lib/strtoofft.h \
  ../lib/timediff.h \
  ../lib/version_win32.h \
  ../lib/warnless.h

CURL_CFILES = \
  slist_wc.c \
  terminal.c \
  tool_binmode.c \
  tool_bname.c \
  tool_cb_dbg.c \
  tool_cb_hdr.c \
  tool_cb_prg.c \
  tool_cb_rea.c \
  tool_cb_see.c \
  tool_cb_soc.c \
  tool_cb_wrt.c \
  tool_cfgable.c \
  tool_dirhie.c \
  tool_doswin.c \
  tool_easysrc.c \
  tool_filetime.c \
  tool_findfile.c \
99
100
101
102
103
104
105

106
107
108
109
110
111
112

113
114
115
116
117
118
119
  tool_writeout.c \
  tool_writeout_json.c \
  tool_xattr.c \
  var.c

CURL_HFILES = \
  slist_wc.h \

  tool_binmode.h \
  tool_bname.h \
  tool_cb_dbg.h \
  tool_cb_hdr.h \
  tool_cb_prg.h \
  tool_cb_rea.h \
  tool_cb_see.h \

  tool_cb_wrt.h \
  tool_cfgable.h \
  tool_dirhie.h \
  tool_doswin.h \
  tool_easysrc.h \
  tool_filetime.h \
  tool_findfile.h \







>







>







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  tool_writeout.c \
  tool_writeout_json.c \
  tool_xattr.c \
  var.c

CURL_HFILES = \
  slist_wc.h \
  terminal.h \
  tool_binmode.h \
  tool_bname.h \
  tool_cb_dbg.h \
  tool_cb_hdr.h \
  tool_cb_prg.h \
  tool_cb_rea.h \
  tool_cb_see.h \
  tool_cb_soc.h \
  tool_cb_wrt.h \
  tool_cfgable.h \
  tool_dirhie.h \
  tool_doswin.h \
  tool_easysrc.h \
  tool_filetime.h \
  tool_findfile.h \
Changes to jni/curl/src/curl.rc.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#define RC_VERSION  CURL_VERSION_MAJOR, CURL_VERSION_MINOR, CURL_VERSION_PATCH, 0

VS_VERSION_INFO VERSIONINFO
  FILEVERSION     RC_VERSION
  PRODUCTVERSION  RC_VERSION
  FILEFLAGSMASK   VS_FFI_FILEFLAGSMASK
#if defined(DEBUGBUILD) || defined(_DEBUG)
  FILEFLAGS VS_FF_DEBUG
#else
  FILEFLAGS 0L
#endif
  FILEOS      VOS__WINDOWS32
  FILETYPE    VFT_APP
  FILESUBTYPE 0L







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#define RC_VERSION  CURL_VERSION_MAJOR, CURL_VERSION_MINOR, CURL_VERSION_PATCH, 0

VS_VERSION_INFO VERSIONINFO
  FILEVERSION     RC_VERSION
  PRODUCTVERSION  RC_VERSION
  FILEFLAGSMASK   VS_FFI_FILEFLAGSMASK
#if defined(DEBUGBUILD) || defined(UNITTESTS) || defined(CURLDEBUG) || defined(_DEBUG)
  FILEFLAGS VS_FF_DEBUG
#else
  FILEFLAGS 0L
#endif
  FILEOS      VOS__WINDOWS32
  FILETYPE    VFT_APP
  FILESUBTYPE 0L
Changes to jni/curl/src/mkhelp.pl.
163
164
165
166
167
168
169

170
171
172
173
174
175
176
}

my $blank;
for my $n (@out) {
    chomp $n;
    $n =~ s/\\/\\\\/g;
    $n =~ s/\"/\\\"/g;


    if(!$n) {
        $blank++;
    }
    else {
        $n =~ s/        /\\t/g;
        printf("  \"%s%s\",\n", $blank?"\\n":"", $n);







>







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
}

my $blank;
for my $n (@out) {
    chomp $n;
    $n =~ s/\\/\\\\/g;
    $n =~ s/\"/\\\"/g;
    $n =~ s/\t/\\t/g;

    if(!$n) {
        $blank++;
    }
    else {
        $n =~ s/        /\\t/g;
        printf("  \"%s%s\",\n", $blank?"\\n":"", $n);
Added jni/curl/src/terminal.c.






















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif

#include "terminal.h"

#include "memdebug.h" /* keep this as LAST include */

#ifdef HAVE_TERMIOS_H
#  include <termios.h>
#elif defined(HAVE_TERMIO_H)
#  include <termio.h>
#endif

/*
 * get_terminal_columns() returns the number of columns in the current
 * terminal. It will return 79 on failure. Also, the number can be very big.
 */

unsigned int get_terminal_columns(void)
{
  unsigned int width = 0;
  char *colp = curl_getenv("COLUMNS");
  if(colp) {
    char *endptr;
    long num = strtol(colp, &endptr, 10);
    if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) &&
       (num < 10000))
      width = (unsigned int)num;
    curl_free(colp);
  }

  if(!width) {
    int cols = 0;

#ifdef TIOCGSIZE
    struct ttysize ts;
    if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts))
      cols = ts.ts_cols;
#elif defined(TIOCGWINSZ)
    struct winsize ts;
    if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts))
      cols = (int)ts.ws_col;
#elif defined(_WIN32) && !defined(CURL_WINDOWS_APP)
    {
      HANDLE  stderr_hnd = GetStdHandle(STD_ERROR_HANDLE);
      CONSOLE_SCREEN_BUFFER_INFO console_info;

      if((stderr_hnd != INVALID_HANDLE_VALUE) &&
         GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) {
        /*
         * Do not use +1 to get the true screen-width since writing a
         * character at the right edge will cause a line wrap.
         */
        cols = (int)
          (console_info.srWindow.Right - console_info.srWindow.Left);
      }
    }
#endif /* TIOCGSIZE */
    if(cols >= 0 && cols < 10000)
      width = (unsigned int)cols;
  }
  if(!width)
    width = 79;
  return width; /* 79 for unknown, might also be very small or very big */
}
Added jni/curl/src/terminal.h.




























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#ifndef HEADER_CURL_TERMINAL_H
#define HEADER_CURL_TERMINAL_H
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

unsigned int get_terminal_columns(void);

#endif /* HEADER_CURL_TERMINAL_H */
Changes to jni/curl/src/tool_cb_dbg.c.
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    /* recalculate */
    if(!known_epoch) {
      epoch_offset = time(NULL) - tv_sec;
      known_epoch = 1;
    }
    secs = epoch_offset + tv_sec;
    /* !checksrc! disable BANNEDFUNC 1 */
    now = localtime(&secs);  /* not thread safe but we don't care */
    msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d",
              now->tm_hour, now->tm_min, now->tm_sec);
    cached_tv_sec = tv_sec;
  }
  return hms_buf;
}








|







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    /* recalculate */
    if(!known_epoch) {
      epoch_offset = time(NULL) - tv_sec;
      known_epoch = 1;
    }
    secs = epoch_offset + tv_sec;
    /* !checksrc! disable BANNEDFUNC 1 */
    now = localtime(&secs);  /* not thread safe but we do not care */
    msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d",
              now->tm_hour, now->tm_min, now->tm_sec);
    cached_tv_sec = tv_sec;
  }
  return hms_buf;
}

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{
  struct OperationConfig *operation = userdata;
  struct GlobalConfig *config = operation->global;
  FILE *output = tool_stderr;
  const char *text;
  struct timeval tv;
  char timebuf[20];
  /* largest signed 64bit is: 9,223,372,036,854,775,807
   * max length in decimal: 1 + (6*3) = 19
   * formatted via TRC_IDS_FORMAT_IDS_2 this becomes 2 + 19 + 1 + 19 + 2 = 43
   * negative xfer-id are not printed, negative conn-ids use TRC_IDS_FORMAT_1
   */
  char idsbuf[60];
  curl_off_t xfer_id, conn_id;








|







95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{
  struct OperationConfig *operation = userdata;
  struct GlobalConfig *config = operation->global;
  FILE *output = tool_stderr;
  const char *text;
  struct timeval tv;
  char timebuf[20];
  /* largest signed 64-bit is: 9,223,372,036,854,775,807
   * max length in decimal: 1 + (6*3) = 19
   * formatted via TRC_IDS_FORMAT_IDS_2 this becomes 2 + 19 + 1 + 19 + 2 = 43
   * negative xfer-id are not printed, negative conn-ids use TRC_IDS_FORMAT_1
   */
  char idsbuf[60];
  curl_off_t xfer_id, conn_id;

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
      traced_data = FALSE;
      break;
    case CURLINFO_DATA_OUT:
    case CURLINFO_DATA_IN:
    case CURLINFO_SSL_DATA_IN:
    case CURLINFO_SSL_DATA_OUT:
      if(!traced_data) {
        /* if the data is output to a tty and we're sending this debug trace
           to stderr or stdout, we don't display the alert about the data not
           being shown as the data _is_ shown then just not via this
           function */
        if(!config->isatty ||
           ((output != tool_stderr) && (output != stdout))) {
          if(!newl)
            log_line_start(output, timebuf, idsbuf, type);
          fprintf(output, "[%zu bytes data]\n", size);







|
|







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
      traced_data = FALSE;
      break;
    case CURLINFO_DATA_OUT:
    case CURLINFO_DATA_IN:
    case CURLINFO_SSL_DATA_IN:
    case CURLINFO_SSL_DATA_OUT:
      if(!traced_data) {
        /* if the data is output to a tty and we are sending this debug trace
           to stderr or stdout, we do not display the alert about the data not
           being shown as the data _is_ shown then just not via this
           function */
        if(!config->isatty ||
           ((output != tool_stderr) && (output != stdout))) {
          if(!newl)
            log_line_start(output, timebuf, idsbuf, type);
          fprintf(output, "[%zu bytes data]\n", size);
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
         (ptr[i + c + 1] == 0x0A)) {
        i += (c + 2 - width);
        break;
      }
      (void)infotype;
      fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ?
              ptr[i + c] : UNPRINTABLE_CHAR);
      /* check again for 0D0A, to avoid an extra \n if it's at width */
      if((tracetype == TRACE_ASCII) &&
         (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
         (ptr[i + c + 2] == 0x0A)) {
        i += (c + 3 - width);
        break;
      }
    }
    fputc('\n', stream); /* newline */
  }
  fflush(stream);
}







|











282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
         (ptr[i + c + 1] == 0x0A)) {
        i += (c + 2 - width);
        break;
      }
      (void)infotype;
      fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ?
              ptr[i + c] : UNPRINTABLE_CHAR);
      /* check again for 0D0A, to avoid an extra \n if it is at width */
      if((tracetype == TRACE_ASCII) &&
         (i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
         (ptr[i + c + 2] == 0x0A)) {
        i += (c + 3 - width);
        break;
      }
    }
    fputc('\n', stream); /* newline */
  }
  fflush(stream);
}
Changes to jni/curl/src/tool_cb_hdr.c.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

#ifdef _WIN32
#define BOLD "\x1b[1m"
#define BOLDOFF "\x1b[22m"
#else
#define BOLD "\x1b[1m"
/* Switch off bold by setting "all attributes off" since the explicit
   bold-off code (21) isn't supported everywhere - like in the mac
   Terminal. */
#define BOLDOFF "\x1b[0m"
/* OSC 8 hyperlink escape sequence */
#define LINK "\x1b]8;;"
#define LINKST "\x1b\\"
#define LINKOFF LINK LINKST
#endif







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

#ifdef _WIN32
#define BOLD "\x1b[1m"
#define BOLDOFF "\x1b[22m"
#else
#define BOLD "\x1b[1m"
/* Switch off bold by setting "all attributes off" since the explicit
   bold-off code (21) is not supported everywhere - like in the mac
   Terminal. */
#define BOLDOFF "\x1b[0m"
/* OSC 8 hyperlink escape sequence */
#define LINK "\x1b]8;;"
#define LINKST "\x1b\\"
#define LINKOFF LINK LINKST
#endif
101
102
103
104
105
106
107
108




109
110
111
112
113
114
115
116
117

118
119
120
121
122
123
124
125
   */

  if(per->config->headerfile && heads->stream) {
    size_t rc = fwrite(ptr, size, nmemb, heads->stream);
    if(rc != cb)
      return rc;
    /* flush the stream to send off what we got earlier */
    (void)fflush(heads->stream);




  }

  curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
  scheme = proto_token(scheme);
  if((scheme == proto_http || scheme == proto_https)) {
    long response = 0;
    curl_easy_getinfo(per->curl, CURLINFO_RESPONSE_CODE, &response);

    if(response/100 != 2)

      /* only care about these headers in 2xx responses */
      ;
    /*
     * Write etag to file when --etag-save option is given.
     */
    else if(per->config->etag_save_file && etag_save->stream &&
            /* match only header that start with etag (case insensitive) */
            checkprefix("etag:", str)) {







|
>
>
>
>








|
>
|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
   */

  if(per->config->headerfile && heads->stream) {
    size_t rc = fwrite(ptr, size, nmemb, heads->stream);
    if(rc != cb)
      return rc;
    /* flush the stream to send off what we got earlier */
    if(fflush(heads->stream)) {
      errorf(per->config->global, "Failed writing headers to %s",
             per->config->headerfile);
      return CURL_WRITEFUNC_ERROR;
    }
  }

  curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
  scheme = proto_token(scheme);
  if((scheme == proto_http || scheme == proto_https)) {
    long response = 0;
    curl_easy_getinfo(per->curl, CURLINFO_RESPONSE_CODE, &response);

    if((response/100 != 2) && (response/100 != 3))
      /* only care about etag and content-disposition headers in 2xx and 3xx
         responses */
      ;
    /*
     * Write etag to file when --etag-save option is given.
     */
    else if(per->config->etag_save_file && etag_save->stream &&
            /* match only header that start with etag (case insensitive) */
            checkprefix("etag:", str)) {
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
      /* not "handled", just show it */
      fwrite(ptr, cb, 1, outs->stream);
  }
  return cb;
}

/*
 * Copies a file name part and returns an ALLOCATED data buffer.
 */
static char *parse_filename(const char *ptr, size_t len)
{
  char *copy;
  char *p;
  char *q;
  char  stop = '\0';







|







269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
      /* not "handled", just show it */
      fwrite(ptr, cb, 1, outs->stream);
  }
  return cb;
}

/*
 * Copies a filename part and returns an ALLOCATED data buffer.
 */
static char *parse_filename(const char *ptr, size_t len)
{
  char *copy;
  char *p;
  char *q;
  char  stop = '\0';
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
    if(!*p) {
      Curl_safefree(copy);
      return NULL;
    }
  }

  /* If the filename contains a backslash, only use filename portion. The idea
     is that even systems that don't handle backslashes as path separators
     probably want the path removed for convenience. */
  q = strrchr(p, '\\');
  if(q) {
    p = q + 1;
    if(!*p) {
      Curl_safefree(copy);
      return NULL;
    }
  }

  /* make sure the file name doesn't end in \r or \n */
  q = strchr(p, '\r');
  if(q)
    *q = '\0';

  q = strchr(p, '\n');
  if(q)
    *q = '\0';







|










|







310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
    if(!*p) {
      Curl_safefree(copy);
      return NULL;
    }
  }

  /* If the filename contains a backslash, only use filename portion. The idea
     is that even systems that do not handle backslashes as path separators
     probably want the path removed for convenience. */
  q = strrchr(p, '\\');
  if(q) {
    p = q + 1;
    if(!*p) {
      Curl_safefree(copy);
      return NULL;
    }
  }

  /* make sure the filename does not end in \r or \n */
  q = strchr(p, '\r');
  if(q)
    *q = '\0';

  q = strchr(p, '\n');
  if(q)
    *q = '\0';
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    if(sc)
      return NULL;
    copy = sanitized;
  }
#endif /* _WIN32 || MSDOS */

  /* in case we built debug enabled, we allow an environment variable
   * named CURL_TESTDIR to prefix the given file name to put it into a
   * specific directory
   */
#ifdef DEBUGBUILD
  {
    char *tdir = curl_getenv("CURL_TESTDIR");
    if(tdir) {
      char buffer[512]; /* suitably large */
      msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy);
      Curl_safefree(copy);
      copy = strdup(buffer); /* clone the buffer, we don't use the libcurl
                                aprintf() or similar since we want to use the
                                same memory code as the "real" parse_filename
                                function */
      curl_free(tdir);
    }
  }
#endif

  return copy;
}

#ifdef LINK
/*
 * Treat the Location: header specially, by writing a special escape
 * sequence that adds a hyperlink to the displayed text. This makes
 * the absolute URL of the redirect clickable in supported terminals,
 * which couldn't happen otherwise for relative URLs. The Location:
 * header is supposed to always be absolute so this theoretically
 * shouldn't be needed but the real world returns plenty of relative
 * URLs here.
 */
static
void write_linked_location(CURL *curl, const char *location, size_t loclen,
                           FILE *stream) {
  /* This would so simple if CURLINFO_REDIRECT_URL were available here */
  CURLU *u = NULL;







|









|
















|

|







345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
    if(sc)
      return NULL;
    copy = sanitized;
  }
#endif /* _WIN32 || MSDOS */

  /* in case we built debug enabled, we allow an environment variable
   * named CURL_TESTDIR to prefix the given filename to put it into a
   * specific directory
   */
#ifdef DEBUGBUILD
  {
    char *tdir = curl_getenv("CURL_TESTDIR");
    if(tdir) {
      char buffer[512]; /* suitably large */
      msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy);
      Curl_safefree(copy);
      copy = strdup(buffer); /* clone the buffer, we do not use the libcurl
                                aprintf() or similar since we want to use the
                                same memory code as the "real" parse_filename
                                function */
      curl_free(tdir);
    }
  }
#endif

  return copy;
}

#ifdef LINK
/*
 * Treat the Location: header specially, by writing a special escape
 * sequence that adds a hyperlink to the displayed text. This makes
 * the absolute URL of the redirect clickable in supported terminals,
 * which could not happen otherwise for relative URLs. The Location:
 * header is supposed to always be absolute so this theoretically
 * should not be needed but the real world returns plenty of relative
 * URLs here.
 */
static
void write_linked_location(CURL *curl, const char *location, size_t loclen,
                           FILE *stream) {
  /* This would so simple if CURLINFO_REDIRECT_URL were available here */
  CURLU *u = NULL;
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
    fprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF,
            space_skipped, location,
            finalurl,
            (int)loclen - space_skipped, loc);
    goto locdone;
  }

  /* Not a "safe" URL: don't linkify it */

locout:
  /* Write the normal output in case of error or unsafe */
  fwrite(location, loclen, 1, stream);

locdone:
  if(u) {







|







446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
    fprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF,
            space_skipped, location,
            finalurl,
            (int)loclen - space_skipped, loc);
    goto locdone;
  }

  /* Not a "safe" URL: do not linkify it */

locout:
  /* Write the normal output in case of error or unsafe */
  fwrite(location, loclen, 1, stream);

locdone:
  if(u) {
Changes to jni/curl/src/tool_cb_prg.c.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif

#define ENABLE_CURLX_PRINTF
/* use our own printf() functions */
#include "curlx.h"

#include "tool_cfgable.h"
#include "tool_cb_prg.h"
#include "tool_util.h"
#include "tool_operate.h"


#include "memdebug.h" /* keep this as LAST include */

#define MAX_BARLENGTH 256

#ifdef HAVE_TERMIOS_H
#  include <termios.h>
#elif defined(HAVE_TERMIO_H)
#  include <termio.h>
#endif

/* 200 values generated by this perl code:

   my $pi = 3.1415;
   foreach my $i (1 .. 200) {
     printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000;
   }
*/







<
<
<
<








>





<
<
<
<
<
<







19
20
21
22
23
24
25




26
27
28
29
30
31
32
33
34
35
36
37
38
39






40
41
42
43
44
45
46
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"





#define ENABLE_CURLX_PRINTF
/* use our own printf() functions */
#include "curlx.h"

#include "tool_cfgable.h"
#include "tool_cb_prg.h"
#include "tool_util.h"
#include "tool_operate.h"
#include "terminal.h"

#include "memdebug.h" /* keep this as LAST include */

#define MAX_BARLENGTH 256







/* 200 values generated by this perl code:

   my $pi = 3.1415;
   foreach my $i (1 .. 200) {
     printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000;
   }
*/
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
{
  char buf[MAX_BARLENGTH + 2];
  int pos;
  int check = bar->width - 2;

  /* bar->width is range checked when assigned */
  DEBUGASSERT(bar->width <= MAX_BARLENGTH);

  memset(buf, ' ', bar->width);
  buf[bar->width] = '\r';
  buf[bar->width + 1] = '\0';

  memcpy(&buf[bar->bar], "-=O=-", 5);

  pos = sinus[bar->tick%200] / (1000000 / check);
  buf[pos] = '#';
  pos = sinus[(bar->tick + 5)%200] / (1000000 / check);
  buf[pos] = '#';
  pos = sinus[(bar->tick + 10)%200] / (1000000 / check);
  buf[pos] = '#';
  pos = sinus[(bar->tick + 15)%200] / (1000000 / check);
  buf[pos] = '#';

  fputs(buf, bar->out);
  bar->tick += 2;
  if(bar->tick >= 200)
    bar->tick -= 200;








>
|
<


|

|

|

|

|







73
74
75
76
77
78
79
80
81

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
{
  char buf[MAX_BARLENGTH + 2];
  int pos;
  int check = bar->width - 2;

  /* bar->width is range checked when assigned */
  DEBUGASSERT(bar->width <= MAX_BARLENGTH);
  buf[0] = '\r';
  memset(&buf[1], ' ', bar->width);

  buf[bar->width + 1] = '\0';

  memcpy(&buf[bar->bar + 1], "-=O=-", 5);

  pos = sinus[bar->tick%200] / (1000000 / check) + 1;
  buf[pos] = '#';
  pos = sinus[(bar->tick + 5)%200] / (1000000 / check) + 1;
  buf[pos] = '#';
  pos = sinus[(bar->tick + 10)%200] / (1000000 / check) + 1;
  buf[pos] = '#';
  pos = sinus[(bar->tick + 15)%200] / (1000000 / check) + 1;
  buf[pos] = '#';

  fputs(buf, bar->out);
  bar->tick += 2;
  if(bar->tick >= 200)
    bar->tick -= 200;

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
    point = dlnow + ulnow + bar->initial_size;

  if(bar->calls) {
    /* after first call... */
    if(total) {
      /* we know the total data to get... */
      if(bar->prev == point)
        /* progress didn't change since last invoke */
        return 0;
      else if((tvdiff(now, bar->prevtime) < 100L) && point < total)
        /* limit progress-bar updating to 10 Hz except when we're at 100% */
        return 0;
    }
    else {
      /* total is unknown */
      if(tvdiff(now, bar->prevtime) < 100L)
        /* limit progress-bar updating to 10 Hz */
        return 0;







|


|







157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    point = dlnow + ulnow + bar->initial_size;

  if(bar->calls) {
    /* after first call... */
    if(total) {
      /* we know the total data to get... */
      if(bar->prev == point)
        /* progress did not change since last invoke */
        return 0;
      else if((tvdiff(now, bar->prevtime) < 100L) && point < total)
        /* limit progress-bar updating to 10 Hz except when we are at 100% */
        return 0;
    }
    else {
      /* total is unknown */
      if(tvdiff(now, bar->prevtime) < 100L)
        /* limit progress-bar updating to 10 Hz */
        return 0;
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
    config->readbusy = FALSE;
    curl_easy_pause(per->curl, CURLPAUSE_CONT);
  }

  return 0;
}

/*
 * get_terminal_columns() returns the number of columns in the current
 * terminal. It will return 79 on failure. Also, the number can be very big.
 */

unsigned int get_terminal_columns(void)
{
  unsigned int width = 0;
  char *colp = curl_getenv("COLUMNS");
  if(colp) {
    char *endptr;
    long num = strtol(colp, &endptr, 10);
    if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) &&
       (num < 10000))
      width = (unsigned int)num;
    curl_free(colp);
  }

  if(!width) {
    int cols = 0;

#ifdef TIOCGSIZE
    struct ttysize ts;
    if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts))
      cols = ts.ts_cols;
#elif defined(TIOCGWINSZ)
    struct winsize ts;
    if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts))
      cols = (int)ts.ws_col;
#elif defined(_WIN32)
    {
      HANDLE  stderr_hnd = GetStdHandle(STD_ERROR_HANDLE);
      CONSOLE_SCREEN_BUFFER_INFO console_info;

      if((stderr_hnd != INVALID_HANDLE_VALUE) &&
         GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) {
        /*
         * Do not use +1 to get the true screen-width since writing a
         * character at the right edge will cause a line wrap.
         */
        cols = (int)
          (console_info.srWindow.Right - console_info.srWindow.Left);
      }
    }
#endif /* TIOCGSIZE */
    if(cols >= 0 && cols < 10000)
      width = (unsigned int)cols;
  }
  if(!width)
    width = 79;
  return width; /* 79 for unknown, might also be very small or very big */
}

void progressbarinit(struct ProgressData *bar,
                     struct OperationConfig *config)
{
  unsigned int cols;
  memset(bar, 0, sizeof(struct ProgressData));

  /* pass the resume from value through to the progress function so it can
   * display progress towards total file not just the part that's left. */
  if(config->use_resume)
    bar->initial_size = config->resume_from;

  cols = get_terminal_columns();
  if(cols > MAX_BARLENGTH)
    bar->width = MAX_BARLENGTH;
  else if(cols > 20)
    bar->width = (int)cols;

  bar->out = tool_stderr;
  bar->tick = 150;
  bar->barmove = 1;
}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







|













216
217
218
219
220
221
222





















































223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
    config->readbusy = FALSE;
    curl_easy_pause(per->curl, CURLPAUSE_CONT);
  }

  return 0;
}






















































void progressbarinit(struct ProgressData *bar,
                     struct OperationConfig *config)
{
  unsigned int cols;
  memset(bar, 0, sizeof(struct ProgressData));

  /* pass the resume from value through to the progress function so it can
   * display progress towards total file not just the part that is left. */
  if(config->use_resume)
    bar->initial_size = config->resume_from;

  cols = get_terminal_columns();
  if(cols > MAX_BARLENGTH)
    bar->width = MAX_BARLENGTH;
  else if(cols > 20)
    bar->width = (int)cols;

  bar->out = tool_stderr;
  bar->tick = 150;
  bar->barmove = 1;
}
Changes to jni/curl/src/tool_cb_prg.h.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
};

struct OperationConfig;

void progressbarinit(struct ProgressData *bar,
                     struct OperationConfig *config);

unsigned int get_terminal_columns(void);

/*
** callback for CURLOPT_PROGRESSFUNCTION
*/

int tool_progress_cb(void *clientp,
                     curl_off_t dltotal, curl_off_t dlnow,
                     curl_off_t ultotal, curl_off_t ulnow);







<
<







41
42
43
44
45
46
47


48
49
50
51
52
53
54
};

struct OperationConfig;

void progressbarinit(struct ProgressData *bar,
                     struct OperationConfig *config);



/*
** callback for CURLOPT_PROGRESSFUNCTION
*/

int tool_progress_cb(void *clientp,
                     curl_off_t dltotal, curl_off_t dlnow,
                     curl_off_t ultotal, curl_off_t ulnow);
Changes to jni/curl/src/tool_cb_rea.c.
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  rc = read(per->infd, buffer, sz*nmemb);
  if(rc < 0) {
    if(errno == EAGAIN) {
      errno = 0;
      config->readbusy = TRUE;
      return CURL_READFUNC_PAUSE;
    }
    /* since size_t is unsigned we can't return negative values fine */
    rc = 0;
  }
  if((per->uploadfilesize != -1) &&
     (per->uploadedsofar + rc > per->uploadfilesize)) {
    /* do not allow uploading more than originally set out to do */
    curl_off_t delta = per->uploadedsofar + rc - per->uploadfilesize;
    warnf(per->config->global, "File size larger in the end than when "







|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  rc = read(per->infd, buffer, sz*nmemb);
  if(rc < 0) {
    if(errno == EAGAIN) {
      errno = 0;
      config->readbusy = TRUE;
      return CURL_READFUNC_PAUSE;
    }
    /* since size_t is unsigned we cannot return negative values fine */
    rc = 0;
  }
  if((per->uploadfilesize != -1) &&
     (per->uploadedsofar + rc > per->uploadfilesize)) {
    /* do not allow uploading more than originally set out to do */
    curl_off_t delta = per->uploadedsofar + rc - per->uploadfilesize;
    warnf(per->config->global, "File size larger in the end than when "
Changes to jni/curl/src/tool_cb_see.c.
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  if(offset > OUR_MAX_SEEK_O) {
    /* Some precaution code to work around problems with different data sizes
       to allow seeking >32bit even if off_t is 32bit. Should be very rare and
       is really valid on weirdo-systems. */
    curl_off_t left = offset;

    if(whence != SEEK_SET)
      /* this code path doesn't support other types */
      return CURL_SEEKFUNC_FAIL;

    if(LSEEK_ERROR == lseek(per->infd, 0, SEEK_SET))
      /* couldn't rewind to beginning */
      return CURL_SEEKFUNC_FAIL;

    while(left) {
      long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left;
      if(LSEEK_ERROR == lseek(per->infd, step, SEEK_CUR))
        /* couldn't seek forwards the desired amount */
        return CURL_SEEKFUNC_FAIL;
      left -= step;
    }
    return CURL_SEEKFUNC_OK;
  }
#endif

  if(LSEEK_ERROR == lseek(per->infd, offset, whence))
    /* couldn't rewind, the reason is in errno but errno is just not portable
       enough and we don't actually care that much why we failed. We'll let
       libcurl know that it may try other means if it wants to. */
    return CURL_SEEKFUNC_CANTSEEK;

  return CURL_SEEKFUNC_OK;
}







|



|





|








|
|





60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  if(offset > OUR_MAX_SEEK_O) {
    /* Some precaution code to work around problems with different data sizes
       to allow seeking >32bit even if off_t is 32bit. Should be very rare and
       is really valid on weirdo-systems. */
    curl_off_t left = offset;

    if(whence != SEEK_SET)
      /* this code path does not support other types */
      return CURL_SEEKFUNC_FAIL;

    if(LSEEK_ERROR == lseek(per->infd, 0, SEEK_SET))
      /* could not rewind to beginning */
      return CURL_SEEKFUNC_FAIL;

    while(left) {
      long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left;
      if(LSEEK_ERROR == lseek(per->infd, step, SEEK_CUR))
        /* could not seek forwards the desired amount */
        return CURL_SEEKFUNC_FAIL;
      left -= step;
    }
    return CURL_SEEKFUNC_OK;
  }
#endif

  if(LSEEK_ERROR == lseek(per->infd, offset, whence))
    /* could not rewind, the reason is in errno but errno is just not portable
       enough and we do not actually care that much why we failed. We will let
       libcurl know that it may try other means if it wants to. */
    return CURL_SEEKFUNC_CANTSEEK;

  return CURL_SEEKFUNC_OK;
}
Added jni/curl/src/tool_cb_soc.c.




















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> /* IPPROTO_TCP */
#endif

#include "tool_cb_soc.h"

/*
** callback for CURLOPT_OPENSOCKETFUNCTION
**
** Notice that only Linux is supported for the moment.
*/

curl_socket_t tool_socket_open_mptcp_cb(void *clientp,
                                        curlsocktype purpose,
                                        struct curl_sockaddr *addr)
{
  int protocol = addr->protocol;

  (void)clientp;
  (void)purpose;

  if(protocol == IPPROTO_TCP)
#if defined(__linux__)
#  ifndef IPPROTO_MPTCP
#  define IPPROTO_MPTCP 262
#  endif
    protocol = IPPROTO_MPTCP;
#else
    return CURL_SOCKET_BAD;
#endif

  return socket(addr->family, addr->socktype, protocol);
}
Added jni/curl/src/tool_cb_soc.h.








































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#ifndef HEADER_CURL_TOOL_CB_SOC_H
#define HEADER_CURL_TOOL_CB_SOC_H
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

/*
** callback for CURLOPT_OPENSOCKETFUNCTION
*/

curl_socket_t tool_socket_open_mptcp_cb(void *clientp,
                                        curlsocktype purpose,
                                        struct curl_sockaddr *addr);

#endif /* HEADER_CURL_TOOL_CB_SOC_H */
Changes to jni/curl/src/tool_cb_wrt.c.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    /* open file for writing */
    file = fopen(fname, "wb");
  }
  else {
    int fd;
    do {
      fd = open(fname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE);
      /* Keep retrying in the hope that it isn't interrupted sometime */
    } while(fd == -1 && errno == EINTR);
    if(config->file_clobber_mode == CLOBBER_NEVER && fd == -1) {
      int next_num = 1;
      size_t len = strlen(fname);
      size_t newlen = len + 13; /* nul + 1-11 digits + dot */
      char *newname;
      /* Guard against wraparound in new filename */
      if(newlen < len) {
        errorf(global, "overflow in filename generation");
        return FALSE;
      }
      newname = malloc(newlen);
      if(!newname) {
        errorf(global, "out of memory");
        return FALSE;
      }
      memcpy(newname, fname, len);
      newname[len] = '.';
      while(fd == -1 && /* haven't successfully opened a file */
            (errno == EEXIST || errno == EISDIR) &&
            /* because we keep having files that already exist */
            next_num < 100 /* and we haven't reached the retry limit */ ) {
        curlx_msnprintf(newname + len + 1, 12, "%d", next_num);
        next_num++;
        do {
          fd = open(newname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE);
          /* Keep retrying in the hope that it isn't interrupted sometime */
        } while(fd == -1 && errno == EINTR);
      }
      outs->filename = newname; /* remember the new one */
      outs->alloc_filename = TRUE;
    }
    /* An else statement to not overwrite existing files and not retry with
       new numbered names (which would cover







|


















|


|




|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    /* open file for writing */
    file = fopen(fname, "wb");
  }
  else {
    int fd;
    do {
      fd = open(fname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE);
      /* Keep retrying in the hope that it is not interrupted sometime */
    } while(fd == -1 && errno == EINTR);
    if(config->file_clobber_mode == CLOBBER_NEVER && fd == -1) {
      int next_num = 1;
      size_t len = strlen(fname);
      size_t newlen = len + 13; /* nul + 1-11 digits + dot */
      char *newname;
      /* Guard against wraparound in new filename */
      if(newlen < len) {
        errorf(global, "overflow in filename generation");
        return FALSE;
      }
      newname = malloc(newlen);
      if(!newname) {
        errorf(global, "out of memory");
        return FALSE;
      }
      memcpy(newname, fname, len);
      newname[len] = '.';
      while(fd == -1 && /* have not successfully opened a file */
            (errno == EEXIST || errno == EISDIR) &&
            /* because we keep having files that already exist */
            next_num < 100 /* and we have not reached the retry limit */ ) {
        curlx_msnprintf(newname + len + 1, 12, "%d", next_num);
        next_num++;
        do {
          fd = open(newname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE);
          /* Keep retrying in the hope that it is not interrupted sometime */
        } while(fd == -1 && errno == EINTR);
      }
      outs->filename = newname; /* remember the new one */
      outs->alloc_filename = TRUE;
    }
    /* An else statement to not overwrite existing files and not retry with
       new numbered names (which would cover
Changes to jni/curl/src/tool_cfgable.h.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

struct OperationConfig {
  bool remote_time;
  char *useragent;
  struct curl_slist *cookies;  /* cookies to serialize into a single line */
  char *cookiejar;          /* write to this file */
  struct curl_slist *cookiefiles;  /* file(s) to load cookies from */
  char *altsvc;             /* alt-svc cache file name */
  char *hsts;               /* HSTS cache file name */
  bool cookiesession;       /* new session? */
  bool encoding;            /* Accept-Encoding please */
  bool tr_encoding;         /* Transfer-Encoding please */
  unsigned long authtype;   /* auth bitmask */
  bool use_resume;
  bool resume_from_current;
  bool disable_epsv;







|
|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

struct OperationConfig {
  bool remote_time;
  char *useragent;
  struct curl_slist *cookies;  /* cookies to serialize into a single line */
  char *cookiejar;          /* write to this file */
  struct curl_slist *cookiefiles;  /* file(s) to load cookies from */
  char *altsvc;             /* alt-svc cache filename */
  char *hsts;               /* HSTS cache filename */
  bool cookiesession;       /* new session? */
  bool encoding;            /* Accept-Encoding please */
  bool tr_encoding;         /* Transfer-Encoding please */
  unsigned long authtype;   /* auth bitmask */
  bool use_resume;
  bool resume_from_current;
  bool disable_epsv;
81
82
83
84
85
86
87


88
89
90
91
92
93
94
  char *iface;
  long localport;
  long localportrange;
  unsigned short porttouse;
  char *range;
  long low_speed_limit;
  long low_speed_time;


  char *dns_servers;   /* dot notation: 1.1.1.1;2.2.2.2 */
  char *dns_interface; /* interface name */
  char *dns_ipv4_addr; /* dot notation */
  char *dns_ipv6_addr; /* dot notation */
  char *userpwd;
  char *login_options;
  char *tls_username;







>
>







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  char *iface;
  long localport;
  long localportrange;
  unsigned short porttouse;
  char *range;
  long low_speed_limit;
  long low_speed_time;
  long ip_tos;         /* IP Type of Service */
  long vlan_priority;  /* VLAN priority */
  char *dns_servers;   /* dot notation: 1.1.1.1;2.2.2.2 */
  char *dns_interface; /* interface name */
  char *dns_ipv4_addr; /* dot notation */
  char *dns_ipv6_addr; /* dot notation */
  char *userpwd;
  char *login_options;
  char *tls_username;
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  bool proxytunnel;
  bool ftp_append;          /* APPE on ftp */
  bool use_ascii;           /* select ascii or text transfer */
  bool autoreferer;         /* automatically set referer */
  bool failonerror;         /* fail on (HTTP) errors */
  bool failwithbody;        /* fail on (HTTP) errors but still store body */
  bool show_headers;        /* show headers to data output */
  bool no_body;             /* don't get the body */
  bool dirlistonly;         /* only get the FTP dir list */
  bool followlocation;      /* follow http redirects */
  bool unrestricted_auth;   /* Continue to send authentication (user+password)
                               when following redirects, even when hostname
                               changed */
  bool netrc_opt;
  bool netrc;







|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  bool proxytunnel;
  bool ftp_append;          /* APPE on ftp */
  bool use_ascii;           /* select ascii or text transfer */
  bool autoreferer;         /* automatically set referer */
  bool failonerror;         /* fail on (HTTP) errors */
  bool failwithbody;        /* fail on (HTTP) errors but still store body */
  bool show_headers;        /* show headers to data output */
  bool no_body;             /* do not get the body */
  bool dirlistonly;         /* only get the FTP dir list */
  bool followlocation;      /* follow http redirects */
  bool unrestricted_auth;   /* Continue to send authentication (user+password)
                               when following redirects, even when hostname
                               changed */
  bool netrc_opt;
  bool netrc;
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
  bool disable_sessionid;

  bool raw;
  bool post301;
  bool post302;
  bool post303;
  bool nokeepalive;         /* for keepalive needs */
  long alivetime;

  bool content_disposition; /* use Content-disposition filename */

  int default_node_flags;   /* default flags to search for each 'node', which
                               is basically each given URL to transfer */

  bool xattr;               /* store metadata in extended attributes */
  long gssapi_delegation;







|
>







245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  bool disable_sessionid;

  bool raw;
  bool post301;
  bool post302;
  bool post303;
  bool nokeepalive;         /* for keepalive needs */
  long alivetime;           /* keepalive-time */
  long alivecnt;            /* keepalive-cnt */
  bool content_disposition; /* use Content-disposition filename */

  int default_node_flags;   /* default flags to search for each 'node', which
                               is basically each given URL to transfer */

  bool xattr;               /* store metadata in extended attributes */
  long gssapi_delegation;
288
289
290
291
292
293
294

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
                        by using the default behavior for -o, -O, and -J.
                        If those options would have overwritten files, like
                        -o and -O would, then overwrite them. In the case of
                        -J, this will not overwrite any files. */
    CLOBBER_NEVER, /* If the file exists, always fail */
    CLOBBER_ALWAYS /* If the file exists, always overwrite it */
  } file_clobber_mode;

  struct GlobalConfig *global;
  struct OperationConfig *prev;
  struct OperationConfig *next;   /* Always last in the struct */
  struct State state;             /* for create_transfer() */
  bool rm_partial;                /* on error, remove partially written output
                                     files */
#ifdef USE_ECH
  char *ech;                      /* Config set by --ech keywords */
  char *ech_config;               /* Config set by "--ech esl:" option */
  char *ech_public;               /* Config set by "--ech pn:" option */
#endif

};

struct GlobalConfig {
  bool showerror;                 /* show errors when silent */
  bool silent;                    /* don't show messages, --silent given */
  bool noprogress;                /* don't show progress bar */
  bool isatty;                    /* Updated internally if output is a tty */
  char *trace_dump;               /* file to dump the network trace to */
  FILE *trace_stream;
  bool trace_fopened;
  trace tracetype;
  bool tracetime;                 /* include timestamp? */
  bool traceids;                  /* include xfer-/conn-id? */
  int progressmode;               /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */
  char *libcurl;                  /* Output libcurl code to this file name */
  bool fail_early;                /* exit on first transfer error */
  bool styled_output;             /* enable fancy output style detection */
  long ms_per_transfer;           /* start next transfer after (at least) this
                                     many milliseconds */
#ifdef CURLDEBUG
  bool test_event_based;
#endif
  bool parallel;
  unsigned short parallel_max; /* MAX_PARALLEL is the maximum */
  bool parallel_connect;
  char *help_category;            /* The help category, if set */
  struct var *variables;







>
















|
|








|




|







291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
                        by using the default behavior for -o, -O, and -J.
                        If those options would have overwritten files, like
                        -o and -O would, then overwrite them. In the case of
                        -J, this will not overwrite any files. */
    CLOBBER_NEVER, /* If the file exists, always fail */
    CLOBBER_ALWAYS /* If the file exists, always overwrite it */
  } file_clobber_mode;
  bool mptcp;                     /* enable MPTCP support */
  struct GlobalConfig *global;
  struct OperationConfig *prev;
  struct OperationConfig *next;   /* Always last in the struct */
  struct State state;             /* for create_transfer() */
  bool rm_partial;                /* on error, remove partially written output
                                     files */
#ifdef USE_ECH
  char *ech;                      /* Config set by --ech keywords */
  char *ech_config;               /* Config set by "--ech esl:" option */
  char *ech_public;               /* Config set by "--ech pn:" option */
#endif

};

struct GlobalConfig {
  bool showerror;                 /* show errors when silent */
  bool silent;                    /* do not show messages, --silent given */
  bool noprogress;                /* do not show progress bar */
  bool isatty;                    /* Updated internally if output is a tty */
  char *trace_dump;               /* file to dump the network trace to */
  FILE *trace_stream;
  bool trace_fopened;
  trace tracetype;
  bool tracetime;                 /* include timestamp? */
  bool traceids;                  /* include xfer-/conn-id? */
  int progressmode;               /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */
  char *libcurl;                  /* Output libcurl code to this filename */
  bool fail_early;                /* exit on first transfer error */
  bool styled_output;             /* enable fancy output style detection */
  long ms_per_transfer;           /* start next transfer after (at least) this
                                     many milliseconds */
#ifdef DEBUGBUILD
  bool test_event_based;
#endif
  bool parallel;
  unsigned short parallel_max; /* MAX_PARALLEL is the maximum */
  bool parallel_connect;
  char *help_category;            /* The help category, if set */
  struct var *variables;
Changes to jni/curl/src/tool_dirhie.c.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#endif

static void show_dir_errno(struct GlobalConfig *global, const char *name)
{
  switch(errno) {
#ifdef EACCES
  case EACCES:
    errorf(global, "You don't have permission to create %s", name);
    break;
#endif
#ifdef ENAMETOOLONG
  case ENAMETOOLONG:
    errorf(global, "The directory name %s is too long", name);
    break;
#endif







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#endif

static void show_dir_errno(struct GlobalConfig *global, const char *name)
{
  switch(errno) {
#ifdef EACCES
  case EACCES:
    errorf(global, "You do not have permission to create %s", name);
    break;
#endif
#ifdef ENAMETOOLONG
  case ENAMETOOLONG:
    errorf(global, "The directory name %s is too long", name);
    break;
#endif
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  dirbuildup = malloc(outlen + 1);
  if(!dirbuildup) {
    Curl_safefree(outdup);
    return CURLE_OUT_OF_MEMORY;
  }
  dirbuildup[0] = '\0';

  /* Allow strtok() here since this isn't used threaded */
  /* !checksrc! disable BANNEDFUNC 2 */
  tempdir = strtok(outdup, PATH_DELIMITERS);

  while(tempdir) {
    bool skip = false;
    tempdir2 = strtok(NULL, PATH_DELIMITERS);
    /* since strtok returns a token for the last word even
       if not ending with DIR_CHAR, we need to prune it */
    if(tempdir2) {
      size_t dlen = strlen(dirbuildup);
      if(dlen)
        msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir);
      else {
        if(outdup == tempdir) {
#if defined(_WIN32) || defined(MSDOS)
          /* Skip creating a drive's current directory.
             It may seem as though that would harmlessly fail but it could be
             a corner case if X: did not exist, since we would be creating it
             erroneously.
             eg if outfile is X:\foo\bar\filename then don't mkdir X:
             This logic takes into account unsupported drives !:, 1:, etc. */
          char *p = strchr(tempdir, ':');
          if(p && !p[1])
            skip = true;
#endif
          /* the output string doesn't start with a separator */
          strcpy(dirbuildup, tempdir);
        }
        else
          msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir);
      }
      /* Create directory. Ignore access denied error to allow traversal. */
      if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) &&







|



















|





|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  dirbuildup = malloc(outlen + 1);
  if(!dirbuildup) {
    Curl_safefree(outdup);
    return CURLE_OUT_OF_MEMORY;
  }
  dirbuildup[0] = '\0';

  /* Allow strtok() here since this is not used threaded */
  /* !checksrc! disable BANNEDFUNC 2 */
  tempdir = strtok(outdup, PATH_DELIMITERS);

  while(tempdir) {
    bool skip = false;
    tempdir2 = strtok(NULL, PATH_DELIMITERS);
    /* since strtok returns a token for the last word even
       if not ending with DIR_CHAR, we need to prune it */
    if(tempdir2) {
      size_t dlen = strlen(dirbuildup);
      if(dlen)
        msnprintf(&dirbuildup[dlen], outlen - dlen, "%s%s", DIR_CHAR, tempdir);
      else {
        if(outdup == tempdir) {
#if defined(_WIN32) || defined(MSDOS)
          /* Skip creating a drive's current directory.
             It may seem as though that would harmlessly fail but it could be
             a corner case if X: did not exist, since we would be creating it
             erroneously.
             eg if outfile is X:\foo\bar\filename then do not mkdir X:
             This logic takes into account unsupported drives !:, 1:, etc. */
          char *p = strchr(tempdir, ':');
          if(p && !p[1])
            skip = true;
#endif
          /* the output string does not start with a separator */
          strcpy(dirbuildup, tempdir);
        }
        else
          msnprintf(dirbuildup, outlen, "%s%s", DIR_CHAR, tempdir);
      }
      /* Create directory. Ignore access denied error to allow traversal. */
      if(!skip && (-1 == mkdir(dirbuildup, (mode_t)0000750)) &&
Changes to jni/curl/src/tool_doswin.c.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#    define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#  else
#    define S_ISCHR(m) (0) /* cannot tell if file is a device */
#  endif
#endif

#ifdef _WIN32
#  define _use_lfn(f) (1)   /* long file names always available */
#elif !defined(__DJGPP__) || (__DJGPP__ < 2)  /* DJGPP 2.0 has _use_lfn() */
#  define _use_lfn(f) (0)  /* long file names never available */
#elif defined(__DJGPP__)
#  include <fcntl.h>                /* _use_lfn(f) prototype */
#endif

#ifndef UNITTESTS
static SANITIZEcode truncate_dryrun(const char *path,
                                    const size_t truncate_pos);







|

|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#    define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#  else
#    define S_ISCHR(m) (0) /* cannot tell if file is a device */
#  endif
#endif

#ifdef _WIN32
#  define _use_lfn(f) (1)   /* long filenames always available */
#elif !defined(__DJGPP__) || (__DJGPP__ < 2)  /* DJGPP 2.0 has _use_lfn() */
#  define _use_lfn(f) (0)  /* long filenames never available */
#elif defined(__DJGPP__)
#  include <fcntl.h>                /* _use_lfn(f) prototype */
#endif

#ifndef UNITTESTS
static SANITIZEcode truncate_dryrun(const char *path,
                                    const size_t truncate_pos);
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
SANITIZE_ALLOW_COLONS:     Allow colons.
Without this flag colons are sanitized.

SANITIZE_ALLOW_PATH:       Allow path separators and colons.
Without this flag path separators and colons are sanitized.

SANITIZE_ALLOW_RESERVED:   Allow reserved device names.
Without this flag a reserved device name is renamed (COM1 => _COM1) unless it's
in a UNC prefixed path.

SANITIZE_ALLOW_TRUNCATE:   Allow truncating a long filename.
Without this flag if the sanitized filename or path will be too long an error
occurs. With this flag the filename --and not any other parts of the path-- may
be truncated to at least a single character. A filename followed by an
alternate data stream (ADS) cannot be truncated in any case.








|
|







94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
SANITIZE_ALLOW_COLONS:     Allow colons.
Without this flag colons are sanitized.

SANITIZE_ALLOW_PATH:       Allow path separators and colons.
Without this flag path separators and colons are sanitized.

SANITIZE_ALLOW_RESERVED:   Allow reserved device names.
Without this flag a reserved device name is renamed (COM1 => _COM1) unless it
is in a UNC prefixed path.

SANITIZE_ALLOW_TRUNCATE:   Allow truncating a long filename.
Without this flag if the sanitized filename or path will be too long an error
occurs. With this flag the filename --and not any other parts of the path-- may
be truncated to at least a single character. A filename followed by an
alternate data stream (ADS) cannot be truncated in any case.

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
      /* UNC prefixed path \\ (eg \\?\C:\foo) */
      max_sanitized_len = 32767-1;
    else
#endif
      max_sanitized_len = PATH_MAX-1;
  }
  else
    /* The maximum length of a filename.
       FILENAME_MAX is often the same as PATH_MAX, in other words it is 260 and
       does not discount the path information therefore we shouldn't use it. */
    max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1;

  len = strlen(file_name);
  if(len > max_sanitized_len) {
    if(!(flags & SANITIZE_ALLOW_TRUNCATE) ||
       truncate_dryrun(file_name, max_sanitized_len))
      return SANITIZE_ERR_INVALID_PATH;







|
|
|







132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
      /* UNC prefixed path \\ (eg \\?\C:\foo) */
      max_sanitized_len = 32767-1;
    else
#endif
      max_sanitized_len = PATH_MAX-1;
  }
  else
    /* The maximum length of a filename. FILENAME_MAX is often the same as
       PATH_MAX, in other words it is 260 and does not discount the path
       information therefore we should not use it. */
    max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1;

  len = strlen(file_name);
  if(len > max_sanitized_len) {
    if(!(flags & SANITIZE_ALLOW_TRUNCATE) ||
       truncate_dryrun(file_name, max_sanitized_len))
      return SANITIZE_ERR_INVALID_PATH;
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  *sanitized = target;
  return SANITIZE_ERR_OK;
}


/*
Test if truncating a path to a file will leave at least a single character in
the filename. Filenames suffixed by an alternate data stream can't be
truncated. This performs a dry run, nothing is modified.

Good truncate_pos 9:    C:\foo\bar  =>  C:\foo\ba
Good truncate_pos 6:    C:\foo      =>  C:\foo
Good truncate_pos 5:    C:\foo      =>  C:\fo
Bad* truncate_pos 5:    C:foo       =>  C:foo
Bad truncate_pos 5:     C:\foo:ads  =>  C:\fo
Bad truncate_pos 9:     C:\foo:ads  =>  C:\foo:ad
Bad truncate_pos 5:     C:\foo\bar  =>  C:\fo
Bad truncate_pos 5:     C:\foo\     =>  C:\fo
Bad truncate_pos 7:     C:\foo\     =>  C:\foo\
Error truncate_pos 7:   C:\foo      =>  (pos out of range)
Bad truncate_pos 1:     C:\foo\     =>  C

* C:foo is ambiguous, C could end up being a drive or file therefore something
  like C:superlongfilename can't be truncated.

Returns
SANITIZE_ERR_OK: Good -- 'path' can be truncated
SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated
!= SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error
*/
SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos)







|















|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  *sanitized = target;
  return SANITIZE_ERR_OK;
}


/*
Test if truncating a path to a file will leave at least a single character in
the filename. Filenames suffixed by an alternate data stream cannot be
truncated. This performs a dry run, nothing is modified.

Good truncate_pos 9:    C:\foo\bar  =>  C:\foo\ba
Good truncate_pos 6:    C:\foo      =>  C:\foo
Good truncate_pos 5:    C:\foo      =>  C:\fo
Bad* truncate_pos 5:    C:foo       =>  C:foo
Bad truncate_pos 5:     C:\foo:ads  =>  C:\fo
Bad truncate_pos 9:     C:\foo:ads  =>  C:\foo:ad
Bad truncate_pos 5:     C:\foo\bar  =>  C:\fo
Bad truncate_pos 5:     C:\foo\     =>  C:\fo
Bad truncate_pos 7:     C:\foo\     =>  C:\foo\
Error truncate_pos 7:   C:\foo      =>  (pos out of range)
Bad truncate_pos 1:     C:\foo\     =>  C

* C:foo is ambiguous, C could end up being a drive or file therefore something
  like C:superlongfilename cannot be truncated.

Returns
SANITIZE_ERR_OK: Good -- 'path' can be truncated
SANITIZE_ERR_INVALID_PATH: Bad -- 'path' cannot be truncated
!= SANITIZE_ERR_OK && != SANITIZE_ERR_INVALID_PATH: Error
*/
SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos)
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

  if(!len || !truncate_pos)
    return SANITIZE_ERR_INVALID_PATH;

  if(strpbrk(&path[truncate_pos - 1], "\\/:"))
    return SANITIZE_ERR_INVALID_PATH;

  /* C:\foo can be truncated but C:\foo:ads can't */
  if(truncate_pos > 1) {
    const char *p = &path[truncate_pos - 1];
    do {
      --p;
      if(*p == ':')
        return SANITIZE_ERR_INVALID_PATH;
    } while(p != path && *p != '\\' && *p != '/');







|







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

  if(!len || !truncate_pos)
    return SANITIZE_ERR_INVALID_PATH;

  if(strpbrk(&path[truncate_pos - 1], "\\/:"))
    return SANITIZE_ERR_INVALID_PATH;

  /* C:\foo can be truncated but C:\foo:ads cannot */
  if(truncate_pos > 1) {
    const char *p = &path[truncate_pos - 1];
    do {
      --p;
      if(*p == ':')
        return SANITIZE_ERR_INVALID_PATH;
    } while(p != path && *p != '\\' && *p != '/');
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
    if(memchr(illegal_aliens, *s, len)) {

      if((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *s == ':')
        *d = ':';
      else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\'))
        *d = *s;
      /* Dots are special: DOS doesn't allow them as the leading character,
         and a file name cannot have more than a single dot.  We leave the
         first non-leading dot alone, unless it comes too close to the
         beginning of the name: we want sh.lex.c to become sh_lex.c, not
         sh.lex-c.  */
      else if(*s == '.') {
        if((flags & SANITIZE_ALLOW_PATH) && idx == 0 &&
           (s[1] == '/' || s[1] == '\\' ||
            (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) {







|
|







353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
  for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
    if(memchr(illegal_aliens, *s, len)) {

      if((flags & (SANITIZE_ALLOW_COLONS|SANITIZE_ALLOW_PATH)) && *s == ':')
        *d = ':';
      else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\'))
        *d = *s;
      /* Dots are special: DOS does not allow them as the leading character,
         and a filename cannot have more than a single dot. We leave the
         first non-leading dot alone, unless it comes too close to the
         beginning of the name: we want sh.lex.c to become sh_lex.c, not
         sh.lex-c.  */
      else if(*s == '.') {
        if((flags & SANITIZE_ALLOW_PATH) && idx == 0 &&
           (s[1] == '/' || s[1] == '\\' ||
            (s[1] == '.' && (s[2] == '/' || s[2] == '\\')))) {
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

  *sanitized = strdup(dos_name);
  return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY);
}
#endif /* MSDOS || UNITTESTS */

/*
Rename file_name if it's a reserved dos device name.

This is a supporting function for sanitize_file_name.

Warning: This is an MSDOS legacy function and was purposely written in a way
that some path information may pass through. For example drive letter names
(C:, D:, etc) are allowed to pass through. For sanitizing a filename use
sanitize_file_name.

Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
*/
SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized,
                                                const char *file_name,
                                                int flags)
{
  /* We could have a file whose name is a device on MS-DOS.  Trying to
   * retrieve such a file would fail at best and wedge us at worst.  We need
   * to rename such files. */
  char *p, *base;
  char fname[PATH_MAX];
#ifdef MSDOS
  struct_stat st_buf;
#endif








|















|
|







441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

  *sanitized = strdup(dos_name);
  return (*sanitized ? SANITIZE_ERR_OK : SANITIZE_ERR_OUT_OF_MEMORY);
}
#endif /* MSDOS || UNITTESTS */

/*
Rename file_name if it is a reserved dos device name.

This is a supporting function for sanitize_file_name.

Warning: This is an MSDOS legacy function and was purposely written in a way
that some path information may pass through. For example drive letter names
(C:, D:, etc) are allowed to pass through. For sanitizing a filename use
sanitize_file_name.

Success: (SANITIZE_ERR_OK) *sanitized points to a sanitized copy of file_name.
Failure: (!= SANITIZE_ERR_OK) *sanitized is NULL.
*/
SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized,
                                                const char *file_name,
                                                int flags)
{
  /* We could have a file whose name is a device on MS-DOS. Trying to
   * retrieve such a file would fail at best and wedge us at worst. We need
   * to rename such files. */
  char *p, *base;
  char fname[PATH_MAX];
#ifdef MSDOS
  struct_stat st_buf;
#endif

556
557
558
559
560
561
562
563
564
565

566
567
568
569
570
571
572
    if(p == fname)
      base = basename(fname);
  }

  /* This is the legacy portion from rename_if_dos_device_name that checks for
     reserved device names. It only works on MSDOS. On Windows XP the stat
     check errors with EINVAL if the device name is reserved. On Windows
     Vista/7/8 it sets mode S_IFREG (regular file or device). According to MSDN
     stat doc the latter behavior is correct, but that doesn't help us identify
     whether it's a reserved device name and not a regular file name. */

#ifdef MSDOS
  if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
    /* Prepend a '_' */
    size_t blen = strlen(base);
    if(blen) {
      if(strlen(fname) == PATH_MAX-1) {
        --blen;







|
|
|
>







556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
    if(p == fname)
      base = basename(fname);
  }

  /* This is the legacy portion from rename_if_dos_device_name that checks for
     reserved device names. It only works on MSDOS. On Windows XP the stat
     check errors with EINVAL if the device name is reserved. On Windows
     Vista/7/8 it sets mode S_IFREG (regular file or device). According to
     MSDN stat doc the latter behavior is correct, but that does not help us
     identify whether it is a reserved device name and not a regular
     filename. */
#ifdef MSDOS
  if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
    /* Prepend a '_' */
    size_t blen = strlen(base);
    if(blen) {
      if(strlen(fname) == PATH_MAX-1) {
        --blen;
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622





623
624
625
626
627
628
629
/*
 * Function to find CACert bundle on a Win32 platform using SearchPath.
 * (SearchPath is already declared via inclusions done in setup header file)
 * (Use the ASCII version instead of the unicode one!)
 * The order of the directories it searches is:
 *  1. application's directory
 *  2. current working directory
 *  3. Windows System directory (e.g. C:\windows\system32)
 *  4. Windows Directory (e.g. C:\windows)
 *  5. all directories along %PATH%
 *
 * For WinXP and later search order actually depends on registry value:
 * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode
 */

CURLcode FindWin32CACert(struct OperationConfig *config,
                         curl_sslbackend backend,
                         const TCHAR *bundle_file)
{
  CURLcode result = CURLE_OK;






  /* Search and set cert file only if libcurl supports SSL.
   *
   * If Schannel is the selected SSL backend then these locations are
   * ignored. We allow setting CA location for schannel only when explicitly
   * specified by the user via CURLOPT_CAINFO / --cacert.
   */
  if(feature_ssl && backend != CURLSSLBACKEND_SCHANNEL) {







|
|












>
>
>
>
>







603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
/*
 * Function to find CACert bundle on a Win32 platform using SearchPath.
 * (SearchPath is already declared via inclusions done in setup header file)
 * (Use the ASCII version instead of the unicode one!)
 * The order of the directories it searches is:
 *  1. application's directory
 *  2. current working directory
 *  3. Windows System directory (e.g. C:\Windows\System32)
 *  4. Windows Directory (e.g. C:\Windows)
 *  5. all directories along %PATH%
 *
 * For WinXP and later search order actually depends on registry value:
 * HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SafeProcessSearchMode
 */

CURLcode FindWin32CACert(struct OperationConfig *config,
                         curl_sslbackend backend,
                         const TCHAR *bundle_file)
{
  CURLcode result = CURLE_OK;

#ifdef CURL_WINDOWS_APP
  (void)config;
  (void)backend;
  (void)bundle_file;
#else
  /* Search and set cert file only if libcurl supports SSL.
   *
   * If Schannel is the selected SSL backend then these locations are
   * ignored. We allow setting CA location for schannel only when explicitly
   * specified by the user via CURLOPT_CAINFO / --cacert.
   */
  if(feature_ssl && backend != CURLSSLBACKEND_SCHANNEL) {
641
642
643
644
645
646
647

648
649
650
651
652
653
654
      if(mstr)
        config->cacert = strdup(mstr);
      curlx_unicodefree(mstr);
      if(!config->cacert)
        result = CURLE_OUT_OF_MEMORY;
    }
  }


  return result;
}


/* Get a list of all loaded modules with full paths.
 * Returns slist on success or NULL on error.







>







647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
      if(mstr)
        config->cacert = strdup(mstr);
      curlx_unicodefree(mstr);
      if(!config->cacert)
        result = CURLE_OUT_OF_MEMORY;
    }
  }
#endif

  return result;
}


/* Get a list of all loaded modules with full paths.
 * Returns slist on success or NULL on error.
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687

  do {
    char *path; /* points to stack allocated buffer */
    struct curl_slist *temp;

#ifdef UNICODE
    /* sizeof(mod.szExePath) is the max total bytes of wchars. the max total
       bytes of multibyte chars won't be more than twice that. */
    char buffer[sizeof(mod.szExePath) * 2];
    if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1,
                            buffer, sizeof(buffer), NULL, NULL))
      goto error;
    path = buffer;
#else
    path = mod.szExePath;







|







680
681
682
683
684
685
686
687
688
689
690
691
692
693
694

  do {
    char *path; /* points to stack allocated buffer */
    struct curl_slist *temp;

#ifdef UNICODE
    /* sizeof(mod.szExePath) is the max total bytes of wchars. the max total
       bytes of multibyte chars will not be more than twice that. */
    char buffer[sizeof(mod.szExePath) * 2];
    if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1,
                            buffer, sizeof(buffer), NULL, NULL))
      goto error;
    path = buffer;
#else
    path = mod.szExePath;
699
700
701
702
703
704
705



706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  slist = NULL;
cleanup:
  if(hnd != INVALID_HANDLE_VALUE)
    CloseHandle(hnd);
  return slist;
}




/* The terminal settings to restore on exit */
static struct TerminalSettings {
  HANDLE hStdOut;
  DWORD dwOutputMode;
  LONG valid;
} TerminalSettings;

#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif

bool tool_term_has_bold;

static void restore_terminal(void)
{
  if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE))
    SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode);
}

/* This is the console signal handler.







>
>
>











<
<







706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726


727
728
729
730
731
732
733
  slist = NULL;
cleanup:
  if(hnd != INVALID_HANDLE_VALUE)
    CloseHandle(hnd);
  return slist;
}

bool tool_term_has_bold;

#ifndef CURL_WINDOWS_APP
/* The terminal settings to restore on exit */
static struct TerminalSettings {
  HANDLE hStdOut;
  DWORD dwOutputMode;
  LONG valid;
} TerminalSettings;

#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif



static void restore_terminal(void)
{
  if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE))
    SetConsoleMode(TerminalSettings.hStdOut, TerminalSettings.dwOutputMode);
}

/* This is the console signal handler.
766
767
768
769
770
771
772

773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788

789

790
791
792
793
794
795
796
      else {
        SetConsoleCtrlHandler(signal_handler, FALSE);
        (void)InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE);
      }
    }
  }
}


LARGE_INTEGER tool_freq;
bool tool_isVistaOrGreater;

CURLcode win32_init(void)
{
  /* curlx_verify_windows_version must be called during init at least once
     because it has its own initialization routine. */
  if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
                                  VERSION_GREATER_THAN_EQUAL))
    tool_isVistaOrGreater = true;
  else
    tool_isVistaOrGreater = false;

  QueryPerformanceFrequency(&tool_freq);


  init_terminal();


  return CURLE_OK;
}

#endif /* _WIN32 */

#endif /* _WIN32 || MSDOS */







>
















>

>







774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
      else {
        SetConsoleCtrlHandler(signal_handler, FALSE);
        (void)InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE);
      }
    }
  }
}
#endif

LARGE_INTEGER tool_freq;
bool tool_isVistaOrGreater;

CURLcode win32_init(void)
{
  /* curlx_verify_windows_version must be called during init at least once
     because it has its own initialization routine. */
  if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
                                  VERSION_GREATER_THAN_EQUAL))
    tool_isVistaOrGreater = true;
  else
    tool_isVistaOrGreater = false;

  QueryPerformanceFrequency(&tool_freq);

#ifndef CURL_WINDOWS_APP
  init_terminal();
#endif

  return CURLE_OK;
}

#endif /* _WIN32 */

#endif /* _WIN32 || MSDOS */
Changes to jni/curl/src/tool_filetime.c.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/* Returns 0 on success, non-zero on file problems */
int getfiletime(const char *filename, struct GlobalConfig *global,
                curl_off_t *stamp)
{
  int rc = 1;

/* Windows stat() may attempt to adjust the unix GMT file time by a daylight
   saving time offset and since it's GMT that is bad behavior. When we have
   access to a 64-bit type we can bypass stat and get the times directly. */
#if defined(_WIN32)
  HANDLE hfile;
  TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename);

  hfile = CreateFile(tchar_filename, FILE_READ_ATTRIBUTES,
                      (FILE_SHARE_READ | FILE_SHARE_WRITE |
                       FILE_SHARE_DELETE),
                      NULL, OPEN_EXISTING, 0, NULL);







|

|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/* Returns 0 on success, non-zero on file problems */
int getfiletime(const char *filename, struct GlobalConfig *global,
                curl_off_t *stamp)
{
  int rc = 1;

/* Windows stat() may attempt to adjust the unix GMT file time by a daylight
   saving time offset and since it is GMT that is bad behavior. When we have
   access to a 64-bit type we can bypass stat and get the times directly. */
#if defined(_WIN32) && !defined(CURL_WINDOWS_APP)
  HANDLE hfile;
  TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename);

  hfile = CreateFile(tchar_filename, FILE_READ_ATTRIBUTES,
                      (FILE_SHARE_READ | FILE_SHARE_WRITE |
                       FILE_SHARE_DELETE),
                      NULL, OPEN_EXISTING, 0, NULL);
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || defined(_WIN32)
void setfiletime(curl_off_t filetime, const char *filename,
                 struct GlobalConfig *global)
{
  if(filetime >= 0) {
/* Windows utime() may attempt to adjust the unix GMT file time by a daylight
   saving time offset and since it's GMT that is bad behavior. When we have
   access to a 64-bit type we can bypass utime and set the times directly. */
#if defined(_WIN32)
    HANDLE hfile;
    TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename);

    /* 910670515199 is the maximum unix filetime that can be used as a
       Windows FILETIME without overflow: 30827-12-31T23:59:59. */
    if(filetime > CURL_OFF_T_C(910670515199)) {
      warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T







|

|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

#if defined(HAVE_UTIME) || defined(HAVE_UTIMES) || defined(_WIN32)
void setfiletime(curl_off_t filetime, const char *filename,
                 struct GlobalConfig *global)
{
  if(filetime >= 0) {
/* Windows utime() may attempt to adjust the unix GMT file time by a daylight
   saving time offset and since it is GMT that is bad behavior. When we have
   access to a 64-bit type we can bypass utime and set the times directly. */
#if defined(_WIN32) && !defined(CURL_WINDOWS_APP)
    HANDLE hfile;
    TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename);

    /* 910670515199 is the maximum unix filetime that can be used as a
       Windows FILETIME without overflow: 30827-12-31T23:59:59. */
    if(filetime > CURL_OFF_T_C(910670515199)) {
      warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
Changes to jni/curl/src/tool_formparse.c.
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  else if(type)
    warnf(config->global, "Field content type not allowed here: %s", type);

  if(pfilename)
    *pfilename = filename;
  else if(filename)
    warnf(config->global,
          "Field file name not allowed here: %s", filename);

  if(pencoder)
    *pencoder = encoder;
  else if(encoder)
    warnf(config->global,
          "Field encoder not allowed here: %s", encoder);








|







633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  else if(type)
    warnf(config->global, "Field content type not allowed here: %s", type);

  if(pfilename)
    *pfilename = filename;
  else if(filename)
    warnf(config->global,
          "Field filename not allowed here: %s", filename);

  if(pencoder)
    *pencoder = encoder;
  else if(encoder)
    warnf(config->global,
          "Field encoder not allowed here: %s", encoder);

689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
 *
 * If you want custom headers added for a single part, write them in a separate
 * file and do like this:
 *
 * 'name=foo;headers=@headerfile' or why not
 * 'name=@filemame;headers=@headerfile'
 *
 * To upload a file, but to fake the file name that will be included in the
 * formpost, do like this:
 *
 * 'name=@filename;filename=/dev/null' or quote the faked filename like:
 * 'name=@filename;filename="play, play, and play.txt"'
 *
 * If filename/path contains ',' or ';', it must be quoted by double-quotes,
 * else curl will fail to figure out the correct filename. if the filename







|







689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
 *
 * If you want custom headers added for a single part, write them in a separate
 * file and do like this:
 *
 * 'name=foo;headers=@headerfile' or why not
 * 'name=@filemame;headers=@headerfile'
 *
 * To upload a file, but to fake the filename that will be included in the
 * formpost, do like this:
 *
 * 'name=@filename;filename=/dev/null' or quote the faked filename like:
 * 'name=@filename;filename="play, play, and play.txt"'
 *
 * If filename/path contains ',' or ';', it must be quoted by double-quotes,
 * else curl will fail to figure out the correct filename. if the filename
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730

int formparse(struct OperationConfig *config,
              const char *input,
              struct tool_mime **mimeroot,
              struct tool_mime **mimecurrent,
              bool literal_value)
{
  /* input MUST be a string in the format 'name=contents' and we'll
     build a linked list with the info */
  char *name = NULL;
  char *contents = NULL;
  char *contp;
  char *data;
  char *type = NULL;
  char *filename = NULL;







|







716
717
718
719
720
721
722
723
724
725
726
727
728
729
730

int formparse(struct OperationConfig *config,
              const char *input,
              struct tool_mime **mimeroot,
              struct tool_mime **mimecurrent,
              bool literal_value)
{
  /* input MUST be a string in the format 'name=contents' and we will
     build a linked list with the info */
  char *name = NULL;
  char *contents = NULL;
  char *contp;
  char *data;
  char *type = NULL;
  char *filename = NULL;
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
        warnf(config->global, "no multipart to terminate");
        goto fail;
      }
      *mimecurrent = (*mimecurrent)->parent;
    }
    else if('@' == contp[0] && !literal_value) {

      /* we use the @-letter to indicate file name(s) */

      struct tool_mime *subparts = NULL;

      do {
        /* since this was a file, it may have a content-type specifier
           at the end too, or a filename. Or both. */
        ++contp;







|







775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
        warnf(config->global, "no multipart to terminate");
        goto fail;
      }
      *mimecurrent = (*mimecurrent)->parent;
    }
    else if('@' == contp[0] && !literal_value) {

      /* we use the @-letter to indicate filename(s) */

      struct tool_mime *subparts = NULL;

      do {
        /* since this was a file, it may have a content-type specifier
           at the end too, or a filename. Or both. */
        ++contp;
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
          res = CURLE_OK;
        }
        SET_TOOL_MIME_PTR(part, filename);
        SET_TOOL_MIME_PTR(part, type);
        SET_TOOL_MIME_PTR(part, encoder);

        /* *contp could be '\0', so we just check with the delimiter */
      } while(sep); /* loop if there's another file name */
      part = (*mimecurrent)->subparts;  /* Set name on group. */
    }
    else {
      if(*contp == '<' && !literal_value) {
        ++contp;
        sep = get_param_part(config, '\0', &contp,
                             &data, &type, NULL, &encoder, &headers);







|







827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
          res = CURLE_OK;
        }
        SET_TOOL_MIME_PTR(part, filename);
        SET_TOOL_MIME_PTR(part, type);
        SET_TOOL_MIME_PTR(part, encoder);

        /* *contp could be '\0', so we just check with the delimiter */
      } while(sep); /* loop if there is another filename */
      part = (*mimecurrent)->subparts;  /* Set name on group. */
    }
    else {
      if(*contp == '<' && !literal_value) {
        ++contp;
        sep = get_param_part(config, '\0', &contp,
                             &data, &type, NULL, &encoder, &headers);
Changes to jni/curl/src/tool_getparam.c.
175
176
177
178
179
180
181

182
183
184
185
186
187
188
  C_INTERFACE,
  C_IPFS_GATEWAY,
  C_IPV4,
  C_IPV6,
  C_JSON,
  C_JUNK_SESSION_COOKIES,
  C_KEEPALIVE,

  C_KEEPALIVE_TIME,
  C_KEY,
  C_KEY_TYPE,
  C_KRB,
  C_KRB4,
  C_LIBCURL,
  C_LIMIT_RATE,







>







175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  C_INTERFACE,
  C_IPFS_GATEWAY,
  C_IPV4,
  C_IPV6,
  C_JSON,
  C_JUNK_SESSION_COOKIES,
  C_KEEPALIVE,
  C_KEEPALIVE_CNT,
  C_KEEPALIVE_TIME,
  C_KEY,
  C_KEY_TYPE,
  C_KRB,
  C_KRB4,
  C_LIBCURL,
  C_LIMIT_RATE,
196
197
198
199
200
201
202

203
204
205
206
207
208
209
  C_MAIL_RCPT,
  C_MAIL_RCPT_ALLOWFAILS,
  C_MANUAL,
  C_MAX_FILESIZE,
  C_MAX_REDIRS,
  C_MAX_TIME,
  C_METALINK,

  C_NEGOTIATE,
  C_NETRC,
  C_NETRC_FILE,
  C_NETRC_OPTIONAL,
  C_NEXT,
  C_NOPROXY,
  C_NPN,







>







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  C_MAIL_RCPT,
  C_MAIL_RCPT_ALLOWFAILS,
  C_MANUAL,
  C_MAX_FILESIZE,
  C_MAX_REDIRS,
  C_MAX_TIME,
  C_METALINK,
  C_MPTCP,
  C_NEGOTIATE,
  C_NETRC,
  C_NETRC_FILE,
  C_NETRC_OPTIONAL,
  C_NEXT,
  C_NOPROXY,
  C_NPN,
324
325
326
327
328
329
330

331
332
333
334
335
336
337
338
339
340

341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  C_TLSV1_3,
  C_TR_ENCODING,
  C_TRACE,
  C_TRACE_ASCII,
  C_TRACE_CONFIG,
  C_TRACE_IDS,
  C_TRACE_TIME,

  C_UNIX_SOCKET,
  C_UPLOAD_FILE,
  C_URL,
  C_URL_QUERY,
  C_USE_ASCII,
  C_USER,
  C_USER_AGENT,
  C_VARIABLE,
  C_VERBOSE,
  C_VERSION,

  C_WDEBUG,
  C_WRITE_OUT,
  C_XATTR
} cmdline_t;

struct LongShort {
  const char *lname;  /* long name option */
  enum {
    ARG_NONE, /* stand-alone but not a boolean */
    ARG_BOOL, /* accepts a --no-[name] prefix */
    ARG_STRG, /* requires an argument */
    ARG_FILE  /* requires an argument, usually a file name */
  } desc;
  char letter;  /* short name option or ' ' */
  cmdline_t cmd;
};

/* this array MUST be alphasorted based on the 'lname' */
static const struct LongShort aliases[]= {







>










>











|







326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  C_TLSV1_3,
  C_TR_ENCODING,
  C_TRACE,
  C_TRACE_ASCII,
  C_TRACE_CONFIG,
  C_TRACE_IDS,
  C_TRACE_TIME,
  C_IP_TOS,
  C_UNIX_SOCKET,
  C_UPLOAD_FILE,
  C_URL,
  C_URL_QUERY,
  C_USE_ASCII,
  C_USER,
  C_USER_AGENT,
  C_VARIABLE,
  C_VERBOSE,
  C_VERSION,
  C_VLAN_PRIORITY,
  C_WDEBUG,
  C_WRITE_OUT,
  C_XATTR
} cmdline_t;

struct LongShort {
  const char *lname;  /* long name option */
  enum {
    ARG_NONE, /* stand-alone but not a boolean */
    ARG_BOOL, /* accepts a --no-[name] prefix */
    ARG_STRG, /* requires an argument */
    ARG_FILE  /* requires an argument, usually a filename */
  } desc;
  char letter;  /* short name option or ' ' */
  cmdline_t cmd;
};

/* this array MUST be alphasorted based on the 'lname' */
static const struct LongShort aliases[]= {
451
452
453
454
455
456
457

458
459
460
461
462
463

464
465
466
467
468
469
470
  {"http2-prior-knowledge",      ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE},
  {"http3",                      ARG_NONE, ' ', C_HTTP3},
  {"http3-only",                 ARG_NONE, ' ', C_HTTP3_ONLY},
  {"ignore-content-length",      ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH},
  {"include",                    ARG_BOOL, 'i', C_INCLUDE},
  {"insecure",                   ARG_BOOL, 'k', C_INSECURE},
  {"interface",                  ARG_STRG, ' ', C_INTERFACE},

  {"ipfs-gateway",               ARG_STRG, ' ', C_IPFS_GATEWAY},
  {"ipv4",                       ARG_NONE, '4', C_IPV4},
  {"ipv6",                       ARG_NONE, '6', C_IPV6},
  {"json",                       ARG_STRG, ' ', C_JSON},
  {"junk-session-cookies",       ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES},
  {"keepalive",                  ARG_BOOL, ' ', C_KEEPALIVE},

  {"keepalive-time",             ARG_STRG, ' ', C_KEEPALIVE_TIME},
  {"key",                        ARG_FILE, ' ', C_KEY},
  {"key-type",                   ARG_STRG, ' ', C_KEY_TYPE},
  {"krb",                        ARG_STRG, ' ', C_KRB},
  {"krb4",                       ARG_STRG, ' ', C_KRB4},
  {"libcurl",                    ARG_STRG, ' ', C_LIBCURL},
  {"limit-rate",                 ARG_STRG, ' ', C_LIMIT_RATE},







>






>







455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
  {"http2-prior-knowledge",      ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE},
  {"http3",                      ARG_NONE, ' ', C_HTTP3},
  {"http3-only",                 ARG_NONE, ' ', C_HTTP3_ONLY},
  {"ignore-content-length",      ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH},
  {"include",                    ARG_BOOL, 'i', C_INCLUDE},
  {"insecure",                   ARG_BOOL, 'k', C_INSECURE},
  {"interface",                  ARG_STRG, ' ', C_INTERFACE},
  {"ip-tos",                     ARG_STRG, ' ', C_IP_TOS},
  {"ipfs-gateway",               ARG_STRG, ' ', C_IPFS_GATEWAY},
  {"ipv4",                       ARG_NONE, '4', C_IPV4},
  {"ipv6",                       ARG_NONE, '6', C_IPV6},
  {"json",                       ARG_STRG, ' ', C_JSON},
  {"junk-session-cookies",       ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES},
  {"keepalive",                  ARG_BOOL, ' ', C_KEEPALIVE},
  {"keepalive-cnt",              ARG_STRG, ' ', C_KEEPALIVE_CNT},
  {"keepalive-time",             ARG_STRG, ' ', C_KEEPALIVE_TIME},
  {"key",                        ARG_FILE, ' ', C_KEY},
  {"key-type",                   ARG_STRG, ' ', C_KEY_TYPE},
  {"krb",                        ARG_STRG, ' ', C_KRB},
  {"krb4",                       ARG_STRG, ' ', C_KRB4},
  {"libcurl",                    ARG_STRG, ' ', C_LIBCURL},
  {"limit-rate",                 ARG_STRG, ' ', C_LIMIT_RATE},
478
479
480
481
482
483
484

485
486
487
488
489
490
491
  {"mail-rcpt",                  ARG_STRG, ' ', C_MAIL_RCPT},
  {"mail-rcpt-allowfails",       ARG_BOOL, ' ', C_MAIL_RCPT_ALLOWFAILS},
  {"manual",                     ARG_BOOL, 'M', C_MANUAL},
  {"max-filesize",               ARG_STRG, ' ', C_MAX_FILESIZE},
  {"max-redirs",                 ARG_STRG, ' ', C_MAX_REDIRS},
  {"max-time",                   ARG_STRG, 'm', C_MAX_TIME},
  {"metalink",                   ARG_BOOL, ' ', C_METALINK},

  {"negotiate",                  ARG_BOOL, ' ', C_NEGOTIATE},
  {"netrc",                      ARG_BOOL, 'n', C_NETRC},
  {"netrc-file",                 ARG_FILE, ' ', C_NETRC_FILE},
  {"netrc-optional",             ARG_BOOL, ' ', C_NETRC_OPTIONAL},
  {"next",                       ARG_NONE, ':', C_NEXT},
  {"noproxy",                    ARG_STRG, ' ', C_NOPROXY},
  {"npn",                        ARG_BOOL, ' ', C_NPN},







>







484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  {"mail-rcpt",                  ARG_STRG, ' ', C_MAIL_RCPT},
  {"mail-rcpt-allowfails",       ARG_BOOL, ' ', C_MAIL_RCPT_ALLOWFAILS},
  {"manual",                     ARG_BOOL, 'M', C_MANUAL},
  {"max-filesize",               ARG_STRG, ' ', C_MAX_FILESIZE},
  {"max-redirs",                 ARG_STRG, ' ', C_MAX_REDIRS},
  {"max-time",                   ARG_STRG, 'm', C_MAX_TIME},
  {"metalink",                   ARG_BOOL, ' ', C_METALINK},
  {"mptcp",                      ARG_BOOL, ' ', C_MPTCP},
  {"negotiate",                  ARG_BOOL, ' ', C_NEGOTIATE},
  {"netrc",                      ARG_BOOL, 'n', C_NETRC},
  {"netrc-file",                 ARG_FILE, ' ', C_NETRC_FILE},
  {"netrc-optional",             ARG_BOOL, ' ', C_NETRC_OPTIONAL},
  {"next",                       ARG_NONE, ':', C_NEXT},
  {"noproxy",                    ARG_STRG, ' ', C_NOPROXY},
  {"npn",                        ARG_BOOL, ' ', C_NPN},
616
617
618
619
620
621
622

623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  {"url-query",                  ARG_STRG, ' ', C_URL_QUERY},
  {"use-ascii",                  ARG_BOOL, 'B', C_USE_ASCII},
  {"user",                       ARG_STRG, 'u', C_USER},
  {"user-agent",                 ARG_STRG, 'A', C_USER_AGENT},
  {"variable",                   ARG_STRG, ' ', C_VARIABLE},
  {"verbose",                    ARG_BOOL, 'v', C_VERBOSE},
  {"version",                    ARG_BOOL, 'V', C_VERSION},

#ifdef USE_WATT32
  {"wdebug",                     ARG_BOOL, ' ', C_WDEBUG},
#endif
  {"write-out",                  ARG_STRG, 'w', C_WRITE_OUT},
  {"xattr",                      ARG_BOOL, ' ', C_XATTR},
};

/* Split the argument of -E to 'certname' and 'passphrase' separated by colon.
 * We allow ':' and '\' to be escaped by '\' so that we can use certificate
 * nicknames containing ':'.  See <https://sourceforge.net/p/curl/bugs/1196/>
 * for details. */
#ifndef UNITTESTS
static
#endif
void parse_cert_parameter(const char *cert_parameter,
                          char **certname,
                          char **passphrase)







>









|







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  {"url-query",                  ARG_STRG, ' ', C_URL_QUERY},
  {"use-ascii",                  ARG_BOOL, 'B', C_USE_ASCII},
  {"user",                       ARG_STRG, 'u', C_USER},
  {"user-agent",                 ARG_STRG, 'A', C_USER_AGENT},
  {"variable",                   ARG_STRG, ' ', C_VARIABLE},
  {"verbose",                    ARG_BOOL, 'v', C_VERBOSE},
  {"version",                    ARG_BOOL, 'V', C_VERSION},
  {"vlan-priority",              ARG_STRG, ' ', C_VLAN_PRIORITY},
#ifdef USE_WATT32
  {"wdebug",                     ARG_BOOL, ' ', C_WDEBUG},
#endif
  {"write-out",                  ARG_STRG, 'w', C_WRITE_OUT},
  {"xattr",                      ARG_BOOL, ' ', C_XATTR},
};

/* Split the argument of -E to 'certname' and 'passphrase' separated by colon.
 * We allow ':' and '\' to be escaped by '\' so that we can use certificate
 * nicknames containing ':'. See <https://sourceforge.net/p/curl/bugs/1196/>
 * for details. */
#ifndef UNITTESTS
static
#endif
void parse_cert_parameter(const char *cert_parameter,
                          char **certname,
                          char **passphrase)
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
  *certname = certname_place;
  param_place = cert_parameter;
  while(*param_place) {
    span = strcspn(param_place, ":\\");
    strncpy(certname_place, param_place, span);
    param_place += span;
    certname_place += span;
    /* we just ate all the non-special chars. now we're on either a special
     * char or the end of the string. */
    switch(*param_place) {
    case '\0':
      break;
    case '\\':
      param_place++;
      switch(*param_place) {







|







674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
  *certname = certname_place;
  param_place = cert_parameter;
  while(*param_place) {
    span = strcspn(param_place, ":\\");
    strncpy(certname_place, param_place, span);
    param_place += span;
    certname_place += span;
    /* we just ate all the non-special chars. now we are on either a special
     * char or the end of the string. */
    switch(*param_place) {
    case '\0':
      break;
    case '\\':
      param_place++;
      switch(*param_place) {
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
          break;
      }
      break;
    case ':':
      /* Since we live in a world of weirdness and confusion, the win32
         dudes can use : when using drive letters and thus c:\file:password
         needs to work. In order not to break compatibility, we still use : as
         separator, but we try to detect when it is used for a file name! On
         windows. */
#ifdef _WIN32
      if((param_place == &cert_parameter[1]) &&
         (cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
         (ISALPHA(cert_parameter[0])) ) {
        /* colon in the second column, followed by a backslash, and the
           first character is an alphabetic letter:

           this is a drive letter colon */
        *certname_place++ = ':';
        param_place++;
        break;
      }
#endif
      /* escaped colons and Windows drive letter colons were handled
       * above; if we're still here, this is a separating colon */
      param_place++;
      if(*param_place) {
        *passphrase = strdup(param_place);
      }
      goto done;
    }
  }







|















|







704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
          break;
      }
      break;
    case ':':
      /* Since we live in a world of weirdness and confusion, the win32
         dudes can use : when using drive letters and thus c:\file:password
         needs to work. In order not to break compatibility, we still use : as
         separator, but we try to detect when it is used for a filename! On
         windows. */
#ifdef _WIN32
      if((param_place == &cert_parameter[1]) &&
         (cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
         (ISALPHA(cert_parameter[0])) ) {
        /* colon in the second column, followed by a backslash, and the
           first character is an alphabetic letter:

           this is a drive letter colon */
        *certname_place++ = ':';
        param_place++;
        break;
      }
#endif
      /* escaped colons and Windows drive letter colons were handled
       * above; if we are still here, this is a separating colon */
      param_place++;
      if(*param_place) {
        *passphrase = strdup(param_place);
      }
      goto done;
    }
  }
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
  return PARAM_OK;
}

#ifdef HAVE_WRITABLE_ARGV
static void cleanarg(argv_item_t str)
{
  /* now that getstr has copied the contents of nextarg, wipe the next
   * argument out so that the username:password isn't displayed in the
   * system process list */
  if(str) {
    size_t len = strlen(str);
    memset(str, ' ', len);
  }
}
#else
#define cleanarg(x)
#endif

/* --data-urlencode */
static ParameterError data_urlencode(struct GlobalConfig *global,
                                     char *nextarg,
                                     char **postp,
                                     size_t *lenp)
{
  /* [name]=[content], we encode the content part only
   * [name]@[file name]
   *
   * Case 2: we first load the file using that name and then encode
   * the content.
   */
  ParameterError err;
  const char *p = strchr(nextarg, '=');
  size_t nlen;
  char is_file;
  char *postdata = NULL;
  size_t size = 0;
  if(!p)
    /* there was no '=' letter, check for a '@' instead */
    p = strchr(nextarg, '@');
  if(p) {
    nlen = p - nextarg; /* length of the name part */
    is_file = *p++; /* pass the separator */
  }
  else {
    /* neither @ nor =, so no name and it isn't a file */
    nlen = 0;
    is_file = 0;
    p = nextarg;
  }
  if('@' == is_file) {
    FILE *file;
    /* a '@' letter, it means that a file name or - (stdin) follows */
    if(!strcmp("-", p)) {
      file = stdin;
      set_binmode(stdin);
    }
    else {
      file = fopen(p, "rb");
      if(!file) {







|

















|


















|






|







831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
  return PARAM_OK;
}

#ifdef HAVE_WRITABLE_ARGV
static void cleanarg(argv_item_t str)
{
  /* now that getstr has copied the contents of nextarg, wipe the next
   * argument out so that the username:password is not displayed in the
   * system process list */
  if(str) {
    size_t len = strlen(str);
    memset(str, ' ', len);
  }
}
#else
#define cleanarg(x)
#endif

/* --data-urlencode */
static ParameterError data_urlencode(struct GlobalConfig *global,
                                     char *nextarg,
                                     char **postp,
                                     size_t *lenp)
{
  /* [name]=[content], we encode the content part only
   * [name]@[filename]
   *
   * Case 2: we first load the file using that name and then encode
   * the content.
   */
  ParameterError err;
  const char *p = strchr(nextarg, '=');
  size_t nlen;
  char is_file;
  char *postdata = NULL;
  size_t size = 0;
  if(!p)
    /* there was no '=' letter, check for a '@' instead */
    p = strchr(nextarg, '@');
  if(p) {
    nlen = p - nextarg; /* length of the name part */
    is_file = *p++; /* pass the separator */
  }
  else {
    /* neither @ nor =, so no name and it is not a file */
    nlen = 0;
    is_file = 0;
    p = nextarg;
  }
  if('@' == is_file) {
    FILE *file;
    /* a '@' letter, it means that a filename or - (stdin) follows */
    if(!strcmp("-", p)) {
      file = stdin;
      set_binmode(stdin);
    }
    else {
      file = fopen(p, "rb");
      if(!file) {
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  char *token, *tmp, *name;
  bool toggle;

  tmp = strdup(config);
  if(!tmp)
    return CURLE_OUT_OF_MEMORY;

  /* Allow strtok() here since this isn't used threaded */
  /* !checksrc! disable BANNEDFUNC 2 */
  token = strtok(tmp, ", ");
  while(token) {
    switch(*token) {
      case '-':
        toggle = FALSE;
        name = token + 1;







|







960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  char *token, *tmp, *name;
  bool toggle;

  tmp = strdup(config);
  if(!tmp)
    return CURLE_OUT_OF_MEMORY;

  /* Allow strtok() here since this is not used threaded */
  /* !checksrc! disable BANNEDFUNC 2 */
  token = strtok(tmp, ", ");
  while(token) {
    switch(*token) {
      case '-':
        toggle = FALSE;
        name = token + 1;
1022
1023
1024
1025
1026
1027
1028














































1029
1030
1031
1032
1033
1034
1035
        singles[l - ' '] = &aliases[j];
      }
    }
    singles_done = TRUE;
  }
  return singles[letter - ' '];
}















































#define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */
static ParameterError url_query(char *nextarg,
                                struct GlobalConfig *global,
                                struct OperationConfig *config)
{
  size_t size = 0;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
        singles[l - ' '] = &aliases[j];
      }
    }
    singles_done = TRUE;
  }
  return singles[letter - ' '];
}

struct TOSEntry {
  const char *name;
  unsigned char value;
};

static const struct TOSEntry tos_entries[] = {
  {"AF11", 0x28},
  {"AF12", 0x30},
  {"AF13", 0x38},
  {"AF21", 0x48},
  {"AF22", 0x50},
  {"AF23", 0x58},
  {"AF31", 0x68},
  {"AF32", 0x70},
  {"AF33", 0x78},
  {"AF41", 0x88},
  {"AF42", 0x90},
  {"AF43", 0x98},
  {"CE",   0x03},
  {"CS0",  0x00},
  {"CS1",  0x20},
  {"CS2",  0x40},
  {"CS3",  0x60},
  {"CS4",  0x80},
  {"CS5",  0xa0},
  {"CS6",  0xc0},
  {"CS7",  0xe0},
  {"ECT0", 0x02},
  {"ECT1", 0x01},
  {"EF",   0xb8},
  {"LE",   0x04},
  {"LOWCOST",     0x02},
  {"LOWDELAY",    0x10},
  {"MINCOST",     0x02},
  {"RELIABILITY", 0x04},
  {"THROUGHPUT",  0x08},
  {"VOICE-ADMIT", 0xb0}
};

static int find_tos(const void *a, const void *b)
{
  const struct TOSEntry *aa = a;
  const struct TOSEntry *bb = b;
  return strcmp(aa->name, bb->name);
}

#define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */
static ParameterError url_query(char *nextarg,
                                struct GlobalConfig *global,
                                struct OperationConfig *config)
{
  size_t size = 0;
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090

  if(cmd == C_DATA_URLENCODE) { /* --data-urlencode */
    err = data_urlencode(global, nextarg, &postdata, &size);
    if(err)
      return err;
  }
  else if('@' == *nextarg && (cmd != C_DATA_RAW)) {
    /* the data begins with a '@' letter, it means that a file name
       or - (stdin) follows */
    nextarg++; /* pass the @ */

    if(!strcmp("-", nextarg)) {
      file = stdin;
      if(cmd == C_DATA_BINARY) /* forced data-binary */
        set_binmode(stdin);







|







1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144

  if(cmd == C_DATA_URLENCODE) { /* --data-urlencode */
    err = data_urlencode(global, nextarg, &postdata, &size);
    if(err)
      return err;
  }
  else if('@' == *nextarg && (cmd != C_DATA_RAW)) {
    /* the data begins with a '@' letter, it means that a filename
       or - (stdin) follows */
    nextarg++; /* pass the @ */

    if(!strcmp("-", nextarg)) {
      file = stdin;
      if(cmd == C_DATA_BINARY) /* forced data-binary */
        set_binmode(stdin);
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
  curl_off_t value;
#ifdef HAVE_WRITABLE_ARGV
  argv_item_t clearthis = NULL;
#else
  (void)cleararg;
#endif

  *usedarg = FALSE; /* default is that we don't use the arg */

  if(('-' != flag[0]) || ('-' == flag[1])) {
    /* this should be a long name */
    const char *word = ('-' == flag[0]) ? flag + 2 : flag;
    bool noflagged = FALSE;
    bool expand = FALSE;
    struct LongShort key;







|







1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
  curl_off_t value;
#ifdef HAVE_WRITABLE_ARGV
  argv_item_t clearthis = NULL;
#else
  (void)cleararg;
#endif

  *usedarg = FALSE; /* default is that we do not use the arg */

  if(('-' != flag[0]) || ('-' == flag[1])) {
    /* this should be a long name */
    const char *word = ('-' == flag[0]) ? flag + 2 : flag;
    bool noflagged = FALSE;
    bool expand = FALSE;
    struct LongShort key;
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
      longopt = TRUE;
    }
    else {
      err = PARAM_OPTION_UNKNOWN;
      goto error;
    }
    if(noflagged && (a->desc != ARG_BOOL)) {
      /* --no- prefixed an option that isn't boolean! */
      err = PARAM_NO_NOT_BOOLEAN;
      goto error;
    }
    else if(expand && nextarg) {
      struct curlx_dynbuf nbuf;
      bool replaced;

      if((a->desc != ARG_STRG) &&
         (a->desc != ARG_FILE)) {
        /* --expand on an option that isn't a string or a filename */
        err = PARAM_EXPAND_ERROR;
        goto error;
      }
      err = varexpand(global, nextarg, &nbuf, &replaced);
      if(err) {
        curlx_dyn_free(&nbuf);
        goto error;







|









|







1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
      longopt = TRUE;
    }
    else {
      err = PARAM_OPTION_UNKNOWN;
      goto error;
    }
    if(noflagged && (a->desc != ARG_BOOL)) {
      /* --no- prefixed an option that is not boolean! */
      err = PARAM_NO_NOT_BOOLEAN;
      goto error;
    }
    else if(expand && nextarg) {
      struct curlx_dynbuf nbuf;
      bool replaced;

      if((a->desc != ARG_STRG) &&
         (a->desc != ARG_FILE)) {
        /* --expand on an option that is not a string or a filename */
        err = PARAM_EXPAND_ERROR;
        goto error;
      }
      err = varexpand(global, nextarg, &nbuf, &replaced);
      if(err) {
        curlx_dyn_free(&nbuf);
        goto error;
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
    }
    letter = a->letter;
    cmd = a->cmd;
    if(a->desc >= ARG_STRG) {
      /* this option requires an extra parameter */
      if(!longopt && parse[1]) {
        nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
        singleopt = TRUE;   /* don't loop anymore after this */
      }
      else if(!nextarg) {
        err = PARAM_REQUIRES_PARAMETER;
        break;
      }
      else {
#ifdef HAVE_WRITABLE_ARGV
        clearthis = cleararg;
#endif
        *usedarg = TRUE; /* mark it as used */
      }

      if((a->desc == ARG_FILE) &&
         (nextarg[0] == '-') && nextarg[1]) {
        /* if the file name looks like a command line option */
        warnf(global, "The file name argument '%s' looks like a flag.",
              nextarg);
      }
      else if(!strncmp("\xe2\x80\x9c", nextarg, 3)) {
        warnf(global, "The argument '%s' starts with a unicode quote where "
              "maybe an ASCII \" was intended?",
              nextarg);
      }







|














|
|







1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
    }
    letter = a->letter;
    cmd = a->cmd;
    if(a->desc >= ARG_STRG) {
      /* this option requires an extra parameter */
      if(!longopt && parse[1]) {
        nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
        singleopt = TRUE;   /* do not loop anymore after this */
      }
      else if(!nextarg) {
        err = PARAM_REQUIRES_PARAMETER;
        break;
      }
      else {
#ifdef HAVE_WRITABLE_ARGV
        clearthis = cleararg;
#endif
        *usedarg = TRUE; /* mark it as used */
      }

      if((a->desc == ARG_FILE) &&
         (nextarg[0] == '-') && nextarg[1]) {
        /* if the filename looks like a command line option */
        warnf(global, "The filename argument '%s' looks like a flag.",
              nextarg);
      }
      else if(!strncmp("\xe2\x80\x9c", nextarg, 3)) {
        warnf(global, "The argument '%s' starts with a unicode quote where "
              "maybe an ASCII \" was intended?",
              nextarg);
      }
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
        config->authtype |= CURLAUTH_BASIC;
      else
        config->authtype &= ~CURLAUTH_BASIC;
      break;
    case C_ANYAUTH: /* --anyauth */
      if(toggle)
        config->authtype = CURLAUTH_ANY;
      /* --no-anyauth simply doesn't touch it */
      break;
#ifdef USE_WATT32
    case C_WDEBUG: /* --wdebug */
      dbug_init();
      break;
#endif
    case C_FTP_CREATE_DIRS: /* --ftp-create-dirs */







|







1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
        config->authtype |= CURLAUTH_BASIC;
      else
        config->authtype &= ~CURLAUTH_BASIC;
      break;
    case C_ANYAUTH: /* --anyauth */
      if(toggle)
        config->authtype = CURLAUTH_ANY;
      /* --no-anyauth simply does not touch it */
      break;
#ifdef USE_WATT32
    case C_WDEBUG: /* --wdebug */
      dbug_init();
      break;
#endif
    case C_FTP_CREATE_DIRS: /* --ftp-create-dirs */
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
      config->xattr = toggle;
      break;
    case C_URL: /* --url */
      if(!config->url_get)
        config->url_get = config->url_list;

      if(config->url_get) {
        /* there's a node here, if it already is filled-in continue to find
           an "empty" node */
        while(config->url_get && (config->url_get->flags & GETOUT_URL))
          config->url_get = config->url_get->next;
      }

      /* now there might or might not be an available node to fill in! */








|







1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
      config->xattr = toggle;
      break;
    case C_URL: /* --url */
      if(!config->url_get)
        config->url_get = config->url_list;

      if(config->url_get) {
        /* there is a node here, if it already is filled-in continue to find
           an "empty" node */
        while(config->url_get && (config->url_get->flags & GETOUT_URL))
          config->url_get = config->url_get->next;
      }

      /* now there might or might not be an available node to fill in! */

1626
1627
1628
1629
1630
1631
1632
















1633
1634
1635
1636
1637
1638
1639
    case C_SOCKS5_HOSTNAME: /* --socks5-hostname */
      err = getstr(&config->proxy, nextarg, DENY_BLANK);
      config->proxyver = CURLPROXY_SOCKS5_HOSTNAME;
      break;
    case C_TCP_NODELAY: /* --tcp-nodelay */
      config->tcp_nodelay = toggle;
      break;
















    case C_PROXY_DIGEST: /* --proxy-digest */
      config->proxydigest = toggle;
      break;
    case C_PROXY_BASIC: /* --proxy-basic */
      config->proxybasic = toggle;
      break;
    case C_RETRY: /* --retry */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
    case C_SOCKS5_HOSTNAME: /* --socks5-hostname */
      err = getstr(&config->proxy, nextarg, DENY_BLANK);
      config->proxyver = CURLPROXY_SOCKS5_HOSTNAME;
      break;
    case C_TCP_NODELAY: /* --tcp-nodelay */
      config->tcp_nodelay = toggle;
      break;
    case C_IP_TOS: { /* --ip-tos */
      struct TOSEntry find;
      const struct TOSEntry *entry;
      find.name = nextarg;
      entry = bsearch(&find, tos_entries,
                      sizeof(tos_entries)/sizeof(*tos_entries),
                      sizeof(*tos_entries), find_tos);
      if(entry)
        config->ip_tos = entry->value;
      else /* numeric tos value */
        err = str2unummax(&config->ip_tos, nextarg, 0xFF);
      break;
    }
    case C_VLAN_PRIORITY: /* --vlan-priority */
      err = str2unummax(&config->vlan_priority, nextarg, 7);
      break;
    case C_PROXY_DIGEST: /* --proxy-digest */
      config->proxydigest = toggle;
      break;
    case C_PROXY_BASIC: /* --proxy-basic */
      config->proxybasic = toggle;
      break;
    case C_RETRY: /* --retry */
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
      /* 16bit base 10 is 5 digits, but we allow 6 so that this catches
         overflows, not just truncates */
      char lrange[7]="";
      char *p = nextarg;
      while(ISDIGIT(*p))
        p++;
      if(*p) {
        /* if there's anything more than a plain decimal number */
        rc = sscanf(p, " - %6s", lrange);
        *p = 0; /* null-terminate to make str2unum() work below */
      }
      else
        rc = 0;

      err = str2unum(&config->localport, nextarg);







|







1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
      /* 16bit base 10 is 5 digits, but we allow 6 so that this catches
         overflows, not just truncates */
      char lrange[7]="";
      char *p = nextarg;
      while(ISDIGIT(*p))
        p++;
      if(*p) {
        /* if there is anything more than a plain decimal number */
        rc = sscanf(p, " - %6s", lrange);
        *p = 0; /* null-terminate to make str2unum() work below */
      }
      else
        rc = 0;

      err = str2unum(&config->localport, nextarg);
1757
1758
1759
1760
1761
1762
1763



1764
1765
1766
1767
1768
1769
1770
      break;
    case C_KEEPALIVE: /* --keepalive */
      config->nokeepalive = (!toggle)?TRUE:FALSE;
      break;
    case C_KEEPALIVE_TIME: /* --keepalive-time */
      err = str2unum(&config->alivetime, nextarg);
      break;



    case C_POST301: /* --post301 */
      config->post301 = toggle;
      break;
    case C_POST302: /* --post302 */
      config->post302 = toggle;
      break;
    case C_POST303: /* --post303 */







>
>
>







1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
      break;
    case C_KEEPALIVE: /* --keepalive */
      config->nokeepalive = (!toggle)?TRUE:FALSE;
      break;
    case C_KEEPALIVE_TIME: /* --keepalive-time */
      err = str2unum(&config->alivetime, nextarg);
      break;
    case C_KEEPALIVE_CNT: /* --keepalive-cnt */
      err = str2unum(&config->alivecnt, nextarg);
      break;
    case C_POST301: /* --post301 */
      config->post301 = toggle;
      break;
    case C_POST302: /* --post302 */
      config->post302 = toggle;
      break;
    case C_POST303: /* --post303 */
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
    case C_SASL_AUTHZID: /* --sasl-authzid */
      err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK);
      break;
    case C_SASL_IR: /* --sasl-ir */
      config->sasl_ir = toggle;
      break;
    case C_TEST_EVENT: /* --test-event */
#ifdef CURLDEBUG
      global->test_event_based = toggle;
#else
      warnf(global, "--test-event is ignored unless a debug build");
#endif
      break;
    case C_UNIX_SOCKET: /* --unix-socket */
      config->abstract_unix_socket = FALSE;







|







1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
    case C_SASL_AUTHZID: /* --sasl-authzid */
      err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK);
      break;
    case C_SASL_IR: /* --sasl-ir */
      config->sasl_ir = toggle;
      break;
    case C_TEST_EVENT: /* --test-event */
#ifdef DEBUGBUILD
      global->test_event_based = toggle;
#else
      warnf(global, "--test-event is ignored unless a debug build");
#endif
      break;
    case C_UNIX_SOCKET: /* --unix-socket */
      config->abstract_unix_socket = FALSE;
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
      break;
    case C_PROGRESS_METER: /* --progress-meter */
      global->noprogress = !toggle;
      break;
    case C_PROGRESS_BAR: /* --progress-bar */
      global->progressmode = toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS;
      break;
    case C_VARIABLE: /* --Variable */
      err = setvariable(global, nextarg);
      break;
    case C_NEXT: /* --next */
      err = PARAM_NEXT_OPERATION;
      break;
    case C_HTTP1_0: /* --http1.0 */
      /* HTTP version 1.0 */







|







1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
      break;
    case C_PROGRESS_METER: /* --progress-meter */
      global->noprogress = !toggle;
      break;
    case C_PROGRESS_BAR: /* --progress-bar */
      global->progressmode = toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS;
      break;
    case C_VARIABLE: /* --variable */
      err = setvariable(global, nextarg);
      break;
    case C_NEXT: /* --next */
      err = PARAM_NEXT_OPERATION;
      break;
    case C_HTTP1_0: /* --http1.0 */
      /* HTTP version 1.0 */
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
        if(!file) {
          errorf(global, "Failed to open %s", &nextarg[1]);
          err = PARAM_READ_ERROR;
        }
        else {
          err = file2memory(&string, &len, file);
          if(!err && string) {
            /* Allow strtok() here since this isn't used threaded */
            /* !checksrc! disable BANNEDFUNC 2 */
            char *h = strtok(string, "\r\n");
            while(h) {
              if(cmd == C_PROXY_HEADER) /* --proxy-header */
                err = add2list(&config->proxyheaders, h);
              else
                err = add2list(&config->headers, h);







|







2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
        if(!file) {
          errorf(global, "Failed to open %s", &nextarg[1]);
          err = PARAM_READ_ERROR;
        }
        else {
          err = file2memory(&string, &len, file);
          if(!err && string) {
            /* Allow strtok() here since this is not used threaded */
            /* !checksrc! disable BANNEDFUNC 2 */
            char *h = strtok(string, "\r\n");
            while(h) {
              if(cmd == C_PROXY_HEADER) /* --proxy-header */
                err = add2list(&config->proxyheaders, h);
              else
                err = add2list(&config->headers, h);
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
      break;
    case C_OUTPUT: /* --output */
    case C_REMOTE_NAME: /* --remote-name */
      /* output file */
      if(!config->url_out)
        config->url_out = config->url_list;
      if(config->url_out) {
        /* there's a node here, if it already is filled-in continue to find
           an "empty" node */
        while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
          config->url_out = config->url_out->next;
      }

      /* now there might or might not be an available node to fill in! */








|







2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
      break;
    case C_OUTPUT: /* --output */
    case C_REMOTE_NAME: /* --remote-name */
      /* output file */
      if(!config->url_out)
        config->url_out = config->url_list;
      if(config->url_out) {
        /* there is a node here, if it already is filled-in continue to find
           an "empty" node */
        while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
          config->url_out = config->url_out->next;
      }

      /* now there might or might not be an available node to fill in! */

2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
      break;
    case C_PROXYTUNNEL: /* --proxytunnel */
      /* proxy tunnel for non-http protocols */
      config->proxytunnel = toggle;
      break;

    case C_DISABLE: /* --disable */
      /* if used first, already taken care of, we do it like this so we don't
         cause an error! */
      break;
    case C_QUOTE: /* --quote */
      /* QUOTE command to send to FTP server */
      switch(nextarg[0]) {
      case '-':
        /* prefixed with a dash makes it a POST TRANSFER one */







|







2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
      break;
    case C_PROXYTUNNEL: /* --proxytunnel */
      /* proxy tunnel for non-http protocols */
      config->proxytunnel = toggle;
      break;

    case C_DISABLE: /* --disable */
      /* if used first, already taken care of, we do it like this so we do not
         cause an error! */
      break;
    case C_QUOTE: /* --quote */
      /* QUOTE command to send to FTP server */
      switch(nextarg[0]) {
      case '-':
        /* prefixed with a dash makes it a POST TRANSFER one */
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
      default:
        err = add2list(&config->quote, nextarg);
        break;
      }
      break;
    case C_RANGE: /* --range */
      /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
         (and won't actually be range by definition). The man page previously
         claimed that to be a good way, why this code is added to work-around
         it. */
      if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
        char buffer[32];
        if(curlx_strtoofft(nextarg, NULL, 10, &value)) {
          warnf(global, "unsupported range point");
          err = PARAM_BAD_USE;
        }
        else {







|
|
|







2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
      default:
        err = add2list(&config->quote, nextarg);
        break;
      }
      break;
    case C_RANGE: /* --range */
      /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
         (and will not actually be range by definition). The manpage
         previously claimed that to be a good way, why this code is added to
         work-around it. */
      if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
        char buffer[32];
        if(curlx_strtoofft(nextarg, NULL, 10, &value)) {
          warnf(global, "unsupported range point");
          err = PARAM_BAD_USE;
        }
        else {
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
      err = add2list(&config->telnet_options, nextarg);
      break;
    case C_UPLOAD_FILE: /* --upload-file */
      /* we are uploading */
      if(!config->url_ul)
        config->url_ul = config->url_list;
      if(config->url_ul) {
        /* there's a node here, if it already is filled-in continue to find
           an "empty" node */
        while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD))
          config->url_ul = config->url_ul->next;
      }

      /* now there might or might not be an available node to fill in! */








|







2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
      err = add2list(&config->telnet_options, nextarg);
      break;
    case C_UPLOAD_FILE: /* --upload-file */
      /* we are uploading */
      if(!config->url_ul)
        config->url_ul = config->url_list;
      if(config->url_ul) {
        /* there is a node here, if it already is filled-in continue to find
           an "empty" node */
        while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD))
          config->url_ul = config->url_ul->next;
      }

      /* now there might or might not be an available node to fill in! */

2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
    case C_VERSION: /* --version */
      if(toggle)    /* --no-version yields no output! */
        err = PARAM_VERSION_INFO_REQUESTED;
      break;
    case C_WRITE_OUT: /* --write-out */
      /* get the output string */
      if('@' == *nextarg) {
        /* the data begins with a '@' letter, it means that a file name
           or - (stdin) follows */
        FILE *file;
        const char *fname;
        nextarg++; /* pass the @ */
        if(!strcmp("-", nextarg)) {
          fname = "<stdin>";
          file = stdin;







|







2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
    case C_VERSION: /* --version */
      if(toggle)    /* --no-version yields no output! */
        err = PARAM_VERSION_INFO_REQUESTED;
      break;
    case C_WRITE_OUT: /* --write-out */
      /* get the output string */
      if('@' == *nextarg) {
        /* the data begins with a '@' letter, it means that a filename
           or - (stdin) follows */
        FILE *file;
        const char *fname;
        nextarg++; /* pass the @ */
        if(!strcmp("-", nextarg)) {
          fname = "<stdin>";
          file = stdin;
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794



2795
2796
2797
2798
2799
2800
2801
        config->timecond = CURL_TIMECOND_LASTMOD;
        nextarg++;
        break;
      }
      now = time(NULL);
      config->condtime = (curl_off_t)curl_getdate(nextarg, &now);
      if(-1 == config->condtime) {
        /* now let's see if it is a file name to get the time from instead! */
        rc = getfiletime(nextarg, global, &value);
        if(!rc)
          /* pull the time out from the file */
          config->condtime = value;
        else {
          /* failed, remove time condition */
          config->timecond = CURL_TIMECOND_NONE;
          warnf(global,
                "Illegal date format for -z, --time-cond (and not "
                "a file name). Disabling time condition. "
                "See curl_getdate(3) for valid date syntax.");
        }
      }



      break;
    default: /* unknown flag */
      err = PARAM_OPTION_UNKNOWN;
      break;
    }
    a = NULL;








|









|



>
>
>







2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
        config->timecond = CURL_TIMECOND_LASTMOD;
        nextarg++;
        break;
      }
      now = time(NULL);
      config->condtime = (curl_off_t)curl_getdate(nextarg, &now);
      if(-1 == config->condtime) {
        /* now let's see if it is a filename to get the time from instead! */
        rc = getfiletime(nextarg, global, &value);
        if(!rc)
          /* pull the time out from the file */
          config->condtime = value;
        else {
          /* failed, remove time condition */
          config->timecond = CURL_TIMECOND_NONE;
          warnf(global,
                "Illegal date format for -z, --time-cond (and not "
                "a filename). Disabling time condition. "
                "See curl_getdate(3) for valid date syntax.");
        }
      }
      break;
    case C_MPTCP: /* --mptcp */
      config->mptcp = TRUE;
      break;
    default: /* unknown flag */
      err = PARAM_OPTION_UNKNOWN;
      break;
    }
    a = NULL;

2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
          }
          else {
            errorf(global, "missing URL before --next");
            result = PARAM_BAD_USE;
          }
        }
        else if(!result && passarg)
          i++; /* we're supposed to skip this */
      }
    }
    else {
      bool used;

      /* Just add the URL please */
      result = getparameter("--url", orig_opt, argv[i], &used, global, config);







|







2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
          }
          else {
            errorf(global, "missing URL before --next");
            result = PARAM_BAD_USE;
          }
        }
        else if(!result && passarg)
          i++; /* we are supposed to skip this */
      }
    }
    else {
      bool used;

      /* Just add the URL please */
      result = getparameter("--url", orig_opt, argv[i], &used, global, config);
Changes to jni/curl/src/tool_getpass.c.
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#ifdef __VMS
/* VMS implementation */
char *getpass_r(const char *prompt, char *buffer, size_t buflen)
{
  long sts;
  short chan;

  /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4  */
  /* distribution so I created this.  May revert back later to */
  /* struct _iosb iosb;                                        */
  struct _iosb
     {
     short int iosb$w_status; /* status     */
     short int iosb$w_bcnt;   /* byte count */
     int       unused;        /* unused     */
     } iosb;







|
|







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#ifdef __VMS
/* VMS implementation */
char *getpass_r(const char *prompt, char *buffer, size_t buflen)
{
  long sts;
  short chan;

  /* MSK, 23-JAN-2004, iosbdef.h was not in VAX V7.2 or CC 6.4  */
  /* distribution so I created this. May revert back later to */
  /* struct _iosb iosb;                                        */
  struct _iosb
     {
     short int iosb$w_status; /* status     */
     short int iosb$w_bcnt;   /* byte count */
     int       unused;        /* unused     */
     } iosb;
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
      if(buffer[i] == '\b')
        /* remove this letter and if this is not the first key, remove the
           previous one as well */
        i = i - (i >= 1 ? 2 : 1);
  }
  /* since echo is disabled, print a newline */
  fputs("\n", tool_stderr);
  /* if user didn't hit ENTER, terminate buffer */
  if(i == buflen)
    buffer[buflen-1] = '\0';

  return buffer; /* we always return success */
}
#define DONE
#endif /* _WIN32 */







|







111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
      if(buffer[i] == '\b')
        /* remove this letter and if this is not the first key, remove the
           previous one as well */
        i = i - (i >= 1 ? 2 : 1);
  }
  /* since echo is disabled, print a newline */
  fputs("\n", tool_stderr);
  /* if user did not hit ENTER, terminate buffer */
  if(i == buflen)
    buffer[buflen-1] = '\0';

  return buffer; /* we always return success */
}
#define DONE
#endif /* _WIN32 */
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
    tcsetattr(fd, TCSANOW, &noecho);
#elif defined(HAVE_TERMIO_H)
    ioctl(fd, TCGETA, &withecho);
    noecho = withecho;
    noecho.c_lflag &= ~(tcflag_t)ECHO;
    ioctl(fd, TCSETA, &noecho);
#else
    /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
    (void)fd;
    return FALSE; /* not disabled */
#endif
    return TRUE; /* disabled */
  }
  /* re-enable echo, assumes we disabled it before (and set the structs we
     now use to reset the terminal status) */







|







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
    tcsetattr(fd, TCSANOW, &noecho);
#elif defined(HAVE_TERMIO_H)
    ioctl(fd, TCGETA, &withecho);
    noecho = withecho;
    noecho.c_lflag &= ~(tcflag_t)ECHO;
    ioctl(fd, TCSETA, &noecho);
#else
    /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we cannot disable echo! */
    (void)fd;
    return FALSE; /* not disabled */
#endif
    return TRUE; /* disabled */
  }
  /* re-enable echo, assumes we disabled it before (and set the structs we
     now use to reset the terminal status) */
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
                char *password,     /* buffer to store password in */
                size_t buflen)      /* size of buffer to store password in */
{
  ssize_t nread;
  bool disabled;
  int fd = open("/dev/tty", O_RDONLY);
  if(-1 == fd)
    fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */

  disabled = ttyecho(FALSE, fd); /* disable terminal echo */

  fputs(prompt, tool_stderr);
  nread = read(fd, password, buflen);
  if(nread > 0)
    password[--nread] = '\0'; /* null-terminate where enter is stored */







|







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
                char *password,     /* buffer to store password in */
                size_t buflen)      /* size of buffer to store password in */
{
  ssize_t nread;
  bool disabled;
  int fd = open("/dev/tty", O_RDONLY);
  if(-1 == fd)
    fd = STDIN_FILENO; /* use stdin if the tty could not be used */

  disabled = ttyecho(FALSE, fd); /* disable terminal echo */

  fputs(prompt, tool_stderr);
  nread = read(fd, password, buflen);
  if(nread > 0)
    password[--nread] = '\0'; /* null-terminate where enter is stored */
Changes to jni/curl/src/tool_getpass.h.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

#ifndef HAVE_GETPASS_R
/* If there's a system-provided function named like this, we trust it is
   also found in one of the standard headers. */

/*
 * Returning NULL will abort the continued operation!
 */
char *getpass_r(const char *prompt, char *buffer, size_t buflen);
#endif







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

#ifndef HAVE_GETPASS_R
/* If there is a system-provided function named like this, we trust it is
   also found in one of the standard headers. */

/*
 * Returning NULL will abort the continued operation!
 */
char *getpass_r(const char *prompt, char *buffer, size_t buflen);
#endif
Changes to jni/curl/src/tool_help.c.
27
28
29
30
31
32
33

34
35
36
37
38
39




40
41
42
43
44
45
46
47

48
49
50
51

52
53
54

55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include "curlx.h"

#include "tool_help.h"
#include "tool_libinfo.h"
#include "tool_util.h"
#include "tool_version.h"
#include "tool_cb_prg.h"


#include "memdebug.h" /* keep this as LAST include */

#ifdef MSDOS
#  define USE_WATT32
#endif





struct category_descriptors {
  const char *opt;
  const char *desc;
  curlhelp_t category;
};

static const struct category_descriptors categories[] = {

  {"auth", "Different types of authentication methods", CURLHELP_AUTH},
  {"connection", "Low level networking operations",
   CURLHELP_CONNECTION},
  {"curl", "The command line tool itself", CURLHELP_CURL},

  {"dns", "General DNS options", CURLHELP_DNS},
  {"file", "FILE protocol options", CURLHELP_FILE},
  {"ftp", "FTP protocol options", CURLHELP_FTP},

  {"http", "HTTP and HTTPS protocol options", CURLHELP_HTTP},
  {"imap", "IMAP protocol options", CURLHELP_IMAP},
  /* important is left out because it is the default help page */
  {"misc", "Options that don't fit into any other category", CURLHELP_MISC},
  {"output", "Filesystem output", CURLHELP_OUTPUT},
  {"pop3", "POP3 protocol options", CURLHELP_POP3},
  {"post", "HTTP Post specific options", CURLHELP_POST},
  {"proxy", "All options related to proxies", CURLHELP_PROXY},
  {"scp", "SCP protocol options", CURLHELP_SCP},
  {"sftp", "SFTP protocol options", CURLHELP_SFTP},
  {"smtp", "SMTP protocol options", CURLHELP_SMTP},
  {"ssh", "SSH protocol options", CURLHELP_SSH},
  {"telnet", "TELNET protocol options", CURLHELP_TELNET},
  {"tftp", "TFTP protocol options", CURLHELP_TFTP},
  {"tls", "All TLS/SSL related options", CURLHELP_TLS},
  {"ech", "All Encrypted Client Hello (ECH) options", CURLHELP_ECH},
  {"upload", "All options for uploads",
   CURLHELP_UPLOAD},
  {"verbose", "Options related to any kind of command line output of curl",
   CURLHELP_VERBOSE},
  {NULL, NULL, CURLHELP_HIDDEN}
};

static void print_category(curlhelp_t category, unsigned int cols)
{
  unsigned int i;
  size_t longopt = 5;
  size_t longdesc = 5;

  for(i = 0; helptext[i].opt; ++i) {
    size_t len;







>






>
>
>
>




|



>
|
<
|

>
|
|
|
>
|
|
<
|

|
|
|
|
|
|
|
|
|
|
|
<
|
<
|
<


|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

55
56
57
58
59
60
61
62
63

64
65
66
67
68
69
70
71
72
73
74
75
76

77

78

79
80
81
82
83
84
85
86
87
88
#include "curlx.h"

#include "tool_help.h"
#include "tool_libinfo.h"
#include "tool_util.h"
#include "tool_version.h"
#include "tool_cb_prg.h"
#include "terminal.h"

#include "memdebug.h" /* keep this as LAST include */

#ifdef MSDOS
#  define USE_WATT32
#endif

#ifndef ARRAYSIZE
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif

struct category_descriptors {
  const char *opt;
  const char *desc;
  unsigned int category;
};

static const struct category_descriptors categories[] = {
  /* important is left out because it is the default help page */
  {"auth", "Authentication methods", CURLHELP_AUTH},

  {"connection", "Manage connections", CURLHELP_CONNECTION},
  {"curl", "The command line tool itself", CURLHELP_CURL},
  {"deprecated", "Legacy", CURLHELP_DEPRECATED},
  {"dns", "Names and resolving", CURLHELP_DNS},
  {"file", "FILE protocol", CURLHELP_FILE},
  {"ftp", "FTP protocol", CURLHELP_FTP},
  {"global", "Global options", CURLHELP_GLOBAL},
  {"http", "HTTP and HTTPS protocol", CURLHELP_HTTP},
  {"imap", "IMAP protocol", CURLHELP_IMAP},

  {"ldap", "LDAP protocol", CURLHELP_LDAP},
  {"output", "Filesystem output", CURLHELP_OUTPUT},
  {"pop3", "POP3 protocol", CURLHELP_POP3},
  {"post", "HTTP POST specific", CURLHELP_POST},
  {"proxy", "Options for proxies", CURLHELP_PROXY},
  {"scp", "SCP protocol", CURLHELP_SCP},
  {"sftp", "SFTP protocol", CURLHELP_SFTP},
  {"smtp", "SMTP protocol", CURLHELP_SMTP},
  {"ssh", "SSH protocol", CURLHELP_SSH},
  {"telnet", "TELNET protocol", CURLHELP_TELNET},
  {"tftp", "TFTP protocol", CURLHELP_TFTP},
  {"timeout", "Timeouts and delays", CURLHELP_TIMEOUT},
  {"tls", "TLS/SSL related", CURLHELP_TLS},

  {"upload", "Upload, sending data", CURLHELP_UPLOAD},

  {"verbose", "Tracing, logging etc", CURLHELP_VERBOSE}

};

static void print_category(unsigned int category, unsigned int cols)
{
  unsigned int i;
  size_t longopt = 5;
  size_t longdesc = 5;

  for(i = 0; helptext[i].opt; ++i) {
    size_t len;
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131



























132
133
134
135
136
137
138
139
140
141
142

143
144
145


146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    }
}

/* Prints category if found. If not, it returns 1 */
static int get_category_content(const char *category, unsigned int cols)
{
  unsigned int i;
  for(i = 0; categories[i].opt; ++i)
    if(curl_strequal(categories[i].opt, category)) {
      printf("%s: %s\n", categories[i].opt, categories[i].desc);
      print_category(categories[i].category, cols);
      return 0;
    }
  return 1;
}

/* Prints all categories and their description */
static void get_categories(void)
{
  unsigned int i;
  for(i = 0; categories[i].opt; ++i)
    printf(" %-11s %s\n", categories[i].opt, categories[i].desc);
}





























void tool_help(char *category)
{
  unsigned int cols = get_terminal_columns();
  puts("Usage: curl [options...] <url>");
  /* If no category was provided */
  if(!category) {
    const char *category_note = "\nThis is not the full help, this "
      "menu is stripped into categories.\nUse \"--help category\" to get "
      "an overview of all categories.\nFor all options use the manual"

      " or \"--help all\".";
    print_category(CURLHELP_IMPORTANT, cols);
    puts(category_note);


  }
  /* Lets print everything if "all" was provided */
  else if(curl_strequal(category, "all"))
    /* Print everything except hidden */
    print_category(~(CURLHELP_HIDDEN), cols);
  /* Lets handle the string "category" differently to not print an errormsg */
  else if(curl_strequal(category, "category"))
    get_categories();
  /* Otherwise print category and handle the case if the cat was not found */
  else if(get_category_content(category, cols)) {
    puts("Invalid category provided, here is a list of all categories:\n");
    get_categories();
  }
  free(category);
}

static bool is_debug(void)
{







|












|


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








|
|
|
>



>
>



|
|





|







112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
    }
}

/* Prints category if found. If not, it returns 1 */
static int get_category_content(const char *category, unsigned int cols)
{
  unsigned int i;
  for(i = 0; i < ARRAYSIZE(categories); ++i)
    if(curl_strequal(categories[i].opt, category)) {
      printf("%s: %s\n", categories[i].opt, categories[i].desc);
      print_category(categories[i].category, cols);
      return 0;
    }
  return 1;
}

/* Prints all categories and their description */
static void get_categories(void)
{
  unsigned int i;
  for(i = 0; i < ARRAYSIZE(categories); ++i)
    printf(" %-11s %s\n", categories[i].opt, categories[i].desc);
}

/* Prints all categories as a comma-separated list of given width */
static void get_categories_list(unsigned int width)
{
  unsigned int i;
  size_t col = 0;
  for(i = 0; i < ARRAYSIZE(categories); ++i) {
    size_t len = strlen(categories[i].opt);
    if(i == ARRAYSIZE(categories) - 1) {
      /* final category */
      if(col + len + 1 < width)
        printf("%s.\n", categories[i].opt);
      else
        /* start a new line first */
        printf("\n%s.\n", categories[i].opt);
    }
    else if(col + len + 2 < width) {
      printf("%s, ", categories[i].opt);
      col += len + 2;
    }
    else {
      /* start a new line first */
      printf("\n%s, ", categories[i].opt);
      col = len + 2;
    }
  }
}


void tool_help(char *category)
{
  unsigned int cols = get_terminal_columns();
  puts("Usage: curl [options...] <url>");
  /* If no category was provided */
  if(!category) {
    const char *category_note = "\nThis is not the full help; this "
      "menu is split into categories.\nUse \"--help category\" to get "
      "an overview of all categories, which are:";
    const char *category_note2 = "For all options use the manual"
      " or \"--help all\".";
    print_category(CURLHELP_IMPORTANT, cols);
    puts(category_note);
    get_categories_list(cols);
    puts(category_note2);
  }
  /* Lets print everything if "all" was provided */
  else if(curl_strequal(category, "all"))
    /* Print everything */
    print_category(CURLHELP_ALL, cols);
  /* Lets handle the string "category" differently to not print an errormsg */
  else if(curl_strequal(category, "category"))
    get_categories();
  /* Otherwise print category and handle the case if the cat was not found */
  else if(get_category_content(category, cols)) {
    puts("Unknown category provided, here is a list of all categories:\n");
    get_categories();
  }
  free(category);
}

static bool is_debug(void)
{
Changes to jni/curl/src/tool_help.h.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

68
69
70

71
72
73
74
75
 ***************************************************************************/
#include "tool_setup.h"

void tool_help(char *category);
void tool_list_engines(void);
void tool_version_info(void);

typedef unsigned int curlhelp_t;

struct helptxt {
  const char *opt;
  const char *desc;
  curlhelp_t categories;
};

/*
 * The bitmask output is generated with the following command
 ------------------------------------------------------------
  make -C docs/cmdline-opts listcats
 */

#define CURLHELP_HIDDEN 1u << 0u
#define CURLHELP_AUTH 1u << 1u
#define CURLHELP_CONNECTION 1u << 2u
#define CURLHELP_CURL 1u << 3u

#define CURLHELP_DNS 1u << 4u
#define CURLHELP_FILE 1u << 5u
#define CURLHELP_FTP 1u << 6u
#define CURLHELP_HTTP 1u << 7u
#define CURLHELP_IMAP 1u << 8u
#define CURLHELP_IMPORTANT 1u << 9u
#define CURLHELP_IPFS 1u << 10u
#define CURLHELP_MISC 1u << 11u
#define CURLHELP_OUTPUT 1u << 12u
#define CURLHELP_POP3 1u << 13u
#define CURLHELP_POST 1u << 14u
#define CURLHELP_PROXY 1u << 15u
#define CURLHELP_SCP 1u << 16u
#define CURLHELP_SFTP 1u << 17u
#define CURLHELP_SMTP 1u << 18u
#define CURLHELP_SSH 1u << 19u
#define CURLHELP_TELNET 1u << 20u
#define CURLHELP_TFTP 1u << 21u

#define CURLHELP_TLS 1u << 22u
#define CURLHELP_UPLOAD 1u << 23u
#define CURLHELP_VERBOSE 1u << 24u

#define CURLHELP_ECH 1u << 25u

extern const struct helptxt helptext[];

#endif /* HEADER_CURL_TOOL_HELP_H */







<
<



|








<
|
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
>
|




25
26
27
28
29
30
31


32
33
34
35
36
37
38
39
40
41
42
43

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
 ***************************************************************************/
#include "tool_setup.h"

void tool_help(char *category);
void tool_list_engines(void);
void tool_version_info(void);



struct helptxt {
  const char *opt;
  const char *desc;
  unsigned int categories;
};

/*
 * The bitmask output is generated with the following command
 ------------------------------------------------------------
  make -C docs/cmdline-opts listcats
 */


#define CURLHELP_AUTH       (1u << 0u)
#define CURLHELP_CONNECTION (1u << 1u)
#define CURLHELP_CURL       (1u << 2u)
#define CURLHELP_DEPRECATED (1u << 3u)
#define CURLHELP_DNS        (1u << 4u)
#define CURLHELP_FILE       (1u << 5u)
#define CURLHELP_FTP        (1u << 6u)
#define CURLHELP_GLOBAL     (1u << 7u)
#define CURLHELP_HTTP       (1u << 8u)
#define CURLHELP_IMAP       (1u << 9u)
#define CURLHELP_IMPORTANT  (1u << 10u)
#define CURLHELP_LDAP       (1u << 11u)
#define CURLHELP_OUTPUT     (1u << 12u)
#define CURLHELP_POP3       (1u << 13u)
#define CURLHELP_POST       (1u << 14u)
#define CURLHELP_PROXY      (1u << 15u)
#define CURLHELP_SCP        (1u << 16u)
#define CURLHELP_SFTP       (1u << 17u)
#define CURLHELP_SMTP       (1u << 18u)
#define CURLHELP_SSH        (1u << 19u)
#define CURLHELP_TELNET     (1u << 20u)
#define CURLHELP_TFTP       (1u << 21u)
#define CURLHELP_TIMEOUT    (1u << 22u)
#define CURLHELP_TLS        (1u << 23u)
#define CURLHELP_UPLOAD     (1u << 24u)
#define CURLHELP_VERBOSE    (1u << 25u)

#define CURLHELP_ALL        (0xfffffffu)

extern const struct helptxt helptext[];

#endif /* HEADER_CURL_TOOL_HELP_H */
Changes to jni/curl/src/tool_helpers.c.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  case PARAM_BAD_USE:
    return "is badly used here";
  case PARAM_BAD_NUMERIC:
    return "expected a proper numerical parameter";
  case PARAM_NEGATIVE_NUMERIC:
    return "expected a positive numerical parameter";
  case PARAM_LIBCURL_DOESNT_SUPPORT:
    return "the installed libcurl version doesn't support this";
  case PARAM_LIBCURL_UNSUPPORTED_PROTOCOL:
    return "a specified protocol is unsupported by libcurl";
  case PARAM_NO_MEM:
    return "out of memory";
  case PARAM_NO_PREFIX:
    return "the given option can't be reversed with a --no- prefix";
  case PARAM_NUMBER_TOO_LARGE:
    return "too large number";
  case PARAM_NO_NOT_BOOLEAN:
    return "used '--no-' for option that isn't a boolean";
  case PARAM_CONTDISP_SHOW_HEADER:
    return "showing headers and --remote-header-name cannot be combined";
  case PARAM_CONTDISP_RESUME_FROM:
    return "--continue-at and --remote-header-name cannot be combined";
  case PARAM_READ_ERROR:
    return "error encountered when reading a file";
  case PARAM_EXPAND_ERROR:







|





|



|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  case PARAM_BAD_USE:
    return "is badly used here";
  case PARAM_BAD_NUMERIC:
    return "expected a proper numerical parameter";
  case PARAM_NEGATIVE_NUMERIC:
    return "expected a positive numerical parameter";
  case PARAM_LIBCURL_DOESNT_SUPPORT:
    return "the installed libcurl version does not support this";
  case PARAM_LIBCURL_UNSUPPORTED_PROTOCOL:
    return "a specified protocol is unsupported by libcurl";
  case PARAM_NO_MEM:
    return "out of memory";
  case PARAM_NO_PREFIX:
    return "the given option cannot be reversed with a --no- prefix";
  case PARAM_NUMBER_TOO_LARGE:
    return "too large number";
  case PARAM_NO_NOT_BOOLEAN:
    return "used '--no-' for option that is not a boolean";
  case PARAM_CONTDISP_SHOW_HEADER:
    return "showing headers and --remote-header-name cannot be combined";
  case PARAM_CONTDISP_RESUME_FROM:
    return "--continue-at and --remote-header-name cannot be combined";
  case PARAM_READ_ERROR:
    return "error encountered when reading a file";
  case PARAM_EXPAND_ERROR:
Changes to jni/curl/src/tool_hugehelp.c.

more than 10,000 changes

Changes to jni/curl/src/tool_ipfs.c.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  /* Try to find the gateway in the IPFS data folder. */
  ipfs_path = curl_getenv("IPFS_PATH");

  if(!ipfs_path) {
    char *home = getenv("HOME");
    if(home && *home)
      ipfs_path = aprintf("%s/.ipfs/", home);
    /* fallback to "~/.ipfs", as that's the default location. */
  }

  if(!ipfs_path || ensure_trailing_slash(&ipfs_path))
    goto fail;

  gateway_composed_file_path = aprintf("%sgateway", ipfs_path);








|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  /* Try to find the gateway in the IPFS data folder. */
  ipfs_path = curl_getenv("IPFS_PATH");

  if(!ipfs_path) {
    char *home = getenv("HOME");
    if(home && *home)
      ipfs_path = aprintf("%s/.ipfs/", home);
    /* fallback to "~/.ipfs", as that is the default location. */
  }

  if(!ipfs_path || ensure_trailing_slash(&ipfs_path))
    goto fail;

  gateway_composed_file_path = aprintf("%sgateway", ipfs_path);

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
    fclose(gateway_file);
  Curl_safefree(gateway);
  Curl_safefree(ipfs_path);
  return NULL;
}

/*
 * Rewrite ipfs://<cid> and ipns://<cid> to a HTTP(S)
 * URL that can be handled by an IPFS gateway.
 */
CURLcode ipfs_url_rewrite(CURLU *uh, const char *protocol, char **url,
                          struct OperationConfig *config)
{
  CURLcode result = CURLE_URL_MALFORMAT;
  CURLUcode getResult;







|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
    fclose(gateway_file);
  Curl_safefree(gateway);
  Curl_safefree(ipfs_path);
  return NULL;
}

/*
 * Rewrite ipfs://<cid> and ipns://<cid> to an HTTP(S)
 * URL that can be handled by an IPFS gateway.
 */
CURLcode ipfs_url_rewrite(CURLU *uh, const char *protocol, char **url,
                          struct OperationConfig *config)
{
  CURLcode result = CURLE_URL_MALFORMAT;
  CURLUcode getResult;
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  }

  getResult = curl_url_get(uh, CURLUPART_HOST, &cid, CURLU_URLDECODE);
  if(getResult || !cid)
    goto clean;

  /* We might have a --ipfs-gateway argument. Check it first and use it. Error
   * if we do have something but if it's an invalid url.
   */
  if(config->ipfs_gateway) {
    /* ensure the gateway ends in a trailing / */
    if(ensure_trailing_slash(&config->ipfs_gateway) != CURLE_OK) {
      result = CURLE_OUT_OF_MEMORY;
      goto clean;
    }







|







158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  }

  getResult = curl_url_get(uh, CURLUPART_HOST, &cid, CURLU_URLDECODE);
  if(getResult || !cid)
    goto clean;

  /* We might have a --ipfs-gateway argument. Check it first and use it. Error
   * if we do have something but if it is an invalid url.
   */
  if(config->ipfs_gateway) {
    /* ensure the gateway ends in a trailing / */
    if(ensure_trailing_slash(&config->ipfs_gateway) != CURLE_OK) {
      result = CURLE_OUT_OF_MEMORY;
      goto clean;
    }
Changes to jni/curl/src/tool_libinfo.c.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/* use our own printf() functions */
#include "curlx.h"

#include "tool_libinfo.h"

#include "memdebug.h" /* keep this as LAST include */

/* global variable definitions, for libcurl run-time info */

static const char *no_protos = NULL;

curl_version_info_data *curlinfo = NULL;
const char * const *built_in_protos = &no_protos;

size_t proto_count = 0;







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/* use our own printf() functions */
#include "curlx.h"

#include "tool_libinfo.h"

#include "memdebug.h" /* keep this as LAST include */

/* global variable definitions, for libcurl runtime info */

static const char *no_protos = NULL;

curl_version_info_data *curlinfo = NULL;
const char * const *built_in_protos = &no_protos;

size_t proto_count = 0;
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  {NULL,             NULL,                0}
};

static const char *fnames[sizeof(maybe_feature) / sizeof(maybe_feature[0])];
const char * const *feature_names = fnames;

/*
 * libcurl_info_init: retrieves run-time information about libcurl,
 * setting a global pointer 'curlinfo' to libcurl's run-time info
 * struct, count protocols and flag those we are interested in.
 * Global pointer feature_names is set to the feature names array. If
 * the latter is not returned by curl_version_info(), it is built from
 * the returned features bit mask.
 */

CURLcode get_libcurl_info(void)
{
  CURLcode result = CURLE_OK;
  const char *const *builtin;

  /* Pointer to libcurl's run-time version information */
  curlinfo = curl_version_info(CURLVERSION_NOW);
  if(!curlinfo)
    return CURLE_FAILED_INIT;

  if(curlinfo->protocols) {
    const struct proto_name_tokenp *p;








|
|











|







122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  {NULL,             NULL,                0}
};

static const char *fnames[sizeof(maybe_feature) / sizeof(maybe_feature[0])];
const char * const *feature_names = fnames;

/*
 * libcurl_info_init: retrieves runtime information about libcurl,
 * setting a global pointer 'curlinfo' to libcurl's runtime info
 * struct, count protocols and flag those we are interested in.
 * Global pointer feature_names is set to the feature names array. If
 * the latter is not returned by curl_version_info(), it is built from
 * the returned features bit mask.
 */

CURLcode get_libcurl_info(void)
{
  CURLcode result = CURLE_OK;
  const char *const *builtin;

  /* Pointer to libcurl's runtime version information */
  curlinfo = curl_version_info(CURLVERSION_NOW);
  if(!curlinfo)
    return CURLE_FAILED_INIT;

  if(curlinfo->protocols) {
    const struct proto_name_tokenp *p;

Changes to jni/curl/src/tool_libinfo.h.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

/* global variable declarations, for libcurl run-time info */


extern curl_version_info_data *curlinfo;

extern const char * const *built_in_protos;
extern size_t proto_count;








|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "tool_setup.h"

/* global variable declarations, for libcurl runtime info */


extern curl_version_info_data *curlinfo;

extern const char * const *built_in_protos;
extern size_t proto_count;

Changes to jni/curl/src/tool_listhelp.c.
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
   "Enable SSH compression",
   CURLHELP_SCP | CURLHELP_SSH},
  {"-K, --config <file>",
   "Read config from a file",
   CURLHELP_CURL},
  {"    --connect-timeout <seconds>",
   "Maximum time allowed to connect",
   CURLHELP_CONNECTION},
  {"    --connect-to <HOST1:PORT1:HOST2:PORT2>",
   "Connect to host",
   CURLHELP_CONNECTION},
  {"-C, --continue-at <offset>",
   "Resumed transfer offset",
   CURLHELP_CONNECTION},
  {"-b, --cookie <data|filename>",
   "Send cookies from string/load from file",
   CURLHELP_HTTP},
  {"-c, --cookie-jar <filename>",
   "Save cookies to <filename> after operation",
   CURLHELP_HTTP},
  {"    --create-dirs",
   "Create necessary local directory hierarchy",
   CURLHELP_CURL},
  {"    --create-file-mode <mode>",
   "File mode for created files",
   CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_FILE | CURLHELP_UPLOAD},
  {"    --crlf",
   "Convert LF to CRLF in upload",
   CURLHELP_FTP | CURLHELP_SMTP},
  {"    --crlfile <file>",







|

|
|











|







79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
   "Enable SSH compression",
   CURLHELP_SCP | CURLHELP_SSH},
  {"-K, --config <file>",
   "Read config from a file",
   CURLHELP_CURL},
  {"    --connect-timeout <seconds>",
   "Maximum time allowed to connect",
   CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
  {"    --connect-to <HOST1:PORT1:HOST2:PORT2>",
   "Connect to host2 instead of host1",
   CURLHELP_CONNECTION | CURLHELP_DNS},
  {"-C, --continue-at <offset>",
   "Resumed transfer offset",
   CURLHELP_CONNECTION},
  {"-b, --cookie <data|filename>",
   "Send cookies from string/load from file",
   CURLHELP_HTTP},
  {"-c, --cookie-jar <filename>",
   "Save cookies to <filename> after operation",
   CURLHELP_HTTP},
  {"    --create-dirs",
   "Create necessary local directory hierarchy",
   CURLHELP_OUTPUT},
  {"    --create-file-mode <mode>",
   "File mode for created files",
   CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_FILE | CURLHELP_UPLOAD},
  {"    --crlf",
   "Convert LF to CRLF in upload",
   CURLHELP_FTP | CURLHELP_SMTP},
  {"    --crlfile <file>",
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203

204
205
206
207
208
209

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  {"    --doh-url <URL>",
   "Resolve hostnames over DoH",
   CURLHELP_DNS},
  {"-D, --dump-header <filename>",
   "Write the received headers to <filename>",
   CURLHELP_HTTP | CURLHELP_FTP},
  {"    --ech <config>",
   "Configure Encrypted Client Hello (ECH) for use with the TLS session",
   CURLHELP_TLS | CURLHELP_ECH},
  {"    --egd-file <file>",
   "EGD socket path for random data",
   CURLHELP_TLS},
  {"    --engine <name>",
   "Crypto engine to use",
   CURLHELP_TLS},
  {"    --etag-compare <file>",
   "Load ETag from file",
   CURLHELP_HTTP},
  {"    --etag-save <file>",
   "Parse incoming ETag and save to a file",
   CURLHELP_HTTP},
  {"    --expect100-timeout <seconds>",
   "How long to wait for 100-continue",
   CURLHELP_HTTP},
  {"-f, --fail",
   "Fail fast with no output on HTTP errors",
   CURLHELP_IMPORTANT | CURLHELP_HTTP},
  {"    --fail-early",
   "Fail on first transfer error",
   CURLHELP_CURL},
  {"    --fail-with-body",
   "Fail on HTTP errors but save the body",
   CURLHELP_HTTP | CURLHELP_OUTPUT},
  {"    --false-start",
   "Enable TLS False Start",
   CURLHELP_TLS},
  {"-F, --form <name=content>",
   "Specify multipart MIME data",
   CURLHELP_HTTP | CURLHELP_UPLOAD},

  {"    --form-escape",
   "Escape form fields using backslash",
   CURLHELP_HTTP | CURLHELP_UPLOAD},
  {"    --form-string <name=string>",
   "Specify multipart MIME data",
   CURLHELP_HTTP | CURLHELP_UPLOAD},

  {"    --ftp-account <data>",
   "Account data string",
   CURLHELP_FTP | CURLHELP_AUTH},
  {"    --ftp-alternative-to-user <command>",
   "String to replace USER [name]",
   CURLHELP_FTP},
  {"    --ftp-create-dirs",
   "Create the remote dirs if not present",
   CURLHELP_FTP | CURLHELP_SFTP | CURLHELP_CURL},
  {"    --ftp-method <method>",
   "Control CWD usage",
   CURLHELP_FTP},
  {"    --ftp-pasv",
   "Send PASV/EPSV instead of PORT",
   CURLHELP_FTP},
  {"-P, --ftp-port <address>",







|
|


|











|





|








|
>


|


|
>








|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  {"    --doh-url <URL>",
   "Resolve hostnames over DoH",
   CURLHELP_DNS},
  {"-D, --dump-header <filename>",
   "Write the received headers to <filename>",
   CURLHELP_HTTP | CURLHELP_FTP},
  {"    --ech <config>",
   "Configure ECH",
   CURLHELP_TLS},
  {"    --egd-file <file>",
   "EGD socket path for random data",
   CURLHELP_DEPRECATED},
  {"    --engine <name>",
   "Crypto engine to use",
   CURLHELP_TLS},
  {"    --etag-compare <file>",
   "Load ETag from file",
   CURLHELP_HTTP},
  {"    --etag-save <file>",
   "Parse incoming ETag and save to a file",
   CURLHELP_HTTP},
  {"    --expect100-timeout <seconds>",
   "How long to wait for 100-continue",
   CURLHELP_HTTP | CURLHELP_TIMEOUT},
  {"-f, --fail",
   "Fail fast with no output on HTTP errors",
   CURLHELP_IMPORTANT | CURLHELP_HTTP},
  {"    --fail-early",
   "Fail on first transfer error",
   CURLHELP_CURL | CURLHELP_GLOBAL},
  {"    --fail-with-body",
   "Fail on HTTP errors but save the body",
   CURLHELP_HTTP | CURLHELP_OUTPUT},
  {"    --false-start",
   "Enable TLS False Start",
   CURLHELP_TLS},
  {"-F, --form <name=content>",
   "Specify multipart MIME data",
   CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST | CURLHELP_IMAP |
   CURLHELP_SMTP},
  {"    --form-escape",
   "Escape form fields using backslash",
   CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST},
  {"    --form-string <name=string>",
   "Specify multipart MIME data",
   CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST | CURLHELP_SMTP |
   CURLHELP_IMAP},
  {"    --ftp-account <data>",
   "Account data string",
   CURLHELP_FTP | CURLHELP_AUTH},
  {"    --ftp-alternative-to-user <command>",
   "String to replace USER [name]",
   CURLHELP_FTP},
  {"    --ftp-create-dirs",
   "Create the remote dirs if not present",
   CURLHELP_FTP | CURLHELP_SFTP},
  {"    --ftp-method <method>",
   "Control CWD usage",
   CURLHELP_FTP},
  {"    --ftp-pasv",
   "Send PASV/EPSV instead of PORT",
   CURLHELP_FTP},
  {"-P, --ftp-port <address>",
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
   "Set CCC mode",
   CURLHELP_FTP | CURLHELP_TLS},
  {"    --ftp-ssl-control",
   "Require TLS for login, clear for transfer",
   CURLHELP_FTP | CURLHELP_TLS},
  {"-G, --get",
   "Put the post data in the URL and use GET",
   CURLHELP_HTTP | CURLHELP_UPLOAD},
  {"-g, --globoff",
   "Disable URL globbing with {} and []",
   CURLHELP_CURL},
  {"    --happy-eyeballs-timeout-ms <ms>",
   "Time for IPv6 before IPv4",
   CURLHELP_CONNECTION},
  {"    --haproxy-clientip <ip>",
   "Set address in HAProxy PROXY",
   CURLHELP_HTTP | CURLHELP_PROXY},
  {"    --haproxy-protocol",
   "Send HAProxy PROXY protocol v1 header",
   CURLHELP_HTTP | CURLHELP_PROXY},
  {"-I, --head",
   "Show document info only",
   CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_FILE},
  {"-H, --header <header/@file>",
   "Pass custom header(s) to server",
   CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP},
  {"-h, --help <category>",
   "Get help for commands",
   CURLHELP_IMPORTANT | CURLHELP_CURL},
  {"    --hostpubmd5 <md5>",
   "Acceptable MD5 hash of host public key",
   CURLHELP_SFTP | CURLHELP_SCP},
  {"    --hostpubsha256 <sha256>",
   "Acceptable SHA256 hash of host public key",
   CURLHELP_SFTP | CURLHELP_SCP},
  {"    --hsts <filename>",
   "Enable HSTS with this cache file",
   CURLHELP_HTTP},
  {"    --http0.9",
   "Allow HTTP 0.9 responses",
   CURLHELP_HTTP},
  {"-0, --http1.0",







|





|

















|


|







240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
   "Set CCC mode",
   CURLHELP_FTP | CURLHELP_TLS},
  {"    --ftp-ssl-control",
   "Require TLS for login, clear for transfer",
   CURLHELP_FTP | CURLHELP_TLS},
  {"-G, --get",
   "Put the post data in the URL and use GET",
   CURLHELP_HTTP},
  {"-g, --globoff",
   "Disable URL globbing with {} and []",
   CURLHELP_CURL},
  {"    --happy-eyeballs-timeout-ms <ms>",
   "Time for IPv6 before IPv4",
   CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
  {"    --haproxy-clientip <ip>",
   "Set address in HAProxy PROXY",
   CURLHELP_HTTP | CURLHELP_PROXY},
  {"    --haproxy-protocol",
   "Send HAProxy PROXY protocol v1 header",
   CURLHELP_HTTP | CURLHELP_PROXY},
  {"-I, --head",
   "Show document info only",
   CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_FILE},
  {"-H, --header <header/@file>",
   "Pass custom header(s) to server",
   CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP},
  {"-h, --help <category>",
   "Get help for commands",
   CURLHELP_IMPORTANT | CURLHELP_CURL},
  {"    --hostpubmd5 <md5>",
   "Acceptable MD5 hash of host public key",
   CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
  {"    --hostpubsha256 <sha256>",
   "Acceptable SHA256 hash of host public key",
   CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
  {"    --hsts <filename>",
   "Enable HSTS with this cache file",
   CURLHELP_HTTP},
  {"    --http0.9",
   "Allow HTTP 0.9 responses",
   CURLHELP_HTTP},
  {"-0, --http1.0",
298
299
300
301
302
303
304
305
306
307



308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356

357
358
359
360
361
362
363
   "Ignore the size of the remote resource",
   CURLHELP_HTTP | CURLHELP_FTP},
  {"-i, --include",
   "Include response headers in output",
   CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
  {"-k, --insecure",
   "Allow insecure server connections",
   CURLHELP_TLS | CURLHELP_SFTP | CURLHELP_SCP},
  {"    --interface <name>",
   "Use network INTERFACE (or address)",



   CURLHELP_CONNECTION},
  {"    --ipfs-gateway <URL>",
   "Gateway for IPFS",
   CURLHELP_IPFS},
  {"-4, --ipv4",
   "Resolve names to IPv4 addresses",
   CURLHELP_CONNECTION | CURLHELP_DNS},
  {"-6, --ipv6",
   "Resolve names to IPv6 addresses",
   CURLHELP_CONNECTION | CURLHELP_DNS},
  {"    --json <data>",
   "HTTP POST JSON",
   CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
  {"-j, --junk-session-cookies",
   "Ignore session cookies read from file",
   CURLHELP_HTTP},



  {"    --keepalive-time <seconds>",
   "Interval time for keepalive probes",
   CURLHELP_CONNECTION},
  {"    --key <key>",
   "Private key filename",
   CURLHELP_TLS | CURLHELP_SSH},
  {"    --key-type <type>",
   "Private key file type (DER/PEM/ENG)",
   CURLHELP_TLS},
  {"    --krb <level>",
   "Enable Kerberos with security <level>",
   CURLHELP_FTP},
  {"    --libcurl <file>",
   "Generate libcurl code for this command line",
   CURLHELP_CURL},
  {"    --limit-rate <speed>",
   "Limit transfer speed to RATE",
   CURLHELP_CONNECTION},
  {"-l, --list-only",
   "List only mode",
   CURLHELP_FTP | CURLHELP_POP3 | CURLHELP_SFTP | CURLHELP_FILE},
  {"    --local-port <range>",
   "Use a local port number within RANGE",
   CURLHELP_CONNECTION},
  {"-L, --location",
   "Follow redirects",
   CURLHELP_HTTP},
  {"    --location-trusted",
   "Like --location, but send auth to other hosts",
   CURLHELP_HTTP | CURLHELP_AUTH},
  {"    --login-options <options>",
   "Server login options",
   CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP | CURLHELP_AUTH},

  {"    --mail-auth <address>",
   "Originator address of the original email",
   CURLHELP_SMTP},
  {"    --mail-from <address>",
   "Mail from this address",
   CURLHELP_SMTP},
  {"    --mail-rcpt <address>",







|

|
>
>
>



|












>
>
>


|











|













|



|
>







300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
   "Ignore the size of the remote resource",
   CURLHELP_HTTP | CURLHELP_FTP},
  {"-i, --include",
   "Include response headers in output",
   CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
  {"-k, --insecure",
   "Allow insecure server connections",
   CURLHELP_TLS | CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
  {"    --interface <name>",
   "Use network interface",
   CURLHELP_CONNECTION},
  {"    --ip-tos <string>",
   "Set IP Type of Service or Traffic Class",
   CURLHELP_CONNECTION},
  {"    --ipfs-gateway <URL>",
   "Gateway for IPFS",
   CURLHELP_CURL},
  {"-4, --ipv4",
   "Resolve names to IPv4 addresses",
   CURLHELP_CONNECTION | CURLHELP_DNS},
  {"-6, --ipv6",
   "Resolve names to IPv6 addresses",
   CURLHELP_CONNECTION | CURLHELP_DNS},
  {"    --json <data>",
   "HTTP POST JSON",
   CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
  {"-j, --junk-session-cookies",
   "Ignore session cookies read from file",
   CURLHELP_HTTP},
  {"    --keepalive-cnt <integer>",
   "Maximum number of keepalive probes",
   CURLHELP_CONNECTION},
  {"    --keepalive-time <seconds>",
   "Interval time for keepalive probes",
   CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
  {"    --key <key>",
   "Private key filename",
   CURLHELP_TLS | CURLHELP_SSH},
  {"    --key-type <type>",
   "Private key file type (DER/PEM/ENG)",
   CURLHELP_TLS},
  {"    --krb <level>",
   "Enable Kerberos with security <level>",
   CURLHELP_FTP},
  {"    --libcurl <file>",
   "Generate libcurl code for this command line",
   CURLHELP_CURL | CURLHELP_GLOBAL},
  {"    --limit-rate <speed>",
   "Limit transfer speed to RATE",
   CURLHELP_CONNECTION},
  {"-l, --list-only",
   "List only mode",
   CURLHELP_FTP | CURLHELP_POP3 | CURLHELP_SFTP | CURLHELP_FILE},
  {"    --local-port <range>",
   "Use a local port number within RANGE",
   CURLHELP_CONNECTION},
  {"-L, --location",
   "Follow redirects",
   CURLHELP_HTTP},
  {"    --location-trusted",
   "As --location, but send auth to other hosts",
   CURLHELP_HTTP | CURLHELP_AUTH},
  {"    --login-options <options>",
   "Server login options",
   CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP | CURLHELP_AUTH |
   CURLHELP_LDAP},
  {"    --mail-auth <address>",
   "Originator address of the original email",
   CURLHELP_SMTP},
  {"    --mail-from <address>",
   "Mail from this address",
   CURLHELP_SMTP},
  {"    --mail-rcpt <address>",
373
374
375
376
377
378
379
380
381
382
383



384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430

431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
   "Maximum file size to download",
   CURLHELP_CONNECTION},
  {"    --max-redirs <num>",
   "Maximum number of redirects allowed",
   CURLHELP_HTTP},
  {"-m, --max-time <seconds>",
   "Maximum time allowed for transfer",
   CURLHELP_CONNECTION},
  {"    --metalink",
   "Process given URLs as metalink XML file",
   CURLHELP_MISC},



  {"    --negotiate",
   "Use HTTP Negotiate (SPNEGO) authentication",
   CURLHELP_AUTH | CURLHELP_HTTP},
  {"-n, --netrc",
   "Must read .netrc for username and password",
   CURLHELP_CURL},
  {"    --netrc-file <filename>",
   "Specify FILE for netrc",
   CURLHELP_CURL},
  {"    --netrc-optional",
   "Use either .netrc or URL",
   CURLHELP_CURL},
  {"-:, --next",
   "Make next URL use its separate set of options",
   CURLHELP_CURL},
  {"    --no-alpn",
   "Disable the ALPN TLS extension",
   CURLHELP_TLS | CURLHELP_HTTP},
  {"-N, --no-buffer",
   "Disable buffering of the output stream",
   CURLHELP_CURL},
  {"    --no-clobber",
   "Do not overwrite files that already exist",
   CURLHELP_CURL | CURLHELP_OUTPUT},
  {"    --no-keepalive",
   "Disable TCP keepalive on the connection",
   CURLHELP_CONNECTION},
  {"    --no-npn",
   "Disable the NPN TLS extension",
   CURLHELP_TLS | CURLHELP_HTTP},
  {"    --no-progress-meter",
   "Do not show the progress meter",
   CURLHELP_VERBOSE},
  {"    --no-sessionid",
   "Disable SSL session-ID reusing",
   CURLHELP_TLS},
  {"    --noproxy <no-proxy-list>",
   "List of hosts which do not use proxy",
   CURLHELP_PROXY},
  {"    --ntlm",
   "HTTP NTLM authentication",
   CURLHELP_AUTH | CURLHELP_HTTP},
  {"    --ntlm-wb",
   "HTTP NTLM authentication with winbind",
   CURLHELP_AUTH | CURLHELP_HTTP},
  {"    --oauth2-bearer <token>",
   "OAuth 2 Bearer Token",

   CURLHELP_AUTH},
  {"-o, --output <file>",
   "Write to file instead of stdout",
   CURLHELP_IMPORTANT | CURLHELP_CURL},
  {"    --output-dir <dir>",
   "Directory to save files in",
   CURLHELP_CURL},
  {"-Z, --parallel",
   "Perform transfers in parallel",
   CURLHELP_CONNECTION | CURLHELP_CURL},
  {"    --parallel-immediate",
   "Do not wait for multiplexing (with --parallel)",
   CURLHELP_CONNECTION | CURLHELP_CURL},
  {"    --parallel-max <num>",
   "Maximum concurrency for parallel transfers",
   CURLHELP_CONNECTION | CURLHELP_CURL},
  {"    --pass <phrase>",
   "Pass phrase for the private key",
   CURLHELP_SSH | CURLHELP_TLS | CURLHELP_AUTH},
  {"    --path-as-is",
   "Do not squash .. sequences in URL path",
   CURLHELP_CURL},
  {"    --pinnedpubkey <hashes>",
   "FILE/HASHES Public key to verify peer against",
   CURLHELP_TLS},
  {"    --post301",
   "Do not switch to GET after a 301 redirect",
   CURLHELP_HTTP | CURLHELP_POST},
  {"    --post302",
   "Do not switch to GET after a 302 redirect",
   CURLHELP_HTTP | CURLHELP_POST},
  {"    --post303",
   "Do not switch to GET after a 303 redirect",
   CURLHELP_HTTP | CURLHELP_POST},
  {"    --preproxy [protocol://]host[:port]",
   "Use this proxy first",
   CURLHELP_PROXY},
  {"-#, --progress-bar",
   "Display transfer progress as a bar",
   CURLHELP_VERBOSE},
  {"    --proto <protocols>",
   "Enable/disable PROTOCOLS",
   CURLHELP_CONNECTION | CURLHELP_CURL},
  {"    --proto-default <protocol>",
   "Use PROTOCOL for any URL missing a scheme",
   CURLHELP_CONNECTION | CURLHELP_CURL},
  {"    --proto-redir <protocols>",







|


|
>
>
>





|


|


|

|






|


|





|














|


>
|


|


|


|

|
|


|

|





|















|







382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
   "Maximum file size to download",
   CURLHELP_CONNECTION},
  {"    --max-redirs <num>",
   "Maximum number of redirects allowed",
   CURLHELP_HTTP},
  {"-m, --max-time <seconds>",
   "Maximum time allowed for transfer",
   CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
  {"    --metalink",
   "Process given URLs as metalink XML file",
   CURLHELP_DEPRECATED},
  {"    --mptcp",
   "Enable Multipath TCP",
   CURLHELP_CONNECTION},
  {"    --negotiate",
   "Use HTTP Negotiate (SPNEGO) authentication",
   CURLHELP_AUTH | CURLHELP_HTTP},
  {"-n, --netrc",
   "Must read .netrc for username and password",
   CURLHELP_AUTH},
  {"    --netrc-file <filename>",
   "Specify FILE for netrc",
   CURLHELP_AUTH},
  {"    --netrc-optional",
   "Use either .netrc or URL",
   CURLHELP_AUTH},
  {"-:, --next",
   "Make next URL use separate options",
   CURLHELP_CURL},
  {"    --no-alpn",
   "Disable the ALPN TLS extension",
   CURLHELP_TLS | CURLHELP_HTTP},
  {"-N, --no-buffer",
   "Disable buffering of the output stream",
   CURLHELP_OUTPUT},
  {"    --no-clobber",
   "Do not overwrite files that already exist",
   CURLHELP_OUTPUT},
  {"    --no-keepalive",
   "Disable TCP keepalive on the connection",
   CURLHELP_CONNECTION},
  {"    --no-npn",
   "Disable the NPN TLS extension",
   CURLHELP_DEPRECATED},
  {"    --no-progress-meter",
   "Do not show the progress meter",
   CURLHELP_VERBOSE},
  {"    --no-sessionid",
   "Disable SSL session-ID reusing",
   CURLHELP_TLS},
  {"    --noproxy <no-proxy-list>",
   "List of hosts which do not use proxy",
   CURLHELP_PROXY},
  {"    --ntlm",
   "HTTP NTLM authentication",
   CURLHELP_AUTH | CURLHELP_HTTP},
  {"    --ntlm-wb",
   "HTTP NTLM authentication with winbind",
   CURLHELP_DEPRECATED},
  {"    --oauth2-bearer <token>",
   "OAuth 2 Bearer Token",
   CURLHELP_AUTH | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
   CURLHELP_LDAP},
  {"-o, --output <file>",
   "Write to file instead of stdout",
   CURLHELP_IMPORTANT | CURLHELP_OUTPUT},
  {"    --output-dir <dir>",
   "Directory to save files in",
   CURLHELP_OUTPUT},
  {"-Z, --parallel",
   "Perform transfers in parallel",
   CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
  {"    --parallel-immediate",
   "Do not wait for multiplexing",
   CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
  {"    --parallel-max <num>",
   "Maximum concurrency for parallel transfers",
   CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
  {"    --pass <phrase>",
   "Passphrase for the private key",
   CURLHELP_SSH | CURLHELP_TLS | CURLHELP_AUTH},
  {"    --path-as-is",
   "Do not squash .. sequences in URL path",
   CURLHELP_CURL},
  {"    --pinnedpubkey <hashes>",
   "Public key to verify peer against",
   CURLHELP_TLS},
  {"    --post301",
   "Do not switch to GET after a 301 redirect",
   CURLHELP_HTTP | CURLHELP_POST},
  {"    --post302",
   "Do not switch to GET after a 302 redirect",
   CURLHELP_HTTP | CURLHELP_POST},
  {"    --post303",
   "Do not switch to GET after a 303 redirect",
   CURLHELP_HTTP | CURLHELP_POST},
  {"    --preproxy [protocol://]host[:port]",
   "Use this proxy first",
   CURLHELP_PROXY},
  {"-#, --progress-bar",
   "Display transfer progress as a bar",
   CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"    --proto <protocols>",
   "Enable/disable PROTOCOLS",
   CURLHELP_CONNECTION | CURLHELP_CURL},
  {"    --proto-default <protocol>",
   "Use PROTOCOL for any URL missing a scheme",
   CURLHELP_CONNECTION | CURLHELP_CURL},
  {"    --proto-redir <protocols>",
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  {"    --proxy-negotiate",
   "HTTP Negotiate (SPNEGO) auth with the proxy",
   CURLHELP_PROXY | CURLHELP_AUTH},
  {"    --proxy-ntlm",
   "NTLM authentication with the proxy",
   CURLHELP_PROXY | CURLHELP_AUTH},
  {"    --proxy-pass <phrase>",
   "Pass phrase for the private key for HTTPS proxy",
   CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
  {"    --proxy-pinnedpubkey <hashes>",
   "FILE/HASHES public key to verify proxy with",
   CURLHELP_PROXY | CURLHELP_TLS},
  {"    --proxy-service-name <name>",
   "SPNEGO proxy service name",
   CURLHELP_PROXY | CURLHELP_TLS},
  {"    --proxy-ssl-allow-beast",
   "Allow security flaw for interop for HTTPS proxy",
   CURLHELP_PROXY | CURLHELP_TLS},
  {"    --proxy-ssl-auto-client-cert",
   "Auto client certificate for proxy",
   CURLHELP_PROXY | CURLHELP_TLS},
  {"    --proxy-tls13-ciphers <ciphersuite list>",
   "TLS 1.3 proxy cipher suites",
   CURLHELP_PROXY | CURLHELP_TLS},







|








|







541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  {"    --proxy-negotiate",
   "HTTP Negotiate (SPNEGO) auth with the proxy",
   CURLHELP_PROXY | CURLHELP_AUTH},
  {"    --proxy-ntlm",
   "NTLM authentication with the proxy",
   CURLHELP_PROXY | CURLHELP_AUTH},
  {"    --proxy-pass <phrase>",
   "Passphrase for private key for HTTPS proxy",
   CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
  {"    --proxy-pinnedpubkey <hashes>",
   "FILE/HASHES public key to verify proxy with",
   CURLHELP_PROXY | CURLHELP_TLS},
  {"    --proxy-service-name <name>",
   "SPNEGO proxy service name",
   CURLHELP_PROXY | CURLHELP_TLS},
  {"    --proxy-ssl-allow-beast",
   "Allow this security flaw for HTTPS proxy",
   CURLHELP_PROXY | CURLHELP_TLS},
  {"    --proxy-ssl-auto-client-cert",
   "Auto client certificate for proxy",
   CURLHELP_PROXY | CURLHELP_TLS},
  {"    --proxy-tls13-ciphers <ciphersuite list>",
   "TLS 1.3 proxy cipher suites",
   CURLHELP_PROXY | CURLHELP_TLS},
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
   "Use HTTP/1.0 proxy on given port",
   CURLHELP_PROXY},
  {"-p, --proxytunnel",
   "HTTP proxy tunnel (using CONNECT)",
   CURLHELP_PROXY},
  {"    --pubkey <key>",
   "SSH Public key filename",
   CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_AUTH},
  {"-Q, --quote <command>",
   "Send command(s) to server before transfer",
   CURLHELP_FTP | CURLHELP_SFTP},
  {"    --random-file <file>",
   "File for reading random data from",
   CURLHELP_MISC},
  {"-r, --range <range>",
   "Retrieve only the bytes within RANGE",
   CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_SFTP | CURLHELP_FILE},
  {"    --rate <max request rate>",
   "Request rate for serial transfers",
   CURLHELP_CONNECTION},
  {"    --raw",
   "Do HTTP raw; no transfer decoding",
   CURLHELP_HTTP},
  {"-e, --referer <URL>",
   "Referrer URL",
   CURLHELP_HTTP},
  {"-J, --remote-header-name",
   "Use the header-provided filename",
   CURLHELP_OUTPUT},
  {"-O, --remote-name",
   "Write output to file named as remote file",
   CURLHELP_IMPORTANT | CURLHELP_OUTPUT},
  {"    --remote-name-all",
   "Use the remote filename for all URLs",
   CURLHELP_OUTPUT},
  {"-R, --remote-time",
   "Set remote file's time on local output",
   CURLHELP_OUTPUT},
  {"    --remove-on-error",
   "Remove output file on errors",
   CURLHELP_CURL},
  {"-X, --request <method>",
   "Specify request method to use",

   CURLHELP_CONNECTION},
  {"    --request-target <path>",
   "Specify the target for this request",
   CURLHELP_HTTP},
  {"    --resolve <[+]host:port:addr[,addr]...>",
   "Resolve host+port to address",
   CURLHELP_CONNECTION | CURLHELP_DNS},
  {"    --retry <num>",
   "Retry request if transient problems occur",
   CURLHELP_CURL},
  {"    --retry-all-errors",
   "Retry all errors (with --retry)",
   CURLHELP_CURL},
  {"    --retry-connrefused",
   "Retry on connection refused (with --retry)",
   CURLHELP_CURL},
  {"    --retry-delay <seconds>",
   "Wait time between retries",
   CURLHELP_CURL},
  {"    --retry-max-time <seconds>",
   "Retry only within this period",
   CURLHELP_CURL},
  {"    --sasl-authzid <identity>",
   "Identity for SASL PLAIN authentication",
   CURLHELP_AUTH},
  {"    --sasl-ir",
   "Initial response in SASL authentication",
   CURLHELP_AUTH},
  {"    --service-name <name>",
   "SPNEGO service name",
   CURLHELP_MISC},
  {"-S, --show-error",
   "Show error even when -s is used",
   CURLHELP_CURL},
  {"-s, --silent",
   "Silent mode",
   CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
  {"    --socks4 <host[:port]>",
   "SOCKS4 proxy on given host + port",
   CURLHELP_PROXY},
  {"    --socks4a <host[:port]>",







|





|





|




















|


>
|

















|


|








|


|







581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
   "Use HTTP/1.0 proxy on given port",
   CURLHELP_PROXY},
  {"-p, --proxytunnel",
   "HTTP proxy tunnel (using CONNECT)",
   CURLHELP_PROXY},
  {"    --pubkey <key>",
   "SSH Public key filename",
   CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH | CURLHELP_AUTH},
  {"-Q, --quote <command>",
   "Send command(s) to server before transfer",
   CURLHELP_FTP | CURLHELP_SFTP},
  {"    --random-file <file>",
   "File for reading random data from",
   CURLHELP_DEPRECATED},
  {"-r, --range <range>",
   "Retrieve only the bytes within RANGE",
   CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_SFTP | CURLHELP_FILE},
  {"    --rate <max request rate>",
   "Request rate for serial transfers",
   CURLHELP_CONNECTION | CURLHELP_GLOBAL},
  {"    --raw",
   "Do HTTP raw; no transfer decoding",
   CURLHELP_HTTP},
  {"-e, --referer <URL>",
   "Referrer URL",
   CURLHELP_HTTP},
  {"-J, --remote-header-name",
   "Use the header-provided filename",
   CURLHELP_OUTPUT},
  {"-O, --remote-name",
   "Write output to file named as remote file",
   CURLHELP_IMPORTANT | CURLHELP_OUTPUT},
  {"    --remote-name-all",
   "Use the remote filename for all URLs",
   CURLHELP_OUTPUT},
  {"-R, --remote-time",
   "Set remote file's time on local output",
   CURLHELP_OUTPUT},
  {"    --remove-on-error",
   "Remove output file on errors",
   CURLHELP_OUTPUT},
  {"-X, --request <method>",
   "Specify request method to use",
   CURLHELP_CONNECTION | CURLHELP_POP3 | CURLHELP_FTP | CURLHELP_IMAP |
   CURLHELP_SMTP},
  {"    --request-target <path>",
   "Specify the target for this request",
   CURLHELP_HTTP},
  {"    --resolve <[+]host:port:addr[,addr]...>",
   "Resolve host+port to address",
   CURLHELP_CONNECTION | CURLHELP_DNS},
  {"    --retry <num>",
   "Retry request if transient problems occur",
   CURLHELP_CURL},
  {"    --retry-all-errors",
   "Retry all errors (with --retry)",
   CURLHELP_CURL},
  {"    --retry-connrefused",
   "Retry on connection refused (with --retry)",
   CURLHELP_CURL},
  {"    --retry-delay <seconds>",
   "Wait time between retries",
   CURLHELP_CURL | CURLHELP_TIMEOUT},
  {"    --retry-max-time <seconds>",
   "Retry only within this period",
   CURLHELP_CURL | CURLHELP_TIMEOUT},
  {"    --sasl-authzid <identity>",
   "Identity for SASL PLAIN authentication",
   CURLHELP_AUTH},
  {"    --sasl-ir",
   "Initial response in SASL authentication",
   CURLHELP_AUTH},
  {"    --service-name <name>",
   "SPNEGO service name",
   CURLHELP_AUTH},
  {"-S, --show-error",
   "Show error even when -s is used",
   CURLHELP_CURL | CURLHELP_GLOBAL},
  {"-s, --silent",
   "Silent mode",
   CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
  {"    --socks4 <host[:port]>",
   "SOCKS4 proxy on given host + port",
   CURLHELP_PROXY},
  {"    --socks4a <host[:port]>",
670
671
672
673
674
675
676
677
678
679

680
681
682
683
684
685
686
687
688
689
690
691

692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
   "SOCKS5 proxy, pass hostname to proxy",
   CURLHELP_PROXY},
  {"-Y, --speed-limit <speed>",
   "Stop transfers slower than this",
   CURLHELP_CONNECTION},
  {"-y, --speed-time <seconds>",
   "Trigger 'speed-limit' abort after this time",
   CURLHELP_CONNECTION},
  {"    --ssl",
   "Try enabling TLS",

   CURLHELP_TLS},
  {"    --ssl-allow-beast",
   "Allow security flaw to improve interop",
   CURLHELP_TLS},
  {"    --ssl-auto-client-cert",
   "Use auto client certificate (Schannel)",
   CURLHELP_TLS},
  {"    --ssl-no-revoke",
   "Disable cert revocation checks (Schannel)",
   CURLHELP_TLS},
  {"    --ssl-reqd",
   "Require SSL/TLS",

   CURLHELP_TLS},
  {"    --ssl-revoke-best-effort",
   "Ignore missing cert CRL dist points",
   CURLHELP_TLS},
  {"-2, --sslv2",
   "SSLv2",
   CURLHELP_TLS},
  {"-3, --sslv3",
   "SSLv3",
   CURLHELP_TLS},
  {"    --stderr <file>",
   "Where to redirect stderr",
   CURLHELP_VERBOSE},
  {"    --styled-output",
   "Enable styled output for HTTP headers",
   CURLHELP_VERBOSE},
  {"    --suppress-connect-headers",
   "Suppress proxy CONNECT response headers",
   CURLHELP_PROXY},
  {"    --tcp-fastopen",
   "Use TCP Fast Open",
   CURLHELP_CONNECTION},
  {"    --tcp-nodelay",







|


>
|











>
|





|


|


|


|







684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
   "SOCKS5 proxy, pass hostname to proxy",
   CURLHELP_PROXY},
  {"-Y, --speed-limit <speed>",
   "Stop transfers slower than this",
   CURLHELP_CONNECTION},
  {"-y, --speed-time <seconds>",
   "Trigger 'speed-limit' abort after this time",
   CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
  {"    --ssl",
   "Try enabling TLS",
   CURLHELP_TLS | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
   CURLHELP_LDAP},
  {"    --ssl-allow-beast",
   "Allow security flaw to improve interop",
   CURLHELP_TLS},
  {"    --ssl-auto-client-cert",
   "Use auto client certificate (Schannel)",
   CURLHELP_TLS},
  {"    --ssl-no-revoke",
   "Disable cert revocation checks (Schannel)",
   CURLHELP_TLS},
  {"    --ssl-reqd",
   "Require SSL/TLS",
   CURLHELP_TLS | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
   CURLHELP_LDAP},
  {"    --ssl-revoke-best-effort",
   "Ignore missing cert CRL dist points",
   CURLHELP_TLS},
  {"-2, --sslv2",
   "SSLv2",
   CURLHELP_DEPRECATED},
  {"-3, --sslv3",
   "SSLv3",
   CURLHELP_DEPRECATED},
  {"    --stderr <file>",
   "Where to redirect stderr",
   CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"    --styled-output",
   "Enable styled output for HTTP headers",
   CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"    --suppress-connect-headers",
   "Suppress proxy CONNECT response headers",
   CURLHELP_PROXY},
  {"    --tcp-fastopen",
   "Use TCP Fast Open",
   CURLHELP_CONNECTION},
  {"    --tcp-nodelay",
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806



807
808
809
810
811
812
813
814
   "TLSv1.3 or greater",
   CURLHELP_TLS},
  {"    --tr-encoding",
   "Request compressed transfer encoding",
   CURLHELP_HTTP},
  {"    --trace <file>",
   "Write a debug trace to FILE",
   CURLHELP_VERBOSE},
  {"    --trace-ascii <file>",
   "Like --trace, but without hex output",
   CURLHELP_VERBOSE},
  {"    --trace-config <string>",
   "Details to log in trace/verbose output",
   CURLHELP_VERBOSE},
  {"    --trace-ids",
   "Transfer + connection ids in verbose output",
   CURLHELP_VERBOSE},
  {"    --trace-time",
   "Add time stamps to trace/verbose output",
   CURLHELP_VERBOSE},
  {"    --unix-socket <path>",
   "Connect through this Unix domain socket",
   CURLHELP_CONNECTION},
  {"-T, --upload-file <file>",
   "Transfer local FILE to destination",
   CURLHELP_IMPORTANT | CURLHELP_UPLOAD},
  {"    --url <url>",
   "URL to work with",
   CURLHELP_CURL},
  {"    --url-query <data>",
   "Add a URL query part",
   CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
  {"-B, --use-ascii",
   "Use ASCII/text transfer",
   CURLHELP_MISC},
  {"-u, --user <user:password>",
   "Server user and password",
   CURLHELP_IMPORTANT | CURLHELP_AUTH},
  {"-A, --user-agent <name>",
   "Send User-Agent <name> to server",
   CURLHELP_IMPORTANT | CURLHELP_HTTP},
  {"    --variable <[%]name=text/@file>",
   "Set variable",
   CURLHELP_CURL},
  {"-v, --verbose",
   "Make the operation more talkative",
   CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
  {"-V, --version",
   "Show version number and quit",
   CURLHELP_IMPORTANT | CURLHELP_CURL},



  {"-w, --write-out <format>",
   "Output FORMAT after completion",
   CURLHELP_VERBOSE},
  {"    --xattr",
   "Store metadata in extended file attributes",
   CURLHELP_MISC},
  { NULL, NULL, CURLHELP_HIDDEN }
};







|


|


|


|


|














|











|



>
>
>





|
|

773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
   "TLSv1.3 or greater",
   CURLHELP_TLS},
  {"    --tr-encoding",
   "Request compressed transfer encoding",
   CURLHELP_HTTP},
  {"    --trace <file>",
   "Write a debug trace to FILE",
   CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"    --trace-ascii <file>",
   "Like --trace, but without hex output",
   CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"    --trace-config <string>",
   "Details to log in trace/verbose output",
   CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"    --trace-ids",
   "Transfer + connection ids in verbose output",
   CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"    --trace-time",
   "Add time stamps to trace/verbose output",
   CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"    --unix-socket <path>",
   "Connect through this Unix domain socket",
   CURLHELP_CONNECTION},
  {"-T, --upload-file <file>",
   "Transfer local FILE to destination",
   CURLHELP_IMPORTANT | CURLHELP_UPLOAD},
  {"    --url <url>",
   "URL to work with",
   CURLHELP_CURL},
  {"    --url-query <data>",
   "Add a URL query part",
   CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
  {"-B, --use-ascii",
   "Use ASCII/text transfer",
   CURLHELP_FTP | CURLHELP_OUTPUT | CURLHELP_LDAP},
  {"-u, --user <user:password>",
   "Server user and password",
   CURLHELP_IMPORTANT | CURLHELP_AUTH},
  {"-A, --user-agent <name>",
   "Send User-Agent <name> to server",
   CURLHELP_IMPORTANT | CURLHELP_HTTP},
  {"    --variable <[%]name=text/@file>",
   "Set variable",
   CURLHELP_CURL},
  {"-v, --verbose",
   "Make the operation more talkative",
   CURLHELP_IMPORTANT | CURLHELP_VERBOSE | CURLHELP_GLOBAL},
  {"-V, --version",
   "Show version number and quit",
   CURLHELP_IMPORTANT | CURLHELP_CURL},
  {"    --vlan-priority <priority>",
   "Set VLAN priority",
   CURLHELP_CONNECTION},
  {"-w, --write-out <format>",
   "Output FORMAT after completion",
   CURLHELP_VERBOSE},
  {"    --xattr",
   "Store metadata in extended file attributes",
   CURLHELP_OUTPUT},
  { NULL, NULL, 0 }
};
Changes to jni/curl/src/tool_main.c.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

/* if we build a static library for unit tests, there is no main() function */
#ifndef UNITTESTS

#if defined(HAVE_PIPE) && defined(HAVE_FCNTL)
/*
 * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
 * open before starting to run.  Otherwise, the first three network
 * sockets opened by curl could be used for input sources, downloaded data
 * or error logs as they will effectively be stdin, stdout and/or stderr.
 *
 * fcntl's F_GETFD instruction returns -1 if the file descriptor is closed,
 * otherwise it returns "the file descriptor flags (which typically can only
 * be FD_CLOEXEC, which is not set here).
 */







|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

/* if we build a static library for unit tests, there is no main() function */
#ifndef UNITTESTS

#if defined(HAVE_PIPE) && defined(HAVE_FCNTL)
/*
 * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
 * open before starting to run. Otherwise, the first three network
 * sockets opened by curl could be used for input sources, downloaded data
 * or error logs as they will effectively be stdin, stdout and/or stderr.
 *
 * fcntl's F_GETFD instruction returns -1 if the file descriptor is closed,
 * otherwise it returns "the file descriptor flags (which typically can only
 * be FD_CLOEXEC, which is not set here).
 */
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#ifdef CURLDEBUG
static void memory_tracking_init(void)
{
  char *env;
  /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
  env = curl_getenv("CURL_MEMDEBUG");
  if(env) {
    /* use the value as file name */
    char fname[CURL_MT_LOGFNAME_BUFSIZE];
    if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
      env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
    strcpy(fname, env);
    curl_free(env);
    curl_dbg_memdebug(fname);
    /* this weird stuff here is to make curl_free() get called before







|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#ifdef CURLDEBUG
static void memory_tracking_init(void)
{
  char *env;
  /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
  env = curl_getenv("CURL_MEMDEBUG");
  if(env) {
    /* use the value as filename */
    char fname[CURL_MT_LOGFNAME_BUFSIZE];
    if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
      env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
    strcpy(fname, env);
    curl_free(env);
    curl_dbg_memdebug(fname);
    /* this weird stuff here is to make curl_free() get called before
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
}

/*
** curl tool main function.
*/
#ifdef _UNICODE
#if defined(__GNUC__)
/* GCC doesn't know about wmain() */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
#pragma GCC diagnostic ignored "-Wmissing-declarations"
#endif
int wmain(int argc, wchar_t *argv[])
#else
int main(int argc, char *argv[])







|







215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
}

/*
** curl tool main function.
*/
#ifdef _UNICODE
#if defined(__GNUC__)
/* GCC does not know about wmain() */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
#pragma GCC diagnostic ignored "-Wmissing-declarations"
#endif
int wmain(int argc, wchar_t *argv[])
#else
int main(int argc, char *argv[])
Changes to jni/curl/src/tool_msgs.c.
25
26
27
28
29
30
31


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

#define ENABLE_CURLX_PRINTF
/* use our own printf() functions */
#include "curlx.h"

#include "tool_cfgable.h"
#include "tool_msgs.h"



#include "memdebug.h" /* keep this as LAST include */

#define WARN_PREFIX "Warning: "
#define NOTE_PREFIX "Note: "
#define ERROR_PREFIX "curl: "

static void voutf(struct GlobalConfig *config,
                  const char *prefix,
                  const char *fmt,
                  va_list ap) CURL_PRINTF(3, 0);

static void voutf(struct GlobalConfig *config,
                  const char *prefix,
                  const char *fmt,
                  va_list ap)
{
  size_t width = (79 - strlen(prefix));
  DEBUGASSERT(!strchr(fmt, '\n'));
  if(!config->silent) {
    size_t len;
    char *ptr;
    char *print_buffer;

    print_buffer = curlx_mvaprintf(fmt, ap);







>
>

















|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

#define ENABLE_CURLX_PRINTF
/* use our own printf() functions */
#include "curlx.h"

#include "tool_cfgable.h"
#include "tool_msgs.h"
#include "tool_cb_prg.h"
#include "terminal.h"

#include "memdebug.h" /* keep this as LAST include */

#define WARN_PREFIX "Warning: "
#define NOTE_PREFIX "Note: "
#define ERROR_PREFIX "curl: "

static void voutf(struct GlobalConfig *config,
                  const char *prefix,
                  const char *fmt,
                  va_list ap) CURL_PRINTF(3, 0);

static void voutf(struct GlobalConfig *config,
                  const char *prefix,
                  const char *fmt,
                  va_list ap)
{
  size_t width = (get_terminal_columns() - strlen(prefix));
  DEBUGASSERT(!strchr(fmt, '\n'));
  if(!config->silent) {
    size_t len;
    char *ptr;
    char *print_buffer;

    print_buffer = curlx_mvaprintf(fmt, ap);
Changes to jni/curl/src/tool_operate.c.
40
41
42
43
44
45
46




47
48
49
50
51
52
53
54
55
56
57
58

59
60
61
62
63
64
65
#ifdef __VMS
#  include <fabdef.h>
#endif

#ifdef __AMIGA__
#  include <proto/dos.h>
#endif





#define ENABLE_CURLX_PRINTF
/* use our own printf() functions */
#include "curlx.h"

#include "tool_binmode.h"
#include "tool_cfgable.h"
#include "tool_cb_dbg.h"
#include "tool_cb_hdr.h"
#include "tool_cb_prg.h"
#include "tool_cb_rea.h"
#include "tool_cb_see.h"

#include "tool_cb_wrt.h"
#include "tool_dirhie.h"
#include "tool_doswin.h"
#include "tool_easysrc.h"
#include "tool_filetime.h"
#include "tool_getparam.h"
#include "tool_helpers.h"







>
>
>
>












>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#ifdef __VMS
#  include <fabdef.h>
#endif

#ifdef __AMIGA__
#  include <proto/dos.h>
#endif

#ifdef HAVE_NETINET_IN_H
#  include <netinet/in.h>
#endif

#define ENABLE_CURLX_PRINTF
/* use our own printf() functions */
#include "curlx.h"

#include "tool_binmode.h"
#include "tool_cfgable.h"
#include "tool_cb_dbg.h"
#include "tool_cb_hdr.h"
#include "tool_cb_prg.h"
#include "tool_cb_rea.h"
#include "tool_cb_see.h"
#include "tool_cb_soc.h"
#include "tool_cb_wrt.h"
#include "tool_dirhie.h"
#include "tool_doswin.h"
#include "tool_easysrc.h"
#include "tool_filetime.h"
#include "tool_getparam.h"
#include "tool_helpers.h"
79
80
81
82
83
84
85



86
87
88
89
90
91
92
93
94
95
96
97
98
99




100
101
102
103
104
105
106
107
108
109
110
111
#include "tool_xattr.h"
#include "tool_vms.h"
#include "tool_help.h"
#include "tool_hugehelp.h"
#include "tool_progress.h"
#include "tool_ipfs.h"
#include "dynbuf.h"




#include "memdebug.h" /* keep this as LAST include */

#ifdef CURLDEBUG
/* libcurl's debug builds provide an extra function */
CURLcode curl_easy_perform_ev(CURL *easy);
#endif

#ifndef O_BINARY
/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
   source code but yet it doesn't ruin anything */
#  define O_BINARY 0
#endif





#define CURL_CA_CERT_ERRORMSG                                               \
  "More details here: https://curl.se/docs/sslcerts.html\n\n"          \
  "curl failed to verify the legitimacy of the server and therefore "       \
  "could not\nestablish a secure connection to it. To learn more about "    \
  "this situation and\nhow to fix it, please visit the web page mentioned " \
  "above.\n"

static CURLcode single_transfer(struct GlobalConfig *global,
                                struct OperationConfig *config,
                                CURLSH *share,
                                bool capath_from_env,
                                bool *added);







>
>
>


<
<
<
<
<



|



>
>
>
>
|
|
|
|
|







84
85
86
87
88
89
90
91
92
93
94
95





96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "tool_xattr.h"
#include "tool_vms.h"
#include "tool_help.h"
#include "tool_hugehelp.h"
#include "tool_progress.h"
#include "tool_ipfs.h"
#include "dynbuf.h"
#ifdef DEBUGBUILD
#include "easyif.h"  /* for libcurl's debug-only curl_easy_perform_ev() */
#endif

#include "memdebug.h" /* keep this as LAST include */






#ifndef O_BINARY
/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
   source code but yet it does not ruin anything */
#  define O_BINARY 0
#endif

#ifndef SOL_IP
#  define SOL_IP IPPROTO_IP
#endif

#define CURL_CA_CERT_ERRORMSG                                              \
  "More details here: https://curl.se/docs/sslcerts.html\n\n"              \
  "curl failed to verify the legitimacy of the server and therefore "      \
  "could not\nestablish a secure connection to it. To learn more about "   \
  "this situation and\nhow to fix it, please visit the webpage mentioned " \
  "above.\n"

static CURLcode single_transfer(struct GlobalConfig *global,
                                struct OperationConfig *config,
                                CURLSH *share,
                                bool capath_from_env,
                                bool *added);
139
140
141
142
143
144
145





























































146
147
148
149
150
151
152
  if(curl_strnequal(string, "pkcs11:", 7)) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}






























































#ifdef __VMS
/*
 * get_vms_file_size does what it takes to get the real size of the file
 *
 * For fixed files, find out the size of the EOF block and adjust.
 *







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  if(curl_strnequal(string, "pkcs11:", 7)) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

#ifdef IP_TOS
static int get_address_family(curl_socket_t sockfd)
{
  struct sockaddr_storage addr;
  socklen_t addrlen = sizeof(addr);
  if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) == 0)
    return addr.ss_family;
  return AF_UNSPEC;
}
#endif

#if defined(IP_TOS) || defined(IPV6_TCLASS) || defined(SO_PRIORITY)
static int sockopt_callback(void *clientp, curl_socket_t curlfd,
                            curlsocktype purpose)
{
  struct OperationConfig *config = (struct OperationConfig *)clientp;
  if(purpose != CURLSOCKTYPE_IPCXN)
    return CURL_SOCKOPT_OK;
  (void)config;
  (void)curlfd;
#if defined(IP_TOS) || defined(IPV6_TCLASS)
  if(config->ip_tos > 0) {
    int tos = (int)config->ip_tos;
    int result = 0;
    switch(get_address_family(curlfd)) {
    case AF_INET:
#ifdef IP_TOS
      result = setsockopt(curlfd, SOL_IP, IP_TOS, (void *)&tos, sizeof(tos));
#endif
      break;
    case AF_INET6:
#ifdef IPV6_TCLASS
      result = setsockopt(curlfd, IPPROTO_IPV6, IPV6_TCLASS,
                          (void *)&tos, sizeof(tos));
#endif
      break;
    }
    if(result < 0) {
      int error = errno;
      warnf(config->global,
            "Setting type of service to %d failed with errno %d: %s;\n",
            tos, error, strerror(error));
    }
  }
#endif
#ifdef SO_PRIORITY
  if(config->vlan_priority > 0) {
    int priority = (int)config->vlan_priority;
    if(setsockopt(curlfd, SOL_SOCKET, SO_PRIORITY,
      (void *)&priority, sizeof(priority)) != 0) {
      int error = errno;
      warnf(config->global, "VLAN priority %d failed with errno %d: %s;\n",
            priority, error, strerror(error));
    }
  }
#endif
  return CURL_SOCKOPT_OK;
}
#endif


#ifdef __VMS
/*
 * get_vms_file_size does what it takes to get the real size of the file
 *
 * For fixed files, find out the size of the EOF block and adjust.
 *
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  curl_off_t uploadfilesize = -1;
  struct_stat fileinfo;
  CURLcode result = CURLE_OK;

  if(per->uploadfile && !stdin_upload(per->uploadfile)) {
    /* VMS Note:
     *
     * Reading binary from files can be a problem...  Only FIXED, VAR
     * etc WITHOUT implied CC will work. Others need a \n appended to
     * a line
     *
     * - Stat gives a size but this is UNRELIABLE in VMS. E.g.
     * a fixed file with implied CC needs to have a byte added for every
     * record processed, this can be derived from Filesize & recordsize
     * for VARiable record files the records need to be counted!  for







|







335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  curl_off_t uploadfilesize = -1;
  struct_stat fileinfo;
  CURLcode result = CURLE_OK;

  if(per->uploadfile && !stdin_upload(per->uploadfile)) {
    /* VMS Note:
     *
     * Reading binary from files can be a problem... Only FIXED, VAR
     * etc WITHOUT implied CC will work. Others need a \n appended to
     * a line
     *
     * - Stat gives a size but this is UNRELIABLE in VMS. E.g.
     * a fixed file with implied CC needs to have a byte added for every
     * record processed, this can be derived from Filesize & recordsize
     * for VARiable record files the records need to be counted!  for
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
    }
    if(per->infd == -1)
#else
      per->infd = open(per->uploadfile, O_RDONLY | O_BINARY);
    if((per->infd == -1) || fstat(per->infd, &fileinfo))
#endif
    {
      helpf(tool_stderr, "Can't open '%s'", per->uploadfile);
      if(per->infd != -1) {
        close(per->infd);
        per->infd = STDIN_FILENO;
      }
      return CURLE_READ_ERROR;
    }
    per->infdopen = TRUE;







|







369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    }
    if(per->infd == -1)
#else
      per->infd = open(per->uploadfile, O_RDONLY | O_BINARY);
    if((per->infd == -1) || fstat(per->infd, &fileinfo))
#endif
    {
      helpf(tool_stderr, "cannot open '%s'", per->uploadfile);
      if(per->infd != -1) {
        close(per->infd);
        per->infd = STDIN_FILENO;
      }
      return CURLE_READ_ERROR;
    }
    per->infdopen = TRUE;
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464

#ifdef _WIN32
  /* Discard incomplete UTF-8 sequence buffered from body */
  if(outs->utf8seq[0])
    memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
#endif

  /* if retry-max-time is non-zero, make sure we haven't exceeded the
     time */
  if(per->retry_numretries &&
     (!config->retry_maxtime ||
      (tvdiff(tvnow(), per->retrystart) <
       config->retry_maxtime*1000L)) ) {
    enum {
      RETRY_NO,
      RETRY_ALL_ERRORS,
      RETRY_TIMEOUT,







|

|







516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532

#ifdef _WIN32
  /* Discard incomplete UTF-8 sequence buffered from body */
  if(outs->utf8seq[0])
    memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
#endif

  /* if retry-max-time is non-zero, make sure we have not exceeded the
     time */
  if(per->retry_remaining &&
     (!config->retry_maxtime ||
      (tvdiff(tvnow(), per->retrystart) <
       config->retry_maxtime*1000L)) ) {
    enum {
      RETRY_NO,
      RETRY_ALL_ERRORS,
      RETRY_TIMEOUT,
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
      curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
      scheme = proto_token(scheme);

      if((scheme == proto_ftp || scheme == proto_ftps) && response / 100 == 4)
        /*
         * This is typically when the FTP server only allows a certain
         * amount of users and we are not one of them.  All 4xx codes
         * are transient.
         */
        retry = RETRY_FTP;
    }

    if(result && !retry && config->retry_all_errors)
      retry = RETRY_ALL_ERRORS;







|







590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
      curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
      curl_easy_getinfo(curl, CURLINFO_SCHEME, &scheme);
      scheme = proto_token(scheme);

      if((scheme == proto_ftp || scheme == proto_ftps) && response / 100 == 4)
        /*
         * This is typically when the FTP server only allows a certain
         * amount of users and we are not one of them. All 4xx codes
         * are transient.
         */
        retry = RETRY_FTP;
    }

    if(result && !retry && config->retry_all_errors)
      retry = RETRY_ALL_ERRORS;
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
        ": FTP error"
      };

      sleeptime = per->retry_sleep;
      if(RETRY_HTTP == retry) {
        curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after);
        if(retry_after) {
          /* store in a 'long', make sure it doesn't overflow */
          if(retry_after > LONG_MAX/1000)
            sleeptime = LONG_MAX;
          else if((retry_after * 1000) > sleeptime)
            sleeptime = (long)retry_after * 1000; /* milliseconds */

          /* if adding retry_after seconds to the process would exceed the
             maximum time allowed for retrying, then exit the retries right







|







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
        ": FTP error"
      };

      sleeptime = per->retry_sleep;
      if(RETRY_HTTP == retry) {
        curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after);
        if(retry_after) {
          /* store in a 'long', make sure it does not overflow */
          if(retry_after > LONG_MAX/1000)
            sleeptime = LONG_MAX;
          else if((retry_after * 1000) > sleeptime)
            sleeptime = (long)retry_after * 1000; /* milliseconds */

          /* if adding retry_after seconds to the process would exceed the
             maximum time allowed for retrying, then exit the retries right
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618

619
620
621
622
623
624
625
626
627
628
629
            }
          }
        }
      }
      warnf(config->global, "Problem %s. "
            "Will retry in %ld seconds. "
            "%ld retries left.",
            m[retry], sleeptime/1000L, per->retry_numretries);

      per->retry_numretries--;
      if(!config->retry_delay) {
        per->retry_sleep *= 2;
        if(per->retry_sleep > RETRY_SLEEP_MAX)
          per->retry_sleep = RETRY_SLEEP_MAX;
      }
      if(outs->bytes && outs->filename && outs->stream) {
        /* We have written data to an output file, we truncate file
         */
        notef(config->global,
              "Throwing away %"  CURL_FORMAT_CURL_OFF_T " bytes",
              outs->bytes);
        fflush(outs->stream);
        /* truncate file at the position where we started appending */
#ifdef HAVE_FTRUNCATE
        if(ftruncate(fileno(outs->stream), outs->init)) {
          /* when truncate fails, we can't just append as then we'll
             create something strange, bail out */
          errorf(config->global, "Failed to truncate file");
          return CURLE_WRITE_ERROR;
        }
        /* now seek to the end of the file, the position where we
           just truncated the file in a large file-safe way */
        rc = fseek(outs->stream, 0, SEEK_END);
#else
        /* ftruncate is not available, so just reposition the file
           to the location we would have truncated it. This won't
           work properly with large files on 32-bit systems, but
           most of those will have ftruncate. */
        rc = fseek(outs->stream, (long)outs->init, SEEK_SET);
#endif
        if(rc) {
          errorf(config->global, "Failed seeking to end of file");
          return CURLE_WRITE_ERROR;
        }
        outs->bytes = 0; /* clear for next round */
      }
      *retryp = TRUE;

      *delay = sleeptime;
      return CURLE_OK;
    }
  } /* if retry_numretries */
noretry:

  if((global->progressmode == CURL_PROGRESS_BAR) &&
     per->progressbar.calls)
    /* if the custom progress bar has been displayed, we output a
       newline here */
    fputs("\n", per->progressbar.out);







|

|















|









|











>



|







640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
            }
          }
        }
      }
      warnf(config->global, "Problem %s. "
            "Will retry in %ld seconds. "
            "%ld retries left.",
            m[retry], sleeptime/1000L, per->retry_remaining);

      per->retry_remaining--;
      if(!config->retry_delay) {
        per->retry_sleep *= 2;
        if(per->retry_sleep > RETRY_SLEEP_MAX)
          per->retry_sleep = RETRY_SLEEP_MAX;
      }
      if(outs->bytes && outs->filename && outs->stream) {
        /* We have written data to an output file, we truncate file
         */
        notef(config->global,
              "Throwing away %"  CURL_FORMAT_CURL_OFF_T " bytes",
              outs->bytes);
        fflush(outs->stream);
        /* truncate file at the position where we started appending */
#ifdef HAVE_FTRUNCATE
        if(ftruncate(fileno(outs->stream), outs->init)) {
          /* when truncate fails, we cannot just append as then we will
             create something strange, bail out */
          errorf(config->global, "Failed to truncate file");
          return CURLE_WRITE_ERROR;
        }
        /* now seek to the end of the file, the position where we
           just truncated the file in a large file-safe way */
        rc = fseek(outs->stream, 0, SEEK_END);
#else
        /* ftruncate is not available, so just reposition the file
           to the location we would have truncated it. This will not
           work properly with large files on 32-bit systems, but
           most of those will have ftruncate. */
        rc = fseek(outs->stream, (long)outs->init, SEEK_SET);
#endif
        if(rc) {
          errorf(config->global, "Failed seeking to end of file");
          return CURLE_WRITE_ERROR;
        }
        outs->bytes = 0; /* clear for next round */
      }
      *retryp = TRUE;
      per->num_retries++;
      *delay = sleeptime;
      return CURLE_OK;
    }
  } /* if retry_remaining */
noretry:

  if((global->progressmode == CURL_PROGRESS_BAR) &&
     per->progressbar.calls)
    /* if the custom progress bar has been displayed, we output a
       newline here */
    fputs("\n", per->progressbar.out);
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
      if(!curl_url_set(uh, CURLUPART_URL, *url,
                       CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME) &&
         !curl_url_get(uh, CURLUPART_SCHEME, &schemep,
                       CURLU_DEFAULT_SCHEME)) {
        if(curl_strequal(schemep, proto_ipfs) ||
           curl_strequal(schemep, proto_ipns)) {
          result = ipfs_url_rewrite(uh, schemep, url, config);
          /* short-circuit proto_token, we know it's ipfs or ipns */
          if(curl_strequal(schemep, proto_ipfs))
            proto = proto_ipfs;
          else if(curl_strequal(schemep, proto_ipns))
            proto = proto_ipns;
          if(result)
            config->synthetic_error = TRUE;
        }







|







776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
      if(!curl_url_set(uh, CURLUPART_URL, *url,
                       CURLU_GUESS_SCHEME | CURLU_NON_SUPPORT_SCHEME) &&
         !curl_url_get(uh, CURLUPART_SCHEME, &schemep,
                       CURLU_DEFAULT_SCHEME)) {
        if(curl_strequal(schemep, proto_ipfs) ||
           curl_strequal(schemep, proto_ipns)) {
          result = ipfs_url_rewrite(uh, schemep, url, config);
          /* short-circuit proto_token, we know it is ipfs or ipns */
          if(curl_strequal(schemep, proto_ipfs))
            proto = proto_ipfs;
          else if(curl_strequal(schemep, proto_ipns))
            proto = proto_ipns;
          if(result)
            config->synthetic_error = TRUE;
        }
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
          }
        }

        if(((urlnode->flags&GETOUT_USEREMOTE) ||
            (per->outfile && strcmp("-", per->outfile)))) {

          /*
           * We have specified a file name to store the result in, or we have
           * decided we want to use the remote file name.
           */

          if(!per->outfile) {
            /* extract the file name from the URL */
            result = get_url_file_name(&per->outfile, per->this_url);
            if(result) {
              errorf(global, "Failed to extract a sensible file name"
                     " from the URL to use for storage");
              break;
            }
            if(!*per->outfile && !config->content_disposition) {
              errorf(global, "Remote file name has no length");
              result = CURLE_WRITE_ERROR;
              break;
            }
          }
          else if(state->urls) {
            /* fill '#1' ... '#9' terms from URL pattern */
            char *storefile = per->outfile;







|
|



|


|




|







1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
          }
        }

        if(((urlnode->flags&GETOUT_USEREMOTE) ||
            (per->outfile && strcmp("-", per->outfile)))) {

          /*
           * We have specified a filename to store the result in, or we have
           * decided we want to use the remote filename.
           */

          if(!per->outfile) {
            /* extract the filename from the URL */
            result = get_url_file_name(&per->outfile, per->this_url);
            if(result) {
              errorf(global, "Failed to extract a sensible filename"
                     " from the URL to use for storage");
              break;
            }
            if(!*per->outfile && !config->content_disposition) {
              errorf(global, "Remote filename has no length");
              result = CURLE_WRITE_ERROR;
              break;
            }
          }
          else if(state->urls) {
            /* fill '#1' ... '#9' terms from URL pattern */
            char *storefile = per->outfile;
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
          if((urlnode->flags & GETOUT_USEREMOTE)
             && config->content_disposition) {
            /* Our header callback MIGHT set the filename */
            DEBUGASSERT(!outs->filename);
          }

          if(config->resume_from_current) {
            /* We're told to continue from where we are now. Get the size
               of the file as it is now and open it for append instead */
            struct_stat fileinfo;
            /* VMS -- Danger, the filesize is only valid for stream files */
            if(0 == stat(per->outfile, &fileinfo))
              /* set offset to current file size: */
              config->resume_from = fileinfo.st_size;
            else







|







1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
          if((urlnode->flags & GETOUT_USEREMOTE)
             && config->content_disposition) {
            /* Our header callback MIGHT set the filename */
            DEBUGASSERT(!outs->filename);
          }

          if(config->resume_from_current) {
            /* We are told to continue from where we are now. Get the size
               of the file as it is now and open it for append instead */
            struct_stat fileinfo;
            /* VMS -- Danger, the filesize is only valid for stream files */
            if(0 == stat(per->outfile, &fileinfo))
              /* set offset to current file size: */
              config->resume_from = fileinfo.st_size;
            else
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
            FILE *file = fopen(outfile, "ab",
                               "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0");
#else
            /* open file for output: */
            FILE *file = fopen(per->outfile, "ab");
#endif
            if(!file) {
              errorf(global, "Can't open '%s'", per->outfile);
              result = CURLE_WRITE_ERROR;
              break;
            }
            outs->fopened = TRUE;
            outs->stream = file;
            outs->init = config->resume_from;
          }
          else {
            outs->stream = NULL; /* open when needed */
          }
          outs->filename = per->outfile;
          outs->s_isreg = TRUE;
        }

        if(per->uploadfile && !stdin_upload(per->uploadfile)) {
          /*
           * We have specified a file to upload and it isn't "-".
           */
          result = add_file_name_to_url(per->curl, &per->this_url,
                                        per->uploadfile);
          if(result)
            break;
        }
        else if(per->uploadfile && stdin_upload(per->uploadfile)) {
          /* count to see if there are more than one auth bit set
             in the authtype field */
          int authbits = 0;
          int bitcheck = 0;
          while(bitcheck < 32) {
            if(config->authtype & (1UL << bitcheck++)) {
              authbits++;
              if(authbits > 1) {
                /* more than one, we're done! */
                break;
              }
            }
          }

          /*
           * If the user has also selected --anyauth or --proxy-anyauth







|
















|















|







1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
            FILE *file = fopen(outfile, "ab",
                               "ctx=stm", "rfm=stmlf", "rat=cr", "mrs=0");
#else
            /* open file for output: */
            FILE *file = fopen(per->outfile, "ab");
#endif
            if(!file) {
              errorf(global, "cannot open '%s'", per->outfile);
              result = CURLE_WRITE_ERROR;
              break;
            }
            outs->fopened = TRUE;
            outs->stream = file;
            outs->init = config->resume_from;
          }
          else {
            outs->stream = NULL; /* open when needed */
          }
          outs->filename = per->outfile;
          outs->s_isreg = TRUE;
        }

        if(per->uploadfile && !stdin_upload(per->uploadfile)) {
          /*
           * We have specified a file to upload and it is not "-".
           */
          result = add_file_name_to_url(per->curl, &per->this_url,
                                        per->uploadfile);
          if(result)
            break;
        }
        else if(per->uploadfile && stdin_upload(per->uploadfile)) {
          /* count to see if there are more than one auth bit set
             in the authtype field */
          int authbits = 0;
          int bitcheck = 0;
          while(bitcheck < 32) {
            if(config->authtype & (1UL << bitcheck++)) {
              authbits++;
              if(authbits > 1) {
                /* more than one, we are done! */
                break;
              }
            }
          }

          /*
           * If the user has also selected --anyauth or --proxy-anyauth
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293




1294
1295
1296
1297
1298
1299
1300
          (per->outfile && !strcmp(per->outfile, "-"));

        /* Avoid having this setopt added to the --libcurl source output. */
        result = curl_easy_setopt(curl, CURLOPT_SHARE, share);
        if(result)
          break;

        /* result is only used when for ipfs and ipns, ignored otherwise */
        result = url_proto(&per->this_url, config, &use_proto);
        if(result && (use_proto == proto_ipfs || use_proto == proto_ipns))
          break;

#ifndef DEBUGBUILD
        /* On most modern OSes, exiting works thoroughly,
           we'll clean everything up via exit(), so don't bother with
           slow cleanups. Crappy ones might need to skip this.
           Note: avoid having this setopt added to the --libcurl source
           output. */
        result = curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
        if(result)
          break;
#endif

        if(!config->tcp_nodelay)
          my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);

        if(config->tcp_fastopen)
          my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);





        /* where to store */
        my_setopt(curl, CURLOPT_WRITEDATA, per);
        my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);

        /* what call to write */
        my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);








<

|




|














>
>
>
>







1334
1335
1336
1337
1338
1339
1340

1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
          (per->outfile && !strcmp(per->outfile, "-"));

        /* Avoid having this setopt added to the --libcurl source output. */
        result = curl_easy_setopt(curl, CURLOPT_SHARE, share);
        if(result)
          break;


        result = url_proto(&per->this_url, config, &use_proto);
        if(result)
          break;

#ifndef DEBUGBUILD
        /* On most modern OSes, exiting works thoroughly,
           we will clean everything up via exit(), so do not bother with
           slow cleanups. Crappy ones might need to skip this.
           Note: avoid having this setopt added to the --libcurl source
           output. */
        result = curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
        if(result)
          break;
#endif

        if(!config->tcp_nodelay)
          my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);

        if(config->tcp_fastopen)
          my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);

        if(config->mptcp)
          my_setopt(curl, CURLOPT_OPENSOCKETFUNCTION,
                    tool_socket_open_mptcp_cb);

        /* where to store */
        my_setopt(curl, CURLOPT_WRITEDATA, per);
        my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);

        /* what call to write */
        my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb);

1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325

        /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
           CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
        my_setopt(curl, CURLOPT_SEEKDATA, per);
        my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);

        {
#ifdef CURLDEBUG
          char *env = getenv("CURL_BUFFERSIZE");
          if(env) {
            long size = strtol(env, NULL, 10);
            if(size)
              my_setopt(curl, CURLOPT_BUFFERSIZE, size);
          }
          else







|







1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397

        /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
           CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
        my_setopt(curl, CURLOPT_SEEKDATA, per);
        my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);

        {
#ifdef DEBUGBUILD
          char *env = getenv("CURL_BUFFERSIZE");
          if(env) {
            long size = strtol(env, NULL, 10);
            if(size)
              my_setopt(curl, CURLOPT_BUFFERSIZE, size);
          }
          else
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
          }

          /* In debug build of curl tool, using
           *    --cert loadmem=<filename>:<password> --cert-type p12
           *  must do the same thing as classic:
           *    --cert <filename>:<password> --cert-type p12
           *  but is designed to test blob */
#if defined(CURLDEBUG) || defined(DEBUGBUILD)
          if(config->cert && (strlen(config->cert) > 8) &&
             (memcmp(config->cert, "loadmem=",8) == 0)) {
            FILE *fInCert = fopen(config->cert + 8, "rb");
            void *certdata = NULL;
            long filesize = 0;
            bool continue_reading = fInCert != NULL;
            if(continue_reading)







|







1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
          }

          /* In debug build of curl tool, using
           *    --cert loadmem=<filename>:<password> --cert-type p12
           *  must do the same thing as classic:
           *    --cert <filename>:<password> --cert-type p12
           *  but is designed to test blob */
#ifdef DEBUGBUILD
          if(config->cert && (strlen(config->cert) > 8) &&
             (memcmp(config->cert, "loadmem=",8) == 0)) {
            FILE *fInCert = fopen(config->cert + 8, "rb");
            void *certdata = NULL;
            long filesize = 0;
            bool continue_reading = fInCert != NULL;
            if(continue_reading)
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
              fclose(fInCert);
            if((filesize > 0) && continue_reading) {
              struct curl_blob structblob;
              structblob.data = certdata;
              structblob.len = (size_t)filesize;
              structblob.flags = CURL_BLOB_COPY;
              my_setopt_str(curl, CURLOPT_SSLCERT_BLOB, &structblob);
              /* if test run well, we are sure we don't reuse
               * original mem pointer */
              memset(certdata, 0, (size_t)filesize);
            }
            free(certdata);
          }
          else
#endif
          my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
          my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
          my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
          my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
                        config->proxy_cert_type);


#if defined(CURLDEBUG) || defined(DEBUGBUILD)
          if(config->key && (strlen(config->key) > 8) &&
             (memcmp(config->key, "loadmem=",8) == 0)) {
            FILE *fInCert = fopen(config->key + 8, "rb");
            void *certdata = NULL;
            long filesize = 0;
            bool continue_reading = fInCert != NULL;
            if(continue_reading)







|














|







1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
              fclose(fInCert);
            if((filesize > 0) && continue_reading) {
              struct curl_blob structblob;
              structblob.data = certdata;
              structblob.len = (size_t)filesize;
              structblob.flags = CURL_BLOB_COPY;
              my_setopt_str(curl, CURLOPT_SSLCERT_BLOB, &structblob);
              /* if test run well, we are sure we do not reuse
               * original mem pointer */
              memset(certdata, 0, (size_t)filesize);
            }
            free(certdata);
          }
          else
#endif
          my_setopt_str(curl, CURLOPT_SSLCERT, config->cert);
          my_setopt_str(curl, CURLOPT_PROXY_SSLCERT, config->proxy_cert);
          my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
          my_setopt_str(curl, CURLOPT_PROXY_SSLCERTTYPE,
                        config->proxy_cert_type);


#ifdef DEBUGBUILD
          if(config->key && (strlen(config->key) > 8) &&
             (memcmp(config->key, "loadmem=",8) == 0)) {
            FILE *fInCert = fopen(config->key + 8, "rb");
            void *certdata = NULL;
            long filesize = 0;
            bool continue_reading = fInCert != NULL;
            if(continue_reading)
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733


1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
              fclose(fInCert);
            if((filesize > 0) && continue_reading) {
              struct curl_blob structblob;
              structblob.data = certdata;
              structblob.len = (size_t)filesize;
              structblob.flags = CURL_BLOB_COPY;
              my_setopt_str(curl, CURLOPT_SSLKEY_BLOB, &structblob);
              /* if test run well, we are sure we don't reuse
               * original mem pointer */
              memset(certdata, 0, (size_t)filesize);
            }
            free(certdata);
          }
          else
#endif
          my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
          my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
          my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
          my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
                        config->proxy_key_type);


          if(config->insecure_ok) {
            my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
            my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
          }
          else {
            my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
            /* libcurl default is strict verifyhost -> 2L   */
            /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
          }

          if(config->doh_insecure_ok) {
            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0L);
            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0L);
          }

          if(config->proxy_insecure_ok) {
            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
          }
          else {
            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
          }

          if(config->verifystatus)
            my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);

          if(config->doh_verifystatus)
            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1L);








|












>
>




<
<
<
<
<










<
<
<







1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811





1812
1813
1814
1815
1816
1817
1818
1819
1820
1821



1822
1823
1824
1825
1826
1827
1828
              fclose(fInCert);
            if((filesize > 0) && continue_reading) {
              struct curl_blob structblob;
              structblob.data = certdata;
              structblob.len = (size_t)filesize;
              structblob.flags = CURL_BLOB_COPY;
              my_setopt_str(curl, CURLOPT_SSLKEY_BLOB, &structblob);
              /* if test run well, we are sure we do not reuse
               * original mem pointer */
              memset(certdata, 0, (size_t)filesize);
            }
            free(certdata);
          }
          else
#endif
          my_setopt_str(curl, CURLOPT_SSLKEY, config->key);
          my_setopt_str(curl, CURLOPT_PROXY_SSLKEY, config->proxy_key);
          my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
          my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
                        config->proxy_key_type);

          /* libcurl default is strict verifyhost -> 1L, verifypeer -> 1L */
          if(config->insecure_ok) {
            my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
            my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
          }






          if(config->doh_insecure_ok) {
            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0L);
            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYHOST, 0L);
          }

          if(config->proxy_insecure_ok) {
            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
            my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
          }




          if(config->verifystatus)
            my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);

          if(config->doh_verifystatus)
            my_setopt(curl, CURLOPT_DOH_SSL_VERIFYSTATUS, 1L);

2039
2040
2041
2042
2043
2044
2045


2046
2047
2048
2049
2050
2051
2052
        /* curl 7.17.1 */
        if(!config->nokeepalive) {
          my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
          if(config->alivetime) {
            my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
            my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
          }


        }
        else
          my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);

        /* curl 7.20.0 */
        if(config->tftp_blksize && proto_tftp)
          my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);







>
>







2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
        /* curl 7.17.1 */
        if(!config->nokeepalive) {
          my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
          if(config->alivetime) {
            my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
            my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
          }
          if(config->alivecnt)
            my_setopt(curl, CURLOPT_TCP_KEEPCNT, config->alivecnt);
        }
        else
          my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);

        /* curl 7.20.0 */
        if(config->tftp_blksize && proto_tftp)
          my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
2192
2193
2194
2195
2196
2197
2198



















2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
        if(config->ech) /* only if set (optional) */
          my_setopt_str(curl, CURLOPT_ECH, config->ech);
        if(config->ech_public) /* only if set (optional) */
          my_setopt_str(curl, CURLOPT_ECH, config->ech_public);
        if(config->ech_config) /* only if set (optional) */
          my_setopt_str(curl, CURLOPT_ECH, config->ech_config);
#endif




















        /* initialize retry vars for loop below */
        per->retry_sleep_default = (config->retry_delay) ?
          config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
        per->retry_numretries = config->req_retry;
        per->retry_sleep = per->retry_sleep_default; /* ms */
        per->retrystart = tvnow();

        state->li++;
        /* Here's looping around each globbed URL */
        if(state->li >= urlnum) {
          state->li = 0;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|







2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
        if(config->ech) /* only if set (optional) */
          my_setopt_str(curl, CURLOPT_ECH, config->ech);
        if(config->ech_public) /* only if set (optional) */
          my_setopt_str(curl, CURLOPT_ECH, config->ech_public);
        if(config->ech_config) /* only if set (optional) */
          my_setopt_str(curl, CURLOPT_ECH, config->ech_config);
#endif

        /* new in 8.9.0 */
        if(config->ip_tos > 0 || config->vlan_priority > 0) {
#if defined(IP_TOS) || defined(IPV6_TCLASS) || defined(SO_PRIORITY)
          my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
          my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
#else
          if(config->ip_tos > 0) {
            errorf(config->global,
                  "Type of service is not supported in this build.");
            result = CURLE_NOT_BUILT_IN;
          }
          if(config->vlan_priority > 0) {
            errorf(config->global,
                  "VLAN priority is not supported in this build.");
            result = CURLE_NOT_BUILT_IN;
          }
#endif
        }

        /* initialize retry vars for loop below */
        per->retry_sleep_default = (config->retry_delay) ?
          config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
        per->retry_remaining = config->req_retry;
        per->retry_sleep = per->retry_sleep_default; /* ms */
        per->retrystart = tvnow();

        state->li++;
        /* Here's looping around each globbed URL */
        if(state->li >= urlnum) {
          state->li = 0;
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
    if(result)
      return result;

    errorbuf = malloc(CURL_ERROR_SIZE);
    if(!errorbuf)
      return CURLE_OUT_OF_MEMORY;

    /* parallel connect means that we don't set PIPEWAIT since pipewait
       will make libcurl prefer multiplexing */
    (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT,
                           global->parallel_connect ? 0L : 1L);
    (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per);
    (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
    (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per);
    (void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L);







|







2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
    if(result)
      return result;

    errorbuf = malloc(CURL_ERROR_SIZE);
    if(!errorbuf)
      return CURLE_OUT_OF_MEMORY;

    /* parallel connect means that we do not set PIPEWAIT since pipewait
       will make libcurl prefer multiplexing */
    (void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT,
                           global->parallel_connect ? 0L : 1L);
    (void)curl_easy_setopt(per->curl, CURLOPT_PRIVATE, per);
    (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
    (void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per);
    (void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L);
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
        /* one or more transfers completed, add more! */
        CURLcode tres = add_parallel_transfers(global, multi, share,
                                               &more_transfers,
                                               &added_transfers);
        if(tres)
          result = tres;
        if(added_transfers)
          /* we added new ones, make sure the loop doesn't exit yet */
          still_running = 1;
      }
      if(is_fatal_error(result) || (result && global->fail_early))
        wrapitup = TRUE;
    }
  }








|







2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
        /* one or more transfers completed, add more! */
        CURLcode tres = add_parallel_transfers(global, multi, share,
                                               &more_transfers,
                                               &added_transfers);
        if(tres)
          result = tres;
        if(added_transfers)
          /* we added new ones, make sure the loop does not exit yet */
          still_running = 1;
      }
      if(is_fatal_error(result) || (result && global->fail_early))
        wrapitup = TRUE;
    }
  }

2486
2487
2488
2489
2490
2491
2492
2493



2494
2495
2496
2497
2498
2499
2500

    if(global->libcurl) {
      result = easysrc_perform();
      if(result)
        break;
    }
    start = tvnow();
#ifdef CURLDEBUG



    if(global->test_event_based)
      result = curl_easy_perform_ev(per->curl);
    else
#endif
      result = curl_easy_perform(per->curl);

    returncode = post_per_transfer(global, per, result, &retry, &delay_ms);







|
>
>
>







2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590

    if(global->libcurl) {
      result = easysrc_perform();
      if(result)
        break;
    }
    start = tvnow();
#ifdef DEBUGBUILD
    if(getenv("CURL_FORBID_REUSE"))
      (void)curl_easy_setopt(per->curl, CURLOPT_FORBID_REUSE, 1L);

    if(global->test_event_based)
      result = curl_easy_perform_ev(per->curl);
    else
#endif
      result = curl_easy_perform(per->curl);

    returncode = post_per_transfer(global, per, result, &retry, &delay_ms);
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571

  /* Check we have a url */
  if(!config->url_list || !config->url_list->url) {
    helpf(tool_stderr, "(%d) no URL specified", CURLE_FAILED_INIT);
    return CURLE_FAILED_INIT;
  }

  /* On WIN32 we can't set the path to curl-ca-bundle.crt
   * at compile time. So we look here for the file in two ways:
   * 1: look at the environment variable CURL_CA_BUNDLE for a path
   * 2: if #1 isn't found, use the windows API function SearchPath()
   *    to find it along the app's path (includes app's dir and CWD)
   *
   * We support the environment variable thing for non-Windows platforms
   * too. Just for the sake of it.
   */
  capath_from_env = false;
  if(!config->cacert &&







|
|

|







2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661

  /* Check we have a url */
  if(!config->url_list || !config->url_list->url) {
    helpf(tool_stderr, "(%d) no URL specified", CURLE_FAILED_INIT);
    return CURLE_FAILED_INIT;
  }

  /* On WIN32 we cannot set the path to curl-ca-bundle.crt at compile time. We
   * look for the file in two ways:
   * 1: look at the environment variable CURL_CA_BUNDLE for a path
   * 2: if #1 is not found, use the windows API function SearchPath()
   *    to find it along the app's path (includes app's dir and CWD)
   *
   * We support the environment variable thing for non-Windows platforms
   * too. Just for the sake of it.
   */
  capath_from_env = false;
  if(!config->cacert &&
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701

  /* cleanup if there are any left */
  for(per = transfers; per;) {
    bool retry;
    long delay;
    CURLcode result2 = post_per_transfer(global, per, result, &retry, &delay);
    if(!result)
      /* don't overwrite the original error */
      result = result2;

    /* Free list of given URLs */
    clean_getout(per->config);

    per = del_per_transfer(per);
  }







|







2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791

  /* cleanup if there are any left */
  for(per = transfers; per;) {
    bool retry;
    long delay;
    CURLcode result2 = post_per_transfer(global, per, result, &retry, &delay);
    if(!result)
      /* do not overwrite the original error */
      result = result2;

    /* Free list of given URLs */
    clean_getout(per->config);

    per = del_per_transfer(per);
  }
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
  setlocale(LC_ALL, "");
  setlocale(LC_NUMERIC, "C");
#endif

  /* Parse .curlrc if necessary */
  if((argc == 1) ||
     (first_arg && strncmp(first_arg, "-q", 2) &&
      !curl_strequal(first_arg, "--disable"))) {
    parseconfig(NULL, global); /* ignore possible failure */

    /* If we had no arguments then make sure a url was specified in .curlrc */
    if((argc < 2) && (!global->first->url_list)) {
      helpf(tool_stderr, NULL);
      result = CURLE_FAILED_INIT;
    }







|







2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
  setlocale(LC_ALL, "");
  setlocale(LC_NUMERIC, "C");
#endif

  /* Parse .curlrc if necessary */
  if((argc == 1) ||
     (first_arg && strncmp(first_arg, "-q", 2) &&
      strcmp(first_arg, "--disable"))) {
    parseconfig(NULL, global); /* ignore possible failure */

    /* If we had no arguments then make sure a url was specified in .curlrc */
    if((argc < 2) && (!global->first->url_list)) {
      helpf(tool_stderr, NULL);
      result = CURLE_FAILED_INIT;
    }
Changes to jni/curl/src/tool_operate.h.
31
32
33
34
35
36
37
38
39
40

41
42
43
44
45
46
47
struct per_transfer {
  /* double linked */
  struct per_transfer *next;
  struct per_transfer *prev;
  struct OperationConfig *config; /* for this transfer */
  struct curl_certinfo *certinfo;
  CURL *curl;
  long retry_numretries;
  long retry_sleep_default;
  long retry_sleep;

  struct timeval start; /* start of this transfer */
  struct timeval retrystart;
  char *this_url;
  unsigned int urlnum; /* the index of the given URL */
  char *outfile;
  bool infdopen; /* TRUE if infd needs closing */
  int infd;







|


>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
struct per_transfer {
  /* double linked */
  struct per_transfer *next;
  struct per_transfer *prev;
  struct OperationConfig *config; /* for this transfer */
  struct curl_certinfo *certinfo;
  CURL *curl;
  long retry_remaining;
  long retry_sleep_default;
  long retry_sleep;
  long num_retries; /* counts the performed retries */
  struct timeval start; /* start of this transfer */
  struct timeval retrystart;
  char *this_url;
  unsigned int urlnum; /* the index of the given URL */
  char *outfile;
  bool infdopen; /* TRUE if infd needs closing */
  int infd;
Changes to jni/curl/src/tool_operhlp.c.
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
    return CURLE_NOT_BUILT_IN;
  else if(ucode == CURLUE_BAD_HANDLE)
    return CURLE_BAD_FUNCTION_ARGUMENT;
  return CURLE_URL_MALFORMAT;
}

/*
 * Adds the file name to the URL if it doesn't already have one.
 * url will be freed before return if the returned pointer is different
 */
CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
{
  CURLcode result = CURLE_URL_MALFORMAT;
  CURLUcode uerr;
  CURLU *uh = curl_url();







|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
    return CURLE_NOT_BUILT_IN;
  else if(ucode == CURLUE_BAD_HANDLE)
    return CURLE_BAD_FUNCTION_ARGUMENT;
  return CURLE_URL_MALFORMAT;
}

/*
 * Adds the filename to the URL if it does not already have one.
 * url will be freed before return if the returned pointer is different
 */
CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
{
  CURLcode result = CURLE_URL_MALFORMAT;
  CURLUcode uerr;
  CURLU *uh = curl_url();
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
      curl_free(query);
      curl_free(path);
      curl_url_cleanup(uh);
      return CURLE_OK;
    }
    ptr = strrchr(path, '/');
    if(!ptr || !*++ptr) {
      /* The URL path has no file name part, add the local file name. In order
         to be able to do so, we have to create a new URL in another buffer.*/

      /* We only want the part of the local path that is on the right
         side of the rightmost slash and backslash. */
      const char *filep = strrchr(filename, '/');
      char *file2 = strrchr(filep?filep:filename, '\\');
      char *encfile;

      if(file2)
        filep = file2 + 1;
      else if(filep)
        filep++;
      else
        filep = filename;

      /* URL encode the file name */
      encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
      if(encfile) {
        char *newpath;
        char *newurl;
        if(ptr)
          /* there is a trailing slash on the path */
          newpath = aprintf("%s%s", path, encfile);







|















|







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
      curl_free(query);
      curl_free(path);
      curl_url_cleanup(uh);
      return CURLE_OK;
    }
    ptr = strrchr(path, '/');
    if(!ptr || !*++ptr) {
      /* The URL path has no filename part, add the local filename. In order
         to be able to do so, we have to create a new URL in another buffer.*/

      /* We only want the part of the local path that is on the right
         side of the rightmost slash and backslash. */
      const char *filep = strrchr(filename, '/');
      char *file2 = strrchr(filep?filep:filename, '\\');
      char *encfile;

      if(file2)
        filep = file2 + 1;
      else if(filep)
        filep++;
      else
        filep = filename;

      /* URL encode the filename */
      encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
      if(encfile) {
        char *newpath;
        char *newurl;
        if(ptr)
          /* there is a trailing slash on the path */
          newpath = aprintf("%s%s", path, encfile);
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
          return CURLE_URL_MALFORMAT;
        }
        *filename = sanitized;
      }
#endif /* _WIN32 || MSDOS */

      /* in case we built debug enabled, we allow an environment variable
       * named CURL_TESTDIR to prefix the given file name to put it into a
       * specific directory
       */
#ifdef DEBUGBUILD
      {
        char *tdir = curl_getenv("CURL_TESTDIR");
        if(tdir) {
          char *alt = aprintf("%s/%s", tdir, *filename);







|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
          return CURLE_URL_MALFORMAT;
        }
        *filename = sanitized;
      }
#endif /* _WIN32 || MSDOS */

      /* in case we built debug enabled, we allow an environment variable
       * named CURL_TESTDIR to prefix the given filename to put it into a
       * specific directory
       */
#ifdef DEBUGBUILD
      {
        char *tdir = curl_getenv("CURL_TESTDIR");
        if(tdir) {
          char *alt = aprintf("%s/%s", tdir, *filename);
Changes to jni/curl/src/tool_paramhlp.c.
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  for(; *val; val++) {
    const char *p = proto_token(*val);

    if(p)
      protoset_set(protoset, p);
  }

  /* Allow strtok() here since this isn't used threaded */
  /* !checksrc! disable BANNEDFUNC 2 */
  for(token = strtok(buffer, sep);
      token;
      token = strtok(NULL, sep)) {
    enum e_action { allow, deny, set } action = allow;

    /* Process token modifiers */







|







395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  for(; *val; val++) {
    const char *p = proto_token(*val);

    if(p)
      protoset_set(protoset, p);
  }

  /* Allow strtok() here since this is not used threaded */
  /* !checksrc! disable BANNEDFUNC 2 */
  for(token = strtok(buffer, sep);
      token;
      token = strtok(NULL, sep)) {
    enum e_action { allow, deny, set } action = allow;

    /* Process token modifiers */
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
 * @param str  the buffer containing the offset
 * @return PARAM_OK if successful, a parameter specific error enum if failure.
 */
ParameterError str2offset(curl_off_t *val, const char *str)
{
  char *endptr;
  if(str[0] == '-')
    /* offsets aren't negative, this indicates weird input */
    return PARAM_NEGATIVE_NUMERIC;

#if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
  {
    CURLofft offt = curlx_strtoofft(str, &endptr, 10, val);
    if(CURL_OFFT_FLOW == offt)
      return PARAM_NUMBER_TOO_LARGE;







|







504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
 * @param str  the buffer containing the offset
 * @return PARAM_OK if successful, a parameter specific error enum if failure.
 */
ParameterError str2offset(curl_off_t *val, const char *str)
{
  char *endptr;
  if(str[0] == '-')
    /* offsets are not negative, this indicates weird input */
    return PARAM_NEGATIVE_NUMERIC;

#if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
  {
    CURLofft offt = curlx_strtoofft(str, &endptr, 10, val);
    if(CURL_OFFT_FLOW == offt)
      return PARAM_NUMBER_TOO_LARGE;
Changes to jni/curl/src/tool_parsecfg.c.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
static bool my_get_line(FILE *fp, struct curlx_dynbuf *, bool *error);

#ifdef _WIN32
static FILE *execpath(const char *filename, char **pathp)
{
  static char filebuffer[512];
  /* Get the filename of our executable. GetModuleFileName is already declared
   * via inclusions done in setup header file.  We assume that we are using
   * the ASCII version here.
   */
  unsigned long len = GetModuleFileNameA(0, filebuffer, sizeof(filebuffer));
  if(len > 0 && len < sizeof(filebuffer)) {
    /* We got a valid filename - get the directory part */
    char *lastdirchar = strrchr(filebuffer, '\\');
    if(lastdirchar) {







|







47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
static bool my_get_line(FILE *fp, struct curlx_dynbuf *, bool *error);

#ifdef _WIN32
static FILE *execpath(const char *filename, char **pathp)
{
  static char filebuffer[512];
  /* Get the filename of our executable. GetModuleFileName is already declared
   * via inclusions done in setup header file. We assume that we are using
   * the ASCII version here.
   */
  unsigned long len = GetModuleFileNameA(0, filebuffer, sizeof(filebuffer));
  if(len > 0 && len < sizeof(filebuffer)) {
    /* We got a valid filename - get the directory part */
    char *lastdirchar = strrchr(filebuffer, '\\');
    if(lastdirchar) {
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
        param = line; /* parameter starts here */
        while(*line && !ISSPACE(*line))
          line++;

        if(*line) {
          *line = '\0'; /* null-terminate */

          /* to detect mistakes better, see if there's data following */
          line++;
          /* pass all spaces */
          while(*line && ISSPACE(*line))
            line++;

          switch(*line) {
          case '\0':
          case '\r':
          case '\n':
          case '#': /* comment */
            break;
          default:
            warnf(operation->global, "%s:%d: warning: '%s' uses unquoted "
                  "whitespace", filename, lineno, option);
            warnf(operation->global, "This may cause side-effects. "
                  "Consider using double quotes?");
          }
        }
        if(!*param)
          /* do this so getparameter can check for required parameters.
             Otherwise it always thinks there's a parameter. */
          param = NULL;
      }

#ifdef DEBUG_CONFIG
      fprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
#endif
      res = getparameter(option, param, NULL, &usedarg, global, operation);
      operation = global->last;

      if(!res && param && *param && !usedarg)
        /* we passed in a parameter that wasn't used! */
        res = PARAM_GOT_EXTRA_PARAMETER;

      if(res == PARAM_NEXT_OPERATION) {
        if(operation->url_list && operation->url_list->url) {
          /* Allocate the next config */
          operation->next = malloc(sizeof(struct OperationConfig));
          if(operation->next) {







|




















|










|







192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
        param = line; /* parameter starts here */
        while(*line && !ISSPACE(*line))
          line++;

        if(*line) {
          *line = '\0'; /* null-terminate */

          /* to detect mistakes better, see if there is data following */
          line++;
          /* pass all spaces */
          while(*line && ISSPACE(*line))
            line++;

          switch(*line) {
          case '\0':
          case '\r':
          case '\n':
          case '#': /* comment */
            break;
          default:
            warnf(operation->global, "%s:%d: warning: '%s' uses unquoted "
                  "whitespace", filename, lineno, option);
            warnf(operation->global, "This may cause side-effects. "
                  "Consider using double quotes?");
          }
        }
        if(!*param)
          /* do this so getparameter can check for required parameters.
             Otherwise it always thinks there is a parameter. */
          param = NULL;
      }

#ifdef DEBUG_CONFIG
      fprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
#endif
      res = getparameter(option, param, NULL, &usedarg, global, operation);
      operation = global->last;

      if(!res && param && *param && !usedarg)
        /* we passed in a parameter that was not used! */
        res = PARAM_GOT_EXTRA_PARAMETER;

      if(res == PARAM_NEXT_OPERATION) {
        if(operation->url_list && operation->url_list->url) {
          /* Allocate the next config */
          operation->next = malloc(sizeof(struct OperationConfig));
          if(operation->next) {
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
          }
          else
            res = PARAM_NO_MEM;
        }
      }

      if(res != PARAM_OK && res != PARAM_NEXT_OPERATION) {
        /* the help request isn't really an error */
        if(!strcmp(filename, "-")) {
          filename = "<stdin>";
        }
        if(res != PARAM_HELP_REQUESTED &&
           res != PARAM_MANUAL_REQUESTED &&
           res != PARAM_VERSION_INFO_REQUESTED &&
           res != PARAM_ENGINES_REQUESTED) {







|







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
          }
          else
            res = PARAM_NO_MEM;
        }
      }

      if(res != PARAM_OK && res != PARAM_NEXT_OPERATION) {
        /* the help request is not really an error */
        if(!strcmp(filename, "-")) {
          filename = "<stdin>";
        }
        if(res != PARAM_HELP_REQUESTED &&
           res != PARAM_MANUAL_REQUESTED &&
           res != PARAM_VERSION_INFO_REQUESTED &&
           res != PARAM_ENGINES_REQUESTED) {
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    curlx_dyn_free(&buf);
    if(file != stdin)
      fclose(file);
    if(fileerror)
      rc = 1;
  }
  else
    rc = 1; /* couldn't open the file */

  free(pathalloc);
  return rc;
}

/*
 * Copies the string from line to the buffer at param, unquoting
 * backslash-quoted characters and NUL-terminating the output string.
 * Stops at the first non-backslash-quoted double quote character or the
 * end of the input string. param must be at least as long as the input
 * string.  Returns the pointer after the last handled input character.
 */
static const char *unslashquote(const char *line, char *param)
{
  while(*line && (*line != '\"')) {
    if(*line == '\\') {
      char out;
      line++;







|










|







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    curlx_dyn_free(&buf);
    if(file != stdin)
      fclose(file);
    if(fileerror)
      rc = 1;
  }
  else
    rc = 1; /* could not open the file */

  free(pathalloc);
  return rc;
}

/*
 * Copies the string from line to the buffer at param, unquoting
 * backslash-quoted characters and NUL-terminating the output string.
 * Stops at the first non-backslash-quoted double quote character or the
 * end of the input string. param must be at least as long as the input
 * string. Returns the pointer after the last handled input character.
 */
static const char *unslashquote(const char *line, char *param)
{
  while(*line && (*line != '\"')) {
    if(*line == '\\') {
      char out;
      line++;
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
{
  char buf[4096];
  *error = FALSE;
  do {
    /* fgets() returns s on success, and NULL on error or when end of file
       occurs while no characters have been read. */
    if(!fgets(buf, sizeof(buf), fp))
      /* only if there's data in the line, return TRUE */
      return curlx_dyn_len(db) ? TRUE : FALSE;
    if(curlx_dyn_add(db, buf)) {
      *error = TRUE; /* error */
      return FALSE; /* stop reading */
    }
  } while(!strchr(buf, '\n'));

  return TRUE; /* continue */
}







|









337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
{
  char buf[4096];
  *error = FALSE;
  do {
    /* fgets() returns s on success, and NULL on error or when end of file
       occurs while no characters have been read. */
    if(!fgets(buf, sizeof(buf), fp))
      /* only if there is data in the line, return TRUE */
      return curlx_dyn_len(db) ? TRUE : FALSE;
    if(curlx_dyn_add(db, buf)) {
      *error = TRUE; /* error */
      return FALSE; /* stop reading */
    }
  } while(!strchr(buf, '\n'));

  return TRUE; /* continue */
}
Changes to jni/curl/src/tool_progress.c.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  if(bytes < CURL_OFF_T_C(100000))
    msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);

  else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);

  else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
    /* 'XX.XM' is good as long as we're less than 100 megs */
    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
              CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
              (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );

  else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
    /* 'XXXXM' is good until we're at 10000MB or above */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);

  else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
    /* 10000 MB - 100 GB, we show it as XX.XG */
    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
              CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
              (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );

  else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
    /* up to 10000GB, display without decimal: XXXXG */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);

  else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
    /* up to 10000TB, display without decimal: XXXXT */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);

  else
    /* up to 10000PB, display without decimal: XXXXP */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);

  /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can
     hold, but our data type is signed so 8192PB will be the maximum. */
  return max5;
}

int xferinfo_cb(void *clientp,
                curl_off_t dltotal,
                curl_off_t dlnow,







|





|




















|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  if(bytes < CURL_OFF_T_C(100000))
    msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);

  else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);

  else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
    /* 'XX.XM' is good as long as we are less than 100 megs */
    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
              CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
              (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );

  else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
    /* 'XXXXM' is good until we are at 10000MB or above */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);

  else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
    /* 10000 MB - 100 GB, we show it as XX.XG */
    msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
              CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
              (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );

  else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
    /* up to 10000GB, display without decimal: XXXXG */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);

  else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
    /* up to 10000TB, display without decimal: XXXXT */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);

  else
    /* up to 10000PB, display without decimal: XXXXP */
    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);

  /* 16384 petabytes (16 exabytes) is the maximum a 64-bit unsigned number can
     hold, but our data type is signed so 8192PB will be the maximum. */
  return max5;
}

int xferinfo_cb(void *clientp,
                curl_off_t dltotal,
                curl_off_t dlnow,
Changes to jni/curl/src/tool_sdecls.h.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 ***************************************************************************/
#include "tool_setup.h"

/*
 * OutStruct variables keep track of information relative to curl's
 * output writing, which may take place to a standard stream or a file.
 *
 * 'filename' member is either a pointer to a file name string or NULL
 * when dealing with a standard stream.
 *
 * 'alloc_filename' member is TRUE when string pointed by 'filename' has been
 * dynamically allocated and 'belongs' to this OutStruct, otherwise FALSE.
 *
 * 'is_cd_filename' member is TRUE when string pointed by 'filename' has been
 * set using a server-specified Content-Disposition filename, otherwise FALSE.
 *
 * 's_isreg' member is TRUE when output goes to a regular file, this also
 * implies that output is 'seekable' and 'appendable' and also that member
 * 'filename' points to file name's string. For any standard stream member
 * 's_isreg' will be FALSE.
 *
 * 'fopened' member is TRUE when output goes to a regular file and it
 * has been fopen'ed, requiring it to be closed later on. In any other
 * case this is FALSE.
 *
 * 'stream' member is a pointer to a stream controlling object as returned







|










|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 ***************************************************************************/
#include "tool_setup.h"

/*
 * OutStruct variables keep track of information relative to curl's
 * output writing, which may take place to a standard stream or a file.
 *
 * 'filename' member is either a pointer to a filename string or NULL
 * when dealing with a standard stream.
 *
 * 'alloc_filename' member is TRUE when string pointed by 'filename' has been
 * dynamically allocated and 'belongs' to this OutStruct, otherwise FALSE.
 *
 * 'is_cd_filename' member is TRUE when string pointed by 'filename' has been
 * set using a server-specified Content-Disposition filename, otherwise FALSE.
 *
 * 's_isreg' member is TRUE when output goes to a regular file, this also
 * implies that output is 'seekable' and 'appendable' and also that member
 * 'filename' points to filename's string. For any standard stream member
 * 's_isreg' will be FALSE.
 *
 * 'fopened' member is TRUE when output goes to a regular file and it
 * has been fopen'ed, requiring it to be closed later on. In any other
 * case this is FALSE.
 *
 * 'stream' member is a pointer to a stream controlling object as returned
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  char          *infile;    /* file to upload, if GETOUT_UPLOAD is set */
  int            flags;     /* options - composed of GETOUT_* bits */
  int            num;       /* which URL number in an invocation */
};

#define GETOUT_OUTFILE    (1<<0)  /* set when outfile is deemed done */
#define GETOUT_URL        (1<<1)  /* set when URL is deemed done */
#define GETOUT_USEREMOTE  (1<<2)  /* use remote file name locally */
#define GETOUT_UPLOAD     (1<<3)  /* if set, -T has been used */
#define GETOUT_NOUPLOAD   (1<<4)  /* if set, -T "" has been used */

/*
 * 'trace' enumeration represents curl's output look'n feel possibilities.
 */








|







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  char          *infile;    /* file to upload, if GETOUT_UPLOAD is set */
  int            flags;     /* options - composed of GETOUT_* bits */
  int            num;       /* which URL number in an invocation */
};

#define GETOUT_OUTFILE    (1<<0)  /* set when outfile is deemed done */
#define GETOUT_URL        (1<<1)  /* set when URL is deemed done */
#define GETOUT_USEREMOTE  (1<<2)  /* use remote filename locally */
#define GETOUT_UPLOAD     (1<<3)  /* if set, -T has been used */
#define GETOUT_NOUPLOAD   (1<<4)  /* if set, -T "" has been used */

/*
 * 'trace' enumeration represents curl's output look'n feel possibilities.
 */

Changes to jni/curl/src/tool_setopt.c.
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#define CLEAN0(s) ADD((&easysrc_clean, s))
#define CLEAN1(f,a) ADDF((&easysrc_clean, f,a))

#define REM0(s) ADD((&easysrc_toohard, s))
#define REM1(f,a) ADDF((&easysrc_toohard, f,a))
#define REM3(f,a,b,c) ADDF((&easysrc_toohard, f,a,b,c))

/* Escape string to C string syntax.  Return NULL if out of memory.
 * Is this correct for those wacky EBCDIC guys? */

#define MAX_STRING_LENGTH_OUTPUT 2000
#define ZERO_TERMINATED -1

static char *c_escape(const char *str, curl_off_t len)
{







|







203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
#define CLEAN0(s) ADD((&easysrc_clean, s))
#define CLEAN1(f,a) ADDF((&easysrc_clean, f,a))

#define REM0(s) ADD((&easysrc_toohard, s))
#define REM1(f,a) ADDF((&easysrc_toohard, f,a))
#define REM3(f,a,b,c) ADDF((&easysrc_toohard, f,a,b,c))

/* Escape string to C string syntax. Return NULL if out of memory.
 * Is this correct for those wacky EBCDIC guys? */

#define MAX_STRING_LENGTH_OUTPUT 2000
#define ZERO_TERMINATED -1

static char *c_escape(const char *str, curl_off_t len)
{
Changes to jni/curl/src/tool_urlglob.c.
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#if defined(__GNUC__) && \
  ((__GNUC__ > 5) || ((__GNUC__ == 5) && (__GNUC_MINOR__ >= 1)))
    if(__builtin_mul_overflow(*amount, with, &sum))
      return 1;
#else
    sum = *amount * with;
    if(sum/with != *amount)
      return 1; /* didn't fit, bail out */
#endif
  }
  *amount = sum;
  return 0;
}

static CURLcode glob_set(struct URLGlob *glob, char **patternp,







|







76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#if defined(__GNUC__) && \
  ((__GNUC__ > 5) || ((__GNUC__ == 5) && (__GNUC_MINOR__ >= 1)))
    if(__builtin_mul_overflow(*amount, with, &sum))
      return 1;
#else
    sum = *amount * with;
    if(sum/with != *amount)
      return 1; /* did not fit, bail out */
#endif
  }
  *amount = sum;
  return 0;
}

static CURLcode glob_set(struct URLGlob *glob, char **patternp,
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
      return GLOBERROR("nested brace", *posp, CURLE_URL_MALFORMAT);

    case '}':                           /* set element completed */
      if(opattern == pattern)
        return GLOBERROR("empty string within braces", *posp,
                         CURLE_URL_MALFORMAT);

      /* add 1 to size since it'll be incremented below */
      if(multiply(amount, pat->content.Set.size + 1))
        return GLOBERROR("range overflow", 0, CURLE_URL_MALFORMAT);

      FALLTHROUGH();
    case ',':

      *buf = '\0';







|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
      return GLOBERROR("nested brace", *posp, CURLE_URL_MALFORMAT);

    case '}':                           /* set element completed */
      if(opattern == pattern)
        return GLOBERROR("empty string within braces", *posp,
                         CURLE_URL_MALFORMAT);

      /* add 1 to size since it will be incremented below */
      if(multiply(amount, pat->content.Set.size + 1))
        return GLOBERROR("range overflow", 0, CURLE_URL_MALFORMAT);

      FALLTHROUGH();
    case ',':

      *buf = '\0';
Changes to jni/curl/src/tool_util.c.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
    now.tv_sec = tsnow.tv_sec;
    now.tv_usec = (int)(tsnow.tv_nsec / 1000);
  }
  /*
  ** Even when the configure process has truly detected monotonic clock
  ** availability, it might happen that it is not actually available at
  ** run-time. When this occurs simply fallback to other time source.
  */
#ifdef HAVE_GETTIMEOFDAY
  else
    (void)gettimeofday(&now, NULL);
#else
  else {
    now.tv_sec = time(NULL);







|







77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
    now.tv_sec = tsnow.tv_sec;
    now.tv_usec = (int)(tsnow.tv_nsec / 1000);
  }
  /*
  ** Even when the configure process has truly detected monotonic clock
  ** availability, it might happen that it is not actually available at
  ** runtime. When this occurs simply fallback to other time source.
  */
#ifdef HAVE_GETTIMEOFDAY
  else
    (void)gettimeofday(&now, NULL);
#else
  else {
    now.tv_sec = time(NULL);
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  return now;
}

#endif

/*
 * Make sure that the first argument is the more recent time, as otherwise
 * we'll get a weird negative time-diff back...
 *
 * Returns: the time difference in number of milliseconds.
 */
long tvdiff(struct timeval newer, struct timeval older)
{
  return (long)(newer.tv_sec-older.tv_sec)*1000+
    (long)(newer.tv_usec-older.tv_usec)/1000;







|







122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  return now;
}

#endif

/*
 * Make sure that the first argument is the more recent time, as otherwise
 * we will get a weird negative time-diff back...
 *
 * Returns: the time difference in number of milliseconds.
 */
long tvdiff(struct timeval newer, struct timeval older)
{
  return (long)(newer.tv_sec-older.tv_sec)*1000+
    (long)(newer.tv_usec-older.tv_usec)/1000;
Changes to jni/curl/src/tool_version.h.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include <curl/curlver.h>

#define CURL_NAME "curl"
#define CURL_COPYRIGHT LIBCURL_COPYRIGHT
#define CURL_VERSION "8.8.0"
#define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR
#define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR
#define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "

#endif /* HEADER_CURL_TOOL_VERSION_H */







|






23
24
25
26
27
28
29
30
31
32
33
34
35
36
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include <curl/curlver.h>

#define CURL_NAME "curl"
#define CURL_COPYRIGHT LIBCURL_COPYRIGHT
#define CURL_VERSION "8.9.0"
#define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR
#define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR
#define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "

#endif /* HEADER_CURL_TOOL_VERSION_H */
Changes to jni/curl/src/tool_vms.c.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  }

  vms_shell = 0;
  return 0;
}

/*
 * VMS has two exit() routines.  When running under a Unix style shell, then
 * Unix style and the __posix_exit() routine is used.
 *
 * When running under the DCL shell, then the VMS encoded codes and decc$exit()
 * is used.
 *
 * We can not use exit() or return a code from main() because the actual
 * routine called depends on both the compiler version, compile options, and







|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  }

  vms_shell = 0;
  return 0;
}

/*
 * VMS has two exit() routines. When running under a Unix style shell, then
 * Unix style and the __posix_exit() routine is used.
 *
 * When running under the DCL shell, then the VMS encoded codes and decc$exit()
 * is used.
 *
 * We can not use exit() or return a code from main() because the actual
 * routine called depends on both the compiler version, compile options, and
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  int value;
};

/* Array of DECC$* feature names and their desired values. */
static const struct decc_feat_t decc_feat_array[] = {
  /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
  { "DECC$ARGV_PARSE_STYLE", 1 },
  /* Preserve case for file names on ODS5 disks. */
  { "DECC$EFS_CASE_PRESERVE", 1 },
  /* Enable multiple dots (and most characters) in ODS5 file names,
     while preserving VMS-ness of ";version". */
  { "DECC$EFS_CHARSET", 1 },
  /* List terminator. */
  { (char *)NULL, 0 }
};

/* Flag to sense if decc_init() was called. */







|

|







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  int value;
};

/* Array of DECC$* feature names and their desired values. */
static const struct decc_feat_t decc_feat_array[] = {
  /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
  { "DECC$ARGV_PARSE_STYLE", 1 },
  /* Preserve case for filenames on ODS5 disks. */
  { "DECC$EFS_CASE_PRESERVE", 1 },
  /* Enable multiple dots (and most characters) in ODS5 filenames,
     while preserving VMS-ness of ";version". */
  { "DECC$EFS_CHARSET", 1 },
  /* List terminator. */
  { (char *)NULL, 0 }
};

/* Flag to sense if decc_init() was called. */
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  /* Loop through all items in the decc_feat_array[]. */
  for(i = 0; decc_feat_array[i].name != NULL; i++) {

    /* Get the feature index. */
    feat_index = decc$feature_get_index(decc_feat_array[i].name);

    if(feat_index >= 0) {
      /* Valid item.  Collect its properties. */
      feat_value = decc$feature_get_value(feat_index, 1);
      feat_value_min = decc$feature_get_value(feat_index, 2);
      feat_value_max = decc$feature_get_value(feat_index, 3);

      if((decc_feat_array[i].value >= feat_value_min) &&
         (decc_feat_array[i].value <= feat_value_max)) {
        /* Valid value.  Set it if necessary. */
        if(feat_value != decc_feat_array[i].value) {
          sts = decc$feature_set_value(feat_index, 1,
                                       decc_feat_array[i].value);
        }
      }
      else {
        /* Invalid DECC feature value. */







|






|







161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  /* Loop through all items in the decc_feat_array[]. */
  for(i = 0; decc_feat_array[i].name != NULL; i++) {

    /* Get the feature index. */
    feat_index = decc$feature_get_index(decc_feat_array[i].name);

    if(feat_index >= 0) {
      /* Valid item. Collect its properties. */
      feat_value = decc$feature_get_value(feat_index, 1);
      feat_value_min = decc$feature_get_value(feat_index, 2);
      feat_value_max = decc$feature_get_value(feat_index, 3);

      if((decc_feat_array[i].value >= feat_value_min) &&
         (decc_feat_array[i].value <= feat_value_max)) {
        /* Valid value. Set it if necessary. */
        if(feat_value != decc_feat_array[i].value) {
          sts = decc$feature_set_value(feat_index, 1,
                                       decc_feat_array[i].value);
        }
      }
      else {
        /* Invalid DECC feature value. */
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
}

/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */

#pragma nostandard

/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
   other attributes.  Note that "nopic" is significant only on VAX. */
#pragma extern_model save
#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
const int spare[8] = {0};
#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt
void (*const x_decc_init)() = decc_init;
#pragma extern_model restore








|







194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
}

/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */

#pragma nostandard

/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
   other attributes. Note that "nopic" is significant only on VAX. */
#pragma extern_model save
#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
const int spare[8] = {0};
#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt
void (*const x_decc_init)() = decc_init;
#pragma extern_model restore

Changes to jni/curl/src/tool_writeout.c.
66
67
68
69
70
71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

95
96
97
98
99
100
101
   with exceptions special cased in the respective function. For example,
   http_version uses CURLINFO_HTTP_VERSION which returns the version as a long,
   however it is output as a string and therefore is handled in writeString.

   Yes: "http_version": "1.1"
   No:  "http_version": 1.1

   Variable names should be in alphabetical order.
   */
static const struct writeoutvar variables[] = {
  {"certs", VAR_CERT, CURLINFO_NONE, writeString},
  {"content_type", VAR_CONTENT_TYPE, CURLINFO_CONTENT_TYPE, writeString},
  {"conn_id", VAR_CONN_ID, CURLINFO_CONN_ID, writeOffset},

  {"errormsg", VAR_ERRORMSG, CURLINFO_NONE, writeString},
  {"exitcode", VAR_EXITCODE, CURLINFO_NONE, writeLong},
  {"filename_effective", VAR_EFFECTIVE_FILENAME, CURLINFO_NONE, writeString},
  {"ftp_entry_path", VAR_FTP_ENTRY_PATH, CURLINFO_FTP_ENTRY_PATH, writeString},
  {"header_json", VAR_HEADER_JSON, CURLINFO_NONE, NULL},
  {"http_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong},
  {"http_connect", VAR_HTTP_CODE_PROXY, CURLINFO_HTTP_CONNECTCODE, writeLong},
  {"http_version", VAR_HTTP_VERSION, CURLINFO_HTTP_VERSION, writeString},
  {"json", VAR_JSON, CURLINFO_NONE, NULL},
  {"local_ip", VAR_LOCAL_IP, CURLINFO_LOCAL_IP, writeString},
  {"local_port", VAR_LOCAL_PORT, CURLINFO_LOCAL_PORT, writeLong},
  {"method", VAR_EFFECTIVE_METHOD, CURLINFO_EFFECTIVE_METHOD, writeString},
  {"num_certs", VAR_NUM_CERTS, CURLINFO_NONE, writeLong},
  {"num_connects", VAR_NUM_CONNECTS, CURLINFO_NUM_CONNECTS, writeLong},
  {"num_headers", VAR_NUM_HEADERS, CURLINFO_NONE, writeLong},
  {"num_redirects", VAR_REDIRECT_COUNT, CURLINFO_REDIRECT_COUNT, writeLong},

  {"onerror", VAR_ONERROR, CURLINFO_NONE, NULL},
  {"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT,
   CURLINFO_PROXY_SSL_VERIFYRESULT, writeLong},
  {"proxy_used", VAR_PROXY_USED, CURLINFO_USED_PROXY, writeLong},
  {"redirect_url", VAR_REDIRECT_URL, CURLINFO_REDIRECT_URL, writeString},
  {"referer", VAR_REFERER, CURLINFO_REFERER, writeString},
  {"remote_ip", VAR_PRIMARY_IP, CURLINFO_PRIMARY_IP, writeString},







|



<

>
















>







66
67
68
69
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
   with exceptions special cased in the respective function. For example,
   http_version uses CURLINFO_HTTP_VERSION which returns the version as a long,
   however it is output as a string and therefore is handled in writeString.

   Yes: "http_version": "1.1"
   No:  "http_version": 1.1

   Variable names MUST be in alphabetical order.
   */
static const struct writeoutvar variables[] = {
  {"certs", VAR_CERT, CURLINFO_NONE, writeString},

  {"conn_id", VAR_CONN_ID, CURLINFO_CONN_ID, writeOffset},
  {"content_type", VAR_CONTENT_TYPE, CURLINFO_CONTENT_TYPE, writeString},
  {"errormsg", VAR_ERRORMSG, CURLINFO_NONE, writeString},
  {"exitcode", VAR_EXITCODE, CURLINFO_NONE, writeLong},
  {"filename_effective", VAR_EFFECTIVE_FILENAME, CURLINFO_NONE, writeString},
  {"ftp_entry_path", VAR_FTP_ENTRY_PATH, CURLINFO_FTP_ENTRY_PATH, writeString},
  {"header_json", VAR_HEADER_JSON, CURLINFO_NONE, NULL},
  {"http_code", VAR_HTTP_CODE, CURLINFO_RESPONSE_CODE, writeLong},
  {"http_connect", VAR_HTTP_CODE_PROXY, CURLINFO_HTTP_CONNECTCODE, writeLong},
  {"http_version", VAR_HTTP_VERSION, CURLINFO_HTTP_VERSION, writeString},
  {"json", VAR_JSON, CURLINFO_NONE, NULL},
  {"local_ip", VAR_LOCAL_IP, CURLINFO_LOCAL_IP, writeString},
  {"local_port", VAR_LOCAL_PORT, CURLINFO_LOCAL_PORT, writeLong},
  {"method", VAR_EFFECTIVE_METHOD, CURLINFO_EFFECTIVE_METHOD, writeString},
  {"num_certs", VAR_NUM_CERTS, CURLINFO_NONE, writeLong},
  {"num_connects", VAR_NUM_CONNECTS, CURLINFO_NUM_CONNECTS, writeLong},
  {"num_headers", VAR_NUM_HEADERS, CURLINFO_NONE, writeLong},
  {"num_redirects", VAR_REDIRECT_COUNT, CURLINFO_REDIRECT_COUNT, writeLong},
  {"num_retries", VAR_NUM_RETRY, CURLINFO_NONE, writeLong},
  {"onerror", VAR_ONERROR, CURLINFO_NONE, NULL},
  {"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT,
   CURLINFO_PROXY_SSL_VERIFYRESULT, writeLong},
  {"proxy_used", VAR_PROXY_USED, CURLINFO_USED_PROXY, writeLong},
  {"redirect_url", VAR_REDIRECT_URL, CURLINFO_REDIRECT_URL, writeString},
  {"referer", VAR_REFERER, CURLINFO_REFERER, writeString},
  {"remote_ip", VAR_PRIMARY_IP, CURLINFO_PRIMARY_IP, writeString},
121
122
123
124
125
126
127
128
129
130
131

132
133
134
135

136
137
138
139
140
141

142
143
144
145

146
147
148
149
150
151
152
153
154
155
156
157
158
  {"time_pretransfer", VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T,
   writeTime},
  {"time_redirect", VAR_REDIRECT_TIME, CURLINFO_REDIRECT_TIME_T, writeTime},
  {"time_starttransfer", VAR_STARTTRANSFER_TIME, CURLINFO_STARTTRANSFER_TIME_T,
   writeTime},
  {"time_total", VAR_TOTAL_TIME, CURLINFO_TOTAL_TIME_T, writeTime},
  {"url", VAR_INPUT_URL, CURLINFO_NONE, writeString},
  {"url.scheme", VAR_INPUT_URLSCHEME, CURLINFO_NONE, writeString},
  {"url.user", VAR_INPUT_URLUSER, CURLINFO_NONE, writeString},
  {"url.password", VAR_INPUT_URLPASSWORD, CURLINFO_NONE, writeString},
  {"url.options", VAR_INPUT_URLOPTIONS, CURLINFO_NONE, writeString},

  {"url.host", VAR_INPUT_URLHOST, CURLINFO_NONE, writeString},
  {"url.port", VAR_INPUT_URLPORT, CURLINFO_NONE, writeString},
  {"url.path", VAR_INPUT_URLPATH, CURLINFO_NONE, writeString},
  {"url.query", VAR_INPUT_URLQUERY, CURLINFO_NONE, writeString},

  {"url.fragment", VAR_INPUT_URLFRAGMENT, CURLINFO_NONE, writeString},
  {"url.zoneid", VAR_INPUT_URLZONEID, CURLINFO_NONE, writeString},
  {"urle.scheme", VAR_INPUT_URLESCHEME, CURLINFO_NONE, writeString},
  {"urle.user", VAR_INPUT_URLEUSER, CURLINFO_NONE, writeString},
  {"urle.password", VAR_INPUT_URLEPASSWORD, CURLINFO_NONE, writeString},
  {"urle.options", VAR_INPUT_URLEOPTIONS, CURLINFO_NONE, writeString},

  {"urle.host", VAR_INPUT_URLEHOST, CURLINFO_NONE, writeString},
  {"urle.port", VAR_INPUT_URLEPORT, CURLINFO_NONE, writeString},
  {"urle.path", VAR_INPUT_URLEPATH, CURLINFO_NONE, writeString},
  {"urle.query", VAR_INPUT_URLEQUERY, CURLINFO_NONE, writeString},

  {"urle.fragment", VAR_INPUT_URLEFRAGMENT, CURLINFO_NONE, writeString},
  {"urle.zoneid", VAR_INPUT_URLEZONEID, CURLINFO_NONE, writeString},
  {"url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString},
  {"urlnum", VAR_URLNUM, CURLINFO_NONE, writeLong},
  {"xfer_id", VAR_EASY_ID, CURLINFO_XFER_ID, writeOffset},
  {NULL, VAR_NONE, CURLINFO_NONE, NULL}
};

static int writeTime(FILE *stream, const struct writeoutvar *wovar,
                     struct per_transfer *per, CURLcode per_result,
                     bool use_json)
{
  bool valid = false;







|
|
<

>
|

<

>
|

|
|
|

>
|

<

>
|

<

|
<







122
123
124
125
126
127
128
129
130

131
132
133
134

135
136
137
138
139
140
141
142
143
144
145

146
147
148
149

150
151

152
153
154
155
156
157
158
  {"time_pretransfer", VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T,
   writeTime},
  {"time_redirect", VAR_REDIRECT_TIME, CURLINFO_REDIRECT_TIME_T, writeTime},
  {"time_starttransfer", VAR_STARTTRANSFER_TIME, CURLINFO_STARTTRANSFER_TIME_T,
   writeTime},
  {"time_total", VAR_TOTAL_TIME, CURLINFO_TOTAL_TIME_T, writeTime},
  {"url", VAR_INPUT_URL, CURLINFO_NONE, writeString},
  {"url.fragment", VAR_INPUT_URLFRAGMENT, CURLINFO_NONE, writeString},
  {"url.host", VAR_INPUT_URLHOST, CURLINFO_NONE, writeString},

  {"url.options", VAR_INPUT_URLOPTIONS, CURLINFO_NONE, writeString},
  {"url.password", VAR_INPUT_URLPASSWORD, CURLINFO_NONE, writeString},
  {"url.path", VAR_INPUT_URLPATH, CURLINFO_NONE, writeString},
  {"url.port", VAR_INPUT_URLPORT, CURLINFO_NONE, writeString},

  {"url.query", VAR_INPUT_URLQUERY, CURLINFO_NONE, writeString},
  {"url.scheme", VAR_INPUT_URLSCHEME, CURLINFO_NONE, writeString},
  {"url.user", VAR_INPUT_URLUSER, CURLINFO_NONE, writeString},
  {"url.zoneid", VAR_INPUT_URLZONEID, CURLINFO_NONE, writeString},
  {"url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString},
  {"urle.fragment", VAR_INPUT_URLEFRAGMENT, CURLINFO_NONE, writeString},
  {"urle.host", VAR_INPUT_URLEHOST, CURLINFO_NONE, writeString},
  {"urle.options", VAR_INPUT_URLEOPTIONS, CURLINFO_NONE, writeString},
  {"urle.password", VAR_INPUT_URLEPASSWORD, CURLINFO_NONE, writeString},
  {"urle.path", VAR_INPUT_URLEPATH, CURLINFO_NONE, writeString},
  {"urle.port", VAR_INPUT_URLEPORT, CURLINFO_NONE, writeString},

  {"urle.query", VAR_INPUT_URLEQUERY, CURLINFO_NONE, writeString},
  {"urle.scheme", VAR_INPUT_URLESCHEME, CURLINFO_NONE, writeString},
  {"urle.user", VAR_INPUT_URLEUSER, CURLINFO_NONE, writeString},
  {"urle.zoneid", VAR_INPUT_URLEZONEID, CURLINFO_NONE, writeString},

  {"urlnum", VAR_URLNUM, CURLINFO_NONE, writeLong},
  {"xfer_id", VAR_EASY_ID, CURLINFO_XFER_ID, writeOffset}

};

static int writeTime(FILE *stream, const struct writeoutvar *wovar,
                     struct per_transfer *per, CURLcode per_result,
                     bool use_json)
{
  bool valid = false;
264
265
266
267
268
269
270









271
272
273
274
275
276
277
      *contentp = part;
    curl_url_cleanup(uh);
  }
  else
    return 1;
  return rc;
}










static int writeString(FILE *stream, const struct writeoutvar *wovar,
                       struct per_transfer *per, CURLcode per_result,
                       bool use_json)
{
  bool valid = false;
  const char *strinfo = NULL;







>
>
>
>
>
>
>
>
>







264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
      *contentp = part;
    curl_url_cleanup(uh);
  }
  else
    return 1;
  return rc;
}

static void certinfo(struct per_transfer *per)
{
  if(!per->certinfo) {
    struct curl_certinfo *certinfo;
    CURLcode res = curl_easy_getinfo(per->curl, CURLINFO_CERTINFO, &certinfo);
    per->certinfo = (!res && certinfo) ? certinfo : NULL;
  }
}

static int writeString(FILE *stream, const struct writeoutvar *wovar,
                       struct per_transfer *per, CURLcode per_result,
                       bool use_json)
{
  bool valid = false;
  const char *strinfo = NULL;
300
301
302
303
304
305
306

307
308
309
310
311
312
313
      if(!curl_easy_getinfo(per->curl, wovar->ci, &strinfo) && strinfo)
        valid = true;
    }
  }
  else {
    switch(wovar->id) {
    case VAR_CERT:

      if(per->certinfo) {
        int i;
        bool error = FALSE;
        for(i = 0; (i < per->certinfo->num_of_certs) && !error; i++) {
          struct curl_slist *slist;

          for(slist = per->certinfo->certinfo[i]; slist; slist = slist->next) {







>







309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
      if(!curl_easy_getinfo(per->curl, wovar->ci, &strinfo) && strinfo)
        valid = true;
    }
  }
  else {
    switch(wovar->id) {
    case VAR_CERT:
      certinfo(per);
      if(per->certinfo) {
        int i;
        bool error = FALSE;
        for(i = 0; (i < per->certinfo->num_of_certs) && !error; i++) {
          struct curl_slist *slist;

          for(slist = per->certinfo->certinfo[i]; slist; slist = slist->next) {
430
431
432
433
434
435
436




437

438
439
440
441
442
443
444

  if(wovar->ci) {
    if(!curl_easy_getinfo(per->curl, wovar->ci, &longinfo))
      valid = true;
  }
  else {
    switch(wovar->id) {




    case VAR_NUM_CERTS:

      longinfo = per->certinfo ? per->certinfo->num_of_certs : 0;
      valid = true;
      break;
    case VAR_NUM_HEADERS:
      longinfo = per->num_headers;
      valid = true;
      break;







>
>
>
>

>







440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459

  if(wovar->ci) {
    if(!curl_easy_getinfo(per->curl, wovar->ci, &longinfo))
      valid = true;
  }
  else {
    switch(wovar->id) {
    case VAR_NUM_RETRY:
      longinfo = per->num_retries;
      valid = true;
      break;
    case VAR_NUM_CERTS:
      certinfo(per);
      longinfo = per->certinfo ? per->certinfo->num_of_certs : 0;
      valid = true;
      break;
    case VAR_NUM_HEADERS:
      longinfo = per->num_headers;
      valid = true;
      break;
505
506
507
508
509
510
511











512
513
514
515
516
517
518
519
520
521

522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550




551
552

553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573


574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
    if(use_json)
      fprintf(stream, "\"%s\":null", wovar->name);
  }

  return 1; /* return 1 if anything was written */
}












void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
                 CURLcode per_result)
{
  FILE *stream = stdout;
  const char *writeinfo = config->writeout;
  const char *ptr = writeinfo;
  bool done = FALSE;
  struct curl_certinfo *certinfo;
  CURLcode res = curl_easy_getinfo(per->curl, CURLINFO_CERTINFO, &certinfo);
  bool fclose_stream = FALSE;


  if(!writeinfo)
    return;

  if(!res && certinfo)
    per->certinfo = certinfo;

  while(ptr && *ptr && !done) {
    if('%' == *ptr && ptr[1]) {
      if('%' == ptr[1]) {
        /* an escaped %-letter */
        fputc('%', stream);
        ptr += 2;
      }
      else {
        /* this is meant as a variable to output */
        char *end;
        size_t vlen;
        if('{' == ptr[1]) {
          int i;
          bool match = FALSE;
          end = strchr(ptr, '}');
          ptr += 2; /* pass the % and the { */
          if(!end) {
            fputs("%{", stream);
            continue;
          }
          vlen = end - ptr;
          for(i = 0; variables[i].name; i++) {




            if((strlen(variables[i].name) == vlen) &&
               curl_strnequal(ptr, variables[i].name, vlen)) {

              match = TRUE;
              switch(variables[i].id) {
              case VAR_ONERROR:
                if(per_result == CURLE_OK)
                  /* this isn't error so skip the rest */
                  done = TRUE;
                break;
              case VAR_STDOUT:
                if(fclose_stream)
                  fclose(stream);
                fclose_stream = FALSE;
                stream = stdout;
                break;
              case VAR_STDERR:
                if(fclose_stream)
                  fclose(stream);
                fclose_stream = FALSE;
                stream = tool_stderr;
                break;
              case VAR_JSON:
                ourWriteOutJSON(stream, variables, per, per_result);


                break;
              case VAR_HEADER_JSON:
                headerJSON(stream, per);
                break;
              default:
                (void)variables[i].writefunc(stream, &variables[i],
                                             per, per_result, false);
                break;
              }
              break;
            }
          }
          if(!match) {
            fprintf(tool_stderr,
                    "curl: unknown --write-out variable: '%.*s'\n",
                    (int)vlen, ptr);
          }
          ptr = end + 1; /* pass the end */
        }
        else if(!strncmp("header{", &ptr[1], 7)) {







>
>
>
>
>
>
>
>
>
>
>







<
<

>




<
<
|












|
|







|
>
>
>
>
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
|
|
|
|
|
<
|
|
|
<
|
<
|







520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544


545
546
547
548
549
550


551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608

609
610
611

612

613
614
615
616
617
618
619
620
    if(use_json)
      fprintf(stream, "\"%s\":null", wovar->name);
  }

  return 1; /* return 1 if anything was written */
}

static int
matchvar(const void *m1, const void *m2)
{
  const struct writeoutvar *v1 = m1;
  const struct writeoutvar *v2 = m2;

  return strcmp(v1->name, v2->name);
}

#define MAX_WRITEOUT_NAME_LENGTH 24

void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
                 CURLcode per_result)
{
  FILE *stream = stdout;
  const char *writeinfo = config->writeout;
  const char *ptr = writeinfo;
  bool done = FALSE;


  bool fclose_stream = FALSE;
  struct dynbuf name;

  if(!writeinfo)
    return;



  curlx_dyn_init(&name, MAX_WRITEOUT_NAME_LENGTH);
  while(ptr && *ptr && !done) {
    if('%' == *ptr && ptr[1]) {
      if('%' == ptr[1]) {
        /* an escaped %-letter */
        fputc('%', stream);
        ptr += 2;
      }
      else {
        /* this is meant as a variable to output */
        char *end;
        size_t vlen;
        if('{' == ptr[1]) {
          struct writeoutvar *wv = NULL;
          struct writeoutvar find = { 0 };
          end = strchr(ptr, '}');
          ptr += 2; /* pass the % and the { */
          if(!end) {
            fputs("%{", stream);
            continue;
          }
          vlen = end - ptr;

          curlx_dyn_reset(&name);
          if(!curlx_dyn_addn(&name, ptr, vlen)) {
            find.name = curlx_dyn_ptr(&name);
            wv = bsearch(&find,
                         variables, sizeof(variables)/sizeof(variables[0]),
                         sizeof(variables[0]), matchvar);
          }
          if(wv) {
            switch(wv->id) {
            case VAR_ONERROR:
              if(per_result == CURLE_OK)
                /* this is not error so skip the rest */
                done = TRUE;
              break;
            case VAR_STDOUT:
              if(fclose_stream)
                fclose(stream);
              fclose_stream = FALSE;
              stream = stdout;
              break;
            case VAR_STDERR:
              if(fclose_stream)
                fclose(stream);
              fclose_stream = FALSE;
              stream = tool_stderr;
              break;
            case VAR_JSON:
              ourWriteOutJSON(stream, variables,
                              sizeof(variables)/sizeof(variables[0]),
                              per, per_result);
              break;
            case VAR_HEADER_JSON:
              headerJSON(stream, per);
              break;
            default:

              (void)wv->writefunc(stream, wv, per, per_result, false);
              break;
            }

          }

          else {
            fprintf(tool_stderr,
                    "curl: unknown --write-out variable: '%.*s'\n",
                    (int)vlen, ptr);
          }
          ptr = end + 1; /* pass the end */
        }
        else if(!strncmp("header{", &ptr[1], 7)) {
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
          ptr += 8;
          if((ptr[0] == '>') && (ptr[1] == '>')) {
            append = TRUE;
            ptr += 2;
          }
          end = strchr(ptr, '}');
          if(end) {
            char fname[512]; /* holds the longest file name */
            size_t flen = end - ptr;
            if(flen < sizeof(fname)) {
              FILE *stream2;
              memcpy(fname, ptr, flen);
              fname[flen] = 0;
              stream2 = fopen(fname, append? FOPEN_APPENDTEXT :
                              FOPEN_WRITETEXT);







|







641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
          ptr += 8;
          if((ptr[0] == '>') && (ptr[1] == '>')) {
            append = TRUE;
            ptr += 2;
          }
          end = strchr(ptr, '}');
          if(end) {
            char fname[512]; /* holds the longest filename */
            size_t flen = end - ptr;
            if(flen < sizeof(fname)) {
              FILE *stream2;
              memcpy(fname, ptr, flen);
              fname[flen] = 0;
              stream2 = fopen(fname, append? FOPEN_APPENDTEXT :
                              FOPEN_WRITETEXT);
669
670
671
672
673
674
675

676
    else {
      fputc(*ptr, stream);
      ptr++;
    }
  }
  if(fclose_stream)
    fclose(stream);

}







>

696
697
698
699
700
701
702
703
704
    else {
      fputc(*ptr, stream);
      ptr++;
    }
  }
  if(fclose_stream)
    fclose(stream);
  curlx_dyn_free(&name);
}
Changes to jni/curl/src/tool_writeout.h.
70
71
72
73
74
75
76

77
78
79
80
81
82
83
  VAR_JSON,
  VAR_LOCAL_IP,
  VAR_LOCAL_PORT,
  VAR_NAMELOOKUP_TIME,
  VAR_NUM_CERTS,
  VAR_NUM_CONNECTS,
  VAR_NUM_HEADERS,

  VAR_ONERROR,
  VAR_PRETRANSFER_TIME,
  VAR_PRIMARY_IP,
  VAR_PRIMARY_PORT,
  VAR_PROXY_SSL_VERIFY_RESULT,
  VAR_PROXY_USED,
  VAR_REDIRECT_COUNT,







>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  VAR_JSON,
  VAR_LOCAL_IP,
  VAR_LOCAL_PORT,
  VAR_NAMELOOKUP_TIME,
  VAR_NUM_CERTS,
  VAR_NUM_CONNECTS,
  VAR_NUM_HEADERS,
  VAR_NUM_RETRY,
  VAR_ONERROR,
  VAR_PRETRANSFER_TIME,
  VAR_PRIMARY_IP,
  VAR_PRIMARY_PORT,
  VAR_PROXY_SSL_VERIFY_RESULT,
  VAR_PROXY_USED,
  VAR_REDIRECT_COUNT,
Changes to jni/curl/src/tool_writeout_json.c.
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
      break;
    default:
      if(*i < 32)
        result = curlx_dyn_addf(out, "\\u%04x", *i);
      else {
        char o = (char)*i;
        if(lowercase && (o >= 'A' && o <= 'Z'))
          /* do not use tolower() since that's locale specific */
          o |= ('a' - 'A');
        result = curlx_dyn_addn(out, &o, 1);
      }
      break;
    }
  }
  if(result)







|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
      break;
    default:
      if(*i < 32)
        result = curlx_dyn_addf(out, "\\u%04x", *i);
      else {
        char o = (char)*i;
        if(lowercase && (o >= 'A' && o <= 'Z'))
          /* do not use tolower() since that is locale specific */
          o |= ('a' - 'A');
        result = curlx_dyn_addn(out, &o, 1);
      }
      break;
    }
  }
  if(result)
97
98
99
100
101
102
103

104
105
106
107
108
109
110
111
112
113
114
115
116
117
      fputs(curlx_dyn_ptr(&out), stream);
    fputc('\"', stream);
  }
  curlx_dyn_free(&out);
}

void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],

                     struct per_transfer *per, CURLcode per_result)
{
  int i;

  fputs("{", stream);

  for(i = 0; mappings[i].name != NULL; i++) {
    if(mappings[i].writefunc &&
       mappings[i].writefunc(stream, &mappings[i], per, per_result, true))
      fputs(",", stream);
  }

  /* The variables are sorted in alphabetical order but as a special case
     curl_version (which is not actually a --write-out variable) is last. */







>


|



|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
      fputs(curlx_dyn_ptr(&out), stream);
    fputc('\"', stream);
  }
  curlx_dyn_free(&out);
}

void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
                     size_t nentries,
                     struct per_transfer *per, CURLcode per_result)
{
  size_t i;

  fputs("{", stream);

  for(i = 0; i < nentries; i++) {
    if(mappings[i].writefunc &&
       mappings[i].writefunc(stream, &mappings[i], per, per_result, true))
      fputs(",", stream);
  }

  /* The variables are sorted in alphabetical order but as a special case
     curl_version (which is not actually a --write-out variable) is last. */
Changes to jni/curl/src/tool_writeout_json.h.
26
27
28
29
30
31
32

33
34
35
36
37
#include "tool_setup.h"
#include "tool_writeout.h"

int jsonquoted(const char *in, size_t len,
               struct curlx_dynbuf *out, bool lowercase);

void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],

                     struct per_transfer *per, CURLcode per_result);
void headerJSON(FILE *stream, struct per_transfer *per);
void jsonWriteString(FILE *stream, const char *in, bool lowercase);

#endif /* HEADER_CURL_TOOL_WRITEOUT_H */







>





26
27
28
29
30
31
32
33
34
35
36
37
38
#include "tool_setup.h"
#include "tool_writeout.h"

int jsonquoted(const char *in, size_t len,
               struct curlx_dynbuf *out, bool lowercase);

void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
                     size_t nentries,
                     struct per_transfer *per, CURLcode per_result);
void headerJSON(FILE *stream, struct per_transfer *per);
void jsonWriteString(FILE *stream, const char *in, bool lowercase);

#endif /* HEADER_CURL_TOOL_WRITEOUT_H */
Changes to jni/curl/src/var.c.
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  const char *finput = f;

  /* The functions are independent and runs left to right */
  while(*f && !err) {
    if(*f == '}')
      /* end of functions */
      break;
    /* On entry, this is known to be a colon already.  In subsequent laps, it
       is also known to be a colon since that is part of the FUNCMATCH()
       checks */
    f++;
    if(FUNCMATCH(f, FUNC_TRIM, FUNC_TRIM_LEN)) {
      size_t len = clen;
      f += FUNC_TRIM_LEN;
      if(clen) {







|







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  const char *finput = f;

  /* The functions are independent and runs left to right */
  while(*f && !err) {
    if(*f == '}')
      /* end of functions */
      break;
    /* On entry, this is known to be a colon already. In subsequent laps, it
       is also known to be a colon since that is part of the FUNCMATCH()
       checks */
    f++;
    if(FUNCMATCH(f, FUNC_TRIM, FUNC_TRIM_LEN)) {
      size_t len = clen;
      f += FUNC_TRIM_LEN;
      if(clen) {
Changes to jni/curl/tests/CMakeLists.txt.
40
41
42
43
44
45
46







































47
48
49
50
51
52
53
      "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/runtests.pl"
      ${test_flags_list}
      "\$TFLAGS"
    DEPENDS testdeps
    VERBATIM USES_TERMINAL
  )
endfunction()








































add_runtests(test-quiet     "-a -s")
add_runtests(test-am        "-a -am")
add_runtests(test-full      "-a -p -r")
# ~flaky means that it'll ignore results of tests using the flaky keyword
add_runtests(test-nonflaky  "-a -p ~flaky ~timing-dependent")
add_runtests(test-ci        "-a -p ~flaky ~timing-dependent -r -rm")







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
      "${PERL_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/runtests.pl"
      ${test_flags_list}
      "\$TFLAGS"
    DEPENDS testdeps
    VERBATIM USES_TERMINAL
  )
endfunction()

# Create configurehelp.pm, used by tests needing to run the C preprocessor.
if(MSVC OR CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
  set(_cpp_cmd "\"${CMAKE_C_COMPILER}\" -E")
  if(APPLE AND NOT CMAKE_OSX_SYSROOT STREQUAL "")
    set(_cpp_cmd "${_cpp_cmd} -isysroot ${CMAKE_OSX_SYSROOT}")
  endif()
  # Add header directories, like autotools builds do.
  get_property(_include_dirs TARGET ${LIB_SELECTED} PROPERTY INCLUDE_DIRECTORIES)
  foreach(_include_dir IN LISTS _include_dirs)
    set(_cpp_cmd "${_cpp_cmd} -I${_include_dir}")
  endforeach()
else()
  set(_cpp_cmd "cpp")
endif()
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/configurehelp.pm" "# This is a generated file.  Do not edit.

package configurehelp;

use strict;
use warnings;
use Exporter;

use vars qw(
    @ISA
    @EXPORT_OK
    \$Cpreprocessor
    );

@ISA = qw(Exporter);

@EXPORT_OK = qw(
    \$Cpreprocessor
    );

\$Cpreprocessor = '${_cpp_cmd}';

1;
")

add_runtests(test-quiet     "-a -s")
add_runtests(test-am        "-a -am")
add_runtests(test-full      "-a -p -r")
# ~flaky means that it'll ignore results of tests using the flaky keyword
add_runtests(test-nonflaky  "-a -p ~flaky ~timing-dependent")
add_runtests(test-ci        "-a -p ~flaky ~timing-dependent -r -rm")
Changes to jni/curl/tests/FILEFORMAT.md.
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

166

167
168
169
170
171
172
173
174

175
176
177
178
179
180
181
replaced by their content at that time.

Available substitute variables include:

- `%CLIENT6IP` - IPv6 address of the client running curl
- `%CLIENTIP` - IPv4 address of the client running curl
- `%CURL` - Path to the curl executable

- `%FILE_PWD` - Current directory, on Windows prefixed with a slash
- `%FTP6PORT` - IPv6 port number of the FTP server
- `%FTPPORT` - Port number of the FTP server
- `%FTPSPORT` - Port number of the FTPS server
- `%FTPTIME2` - Timeout in seconds that should be just sufficient to receive a
  response from the test FTP server
- `%FTPTIME3` - Even longer than `%FTPTIME2`
- `%GOPHER6PORT` - IPv6 port number of the Gopher server
- `%GOPHERPORT` - Port number of the Gopher server
- `%GOPHERSPORT` - Port number of the Gophers server
- `%HOST6IP` - IPv6 address of the host running this test
- `%HOSTIP` - IPv4 address of the host running this test

- `%HTTP6PORT` - IPv6 port number of the HTTP server
- `%HTTPPORT` - Port number of the HTTP server
- `%HTTP2PORT` - Port number of the HTTP/2 server
- `%HTTPSPORT` - Port number of the HTTPS server
- `%HTTPSPROXYPORT` - Port number of the HTTPS-proxy
- `%HTTPTLS6PORT` - IPv6 port number of the HTTP TLS server
- `%HTTPTLSPORT` - Port number of the HTTP TLS server
- `%HTTPUNIXPATH` - Path to the Unix socket of the HTTP server
- `%SOCKSUNIXPATH` - Path to the Unix socket of the SOCKS server
- `%IMAP6PORT` - IPv6 port number of the IMAP server
- `%IMAPPORT` - Port number of the IMAP server
- `%LOGDIR` - Log directory relative to %PWD
- `%MQTTPORT` - Port number of the MQTT server
- `%TELNETPORT` - Port number of the telnet server
- `%NOLISTENPORT` - Port number where no service is listening
- `%POP36PORT` - IPv6 port number of the POP3 server
- `%POP3PORT` - Port number of the POP3 server
- `%POSIX_PWD` - Current directory somewhat mingw friendly
- `%PROXYPORT` - Port number of the HTTP proxy
- `%PWD` - Current directory
- `%RTSP6PORT` - IPv6 port number of the RTSP server
- `%RTSPPORT` - Port number of the RTSP server
- `%SMBPORT` - Port number of the SMB server
- `%SMBSPORT` - Port number of the SMBS server
- `%SMTP6PORT` - IPv6 port number of the SMTP server
- `%SMTPPORT` - Port number of the SMTP server
- `%SOCKSPORT` - Port number of the SOCKS4/5 server

- `%SRCDIR` - Full path to the source dir

- `%SSHPORT` - Port number of the SCP/SFTP server
- `%SSHSRVMD5` - MD5 of SSH server's public key
- `%SSHSRVSHA256` - SHA256 of SSH server's public key
- `%SSH_PWD` - Current directory friendly for the SSH server
- `%TESTNUMBER` - Number of the test case
- `%TFTP6PORT` - IPv6 port number of the TFTP server
- `%TFTPPORT` - Port number of the TFTP server
- `%USER` - Login ID of the user running the test

- `%VERSION` - the full version number of the tested curl

# `<testcase>`

Each test is always specified entirely within the `testcase` tag. Each test
case is split up in four main sections: `info`, `reply`, `client` and
`verify`.







>












>


<





<




<













>

>



|




>







120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145
146
147

148
149
150
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
replaced by their content at that time.

Available substitute variables include:

- `%CLIENT6IP` - IPv6 address of the client running curl
- `%CLIENTIP` - IPv4 address of the client running curl
- `%CURL` - Path to the curl executable
- `%DATE` - current YYYY-MM-DD date
- `%FILE_PWD` - Current directory, on Windows prefixed with a slash
- `%FTP6PORT` - IPv6 port number of the FTP server
- `%FTPPORT` - Port number of the FTP server
- `%FTPSPORT` - Port number of the FTPS server
- `%FTPTIME2` - Timeout in seconds that should be just sufficient to receive a
  response from the test FTP server
- `%FTPTIME3` - Even longer than `%FTPTIME2`
- `%GOPHER6PORT` - IPv6 port number of the Gopher server
- `%GOPHERPORT` - Port number of the Gopher server
- `%GOPHERSPORT` - Port number of the Gophers server
- `%HOST6IP` - IPv6 address of the host running this test
- `%HOSTIP` - IPv4 address of the host running this test
- `%HTTP2PORT` - Port number of the HTTP/2 server
- `%HTTP6PORT` - IPv6 port number of the HTTP server
- `%HTTPPORT` - Port number of the HTTP server

- `%HTTPSPORT` - Port number of the HTTPS server
- `%HTTPSPROXYPORT` - Port number of the HTTPS-proxy
- `%HTTPTLS6PORT` - IPv6 port number of the HTTP TLS server
- `%HTTPTLSPORT` - Port number of the HTTP TLS server
- `%HTTPUNIXPATH` - Path to the Unix socket of the HTTP server

- `%IMAP6PORT` - IPv6 port number of the IMAP server
- `%IMAPPORT` - Port number of the IMAP server
- `%LOGDIR` - Log directory relative to %PWD
- `%MQTTPORT` - Port number of the MQTT server

- `%NOLISTENPORT` - Port number where no service is listening
- `%POP36PORT` - IPv6 port number of the POP3 server
- `%POP3PORT` - Port number of the POP3 server
- `%POSIX_PWD` - Current directory somewhat mingw friendly
- `%PROXYPORT` - Port number of the HTTP proxy
- `%PWD` - Current directory
- `%RTSP6PORT` - IPv6 port number of the RTSP server
- `%RTSPPORT` - Port number of the RTSP server
- `%SMBPORT` - Port number of the SMB server
- `%SMBSPORT` - Port number of the SMBS server
- `%SMTP6PORT` - IPv6 port number of the SMTP server
- `%SMTPPORT` - Port number of the SMTP server
- `%SOCKSPORT` - Port number of the SOCKS4/5 server
- `%SOCKSUNIXPATH` - Path to the Unix socket of the SOCKS server
- `%SRCDIR` - Full path to the source dir
- `%SSH_PWD` - Current directory friendly for the SSH server
- `%SSHPORT` - Port number of the SCP/SFTP server
- `%SSHSRVMD5` - MD5 of SSH server's public key
- `%SSHSRVSHA256` - SHA256 of SSH server's public key
- `%TELNETPORT` - Port number of the telnet server
- `%TESTNUMBER` - Number of the test case
- `%TFTP6PORT` - IPv6 port number of the TFTP server
- `%TFTPPORT` - Port number of the TFTP server
- `%USER` - Login ID of the user running the test
- `%VERNUM` - the version number of the tested curl (without -DEV)
- `%VERSION` - the full version number of the tested curl

# `<testcase>`

Each test is always specified entirely within the `testcase` tag. Each test
case is split up in four main sections: `info`, `reply`, `client` and
`verify`.
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
- `alt-svc`
- `bearssl`
- `brotli`
- `c-ares`
- `CharConv`
- `cookies`
- `crypto`
- `debug`
- `DoH`
- `getrlimit`
- `GnuTLS`
- `GSS-API`
- `h2c`
- `headers-api`
- `HSTS`
- `HTTP-auth`
- `http/2`
- `http/3`
- `https-proxy`
- `hyper`
- `idn`
- `ipv6`
- `Kerberos`
- `large_file`
- `large-time` (time_t is larger than 32 bit)
- `ld_preload`
- `libssh2`
- `libssh`
- `oldlibssh` (versions before 0.9.4)
- `libz`
- `manual`







|










|

|
|

|







428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
- `alt-svc`
- `bearssl`
- `brotli`
- `c-ares`
- `CharConv`
- `cookies`
- `crypto`
- `Debug`
- `DoH`
- `getrlimit`
- `GnuTLS`
- `GSS-API`
- `h2c`
- `headers-api`
- `HSTS`
- `HTTP-auth`
- `http/2`
- `http/3`
- `HTTPS-proxy`
- `hyper`
- `IDN`
- `IPv6`
- `Kerberos`
- `Largefile`
- `large-time` (time_t is larger than 32 bit)
- `ld_preload`
- `libssh2`
- `libssh`
- `oldlibssh` (versions before 0.9.4)
- `libz`
- `manual`
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
- `threaded-resolver`
- `TLS-SRP`
- `TrackMemory`
- `typecheck`
- `threadsafe`
- `Unicode`
- `unittest`
- `unix-sockets`
- `verbose-strings`
- `wakeup`
- `win32`
- `wolfssh`
- `wolfssl`
- `xattr`
- `zstd`







|







479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
- `threaded-resolver`
- `TLS-SRP`
- `TrackMemory`
- `typecheck`
- `threadsafe`
- `Unicode`
- `unittest`
- `UnixSockets`
- `verbose-strings`
- `wakeup`
- `win32`
- `wolfssh`
- `wolfssl`
- `xattr`
- `zstd`
584
585
586
587
588
589
590









591
592
593
594
595
596
597

### `<file name="%LOGDIR/filename" [nonewline="yes"]>`
This creates the named file with this content before the test case is run,
which is useful if the test case needs a file to act on.

If `nonewline="yes"` is used, the created file will have the final newline
stripped off.










### `<stdin [nonewline="yes"]>`
Pass this given data on stdin to the tool.

If `nonewline` is set, we will cut off the trailing newline of this given data
before comparing with the one actually received by the client








>
>
>
>
>
>
>
>
>







586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608

### `<file name="%LOGDIR/filename" [nonewline="yes"]>`
This creates the named file with this content before the test case is run,
which is useful if the test case needs a file to act on.

If `nonewline="yes"` is used, the created file will have the final newline
stripped off.

### `<file1>`
1 to 4 can be appended to 'file' to create more files.

### `<file2>`

### `<file3>`

### `<file4>`

### `<stdin [nonewline="yes"]>`
Pass this given data on stdin to the tool.

If `nonewline` is set, we will cut off the trailing newline of this given data
before comparing with the one actually received by the client

623
624
625
626
627
628
629
630
631
632
633
634



635
636
637
638
639
640
641
### `<proxy [nonewline="yes"][crlf="yes"]>`

The protocol dump curl should transmit to an HTTP proxy (when the http-proxy
server is used), if `nonewline` is set, we will cut off the trailing newline
of this given data before comparing with the one actually sent by the client
The `<strip>` and `<strippart>` rules are applied before comparisons are made.

### `<stderr [mode="text"] [nonewline="yes"]>`
This verifies that this data was passed to stderr.

Use the mode="text" attribute if the output is in text mode on platforms that
have a text/binary difference.




If `nonewline` is set, we will cut off the trailing newline of this given data
before comparing with the one actually received by the client

### `<stdout [mode="text"] [nonewline="yes"] [crlf="yes"] [loadfile="filename"]>`
This verifies that this data was passed to stdout.








|




>
>
>







634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
### `<proxy [nonewline="yes"][crlf="yes"]>`

The protocol dump curl should transmit to an HTTP proxy (when the http-proxy
server is used), if `nonewline` is set, we will cut off the trailing newline
of this given data before comparing with the one actually sent by the client
The `<strip>` and `<strippart>` rules are applied before comparisons are made.

### `<stderr [mode="text"] [nonewline="yes"] [crlf="yes"]>`
This verifies that this data was passed to stderr.

Use the mode="text" attribute if the output is in text mode on platforms that
have a text/binary difference.

`crlf=yes` forces the newlines to become CRLF even if not written so in the
test.

If `nonewline` is set, we will cut off the trailing newline of this given data
before comparing with the one actually received by the client

### `<stdout [mode="text"] [nonewline="yes"] [crlf="yes"] [loadfile="filename"]>`
This verifies that this data was passed to stdout.

Changes to jni/curl/tests/Makefile.am.
36
37
38
39
40
41
42


43
44
45
46
47
48
49
 test1173.pl  \
 test1175.pl  \
 test1177.pl  \
 test1222.pl  \
 test1275.pl  \
 test1276.pl  \
 test1477.pl  \


 test1544.pl  \
 test971.pl

EXTRA_DIST =        \
 CMakeLists.txt     \
 FILEFORMAT.md      \
 README.md          \







>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 test1173.pl  \
 test1175.pl  \
 test1177.pl  \
 test1222.pl  \
 test1275.pl  \
 test1276.pl  \
 test1477.pl  \
 test1486.pl  \
 test1488.pl  \
 test1544.pl  \
 test971.pl

EXTRA_DIST =        \
 CMakeLists.txt     \
 FILEFORMAT.md      \
 README.md          \
158
159
160
161
162
163
164
165
166
167
168

checksrc:
	(cd libtest && $(MAKE) checksrc)
	(cd unit && $(MAKE) checksrc)
	(cd server && $(MAKE) checksrc)
	(cd http && $(MAKE) checksrc)

if CURLDEBUG
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif







|



160
161
162
163
164
165
166
167
168
169
170

checksrc:
	(cd libtest && $(MAKE) checksrc)
	(cd unit && $(MAKE) checksrc)
	(cd server && $(MAKE) checksrc)
	(cd http && $(MAKE) checksrc)

if DEBUGBUILD
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif
Changes to jni/curl/tests/Makefile.in.
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







129
130
131
132
133
134
135

136
137
138
139
140
141
142
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
310
311
312
313
314
315
316


317
318
319
320
321
322
323
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
463
464
465
466
467
468
469


470
471
472
473
474
475
476
 test1173.pl  \
 test1175.pl  \
 test1177.pl  \
 test1222.pl  \
 test1275.pl  \
 test1276.pl  \
 test1477.pl  \


 test1544.pl  \
 test971.pl

EXTRA_DIST = \
 CMakeLists.txt     \
 FILEFORMAT.md      \
 README.md          \







>
>







464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
 test1173.pl  \
 test1175.pl  \
 test1177.pl  \
 test1222.pl  \
 test1275.pl  \
 test1276.pl  \
 test1477.pl  \
 test1486.pl  \
 test1488.pl  \
 test1544.pl  \
 test971.pl

EXTRA_DIST = \
 CMakeLists.txt     \
 FILEFORMAT.md      \
 README.md          \
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
		am__skip_mode_fix=: \
	        distdir) \
	      || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-recursive
@CURLDEBUG_FALSE@all-local:
all-am: Makefile all-local
installdirs: installdirs-recursive
installdirs-am:
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive







|







739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
		am__skip_mode_fix=: \
	        distdir) \
	      || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-recursive
@DEBUGBUILD_FALSE@all-local:
all-am: Makefile all-local
installdirs: installdirs-recursive
installdirs-am:
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
894
895
896
897
898
899
900
901
902
903
904
905
checksrc:
	(cd libtest && $(MAKE) checksrc)
	(cd unit && $(MAKE) checksrc)
	(cd server && $(MAKE) checksrc)
	(cd http && $(MAKE) checksrc)

# for debug builds, we scan the sources on all regular make invokes
@CURLDEBUG_TRUE@all-local: checksrc

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:







|




897
898
899
900
901
902
903
904
905
906
907
908
checksrc:
	(cd libtest && $(MAKE) checksrc)
	(cd unit && $(MAKE) checksrc)
	(cd server && $(MAKE) checksrc)
	(cd http && $(MAKE) checksrc)

# for debug builds, we scan the sources on all regular make invokes
@DEBUGBUILD_TRUE@all-local: checksrc

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
Changes to jni/curl/tests/certs/EdelCurlRoot-ca.prm.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30














extensions = x509v3
[ req ]
default_bits                    = 2048
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only
[ req_DN ]
countryName                     = "Country Name"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = Northern Nowhere Trust Anchor
[ x509v3 ]
basicConstraints = critical,CA:true
keyUsage        = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl















|
<
<
<
<
<
<
<
<
<
<
<

|
|
|













>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2











3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
extensions = x509v3












[ x509v3 ]
basicConstraints        = critical,CA:true
keyUsage                = critical,keyCertSign,cRLSign
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 2048
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = Northern Nowhere Trust Anchor
Changes to jni/curl/tests/certs/Makefile.in.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







105
106
107
108
109
110
111

112
113
114
115
116
117
118
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
287
288
289
290
291
292
293


294
295
296
297
298
299
300
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
Changes to jni/curl/tests/certs/Server-localhost-firstSAN-sv.pem.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost,DNS:localhost1,DNS:localhost2
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost.nn

[something]
# The key
# the certificate
# some dhparam
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqFG49ghwozY+A
r1DtF5dt5qhhPqyorBPOmespLElz+RJANcR5hA2esCjEn2TjwW0tcRFdSxRhIEsY
ocshbZ54GxHSgxyJddV3PcrIgxd0XESyH6zzi8VqNHqGqwj1PXlyqzZII94rukzg
7xiRZJfGCZLtJtKnDaIhHzQGx5kXslCWtg+b7UX/voFHKeXzSdshZUTejSsSBxIN
Wcy7TRozwHp+5VsGUGKyf49cbZHLalzj5K65qw027wrVbQdbJVggDdJLJQ/oEfXO
GbEpxtNJ1/JKeFLSxfxPEWPxTneuCodlRUm2rCEbyJTBDOcT5r7z/6K9aEzGNAQr

>

|
|
|
|
|
|














|
|
|
|


|
|
|
|
|
|
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





36
37
38
39
40
41
42
extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost,DNS:localhost1,DNS:localhost2
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost.nn





-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqFG49ghwozY+A
r1DtF5dt5qhhPqyorBPOmespLElz+RJANcR5hA2esCjEn2TjwW0tcRFdSxRhIEsY
ocshbZ54GxHSgxyJddV3PcrIgxd0XESyH6zzi8VqNHqGqwj1PXlyqzZII94rukzg
7xiRZJfGCZLtJtKnDaIhHzQGx5kXslCWtg+b7UX/voFHKeXzSdshZUTejSsSBxIN
Wcy7TRozwHp+5VsGUGKyf49cbZHLalzj5K65qw027wrVbQdbJVggDdJLJQ/oEfXO
GbEpxtNJ1/JKeFLSxfxPEWPxTneuCodlRUm2rCEbyJTBDOcT5r7z/6K9aEzGNAQr
Changes to jni/curl/tests/certs/Server-localhost-firstSAN-sv.prm.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost,DNS:localhost1,DNS:localhost2
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost.nn

[something]
# The key
# the certificate
# some dhparam

>

|
|
|
|
|
|














|
|
|
|


|
|
|
|
|
|
<
<
<
<
<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost,DNS:localhost1,DNS:localhost2
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost.nn





Changes to jni/curl/tests/certs/Server-localhost-lastSAN-sv.pem.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost1,DNS:localhost2,DNS:localhost
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost.nn

[something]
# The key
# the certificate
# some dhparam
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIhP5pZDPD3LV0
iseyu9lp4qmVbV+3JeaCACv1UyHnKK5mtjj9FbGRiFIxKbtz4uCZYpVENVHXVMjS
bSU88C4DG6ihJeGDmly9ZVeTRH6jzN2sWWlgAeCAudDEcGPPF6DGEw8hO8jBRk4Y
/Wo2diRKV9hzLxNCoC6QH7+EnYHnvfh1U/P6UuHwqvYj1w1hFwzlmqvi1ejDyWsq
ptr5y/ZNHUBTfmgvUZ/TF5U0ITINR9apTSi74FATL1t2oZBaUUgvztvZ2i7ROg/7
gGEkCwt5skXNHS1m7kqWXQi3xICVLU6OrA4V+iwGDEl0SYF3F6WyAd6qiCuaZhO7

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





36
37
38
39
40
41
42
extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost1,DNS:localhost2,DNS:localhost
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost.nn





-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIhP5pZDPD3LV0
iseyu9lp4qmVbV+3JeaCACv1UyHnKK5mtjj9FbGRiFIxKbtz4uCZYpVENVHXVMjS
bSU88C4DG6ihJeGDmly9ZVeTRH6jzN2sWWlgAeCAudDEcGPPF6DGEw8hO8jBRk4Y
/Wo2diRKV9hzLxNCoC6QH7+EnYHnvfh1U/P6UuHwqvYj1w1hFwzlmqvi1ejDyWsq
ptr5y/ZNHUBTfmgvUZ/TF5U0ITINR9apTSi74FATL1t2oZBaUUgvztvZ2i7ROg/7
gGEkCwt5skXNHS1m7kqWXQi3xICVLU6OrA4V+iwGDEl0SYF3F6WyAd6qiCuaZhO7
Changes to jni/curl/tests/certs/Server-localhost-lastSAN-sv.prm.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost1,DNS:localhost2,DNS:localhost
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost.nn

[something]
# The key
# the certificate
# some dhparam

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost1,DNS:localhost2,DNS:localhost
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost.nn





Changes to jni/curl/tests/certs/Server-localhost-sv.pem.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost 

[something]
# The key
# the certificate
# some dhparam
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDGuAQ91voxoNf3
6YhLWl5vb9v0yUt+bCrPNHsquhpxrX94bPceygfQKQNJ5GOGTPZnP70yacu4FecO
zyg9npaRjk9zqSd3TCZhzdbnTjxkwxO6juwDD7zUg7OU8r7QGDDFUknLmmDP87nK
L2OdNO6HOljnoZnd3FaH4aDXazeuuxPbffoqPZw5efYBpuM65xgUy8dXuYPRurgs
WsSXL+6NaEg3+BfbMrnqJU8oVwE5E9zA99DMZfkruEyhWxHOROIouWNi/Qj6ts1J
1bn+nmicmrUaPsy/DnTbUj8lMM19AkHHyYpYEjUlIZXEa8P1ecIAy+9/15+Jyf/A

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





36
37
38
39
40
41
42
extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost





-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDGuAQ91voxoNf3
6YhLWl5vb9v0yUt+bCrPNHsquhpxrX94bPceygfQKQNJ5GOGTPZnP70yacu4FecO
zyg9npaRjk9zqSd3TCZhzdbnTjxkwxO6juwDD7zUg7OU8r7QGDDFUknLmmDP87nK
L2OdNO6HOljnoZnd3FaH4aDXazeuuxPbffoqPZw5efYBpuM65xgUy8dXuYPRurgs
WsSXL+6NaEg3+BfbMrnqJU8oVwE5E9zA99DMZfkruEyhWxHOROIouWNi/Qj6ts1J
1bn+nmicmrUaPsy/DnTbUj8lMM19AkHHyYpYEjUlIZXEa8P1ecIAy+9/15+Jyf/A
Changes to jni/curl/tests/certs/Server-localhost-sv.prm.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost 

[something]
# The key
# the certificate
# some dhparam

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost





Changes to jni/curl/tests/certs/Server-localhost.nn-sv.pem.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost.nn
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost.nn 

[something]
# The key
# the certificate
# some dhparam
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCjmuQP4L2TqVqn
Xq2FXtbgmLTpIuBikMPZVzcWXVc9aMrizy9GZxoMrw6JhgEG39bJgBUKQ4VAP9ru
7ngJfJDkiWOSQAsiHOLTFqmTYuQEerCrJTp0AkTq8TGJlCl0oOK7rucP8Thqhx7d
W+akzJes0wGacSejIm3YSsdJXBauYacGOpC033Gvpf1RRnXNeOAMUplBT1YppqKj
3dl+KT5opa/ANLVzUhIEkAcb9YujcVbFlU5iGNTs6U6QG5EluzIV2xU4WRTJxcYK
CKot9WeqL+uXdIqLPl8JJ7C/s6OF6Xr1Odwdx/Q0c9jy7bDJHSqF7uL7UQle/7+8

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





36
37
38
39
40
41
42
extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost.nn
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost.nn





-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCjmuQP4L2TqVqn
Xq2FXtbgmLTpIuBikMPZVzcWXVc9aMrizy9GZxoMrw6JhgEG39bJgBUKQ4VAP9ru
7ngJfJDkiWOSQAsiHOLTFqmTYuQEerCrJTp0AkTq8TGJlCl0oOK7rucP8Thqhx7d
W+akzJes0wGacSejIm3YSsdJXBauYacGOpC033Gvpf1RRnXNeOAMUplBT1YppqKj
3dl+KT5opa/ANLVzUhIEkAcb9YujcVbFlU5iGNTs6U6QG5EluzIV2xU4WRTJxcYK
CKot9WeqL+uXdIqLPl8JJ7C/s6OF6Xr1Odwdx/Q0c9jy7bDJHSqF7uL7UQle/7+8
Changes to jni/curl/tests/certs/Server-localhost.nn-sv.prm.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost.nn
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost.nn 

[something]
# The key
# the certificate
# some dhparam

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost.nn
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost.nn





Changes to jni/curl/tests/certs/Server-localhost0h-sv.pem.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
extensions = x509v3

[ x509v3 ]
#subjectAltName = DNS:localhost\0h
subjectAltName = DER:30:0d:82:0b:6c:6f:63:61:6c:68:6f:73:74:00:68
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost 

[something]
# The key
# the certificate
# some dhparam
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfKZNYgh2iuAcq
so+TDt8VSXIGkxlKLcW9VpJa2vTTmgEc7kdXDp7Y1w3Ezkui8PwH7JHplQj06V3y
SfMLmPDYx9RnL/vylDsUyAbaOXCK+UtwqHRrP1vRpBzqvfGeweLnmIhP6Uu2yNae
AfO3ye7N4teWaBTXRMYRE59sBk5XmFPIQN6dRB9q9AGwVkdeO7U8KZuW85paeNER
USUOQ4JK099UWkYA3rCiLmVURECcZNPoP+is4wz7NgrFeTepou8GFEOsniDeMNLq
eX3v8gyTcI27FP9MVkHkKt6SCs5lLNP7KQ9P+RbXYlROTKgFNF3mIOOJvHsf3yFX

>

|
|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36





37
38
39
40
41
42
43
extensions = x509v3

[ x509v3 ]
#subjectAltName         = DNS:localhost\0h
subjectAltName          = DER:30:0d:82:0b:6c:6f:63:61:6c:68:6f:73:74:00:68
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost





-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfKZNYgh2iuAcq
so+TDt8VSXIGkxlKLcW9VpJa2vTTmgEc7kdXDp7Y1w3Ezkui8PwH7JHplQj06V3y
SfMLmPDYx9RnL/vylDsUyAbaOXCK+UtwqHRrP1vRpBzqvfGeweLnmIhP6Uu2yNae
AfO3ye7N4teWaBTXRMYRE59sBk5XmFPIQN6dRB9q9AGwVkdeO7U8KZuW85paeNER
USUOQ4JK099UWkYA3rCiLmVURECcZNPoP+is4wz7NgrFeTepou8GFEOsniDeMNLq
eX3v8gyTcI27FP9MVkHkKt6SCs5lLNP7KQ9P+RbXYlROTKgFNF3mIOOJvHsf3yFX
Changes to jni/curl/tests/certs/Server-localhost0h-sv.prm.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
36
37
38
39
extensions = x509v3

[ x509v3 ]
#subjectAltName = DNS:localhost\0h
subjectAltName = DER:30:0d:82:0b:6c:6f:63:61:6c:68:6f:73:74:00:68
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 1024
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost 

[something]
# The key
# the certificate
# some dhparam

>

|
|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36





extensions = x509v3

[ x509v3 ]
#subjectAltName         = DNS:localhost\0h
subjectAltName          = DER:30:0d:82:0b:6c:6f:63:61:6c:68:6f:73:74:00:68
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 1024
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost





Changes to jni/curl/tests/certs/scripts/Makefile.in.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







105
106
107
108
109
110
111

112
113
114
115
116
117
118
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
229
230
231
232
233
234
235


236
237
238
239
240
241
242
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
Changes to jni/curl/tests/certs/stunnel-sv.pem.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 12048
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost

[something]
# The key
# the certificate
# some dhparam
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrCrAD0Hb+Xs4V
3mHV45FvfNa7yiaOeL4mNdGmWfHVPFU+CSzsoNSvDjxaorWweFGVYoCAcchOn1lZ
k0ASsqnOss0Xi58n8+PPI3gG0gYjX5sg7EJ3Zq2kXoK0TZRy6hNkcvzLgyzXoYv1
LkzTwYiyyJgZX++Y/GKAs2fMHyP8XzjNgm4tltk1k/4pomllwN9Fqz+sFxgAgEq3
ybq4Xym7xKwWl8xXNBDJNmVsPtiJRcilQoR8Xs0a6PE+VbMhD9A2E/LEL7lzQfqH
qtxE1mSW5FpQ+Uqf4KLnafStWs86IOWnCeLP6BmhAK6ouyICNFyzz7UkTHa/renx

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





36
37
38
39
40
41
42
extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 12048
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost





-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrCrAD0Hb+Xs4V
3mHV45FvfNa7yiaOeL4mNdGmWfHVPFU+CSzsoNSvDjxaorWweFGVYoCAcchOn1lZ
k0ASsqnOss0Xi58n8+PPI3gG0gYjX5sg7EJ3Zq2kXoK0TZRy6hNkcvzLgyzXoYv1
LkzTwYiyyJgZX++Y/GKAs2fMHyP8XzjNgm4tltk1k/4pomllwN9Fqz+sFxgAgEq3
ybq4Xym7xKwWl8xXNBDJNmVsPtiJRcilQoR8Xs0a6PE+VbMhD9A2E/LEL7lzQfqH
qtxE1mSW5FpQ+Uqf4KLnafStWs86IOWnCeLP6BmhAK6ouyICNFyzz7UkTHa/renx
Changes to jni/curl/tests/certs/stunnel-sv.prm.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 12048
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost

[something]
# The key
# the certificate
# some dhparam

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 12048
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost





Changes to jni/curl/tests/conftest.py.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
        ])
    if env.has_caddy():
        report.extend([
            f'  Caddy: {env.caddy_version()}, http:{env.caddy_http_port} https:{env.caddy_https_port}'
        ])
    if env.has_vsftpd():
        report.extend([
            f'  VsFTPD: {env.vsftpd_version()}, ftp:{env.ftp_port}'
        ])
    return '\n'.join(report)


def pytest_addoption(parser):
    parser.addoption("--repeat", action="store", type=int, default=1,
                     help='Number of times to repeat each test')







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
        ])
    if env.has_caddy():
        report.extend([
            f'  Caddy: {env.caddy_version()}, http:{env.caddy_http_port} https:{env.caddy_https_port}'
        ])
    if env.has_vsftpd():
        report.extend([
            f'  VsFTPD: {env.vsftpd_version()}, ftp:{env.ftp_port}, ftps:{env.ftps_port}'
        ])
    return '\n'.join(report)


def pytest_addoption(parser):
    parser.addoption("--repeat", action="store", type=int, default=1,
                     help='Number of times to repeat each test')
Changes to jni/curl/tests/data/Makefile.in.
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







129
130
131
132
133
134
135

136
137
138
139
140
141
142
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
253
254
255
256
257
258
259


260
261
262
263
264
265
266
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
test399 test400 test401 test402 test403 test404 test405 test406 test407 \
test408 test409 test410 test411 test412 test413 test414 test415 test416 \
test417 test418 test419 test420 test421 test422 test423 test424 test425 \
test426 test427 test428 test429 test430 test431 test432 test433 test434 \
test435 test436 test437 test438 test439 test440 test441 test442 test443 \
test444 test445 test446 test447 test448 test449 test450 test451 test452 \
test453 test454 test455 test456 test457 test458 test459 test460 test461 \
test462 test463 test467 test468 test469 test470 test471 \
\
test490 test491 test492 test493 test494 test495 test496 test497 test498 \
test499 test500 test501 test502 test503 test504 test505 test506 test507 \
test508 test509 test510 test511 test512 test513 test514 test515 test516 \
test517 test518 test519 test520 test521 test522 test523 test524 test525 \
test526 test527 test528 test529 test530 test531 test532 test533 test534 \
test535 test536 test537 test538 test539 test540 test541 test542 test543 \







|







441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
test399 test400 test401 test402 test403 test404 test405 test406 test407 \
test408 test409 test410 test411 test412 test413 test414 test415 test416 \
test417 test418 test419 test420 test421 test422 test423 test424 test425 \
test426 test427 test428 test429 test430 test431 test432 test433 test434 \
test435 test436 test437 test438 test439 test440 test441 test442 test443 \
test444 test445 test446 test447 test448 test449 test450 test451 test452 \
test453 test454 test455 test456 test457 test458 test459 test460 test461 \
test462 test463 test467 test468 test469 test470 test471 test472 test473 \
\
test490 test491 test492 test493 test494 test495 test496 test497 test498 \
test499 test500 test501 test502 test503 test504 test505 test506 test507 \
test508 test509 test510 test511 test512 test513 test514 test515 test516 \
test517 test518 test519 test520 test521 test522 test523 test524 test525 \
test526 test527 test528 test529 test530 test531 test532 test533 test534 \
test535 test536 test537 test538 test539 test540 test541 test542 test543 \
555
556
557
558
559
560
561
562

563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
test1423 test1424 test1425 test1426 test1427 test1428 test1429 test1430 \
test1431 test1432 test1433 test1434 test1435 test1436 test1437 test1438 \
test1439 test1440 test1441 test1442 test1443 test1444 test1445 test1446 \
test1447 test1448 test1449 test1450 test1451 test1452 test1453 test1454 \
test1455 test1456 test1457 test1458 test1459 test1460 test1461 test1462 \
test1463 test1464 test1465 test1466 test1467 test1468 test1469 test1470 \
test1471 test1472 test1473 test1474 test1475 test1476 test1477 test1478 \
test1479 test1480 test1481 test1482 test1483 \

\
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
test1516 test1517 test1518 test1519 test1520 test1521 test1522 test1523 \
test1524 test1525 test1526 test1527 test1528 test1529 test1530 test1531 \
test1532 test1533 test1534 test1535 test1536 test1537 test1538 test1539 \
test1540 test1541 test1542 test1543 test1544 test1545 \
\
test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \
test1566 test1567 test1568 test1569 test1570 \
\
test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
test1598 \
test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \
test1608 test1609 test1610 test1611 test1612 test1613 test1614 test1615 \
test1616 \
test1620 test1621 \
\
test1630 test1631 test1632 test1633 test1634 test1635 \
\
test1650 test1651 test1652 test1653 test1654 test1655 \
test1660 test1661 test1662 \
\
test1670 test1671 \
\
test1680 test1681 test1682 test1683 \
\
test1700 test1701 test1702 test1703 test1704 \
\
test1800 test1801 \
\
test1900 test1901          test1903 test1904 test1905 test1906 test1907 \
test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \
test1916 test1917 test1918 test1919 \
\







|
>






|















|





|







556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
test1423 test1424 test1425 test1426 test1427 test1428 test1429 test1430 \
test1431 test1432 test1433 test1434 test1435 test1436 test1437 test1438 \
test1439 test1440 test1441 test1442 test1443 test1444 test1445 test1446 \
test1447 test1448 test1449 test1450 test1451 test1452 test1453 test1454 \
test1455 test1456 test1457 test1458 test1459 test1460 test1461 test1462 \
test1463 test1464 test1465 test1466 test1467 test1468 test1469 test1470 \
test1471 test1472 test1473 test1474 test1475 test1476 test1477 test1478 \
test1479 test1480 test1481 test1482 test1483 test1484 test1485 test1486 \
test1487 test1488 \
\
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
test1516 test1517 test1518 test1519 test1520 test1521 test1522 test1523 \
test1524 test1525 test1526 test1527 test1528 test1529 test1530 test1531 \
test1532 test1533 test1534 test1535 test1536 test1537 test1538 test1539 \
test1540 test1541 test1542 test1543 test1544 test1545 test1546 \
\
test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \
test1566 test1567 test1568 test1569 test1570 \
\
test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
test1598 \
test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \
test1608 test1609 test1610 test1611 test1612 test1613 test1614 test1615 \
test1616 \
test1620 test1621 \
\
test1630 test1631 test1632 test1633 test1634 test1635 \
\
test1650 test1651 test1652 test1653 test1654 test1655 \
test1660 test1661 test1662 test1663 \
\
test1670 test1671 \
\
test1680 test1681 test1682 test1683 \
\
test1700 test1701 test1702 test1703 test1704 test1705 test1706 \
\
test1800 test1801 \
\
test1900 test1901          test1903 test1904 test1905 test1906 test1907 \
test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \
test1916 test1917 test1918 test1919 \
\
Changes to jni/curl/tests/data/Makefile.inc.
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
test399 test400 test401 test402 test403 test404 test405 test406 test407 \
test408 test409 test410 test411 test412 test413 test414 test415 test416 \
test417 test418 test419 test420 test421 test422 test423 test424 test425 \
test426 test427 test428 test429 test430 test431 test432 test433 test434 \
test435 test436 test437 test438 test439 test440 test441 test442 test443 \
test444 test445 test446 test447 test448 test449 test450 test451 test452 \
test453 test454 test455 test456 test457 test458 test459 test460 test461 \
test462 test463 test467 test468 test469 test470 test471 \
\
test490 test491 test492 test493 test494 test495 test496 test497 test498 \
test499 test500 test501 test502 test503 test504 test505 test506 test507 \
test508 test509 test510 test511 test512 test513 test514 test515 test516 \
test517 test518 test519 test520 test521 test522 test523 test524 test525 \
test526 test527 test528 test529 test530 test531 test532 test533 test534 \
test535 test536 test537 test538 test539 test540 test541 test542 test543 \







|







69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
test399 test400 test401 test402 test403 test404 test405 test406 test407 \
test408 test409 test410 test411 test412 test413 test414 test415 test416 \
test417 test418 test419 test420 test421 test422 test423 test424 test425 \
test426 test427 test428 test429 test430 test431 test432 test433 test434 \
test435 test436 test437 test438 test439 test440 test441 test442 test443 \
test444 test445 test446 test447 test448 test449 test450 test451 test452 \
test453 test454 test455 test456 test457 test458 test459 test460 test461 \
test462 test463 test467 test468 test469 test470 test471 test472 test473 \
\
test490 test491 test492 test493 test494 test495 test496 test497 test498 \
test499 test500 test501 test502 test503 test504 test505 test506 test507 \
test508 test509 test510 test511 test512 test513 test514 test515 test516 \
test517 test518 test519 test520 test521 test522 test523 test524 test525 \
test526 test527 test528 test529 test530 test531 test532 test533 test534 \
test535 test536 test537 test538 test539 test540 test541 test542 test543 \
184
185
186
187
188
189
190
191

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
test1423 test1424 test1425 test1426 test1427 test1428 test1429 test1430 \
test1431 test1432 test1433 test1434 test1435 test1436 test1437 test1438 \
test1439 test1440 test1441 test1442 test1443 test1444 test1445 test1446 \
test1447 test1448 test1449 test1450 test1451 test1452 test1453 test1454 \
test1455 test1456 test1457 test1458 test1459 test1460 test1461 test1462 \
test1463 test1464 test1465 test1466 test1467 test1468 test1469 test1470 \
test1471 test1472 test1473 test1474 test1475 test1476 test1477 test1478 \
test1479 test1480 test1481 test1482 test1483 \

\
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
test1516 test1517 test1518 test1519 test1520 test1521 test1522 test1523 \
test1524 test1525 test1526 test1527 test1528 test1529 test1530 test1531 \
test1532 test1533 test1534 test1535 test1536 test1537 test1538 test1539 \
test1540 test1541 test1542 test1543 test1544 test1545 \
\
test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \
test1566 test1567 test1568 test1569 test1570 \
\
test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
test1598 \
test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \
test1608 test1609 test1610 test1611 test1612 test1613 test1614 test1615 \
test1616 \
test1620 test1621 \
\
test1630 test1631 test1632 test1633 test1634 test1635 \
\
test1650 test1651 test1652 test1653 test1654 test1655 \
test1660 test1661 test1662 \
\
test1670 test1671 \
\
test1680 test1681 test1682 test1683 \
\
test1700 test1701 test1702 test1703 test1704 \
\
test1800 test1801 \
\
test1900 test1901          test1903 test1904 test1905 test1906 test1907 \
test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \
test1916 test1917 test1918 test1919 \
\







|
>






|















|





|







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
test1423 test1424 test1425 test1426 test1427 test1428 test1429 test1430 \
test1431 test1432 test1433 test1434 test1435 test1436 test1437 test1438 \
test1439 test1440 test1441 test1442 test1443 test1444 test1445 test1446 \
test1447 test1448 test1449 test1450 test1451 test1452 test1453 test1454 \
test1455 test1456 test1457 test1458 test1459 test1460 test1461 test1462 \
test1463 test1464 test1465 test1466 test1467 test1468 test1469 test1470 \
test1471 test1472 test1473 test1474 test1475 test1476 test1477 test1478 \
test1479 test1480 test1481 test1482 test1483 test1484 test1485 test1486 \
test1487 test1488 \
\
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
test1516 test1517 test1518 test1519 test1520 test1521 test1522 test1523 \
test1524 test1525 test1526 test1527 test1528 test1529 test1530 test1531 \
test1532 test1533 test1534 test1535 test1536 test1537 test1538 test1539 \
test1540 test1541 test1542 test1543 test1544 test1545 test1546 \
\
test1550 test1551 test1552 test1553 test1554 test1555 test1556 test1557 \
test1558 test1559 test1560 test1561 test1562 test1563 test1564 test1565 \
test1566 test1567 test1568 test1569 test1570 \
\
test1590 test1591 test1592 test1593 test1594 test1595 test1596 test1597 \
test1598 \
test1600 test1601 test1602 test1603 test1604 test1605 test1606 test1607 \
test1608 test1609 test1610 test1611 test1612 test1613 test1614 test1615 \
test1616 \
test1620 test1621 \
\
test1630 test1631 test1632 test1633 test1634 test1635 \
\
test1650 test1651 test1652 test1653 test1654 test1655 \
test1660 test1661 test1662 test1663 \
\
test1670 test1671 \
\
test1680 test1681 test1682 test1683 \
\
test1700 test1701 test1702 test1703 test1704 test1705 test1706 \
\
test1800 test1801 \
\
test1900 test1901          test1903 test1904 test1905 test1906 test1907 \
test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \
test1916 test1917 test1918 test1919 \
\
Changes to jni/curl/tests/data/test1034.
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
#
# Client-side
<client>
<server>
none
</server>
<features>
idn

http
proxy
</features>
<setenv>
LC_ALL=
LC_CTYPE=en_US.UTF-8
</setenv>







<
>







19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
#
# Client-side
<client>
<server>
none
</server>
<features>

IDN
http
proxy
</features>
<setenv>
LC_ALL=
LC_CTYPE=en_US.UTF-8
</setenv>
Changes to jni/curl/tests/data/test1035.
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
#
# Client-side
<client>
<server>
none
</server>
<features>
idn

http
proxy
</features>
<setenv>
LC_ALL=
LC_CTYPE=en_US.UTF-8
</setenv>







<
>







17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
#
# Client-side
<client>
<server>
none
</server>
<features>

IDN
http
proxy
</features>
<setenv>
LC_ALL=
LC_CTYPE=en_US.UTF-8
</setenv>
Changes to jni/curl/tests/data/test1044.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
213 20080726102659
</mdtm>
</reply>

# Client-side
<client>
<features>
large_file
</features>
<server>
ftp
</server>
<name>
FTP download large file info with -I
</name>







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
213 20080726102659
</mdtm>
</reply>

# Client-side
<client>
<features>
Largefile
</features>
<server>
ftp
</server>
<name>
FTP download large file info with -I
</name>
Changes to jni/curl/tests/data/test1046.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with numeric localhost --interface
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with numeric localhost --interface
</name>
Changes to jni/curl/tests/data/test1048.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
</datacheck>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP-IPv6 dir list PASV with localhost --interface
</name>







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
</datacheck>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP-IPv6 dir list PASV with localhost --interface
</name>
Changes to jni/curl/tests/data/test1050.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
dr-xr-xr-x   5 0        1            512 Oct  1  1997 usr
</datacheck>
</reply>

# Client-side
<client>
<features>
ipv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP-IPv6 dir list, EPRT with specified IP
</name>







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
dr-xr-xr-x   5 0        1            512 Oct  1  1997 usr
</datacheck>
</reply>

# Client-side
<client>
<features>
IPv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP-IPv6 dir list, EPRT with specified IP
</name>
Changes to jni/curl/tests/data/test1056.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<client>
# This test relies on the IPv6 scope field being ignored when connecting to
# ipv6-localhost (i.e. [::1%259999] is treated as [::1]). Maybe this is a bit
# dodgy, but it happens on all our test platforms but Windows so skip this
# test there. This feature doesn't work on msys or Cygwin, so use a precheck
# to skip those.
<features>
ipv6
!win32
</features>
<server>
http
http-ipv6
</server>
<name>







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<client>
# This test relies on the IPv6 scope field being ignored when connecting to
# ipv6-localhost (i.e. [::1%259999] is treated as [::1]). Maybe this is a bit
# dodgy, but it happens on all our test platforms but Windows so skip this
# test there. This feature doesn't work on msys or Cygwin, so use a precheck
# to skip those.
<features>
IPv6
!win32
</features>
<server>
http
http-ipv6
</server>
<name>
Changes to jni/curl/tests/data/test1063.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Client-side
<client>
<server>
none
</server>
<features>
file
large_file
</features>
<name>
Invalid large X- range on a file://
</name>
# This range value is 2**32+7, which will be truncated to the valid value 7
# if the large file support is not working correctly
<command>







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Client-side
<client>
<server>
none
</server>
<features>
file
Largefile
</features>
<name>
Invalid large X- range on a file://
</name>
# This range value is 2**32+7, which will be truncated to the valid value 7
# if the large file support is not working correctly
<command>
Changes to jni/curl/tests/data/test1083.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with ip6-localhost --interface
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with ip6-localhost --interface
</name>
Changes to jni/curl/tests/data/test1085.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</reply>

#
# Client-side
<client>
<features>
http
ipv6
</features>
<server>
none
</server>
<name>
HTTP-IPv6 GET with invalid --interface
</name>







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</reply>

#
# Client-side
<client>
<features>
http
IPv6
</features>
<server>
none
</server>
<name>
HTTP-IPv6 GET with invalid --interface
</name>
Changes to jni/curl/tests/data/test1100.
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

# Client-side
<client>
<features>
NTLM
SSL
!SSPI
debug
</features>
<server>
http
</server>
<name>
HTTP POST with NTLM authorization and following a 302 redirect
</name>







|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

# Client-side
<client>
<features>
NTLM
SSL
!SSPI
Debug
</features>
<server>
http
</server>
<name>
HTTP POST with NTLM authorization and following a 302 redirect
</name>
Changes to jni/curl/tests/data/test116.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Client-side
<client>
<server>
ftp
</server>
# EPRT is only sent when IPv6 is enabled
<features>
ipv6
</features>
<name>
FTP download, failed PORT
</name>
<command>
ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -P 1.2.3.4
</command>







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Client-side
<client>
<server>
ftp
</server>
# EPRT is only sent when IPv6 is enabled
<features>
IPv6
</features>
<name>
FTP download, failed PORT
</name>
<command>
ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -P 1.2.3.4
</command>
Changes to jni/curl/tests/data/test1173.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Client-side
<client>
<server>
none
</server>

<name>
Man page syntax checks
</name>

<command type="perl">
%SRCDIR/test1173.pl %SRCDIR/../docs/libcurl/symbols-in-versions %PWD/../docs/*.1  %PWD/../docs/cmdline-opts/*.1 %PWD/../docs/libcurl/*.3 %PWD/../docs/libcurl/opts/*.3
</command>
</client>








|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Client-side
<client>
<server>
none
</server>

<name>
Manpage syntax checks
</name>

<command type="perl">
%SRCDIR/test1173.pl %SRCDIR/../docs/libcurl/symbols-in-versions %PWD/../docs/*.1  %PWD/../docs/cmdline-opts/*.1 %PWD/../docs/libcurl/*.3 %PWD/../docs/libcurl/opts/*.3
</command>
</client>

Changes to jni/curl/tests/data/test1203.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.
</data>
</reply>

# Client-side
<client>
<features>
ipv6
</features>
<server>
gopher-ipv6
</server>
<name>
Gopher IPv6 index
</name>







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.
</data>
</reply>

# Client-side
<client>
<features>
IPv6
</features>
<server>
gopher-ipv6
</server>
<name>
Gopher IPv6 index
</name>
Changes to jni/curl/tests/data/test1210.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J without Content-Disposition
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J without Content-Disposition
</name>
Changes to jni/curl/tests/data/test1230.
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
</datacheck>
</reply>

#
# Client-side
<client>
<features>
ipv6
proxy
</features>
<server>
http-proxy
http-ipv6
http
</server>







|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
</datacheck>
</reply>

#
# Client-side
<client>
<features>
IPv6
proxy
</features>
<server>
http-proxy
http-ipv6
http
</server>
Changes to jni/curl/tests/data/test1268.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#
# Client-side
<client>
<server>
none
</server>
<features>
unix-sockets
</features>
<name>
file name argument looks like a flag
</name>
<command>
--stderr %LOGDIR/moo%TESTNUMBER --unix-socket -k hej://moo
</command>
</client>

<verify>
<file name="%LOGDIR/moo%TESTNUMBER" mode="text">
Warning: The file name argument '-k' looks like a flag.
curl: (1) Protocol "hej" not supported
</file>

# we expect an error since we provide a weird URL
<errorcode>
1
</errorcode>







|


|








|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#
# Client-side
<client>
<server>
none
</server>
<features>
UnixSockets
</features>
<name>
filename argument looks like a flag
</name>
<command>
--stderr %LOGDIR/moo%TESTNUMBER --unix-socket -k hej://moo
</command>
</client>

<verify>
<file name="%LOGDIR/moo%TESTNUMBER" mode="text">
Warning: The filename argument '-k' looks like a flag.
curl: (1) Protocol "hej" not supported
</file>

# we expect an error since we provide a weird URL
<errorcode>
1
</errorcode>
Changes to jni/curl/tests/data/test1294.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</reply>

#
# Client-side
<client>
# hyper doesn't support the added crazy header
<features>
debug
!hyper
</features>
<server>
http
</server>
<name>
HTTP GET with split initial request send







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</reply>

#
# Client-side
<client>
# hyper doesn't support the added crazy header
<features>
Debug
!hyper
</features>
<server>
http
</server>
<name>
HTTP GET with split initial request send
Changes to jni/curl/tests/data/test1295.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</data>
</reply>

#
# Client-side
<client>
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP POST with split initial request send
</name>







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</data>
</reply>

#
# Client-side
<client>
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP POST with split initial request send
</name>
Changes to jni/curl/tests/data/test1296.
47
48
49
50
51
52
53
54
Authorization: Basic dXNlcgpuYW1lOnBhc3N3b3Jk
User-Agent: curl/%VERSION
Accept: */*

</protocol>
</verify>
</testcase>








<
47
48
49
50
51
52
53

Authorization: Basic dXNlcgpuYW1lOnBhc3N3b3Jk
User-Agent: curl/%VERSION
Accept: */*

</protocol>
</verify>
</testcase>

Changes to jni/curl/tests/data/test1310.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

</reply>

# Client-side
<client>
<features>
NTLM_WB
debug
</features>
<server>
http
</server>
<name>
HTTP with NTLM delegation to winbind helper
</name>







|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

</reply>

# Client-side
<client>
<features>
NTLM_WB
Debug
</features>
<server>
http
</server>
<name>
HTTP with NTLM delegation to winbind helper
</name>
Changes to jni/curl/tests/data/test1311.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J and Content-Disposition
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J and Content-Disposition
</name>
Changes to jni/curl/tests/data/test1312.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J, Content-Disposition and ; in filename
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J, Content-Disposition and ; in filename
</name>
Changes to jni/curl/tests/data/test1313.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J, Content-Disposition, uneven quotes
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J, Content-Disposition, uneven quotes
</name>
Changes to jni/curl/tests/data/test1334.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O without Content-Disposition, -D file
</name>







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O without Content-Disposition, -D file
</name>
Changes to jni/curl/tests/data/test1335.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O without Content-Disposition, -D stdout
</name>







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O without Content-Disposition, -D stdout
</name>
Changes to jni/curl/tests/data/test1336.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O and Content-Disposition, -D file
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O and Content-Disposition, -D file
</name>
Changes to jni/curl/tests/data/test1337.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O and Content-Disposition, -D stdout
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O and Content-Disposition, -D stdout
</name>
Changes to jni/curl/tests/data/test1338.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J without Content-Disposition, -D file
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J without Content-Disposition, -D file
</name>
Changes to jni/curl/tests/data/test1339.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J without Content-Disposition, -D stdout
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J without Content-Disposition, -D stdout
</name>
Changes to jni/curl/tests/data/test1340.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J and Content-Disposition, -D file
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J and Content-Disposition, -D file
</name>
Changes to jni/curl/tests/data/test1341.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J and Content-Disposition, -D stdout
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J and Content-Disposition, -D stdout
</name>
Changes to jni/curl/tests/data/test1342.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i without Content-Disposition, -D file
</name>







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i without Content-Disposition, -D file
</name>
Changes to jni/curl/tests/data/test1343.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i without Content-Disposition, -D stdout
</name>







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i without Content-Disposition, -D stdout
</name>
Changes to jni/curl/tests/data/test1344.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i and Content-Disposition, -D file
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i and Content-Disposition, -D file
</name>
Changes to jni/curl/tests/data/test1345.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i and Content-Disposition, -D stdout
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i and Content-Disposition, -D stdout
</name>
Changes to jni/curl/tests/data/test1346.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i without Content-Disposition, without -D
</name>







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i without Content-Disposition, without -D
</name>
Changes to jni/curl/tests/data/test1347.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i and Content-Disposition, without -D
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O -i and Content-Disposition, without -D
</name>
Changes to jni/curl/tests/data/test1348.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without Content-Disposition inside, using -O
</name>







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without Content-Disposition inside, using -O
</name>
Changes to jni/curl/tests/data/test1349.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -D file
</name>







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -D file
</name>
Changes to jni/curl/tests/data/test1350.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -D stdout
</name>







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -D stdout
</name>
Changes to jni/curl/tests/data/test1351.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -J -D file
</name>







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -J -D file
</name>
Changes to jni/curl/tests/data/test1352.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -J -D stdout
</name>







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -J -D stdout
</name>
Changes to jni/curl/tests/data/test1353.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -i -D file
</name>







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -i -D file
</name>
Changes to jni/curl/tests/data/test1354.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -i -D stdout
</name>







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -i -D stdout
</name>
Changes to jni/curl/tests/data/test1355.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -i, without -D
</name>







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file without C-D inside, using -O -i, without -D
</name>
Changes to jni/curl/tests/data/test1356.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with Content-Disposition inside, using -O
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with Content-Disposition inside, using -O
</name>
Changes to jni/curl/tests/data/test1357.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -D file
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -D file
</name>
Changes to jni/curl/tests/data/test1358.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -D stdout
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -D stdout
</name>
Changes to jni/curl/tests/data/test1359.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -J -D file
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -J -D file
</name>
Changes to jni/curl/tests/data/test1360.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -J -D stdout
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -J -D stdout
</name>
Changes to jni/curl/tests/data/test1361.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -i -D file
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -i -D file
</name>
Changes to jni/curl/tests/data/test1362.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -i -D stdout
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -i -D stdout
</name>
Changes to jni/curl/tests/data/test1363.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -i, without -D
</name>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O output in, using the CURL_TESTDIR variable
<features>
Debug
</features>
<server>
ftp
</server>
<name>
FTP download, file with C-D inside, using -O -i, without -D
</name>
Changes to jni/curl/tests/data/test1408.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</reply>

#
# Client-side
<client>
<features>
cookies
ipv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP receive cookies over IPV6
</name>







|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</reply>

#
# Client-side
<client>
<features>
cookies
IPv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP receive cookies over IPV6
</name>
Changes to jni/curl/tests/data/test1422.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
debug
file
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J and Content-Disposition (empty file)







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -O and -J output in, using the CURL_TESTDIR variable
<features>
Debug
file
</features>
<server>
http
</server>
<name>
HTTP GET with -O -J and Content-Disposition (empty file)
Changes to jni/curl/tests/data/test1425.

cannot compute difference between binary files

Changes to jni/curl/tests/data/test1426.

cannot compute difference between binary files

Changes to jni/curl/tests/data/test1435.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<testcase>
<info>
<keywords>
HTTP
HTTP GET
unix sockets
</keywords>
</info>

<reply>
<data>
HTTP/1.1 200 OK
Date: Sun, 16 Nov 2014 23:47:38 GMT
Content-Length: 17

Based on test300
</data>
</reply>

<client>
<features>
unix-sockets
</features>
<server>
http-unix
</server>
<name>
simple HTTP GET over Unix socket
</name>





|















|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<testcase>
<info>
<keywords>
HTTP
HTTP GET
UnixSockets
</keywords>
</info>

<reply>
<data>
HTTP/1.1 200 OK
Date: Sun, 16 Nov 2014 23:47:38 GMT
Content-Length: 17

Based on test300
</data>
</reply>

<client>
<features>
UnixSockets
</features>
<server>
http-unix
</server>
<name>
simple HTTP GET over Unix socket
</name>
Changes to jni/curl/tests/data/test1436.
1
2
3
4
5
6
7
8
9
10
11
12
13
<testcase>
<info>
<keywords>
HTTP
HTTP GET
unix sockets
</keywords>
</info>

<reply>
<data1>
HTTP/1.1 200 OK
Date: Mon, 17 Nov 2014 13:42:47 GMT





|







1
2
3
4
5
6
7
8
9
10
11
12
13
<testcase>
<info>
<keywords>
HTTP
HTTP GET
UnixSockets
</keywords>
</info>

<reply>
<data1>
HTTP/1.1 200 OK
Date: Mon, 17 Nov 2014 13:42:47 GMT
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

Third
</data3>
</reply>

<client>
<features>
unix-sockets
</features>
<server>
http-unix
</server>
<name>
HTTP requests with multiple connections over Unix socket
</name>







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

Third
</data3>
</reply>

<client>
<features>
UnixSockets
</features>
<server>
http-unix
</server>
<name>
HTTP requests with multiple connections over Unix socket
</name>
Changes to jni/curl/tests/data/test1443.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# This relies on the debug feature to allow us to set a directory
# in which to store the -O output
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O and --remote-time
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#
# Client-side
<client>
# This relies on the debug feature to allow us to set a directory
# in which to store the -O output
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -O and --remote-time
</name>
Changes to jni/curl/tests/data/test1448.
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
#
# Client-side
<client>
<server>
http
</server>
<features>
idn

</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");'







<
>







35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
#
# Client-side
<client>
<server>
http
</server>
<features>

IDN
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");'
Changes to jni/curl/tests/data/test1454.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<reply>
</reply>

#
# Client-side
<client>
<features>
!ipv6
</features>
<server>
http
</server>
<name>
--connect-to with IPv6 address w/o IPv6 support!
</name>







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<reply>
</reply>

#
# Client-side
<client>
<features>
!IPv6
</features>
<server>
http
</server>
<name>
--connect-to with IPv6 address w/o IPv6 support!
</name>
Changes to jni/curl/tests/data/test1456.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with PROXY protocol
</name>







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with PROXY protocol
</name>
Changes to jni/curl/tests/data/test1459.
41
42
43
44
45
46
47
48
60
</errorcode>
<valgrind>
disable
</valgrind>
</verify>
</testcase>








<
41
42
43
44
45
46
47

60
</errorcode>
<valgrind>
disable
</valgrind>
</verify>
</testcase>

Changes to jni/curl/tests/data/test1460.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP GET with -Ji and Content-Disposition with existing file
</name>







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -Ji and Content-Disposition with existing file
</name>
Changes to jni/curl/tests/data/test1461.
41
42
43
44
45
46
47
48
49



50
51
52
53
 -s, --silent                Silent mode
 -T, --upload-file <file>    Transfer local FILE to destination
 -u, --user <user:password>  Server user and password
 -A, --user-agent <name>     Send User-Agent <name> to server
 -v, --verbose               Make the operation more talkative
 -V, --version               Show version number and quit

This is not the full help, this menu is stripped into categories.
Use "--help category" to get an overview of all categories.



For all options use the manual or "--help all".
</stdout>
</verify>
</testcase>







|
|
>
>
>




41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
 -s, --silent                Silent mode
 -T, --upload-file <file>    Transfer local FILE to destination
 -u, --user <user:password>  Server user and password
 -A, --user-agent <name>     Send User-Agent <name> to server
 -v, --verbose               Make the operation more talkative
 -V, --version               Show version number and quit

This is not the full help; this menu is split into categories.
Use "--help category" to get an overview of all categories, which are:
auth, connection, curl, deprecated, dns, file, ftp, global, http, imap, ldap, 
output, pop3, post, proxy, scp, sftp, smtp, ssh, telnet, tftp, timeout, tls, 
upload, verbose.
For all options use the manual or "--help all".
</stdout>
</verify>
</testcase>
Changes to jni/curl/tests/data/test1462.
28
29
30
31
32
33
34
35
36
37
38
39

40
41
42

43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60
61
62
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
<stdout mode="text">
Usage: curl [options...] <url>
Invalid category provided, here is a list of all categories:

 auth        Different types of authentication methods
 connection  Low level networking operations
 curl        The command line tool itself

 dns         General DNS options
 file        FILE protocol options
 ftp         FTP protocol options

 http        HTTP and HTTPS protocol options
 imap        IMAP protocol options
 misc        Options that don't fit into any other category
 output      Filesystem output
 pop3        POP3 protocol options
 post        HTTP Post specific options
 proxy       All options related to proxies
 scp         SCP protocol options
 sftp        SFTP protocol options
 smtp        SMTP protocol options
 ssh         SSH protocol options
 telnet      TELNET protocol options
 tftp        TFTP protocol options

 tls         All TLS/SSL related options
 ech         All Encrypted Client Hello (ECH) options
 upload      All options for uploads
 verbose     Options related to any kind of command line output of curl
</stdout>
</verify>
</testcase>







|

|
|

>
|
|
|
>
|
|
|

|
|
|
|
|
|
|
|
|
>
|
<
|
|



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

60
61
62
63
64
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
<stdout mode="text">
Usage: curl [options...] <url>
Unknown category provided, here is a list of all categories:

 auth        Authentication methods
 connection  Manage connections
 curl        The command line tool itself
 deprecated  Legacy
 dns         Names and resolving
 file        FILE protocol
 ftp         FTP protocol
 global      Global options
 http        HTTP and HTTPS protocol
 imap        IMAP protocol
 ldap        LDAP protocol
 output      Filesystem output
 pop3        POP3 protocol
 post        HTTP POST specific
 proxy       Options for proxies
 scp         SCP protocol
 sftp        SFTP protocol
 smtp        SMTP protocol
 ssh         SSH protocol
 telnet      TELNET protocol
 tftp        TFTP protocol
 timeout     Timeouts and delays
 tls         TLS/SSL related

 upload      Upload, sending data
 verbose     Tracing, logging etc
</stdout>
</verify>
</testcase>
Changes to jni/curl/tests/data/test1463.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
<stdout mode="text">
Usage: curl [options...] <url>
file: FILE protocol options
     --create-file-mode <mode>  File mode for created files
 -I, --head                     Show document info only
 -l, --list-only                List only mode
 -r, --range <range>            Retrieve only the bytes within RANGE
</stdout>
</verify>
</testcase>







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
<stdout mode="text">
Usage: curl [options...] <url>
file: FILE protocol
     --create-file-mode <mode>  File mode for created files
 -I, --head                     Show document info only
 -l, --list-only                List only mode
 -r, --range <range>            Retrieve only the bytes within RANGE
</stdout>
</verify>
</testcase>
Changes to jni/curl/tests/data/test1464.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
<stdout mode="text">
Usage: curl [options...] <url>
file: FILE protocol options
     --create-file-mode <mode>  File mode for created files
 -I, --head                     Show document info only
 -l, --list-only                List only mode
 -r, --range <range>            Retrieve only the bytes within RANGE
</stdout>
</verify>
</testcase>







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
<stdout mode="text">
Usage: curl [options...] <url>
file: FILE protocol
     --create-file-mode <mode>  File mode for created files
 -I, --head                     Show document info only
 -l, --list-only                List only mode
 -r, --range <range>            Retrieve only the bytes within RANGE
</stdout>
</verify>
</testcase>
Changes to jni/curl/tests/data/test1467.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<testcase>
<info>
<keywords>
HTTP
HTTP GET
SOCKS5
unix sockets
</keywords>
</info>

#
# Server-side
<reply>
<data>






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
<testcase>
<info>
<keywords>
HTTP
HTTP GET
SOCKS5
UnixSockets
</keywords>
</info>

#
# Server-side
<reply>
<data>
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</reply>

#
# Client-side
<client>
<features>
proxy
unix-sockets
</features>
<server>
http
socks5unix
</server>
<name>
HTTP GET via SOCKS5 proxy via unix sockets







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</reply>

#
# Client-side
<client>
<features>
proxy
UnixSockets
</features>
<server>
http
socks5unix
</server>
<name>
HTTP GET via SOCKS5 proxy via unix sockets
Changes to jni/curl/tests/data/test1468.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<testcase>
<info>
<keywords>
HTTP
HTTP GET
SOCKS5
SOCKS5h
unix sockets
</keywords>
</info>

#
# Server-side
<reply>
<data>







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<testcase>
<info>
<keywords>
HTTP
HTTP GET
SOCKS5
SOCKS5h
UnixSockets
</keywords>
</info>

#
# Server-side
<reply>
<data>
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
</reply>

#
# Client-side
<client>
<features>
proxy
unix-sockets
</features>
<server>
http
socks5unix
</server>
<name>
HTTP GET with host name using SOCKS5h via unix sockets







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
</reply>

#
# Client-side
<client>
<features>
proxy
UnixSockets
</features>
<server>
http
socks5unix
</server>
<name>
HTTP GET with host name using SOCKS5h via unix sockets
Changes to jni/curl/tests/data/test1470.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<testcase>
<info>
<keywords>
HTTPS
HTTP
HTTP GET
SOCKS5
SOCKS5h
unix sockets
</keywords>
</info>

#
# Server-side
<reply>
<data>








|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<testcase>
<info>
<keywords>
HTTPS
HTTP
HTTP GET
SOCKS5
SOCKS5h
UnixSockets
</keywords>
</info>

#
# Server-side
<reply>
<data>
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
</reply>

#
# Client-side
<client>
<features>
proxy
unix-sockets
</features>
<server>
https
socks5unix
</server>
<name>
HTTPS GET with host name using SOCKS5h via unix sockets







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
</reply>

#
# Client-side
<client>
<features>
proxy
UnixSockets
</features>
<server>
https
socks5unix
</server>
<name>
HTTPS GET with host name using SOCKS5h via unix sockets
Added jni/curl/tests/data/test1484.










































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<testcase>
<info>
<keywords>
HTTP
HTTP HEAD
</keywords>
</info>

#
# Server-side
<reply>
<data>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Transfer-Encoding: chunked

HEAD response with content
</data>
# make sure no data is written
<datacheck>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Transfer-Encoding: chunked

</datacheck>
</reply>

#
# Client-side
<client>
<server>
http
</server>
<name>
HTTP HEAD with response body to ignore
</name>
<command>
-I http://%HOSTIP:%HTTPPORT/%TESTNUMBER --http1.1
</command>
</client>

#
# Verify data after the test has been "shot"
<verify>
<protocol>
HEAD /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*

</protocol>
</verify>
</testcase>
Added jni/curl/tests/data/test1485.






































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<testcase>
<info>
<keywords>
HTTP
HTTP GET
</keywords>
</info>

# Server-side
<reply>
<data>
HTTP/1.1 200 OK
Server: Someone
Content-Length: 7

123456
</data>
<datacheck>
HTTP/1.1 200 OK
Server: Someone
Content-Length: 7

123456
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<tool>
lib%TESTNUMBER
</tool>
<name>
get curlinfo on last header in callback
</name>
<command>
http://%HOSTIP:%HTTPPORT/%TESTNUMBER
</command>
</client>

# Verify data after the test has been "shot"
<verify>
<protocol>
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*

</protocol>
</verify>
</testcase>
Added jni/curl/tests/data/test1486.
































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<testcase>
<info>
<keywords>
source analysis
docs
--write-out
</keywords>
</info>

#
# Client-side
<client>
<server>
none
</server>

<name>
Verify that write-out.md and tool_writeout.c are in sync
</name>

<command type="perl">
%SRCDIR/test1486.pl %SRCDIR
</command>
</client>

<verify>
<stdout>
OK
</stdout>
</verify>

</testcase>
Added jni/curl/tests/data/test1487.




























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<testcase>
<info>
<keywords>
HTTP
HTTP GET
-J
</keywords>
</info>

#
<reply>
<data nocheck="yes">
HTTP/1.1 301 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 6
Connection: close
Content-Type: text/html
Content-Disposition: filename=name%TESTNUMBER; charset=funny; option=strange

12345
</data>
</reply>

#
# Client-side
<client>
# this relies on the debug feature to allow us to set directory to store the
# -J output in
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP GET with -J and Content-Disposition on 301
</name>
<setenv>
CURL_TESTDIR=%LOGDIR
</setenv>
<command option="no-output,no-include">
http://%HOSTIP:%HTTPPORT/%TESTNUMBER -J -O
</command>
</client>

#
# Verify data after the test has been "shot"
<verify>
<protocol>
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*

</protocol>
<file name="%LOGDIR/name%TESTNUMBER">
12345
</file>

</verify>
</testcase>
Added jni/curl/tests/data/test1488.






























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<testcase>
<info>
<keywords>
documentation
symbols-in-versions
manpages
</keywords>
</info>

#
# Client-side
<client>
<server>
none
</server>

<name>
symbols-in-versions and manpages agree on added-in versions
</name>

<command type="perl">
%SRCDIR/test1488.pl %SRCDIR/.. ../include/curl
</command>
</client>

<verify>
<stdout>
OK
</stdout>
</verify>
</testcase>
Changes to jni/curl/tests/data/test1538.
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<verify>
<stdout>
e0: No error
e1: Unsupported protocol
e2: Failed initialization
e3: URL using bad/illegal format or missing URL
e4: A requested feature, protocol or option was not found built-in in this libcurl due to a build-time decision.
e5: Couldn't resolve proxy name
e6: Couldn't resolve host name
e7: Couldn't connect to server
e8: Weird server reply
e9: Access denied to remote resource
e10: FTP: The server failed to connect to data port
e11: FTP: unknown PASS reply
e12: FTP: Accepting server connect has timed out
e13: FTP: unknown PASV reply
e14: FTP: unknown 227 response format
e15: FTP: can't figure out the host in the PASV response
e16: Error in the HTTP2 framing layer
e17: FTP: couldn't set file type
e18: Transferred a partial file
e19: FTP: couldn't retrieve (RETR failed) the specified file
e20: Unknown error
e21: Quote command returned error
e22: HTTP response code said error
e23: Failed writing received data to disk/application
e24: Unknown error
e25: Upload failed (at start/before it took off)
e26: Failed to open/read local data from file/application
e27: Out of memory
e28: Timeout was reached
e29: Unknown error
e30: FTP: command PORT failed
e31: FTP: command REST failed
e32: Unknown error
e33: Requested range was not delivered by the server
e34: Internal problem setting up the POST
e35: SSL connect error
e36: Couldn't resume download
e37: Couldn't read a file:// file
e38: LDAP: cannot bind
e39: LDAP: search failed
e40: Unknown error
e41: A required function in the library was not found
e42: Operation was aborted by an application callback
e43: A libcurl function was given a bad argument
e44: Unknown error







|
|
|







|

|

|
















|
|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<verify>
<stdout>
e0: No error
e1: Unsupported protocol
e2: Failed initialization
e3: URL using bad/illegal format or missing URL
e4: A requested feature, protocol or option was not found built-in in this libcurl due to a build-time decision.
e5: Could not resolve proxy name
e6: Could not resolve hostname
e7: Could not connect to server
e8: Weird server reply
e9: Access denied to remote resource
e10: FTP: The server failed to connect to data port
e11: FTP: unknown PASS reply
e12: FTP: Accepting server connect has timed out
e13: FTP: unknown PASV reply
e14: FTP: unknown 227 response format
e15: FTP: cannot figure out the host in the PASV response
e16: Error in the HTTP2 framing layer
e17: FTP: could not set file type
e18: Transferred a partial file
e19: FTP: could not retrieve (RETR failed) the specified file
e20: Unknown error
e21: Quote command returned error
e22: HTTP response code said error
e23: Failed writing received data to disk/application
e24: Unknown error
e25: Upload failed (at start/before it took off)
e26: Failed to open/read local data from file/application
e27: Out of memory
e28: Timeout was reached
e29: Unknown error
e30: FTP: command PORT failed
e31: FTP: command REST failed
e32: Unknown error
e33: Requested range was not delivered by the server
e34: Internal problem setting up the POST
e35: SSL connect error
e36: Could not resume download
e37: Could not read a file:// file
e38: LDAP: cannot bind
e39: LDAP: search failed
e40: Unknown error
e41: A required function in the library was not found
e42: Operation was aborted by an application callback
e43: A libcurl function was given a bad argument
e44: Unknown error
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
e52: Server returned nothing (no headers, no data)
e53: SSL crypto engine not found
e54: Can not set SSL crypto engine as default
e55: Failed sending data to the peer
e56: Failure when receiving data from the peer
e57: Unknown error
e58: Problem with the local SSL certificate
e59: Couldn't use specified SSL cipher
e60: SSL peer certificate or SSH remote key was not OK
e61: Unrecognized or bad HTTP Content or Transfer-Encoding
e62: Unknown error
e63: Maximum file size exceeded
e64: Requested SSL level failed
e65: Send failed since rewinding of the data stream failed
e66: Failed to initialise SSL crypto engine







|







87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
e52: Server returned nothing (no headers, no data)
e53: SSL crypto engine not found
e54: Can not set SSL crypto engine as default
e55: Failed sending data to the peer
e56: Failure when receiving data from the peer
e57: Unknown error
e58: Problem with the local SSL certificate
e59: Could not use specified SSL cipher
e60: SSL peer certificate or SSH remote key was not OK
e61: Unrecognized or bad HTTP Content or Transfer-Encoding
e62: Unknown error
e63: Maximum file size exceeded
e64: Requested SSL level failed
e65: Send failed since rewinding of the data stream failed
e66: Failed to initialise SSL crypto engine
Changes to jni/curl/tests/data/test1542.
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Accept: */*

</protocol>
<file name="%LOGDIR/stderr%TESTNUMBER" mode="text">
== Info: Connection #0 to host %HOSTIP left intact
== Info: Connection #0 to host %HOSTIP left intact
== Info: Connection #0 to host %HOSTIP left intact
== Info: Closing connection
== Info: Connection #1 to host %HOSTIP left intact
</file>
<stripfile>
$_ = '' if (($_ !~ /left intact/) && ($_ !~ /Closing connection/))
</stripfile>
</verify>
</testcase>







|



|



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Accept: */*

</protocol>
<file name="%LOGDIR/stderr%TESTNUMBER" mode="text">
== Info: Connection #0 to host %HOSTIP left intact
== Info: Connection #0 to host %HOSTIP left intact
== Info: Connection #0 to host %HOSTIP left intact
== Info: shutting down connection #0
== Info: Connection #1 to host %HOSTIP left intact
</file>
<stripfile>
$_ = '' if (($_ !~ /left intact/) && ($_ !~ /(closing|shutting down) connection #\d+/))
</stripfile>
</verify>
</testcase>
Added jni/curl/tests/data/test1546.






























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<testcase>
<info>
<keywords>
HTTP
HTTP GET
Transfer-Encoding
</keywords>
</info>
#
# Server-side
<reply>
<data>
HTTP/1.1 200 OK
Date: Mon, 29 Nov 2004 21:56:53 GMT
Server: Apache
Transfer-Encoding: chunked, gzip

0

</data>

<datacheck>
HTTP/1.1 200 OK
Date: Mon, 29 Nov 2004 21:56:53 GMT
Server: Apache
</datacheck>

</reply>

#
# Client-side
<client>
<features>
libz
</features>
<server>
http
</server>
<name>
HTTP transfer-encoding wrong order
</name>
<command>
http://%HOSTIP:%HTTPPORT/%TESTNUMBER --tr-encoding
</command>
</client>

#
# Verify data after the test has been "shot"
<verify>
<protocol>
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
Connection: TE
TE: gzip

</protocol>
<errorcode>
61
</errorcode>
</verify>
</testcase>
Changes to jni/curl/tests/data/test159.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# Client-side
<client>
<features>
NTLM
SSL
!SSPI
debug
</features>
<server>
http
</server>
<name>
HTTP with NTLM authorization when talking HTTP/1.0 (known to fail)
</name>







|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

# Client-side
<client>
<features>
NTLM
SSL
!SSPI
Debug
</features>
<server>
http
</server>
<name>
HTTP with NTLM authorization when talking HTTP/1.0 (known to fail)
</name>
Changes to jni/curl/tests/data/test165.
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
#
# Client-side
<client>
<server>
http
</server>
<features>
idn

proxy
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







24
25
26
27
28
29
30

31
32
33
34
35
36
37
38
#
# Client-side
<client>
<server>
http
</server>
<features>

IDN
proxy
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test1662.
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
</reply>

#
# Client-side
<client>
<features>
Mime
debug
</features>
<server>
http
</server>
<name>
HTTP formpost from callback and a redirect and switch to GET
</name>







|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
</reply>

#
# Client-side
<client>
<features>
Mime
Debug
</features>
<server>
http
</server>
<name>
HTTP formpost from callback and a redirect and switch to GET
</name>
Added jni/curl/tests/data/test1663.














































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<testcase>
<info>
<keywords>
unittest
interface
bind
</keywords>
</info>

#
# Client-side
<client>
<server>
none
</server>
<features>
unittest
</features>
<name>
unit tests for interface option parsing
</name>
</client>
</testcase>
Added jni/curl/tests/data/test1705.




























































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
<testcase>
<info>
<keywords>
script
documentation
managen
</keywords>
</info>

#
# Client-side
<client>
<server>
none
</server>

<name>
managen makes manpage
</name>

<file name="%LOGDIR/mainpage.idx">
_header.md
%options
_footer.md
</file>

<file1 name="%LOGDIR/_header.md">
<!-- Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. -->
<!-- SPDX-License-Identifier: curl -->
# DESCRIPTION

**curl** is a tool for transferring data from or to a server using URLs. It
supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS,
IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP,
SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.

curl is powered by libcurl for all transfer-related features. See
*libcurl(3)* for details.
</file1>
<file2 name="%LOGDIR/option1.md">
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: v
Long: fakeitreal
Mutexed: trace trace-ascii
Help: Make the operation more talkative
Category: important verbose global
Added: 4.0
Multi: boolean
Scope: global
See-also:
  - include
  - silent
  - trace
  - trace-ascii
Example:
  - --verbose $URL
---

# `--verbose`

Makes curl verbose during the operation. Useful for debugging and seeing
what's going on under the hood. A line starting with \> means header data sent
by curl, \< means header data received by curl that is hidden in normal cases,
and a line starting with * means additional info provided by curl.

If you only want HTTP headers in the output, --include or --dump-header might
be more suitable options.

If you think this option still does not give you enough details, consider using
--trace or --trace-ascii instead.

Note that verbose output of curl activities and network traffic might contain
sensitive data, including usernames, credentials or secret data content. Be
aware and be careful when sharing trace logs with others.

End with a quote

    hello
</file2>
<file3 name="%LOGDIR/option2.md">
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proto
Arg: <protocols>
Help: Enable/disable PROTOCOLS
Added: 7.20.2
Category: connection curl
Multi: single
See-also:
  - fakeitreal
  - proto-default
Example:
  - --proto =http,https,sftp $URL
---

# `--proto`

Limit what protocols to allow for transfers. Protocols are evaluated left to
right, are comma separated, and are each a protocol name or 'all', optionally
prefixed by zero or more modifiers. Available modifiers are:

## +
Permit this protocol in addition to protocols already permitted (this is
the default if no modifier is used).

## -
Deny this protocol, removing it from the list of protocols already permitted.

## =
Permit only this protocol (ignoring the list already permitted), though
subject to later modification by subsequent entries in the comma separated
list.

##

For example: --proto -ftps uses the default protocols, but disables ftps

--proto -all,https,+http only enables http and https

--proto =http,https also only enables http and https

Unknown and disabled protocols produce a warning. This allows scripts to
safely rely on being able to disable potentially dangerous protocols, without
relying upon support for that protocol being built into curl to avoid an error.

This option can be used multiple times, in which case the effect is the same
as concatenating the protocols into one instance of the option.
</file3>
<file4 name="%LOGDIR/_footer.md">
<!-- Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. -->
<!-- SPDX-License-Identifier: curl -->
# PROXY PROTOCOL PREFIXES
The proxy string may be specified with a protocol:// prefix to specify
alternative proxy protocols. (Added in 7.21.7)

If no protocol is specified in the proxy string or if the string does not
match a supported one, the proxy is treated as an HTTP proxy.

The supported proxy protocol prefixes are as follows:
## http://
Makes it use it as an HTTP proxy. The default if no scheme prefix is used.
## https://
Makes it treated as an **HTTPS** proxy.
## socks4://
Makes it the equivalent of --socks4
## socks4a://
Makes it the equivalent of --socks4a
## socks5://
Makes it the equivalent of --socks5
## socks5h://
Makes it the equivalent of --socks5-hostname
</file4>

<command type="perl">
%SRCDIR/../scripts/managen -d %LOGDIR -I %SRCDIR/../include mainpage option1.md option2.md
</command>
</client>

<verify>
<stderr>
option1.md:19:1:WARN: see-also a non-existing option: include
option1.md:19:1:WARN: see-also a non-existing option: silent
option1.md:19:1:WARN: see-also a non-existing option: trace
option1.md:19:1:WARN: see-also a non-existing option: trace-ascii
WARN: option1.md mutexes a non-existing option: trace
WARN: option1.md mutexes a non-existing option: trace-ascii
option2.md:15:1:WARN: see-also a non-existing option: proto-default
</stderr>
<stdout>
.\" **************************************************************************
.\" *                                  _   _ ____  _
.\" *  Project                     ___| | | |  _ \| |
.\" *                             / __| | | | |_) | |
.\" *                            | (__| |_| |  _ <| |___
.\" *                             \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
.\" * are also available at https://curl.se/docs/copyright.html.
.\" *
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
.\" * copies of the Software, and permit persons to whom the Software is
.\" * furnished to do so, under the terms of the COPYING file.
.\" *
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\" * KIND, either express or implied.
.\" *
.\" * SPDX-License-Identifier: curl
.\" *
.\" **************************************************************************
.\"
.\" DO NOT EDIT. Generated by the curl project managen manpage generator.
.\"
.TH curl 1 "%DATE" "curl %VERNUM" "curl Manual"
.SH DESCRIPTION
\fBcurl\fP is a tool for transferring data from or to a server using URLs. It
supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS,
IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP,
SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.

curl is powered by libcurl for all transfer\-related features. See
\fIlibcurl(3)\fP for details.
.IP "\-v, \-\-fakeitreal"
Makes curl verbose during the operation. Useful for debugging and seeing
what\(aqs going on under the hood. A line starting with > means header data sent
by curl, < means header data received by curl that is hidden in normal cases,
and a line starting with * means additional info provided by curl.

If you only want HTTP headers in the output, \fI\-\-include\fP or \fI\-\-dump\-header\fP might
be more suitable options.

If you think this option still does not give you enough details, consider using
\fI\-\-trace\fP or \fI\-\-trace\-ascii\fP instead.

Note that verbose output of curl activities and network traffic might contain
sensitive data, including usernames, credentials or secret data content. Be
aware and be careful when sharing trace logs with others.

End with a quote
.nf

hello
.fi

This option is global and does not need to be specified for each use of --next.

Providing --fakeitreal multiple times has no extra effect.
Disable it again with \-\-no-fakeitreal.

Example:
.nf
 curl --verbose https://example.com
.fi

This option is mutually exclusive with \fI\-\-trace\fP and \fI\-\-trace\-ascii\fP.
See also \fI\-\-include\fP, \fI\-\-silent\fP, \fI\-\-trace\fP and \fI\-\-trace\-ascii\fP.
.IP "\-\-proto <protocols>"
Limit what protocols to allow for transfers. Protocols are evaluated left to
right, are comma separated, and are each a protocol name or \(aqall\(aq, optionally
prefixed by zero or more modifiers. Available modifiers are:
.RS
.IP +
Permit this protocol in addition to protocols already permitted (this is
the default if no modifier is used).
.IP -
Deny this protocol, removing it from the list of protocols already permitted.
.IP =
Permit only this protocol (ignoring the list already permitted), though
subject to later modification by subsequent entries in the comma separated
list.
.RE
.IP
For example: \fI\-\-proto\fP \-ftps uses the default protocols, but disables ftps

\fI\-\-proto\fP \-all,https,+http only enables http and https

\fI\-\-proto\fP =http,https also only enables http and https

Unknown and disabled protocols produce a warning. This allows scripts to
safely rely on being able to disable potentially dangerous protocols, without
relying upon support for that protocol being built into curl to avoid an error.

This option can be used multiple times, in which case the effect is the same
as concatenating the protocols into one instance of the option.

If --proto is provided several times, the last set value is used.

Example:
.nf
 curl --proto =http,https,sftp https://example.com
.fi

See also \fI-v, \-\-fakeitreal\fP and \fI\-\-proto\-default\fP.
.SH PROXY PROTOCOL PREFIXES
The proxy string may be specified with a protocol:// prefix to specify
alternative proxy protocols.

If no protocol is specified in the proxy string or if the string does not
match a supported one, the proxy is treated as an HTTP proxy.

The supported proxy protocol prefixes are as follows:
.IP http://
Makes it use it as an HTTP proxy. The default if no scheme prefix is used.
.IP https://
Makes it treated as an \fBHTTPS\fP proxy.
.IP socks4://
Makes it the equivalent of \fI\-\-socks4\fP
.IP socks4a://
Makes it the equivalent of \fI\-\-socks4a\fP
.IP socks5://
Makes it the equivalent of \fI\-\-socks5\fP
.IP socks5h://
Makes it the equivalent of \fI\-\-socks5\-hostname\fP
</stdout>
</verify>

</testcase>
Added jni/curl/tests/data/test1706.
































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
<testcase>
<info>
<keywords>
script
documentation
managen
</keywords>
</info>

#
# Client-side
<client>
<server>
none
</server>

<name>
managen makes ASCII page
</name>

<file name="%LOGDIR/mainpage.idx">
_header.md
%options
_footer.md
</file>

<file1 name="%LOGDIR/_header.md">
<!-- Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. -->
<!-- SPDX-License-Identifier: curl -->
# DESCRIPTION

**curl** is a tool for transferring data from or to a server using URLs. It
supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS,
IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP,
SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.

curl is powered by libcurl for all transfer-related features. See
*libcurl(3)* for details.
</file1>
<file2 name="%LOGDIR/option1.md">
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Short: v
Long: fakeitreal
Mutexed: trace trace-ascii
Help: Make the operation more talkative
Category: important verbose global
Added: 4.0
Multi: boolean
Scope: global
See-also:
  - include
  - silent
  - trace
  - trace-ascii
Example:
  - --verbose $URL
---

# `--verbose`

Makes curl verbose during the operation. Useful for debugging and seeing
what's going on under the hood. A line starting with \> means header data sent
by curl, \< means header data received by curl that is hidden in normal cases,
and a line starting with * means additional info provided by curl.

If you only want HTTP headers in the output, --include or --dump-header might
be more suitable options.

If you think this option still does not give you enough details, consider using
--trace or --trace-ascii instead.

Note that verbose output of curl activities and network traffic might contain
sensitive data, including usernames, credentials or secret data content. Be
aware and be careful when sharing trace logs with others.
</file2>
<file3 name="%LOGDIR/option2.md">
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: proto
Arg: <protocols>
Help: Enable/disable PROTOCOLS
Added: 7.20.2
Category: connection curl
Multi: single
See-also:
  - fakeitreal
  - proto-default
Example:
  - --proto =http,https,sftp $URL
---

# `--proto`

Limit what protocols to allow for transfers. Protocols are evaluated left to
right, are comma separated, and are each a protocol name or 'all', optionally
prefixed by zero or more modifiers. Available modifiers are:

## +
Permit this protocol in addition to protocols already permitted (this is
the default if no modifier is used).

## -
Deny this protocol, removing it from the list of protocols already permitted.

## =
Permit only this protocol (ignoring the list already permitted), though
subject to later modification by subsequent entries in the comma separated
list.

##

For example: --proto -ftps uses the default protocols, but disables ftps

--proto -all,https,+http only enables http and https

--proto =http,https also only enables http and https

Unknown and disabled protocols produce a warning. This allows scripts to
safely rely on being able to disable potentially dangerous protocols, without
relying upon support for that protocol being built into curl to avoid an error.

This option can be used multiple times, in which case the effect is the same
as concatenating the protocols into one instance of the option.
</file3>
<file4 name="%LOGDIR/_footer.md">
<!-- Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. -->
<!-- SPDX-License-Identifier: curl -->
# PROXY PROTOCOL PREFIXES
The proxy string may be specified with a protocol:// prefix to specify
alternative proxy protocols. (Added in 7.21.7)

If no protocol is specified in the proxy string or if the string does not
match a supported one, the proxy is treated as an HTTP proxy.

The supported proxy protocol prefixes are as follows:
## http://
Makes it use it as an HTTP proxy. The default if no scheme prefix is used.
## https://
Makes it treated as an **HTTPS** proxy.
## socks4://
Makes it the equivalent of --socks4
## socks4a://
Makes it the equivalent of --socks4a
## socks5://
Makes it the equivalent of --socks5
## socks5h://
Makes it the equivalent of --socks5-hostname
</file4>

<command type="perl">
%SRCDIR/../scripts/managen -d %LOGDIR ascii option1.md option2.md
</command>
</client>

<verify>
<stderr>
option1.md:19:1:WARN: see-also a non-existing option: include
option1.md:19:1:WARN: see-also a non-existing option: silent
option1.md:19:1:WARN: see-also a non-existing option: trace
option1.md:19:1:WARN: see-also a non-existing option: trace-ascii
WARN: option1.md mutexes a non-existing option: trace
WARN: option1.md mutexes a non-existing option: trace-ascii
option2.md:15:1:WARN: see-also a non-existing option: proto-default
</stderr>
<stdout>
DESCRIPTION

    curl is a tool  for transferring data  from or to a  server using URLs.  It
    supports these protocols:  DICT, FILE,  FTP, FTPS,  GOPHER, GOPHERS,  HTTP,
    HTTPS, IMAP,  IMAPS, LDAP,  LDAPS, MQTT,  POP3, POP3S,  RTMP, RTMPS,  RTSP,
    SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.

    curl  is  powered  by  libcurl  for  all  transfer-related  features.   See
    libcurl(3) for details.

    -v, --fakeitreal
	    Makes curl verbose during the  operation. Useful for debugging  and
	    seeing what's  going on  under the  hood. A  line  starting with  >
	    means header data  sent by curl,  < means  header data received  by
	    curl that is  hidden in normal  cases, and a  line starting with  *
	    means additional info provided by curl.

	    If  you  only  want  HTTP  headers  in  the  output,  --include  or
	    --dump-header might be more suitable options.

	    If you think this  option still does  not give you enough  details,
	    consider using --trace or --trace-ascii instead.

	    Note that verbose  output of  curl activities  and network  traffic
	    might contain sensitive data,  including usernames, credentials  or
	    secret data content.  Be aware  and be careful  when sharing  trace
	    logs with others.

	    This option is global  and does not need  to be specified for  each
	    use of --next. Providing --fakeitreal  multiple times has no  extra
	    effect. Disable it again with --no-fakeitreal.

	    Example:
	     curl --verbose https://example.com

	    This option is mutually  exclusive with --trace and  --trace-ascii.
	    See also --include, --silent, --trace and --trace-ascii.

    --proto <protocols>
	    Limit  what  protocols  to  allow  for  transfers.  Protocols   are
	    evaluated left  to  right, are  comma  separated, and  are  each  a
	    protocol name  or  'all',  optionally  prefixed  by  zero  or  more
	    modifiers. Available modifiers are:

	    +

		Permit  this  protocol   in  addition   to  protocols   already
		permitted (this is the default if no modifier is used).

	    -

		Deny this  protocol, removing  it from  the list  of  protocols
		already permitted.

	    =

		Permit  only   this  protocol   (ignoring  the   list   already
		permitted), though subject to later modification by  subsequent
		entries in  the  comma  separated list.  For  example:  --proto
		-ftps uses the default protocols, but disables ftps

		--proto -all,https,+http only enables http and https

		--proto =http,https also only enables http and https

		Unknown and disabled protocols  produce a warning. This  allows
		scripts to safely  rely on  being able  to disable  potentially
		dangerous protocols,  without  relying upon  support  for  that
		protocol being built into curl to avoid an error.

		This option  can be  used  multiple times,  in which  case  the
		effect is  the same  as concatenating  the protocols  into  one
		instance of the option.

	    If --proto is provided several times, the last set value is used.

	    Example:
	     curl --proto =http,https,sftp https://example.com

	    See also --fakeitreal and --proto-default.

PROXY PROTOCOL PREFIXES

    The proxy  string may be  specified with  a protocol://  prefix to  specify
    alternative proxy protocols.

    If no protocol is specified in the  proxy string or if the string does  not
    match a supported one, the proxy is treated as an HTTP proxy.

    The supported proxy protocol prefixes are as follows:

    http://

	Makes it use it as  an HTTP proxy. The  default if no scheme prefix  is
	used.

    https://

	Makes it treated as an HTTPS proxy.

    socks4://

	Makes it the equivalent of --socks4

    socks4a://

	Makes it the equivalent of --socks4a

    socks5://

	Makes it the equivalent of --socks5

    socks5h://

	Makes it the equivalent of --socks5-hostname

</stdout>
</verify>

</testcase>
Changes to jni/curl/tests/data/test1908.
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<server>
http
</server>

# require debug so that alt-svc can work over plain old HTTP
<features>
alt-svc
debug
</features>
<name>
alt-svc cache save after resetting the handle
</name>
<setenv>
# make debug-curl accept Alt-Svc over plain HTTP
CURL_ALTSVC_HTTP="yeah"







|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<server>
http
</server>

# require debug so that alt-svc can work over plain old HTTP
<features>
alt-svc
Debug
</features>
<name>
alt-svc cache save after resetting the handle
</name>
<setenv>
# make debug-curl accept Alt-Svc over plain HTTP
CURL_ALTSVC_HTTP="yeah"
Changes to jni/curl/tests/data/test1933.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>

<name>
HTTP AWS_SIGV4 with one provider and auth cred via URL
</name>
<tool>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>

<name>
HTTP AWS_SIGV4 with one provider and auth cred via URL
</name>
<tool>
Changes to jni/curl/tests/data/test1934.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>

<name>
HTTP AWS_SIGV4 with two providers
</name>
<tool>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>

<name>
HTTP AWS_SIGV4 with two providers
</name>
<tool>
Changes to jni/curl/tests/data/test1935.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>

<name>
HTTP AWS_SIGV4 with two providers and region
</name>
<tool>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>

<name>
HTTP AWS_SIGV4 with two providers and region
</name>
<tool>
Changes to jni/curl/tests/data/test1936.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>

<name>
HTTP AWS_SIGV4 with two providers, region and service
</name>
<tool>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>

<name>
HTTP AWS_SIGV4 with two providers, region and service
</name>
<tool>
Changes to jni/curl/tests/data/test1937.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>

<name>
HTTP POST with AWS_SIGV4
</name>
<tool>







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>

<name>
HTTP POST with AWS_SIGV4
</name>
<tool>
Changes to jni/curl/tests/data/test1938.

cannot compute difference between binary files

Changes to jni/curl/tests/data/test1955.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1956.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1957.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1958.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1959.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test196.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40



41
42
<server>
ftp
</server>
<name>
FTP transient error, retry request once
</name>
<command>
ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --retry 1
</command>
</client>

# Verify data after the test has been "shot"
<verify>
# 67 is CURLE_LOGIN_DENIED
<errorcode>
67
</errorcode>
<protocol>
USER anonymous
PASS ftp@example.com
USER anonymous
PASS ftp@example.com
</protocol>



</verify>
</testcase>







|















>
>
>


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<server>
ftp
</server>
<name>
FTP transient error, retry request once
</name>
<command>
ftp://%HOSTIP:%FTPPORT/%TESTNUMBER --retry 1 -w '%{num_retries}\n'
</command>
</client>

# Verify data after the test has been "shot"
<verify>
# 67 is CURLE_LOGIN_DENIED
<errorcode>
67
</errorcode>
<protocol>
USER anonymous
PASS ftp@example.com
USER anonymous
PASS ftp@example.com
</protocol>
<stdout>
1
</stdout>
</verify>
</testcase>
Changes to jni/curl/tests/data/test1970.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1971.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1972.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1973.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1974.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test1975.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<client>
<server>
http
</server>
# this relies on the debug feature which allow to set the time
<features>
SSL
Debug
crypto
</features>
<setenv>
CURL_FORCEHOST=1
</setenv>

<name>
Changes to jni/curl/tests/data/test2046.
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
#
# Client-side
<client>
<server>
http
</server>
<features>
idn

</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");'







<
>







35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
#
# Client-side
<client>
<server>
http
</server>
<features>

IDN
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
perl -MI18N::Langinfo=langinfo,CODESET -e 'die "Needs a UTF-8 locale" if (lc(langinfo(CODESET())) ne "utf-8");'
Changes to jni/curl/tests/data/test2047.
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
#
# Client-side
<client>
<server>
http
</server>
<features>
idn

proxy
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
#
# Client-side
<client>
<server>
http
</server>
<features>

IDN
proxy
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test2056.
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</server>
<name>
HTTP Negotiate authentication (stub krb5)
</name>
<features>
GSS-API
ld_preload
!debug
</features>
<setenv>
LD_PRELOAD=%PWD/libtest/.libs/libstubgss.so
CURL_STUB_GSS_CREDS="KRB5_Alice"
</setenv>
<command>
--negotiate http://%HOSTIP:%HTTPPORT/%TESTNUMBER







|







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</server>
<name>
HTTP Negotiate authentication (stub krb5)
</name>
<features>
GSS-API
ld_preload
!Debug
</features>
<setenv>
LD_PRELOAD=%PWD/libtest/.libs/libstubgss.so
CURL_STUB_GSS_CREDS="KRB5_Alice"
</setenv>
<command>
--negotiate http://%HOSTIP:%HTTPPORT/%TESTNUMBER
Changes to jni/curl/tests/data/test2057.
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
</server>
<name>
HTTP Negotiate authentication (stub ntlm)
</name>
<features>
GSS-API
ld_preload
!debug
</features>
<setenv>
LD_PRELOAD=%PWD/libtest/.libs/libstubgss.so
CURL_STUB_GSS_CREDS="NTLM_Alice"
</setenv>
<command>
--negotiate http://%HOSTIP:%HTTPPORT/%TESTNUMBER







|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
</server>
<name>
HTTP Negotiate authentication (stub ntlm)
</name>
<features>
GSS-API
ld_preload
!Debug
</features>
<setenv>
LD_PRELOAD=%PWD/libtest/.libs/libstubgss.so
CURL_STUB_GSS_CREDS="NTLM_Alice"
</setenv>
<command>
--negotiate http://%HOSTIP:%HTTPPORT/%TESTNUMBER
Changes to jni/curl/tests/data/test2100.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
http
</server>

# requires debug so that it can use the DoH server without https
# requires IPv6 so that we can assume and compare both DoH requests

<features>
debug
DoH
ipv6
</features>
<name>
HTTP GET using DoH
</name>
<command>
http://foo.example.com:%HTTPPORT/%TESTNUMBER --doh-url http://%HOSTIP:%HTTPPORT/%TESTNUMBER0001
</command>







|

|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
http
</server>

# requires debug so that it can use the DoH server without https
# requires IPv6 so that we can assume and compare both DoH requests

<features>
Debug
DoH
IPv6
</features>
<name>
HTTP GET using DoH
</name>
<command>
http://foo.example.com:%HTTPPORT/%TESTNUMBER --doh-url http://%HOSTIP:%HTTPPORT/%TESTNUMBER0001
</command>
Changes to jni/curl/tests/data/test212.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Client-side
<client>
<server>
ftp
</server>
# EPRT is only sent when IPv6 is enabled
<features>
ipv6
</features>
<name>
Get two FTP files with no remote EPRT support
</name>
<command>
ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER -P -
</command>







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Client-side
<client>
<server>
ftp
</server>
# EPRT is only sent when IPv6 is enabled
<features>
IPv6
</features>
<name>
Get two FTP files with no remote EPRT support
</name>
<command>
ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER ftp://%HOSTIP:%FTPPORT/a/path/%TESTNUMBER -P -
</command>
Changes to jni/curl/tests/data/test2300.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

#
# Client-side
<client>
# for the forced CURL_ENTROPY
<features>
debug
ws
</features>
<server>
http
</server>
<name>
WebSockets upgrade only







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</reply>

#
# Client-side
<client>
# for the forced CURL_ENTROPY
<features>
Debug
ws
</features>
<server>
http
</server>
<name>
WebSockets upgrade only
Changes to jni/curl/tests/data/test2301.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
debug
ws
</features>
<server>
http
</server>
<name>
WebSockets via callback (raw mode) + curl_ws_send()







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
Debug
ws
</features>
<server>
http
</server>
<name>
WebSockets via callback (raw mode) + curl_ws_send()
Changes to jni/curl/tests/data/test2302.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
debug
ws
</features>
<server>
http
</server>
<name>
WebSockets via callback (frame mode) + curl_ws_send()







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
Debug
ws
</features>
<server>
http
</server>
<name>
WebSockets via callback (frame mode) + curl_ws_send()
Changes to jni/curl/tests/data/test2303.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
debug
ws
</features>
<server>
http
</server>
<name>
WebSockets but gets a 200 back







|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
Debug
ws
</features>
<server>
http
</server>
<name>
WebSockets but gets a 200 back
Changes to jni/curl/tests/data/test2304.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
debug
ws
</features>
<server>
http
</server>
<name>
WebSockets curl_ws_recv() with closed connection







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
Debug
ws
</features>
<server>
http
</server>
<name>
WebSockets curl_ws_recv() with closed connection
Changes to jni/curl/tests/data/test2305.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
debug
ws
</features>
<server>
http
</server>
<name>
WebSocket curl_ws_recv() loop reading three larger frames







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
Debug
ws
</features>
<server>
http
</server>
<name>
WebSocket curl_ws_recv() loop reading three larger frames
Changes to jni/curl/tests/data/test2307.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
debug
ws
!hyper
</features>
<server>
http
</server>
<name>







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
# require debug for the forced CURL_ENTROPY
<features>
Debug
ws
!hyper
</features>
<server>
http
</server>
<name>
Changes to jni/curl/tests/data/test240.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET
</name>







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET
</name>
Changes to jni/curl/tests/data/test2400.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</data>
</reply>

#
# Client-side
<client>
<features>
debug
h2c
SSL
</features>
<server>
http
http/2
</server>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</data>
</reply>

#
# Client-side
<client>
<features>
Debug
h2c
SSL
</features>
<server>
http
http/2
</server>
Changes to jni/curl/tests/data/test2401.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</data>
</reply>

#
# Client-side
<client>
<features>
debug
h2c
SSL
</features>
<server>
http
http/2
</server>







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</data>
</reply>

#
# Client-side
<client>
<features>
Debug
h2c
SSL
</features>
<server>
http
http/2
</server>
Changes to jni/curl/tests/data/test2406.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</data>
</reply>

#
# Client-side
<client>
<features>
debug
h2c
SSL
</features>
<server>
http
http/2
</server>







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</data>
</reply>

#
# Client-side
<client>
<features>
Debug
h2c
SSL
</features>
<server>
http
http/2
</server>
Changes to jni/curl/tests/data/test241.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET (using ip6-localhost)
</name>







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET (using ip6-localhost)
</name>
Changes to jni/curl/tests/data/test242.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with username+password in URL
</name>







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with username+password in URL
</name>
Changes to jni/curl/tests/data/test2501.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</data>
</reply>

#
# Client-side
<client>
<features>
debug
http
http/3
</features>
<server>
http
http/3
</server>







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</data>
</reply>

#
# Client-side
<client>
<features>
Debug
http
http/3
</features>
<server>
http
http/3
</server>
Changes to jni/curl/tests/data/test252.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</datacheck>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP IPv6 dir list PASV
</name>







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</datacheck>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP IPv6 dir list PASV
</name>
Changes to jni/curl/tests/data/test253.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</datacheck>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP IPv6 dir list with EPRT
</name>







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</datacheck>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP IPv6 dir list with EPRT
</name>
Changes to jni/curl/tests/data/test254.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</datacheck>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP IPv6 dir list PASV and --disable-epsv
</name>







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</datacheck>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP IPv6 dir list PASV and --disable-epsv
</name>
Changes to jni/curl/tests/data/test255.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</datacheck>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP IPv6 dir list with EPRT and --disable-eprt
</name>







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</datacheck>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
ftp-ipv6
</server>
<name>
FTP IPv6 dir list with EPRT and --disable-eprt
</name>
Changes to jni/curl/tests/data/test2600.
11
12
13
14
15
16
17
18
19

20
21
22
23
24
25
# Client-side
<client>
<server>
none
</server>
<features>
unittest
debug
http

</features>
<name>
connection filter connect/destroy unit tests
</name>
</client>
</testcase>







|

>






11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Client-side
<client>
<server>
none
</server>
<features>
unittest
Debug
http
!win32
</features>
<name>
connection filter connect/destroy unit tests
</name>
</client>
</testcase>
Changes to jni/curl/tests/data/test263.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
proxy
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with proxy specified using IPv6-numerical address







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
proxy
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with proxy specified using IPv6-numerical address
Changes to jni/curl/tests/data/test3029.
Changes to jni/curl/tests/data/test3030.
Changes to jni/curl/tests/data/test3102.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#
# Client-side
<client>
# SSL with libraries supporting CURLOPT_CERTINFO
<features>
SSL
!bearssl
!mbedtls
!rustls
!wolfssl
</features>
<server>
https
</server>
<tool>







<







16
17
18
19
20
21
22

23
24
25
26
27
28
29
#
# Client-side
<client>
# SSL with libraries supporting CURLOPT_CERTINFO
<features>
SSL
!bearssl

!rustls
!wolfssl
</features>
<server>
https
</server>
<tool>
Changes to jni/curl/tests/data/test3202.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with PROXY protocol with spoofed client IP
</name>







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
</features>
<server>
http-ipv6
</server>
<name>
HTTP-IPv6 GET with PROXY protocol with spoofed client IP
</name>
Changes to jni/curl/tests/data/test356.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</data>
</reply>

#
# Client-side
<client>
<features>
debug
alt-svc
</features>
<server>
http
</server>
<name>
parse incoming Alt-Svc and save to file







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</data>
</reply>

#
# Client-side
<client>
<features>
Debug
alt-svc
</features>
<server>
http
</server>
<name>
parse incoming Alt-Svc and save to file
Changes to jni/curl/tests/data/test358.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
<features>
alt-svc
debug
h2c
</features>
<server>
http
http/2
</server>
<name>







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
<features>
alt-svc
Debug
h2c
</features>
<server>
http
http/2
</server>
<name>
Changes to jni/curl/tests/data/test359.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
<features>
alt-svc
debug
h2c
</features>
<server>
https
http/2
</server>
<name>







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
</reply>

#
# Client-side
<client>
<features>
alt-svc
Debug
h2c
</features>
<server>
https
http/2
</server>
<name>
Changes to jni/curl/tests/data/test363.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
</datacheck>
</reply>

#
# Client-side
<client>
<features>
debug
proxy
</features>
<server>
http
http-proxy
</server>
<name>







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
</datacheck>
</reply>

#
# Client-side
<client>
<features>
Debug
proxy
</features>
<server>
http
http-proxy
</server>
<name>
Changes to jni/curl/tests/data/test412.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</reply>

#
# Client-side
<client>
<features>
alt-svc
debug
</features>
<server>
http
</server>
<name>
alt-svc using host name with trailing dot in URL
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</reply>

#
# Client-side
<client>
<features>
alt-svc
Debug
</features>
<server>
http
</server>
<name>
alt-svc using host name with trailing dot in URL
</name>
Changes to jni/curl/tests/data/test413.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</reply>

#
# Client-side
<client>
<features>
alt-svc
debug
</features>
<server>
http
</server>
<name>
alt-svc using host name with trailing dot on host from file
</name>







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</reply>

#
# Client-side
<client>
<features>
alt-svc
Debug
</features>
<server>
http
</server>
<name>
alt-svc using host name with trailing dot on host from file
</name>
Changes to jni/curl/tests/data/test437.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</data>
</reply>

#
# Client-side
<client>
<features>
debug
alt-svc
</features>
<server>
http
</server>
<name>
Alt-Svc to numerical IPv6 address







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</data>
</reply>

#
# Client-side
<client>
<features>
Debug
alt-svc
</features>
<server>
http
</server>
<name>
Alt-Svc to numerical IPv6 address
Changes to jni/curl/tests/data/test438.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</reply>

#
# Client-side
<client>
<features>
alt-svc
debug
ipv6
</features>
<server>
http
http-ipv6
</server>
<name>
HTTPS IPv4 GET translated by alt-svc to IPv6 address







|
|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</reply>

#
# Client-side
<client>
<features>
alt-svc
Debug
IPv6
</features>
<server>
http
http-ipv6
</server>
<name>
HTTPS IPv4 GET translated by alt-svc to IPv6 address
Changes to jni/curl/tests/data/test439.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#
# Client-side
<client>
<server>
http
</server>
<features>
debug
</features>
<name>
aws-sigv4 with query
</name>
<command>
"http://fake.fake.fake:8000/%TESTNUMBER/?name=me%&noval&aim=b%aad&&&weirdo=*.//-" -u user:secret --aws-sigv4 "aws:amz:us-east-2:es" --connect-to fake.fake.fake:8000:%HOSTIP:%HTTPPORT
</command>







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#
# Client-side
<client>
<server>
http
</server>
<features>
Debug
</features>
<name>
aws-sigv4 with query
</name>
<command>
"http://fake.fake.fake:8000/%TESTNUMBER/?name=me%&noval&aim=b%aad&&&weirdo=*.//-" -u user:secret --aws-sigv4 "aws:amz:us-east-2:es" --connect-to fake.fake.fake:8000:%HOSTIP:%HTTPPORT
</command>
Changes to jni/curl/tests/data/test446.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
https
http-proxy
</server>
<features>
HSTS
proxy
https
debug
</features>
<setenv>
CURL_HSTS_HTTP=yes
CURL_TIME=2000000000
</setenv>

<name>







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
https
http-proxy
</server>
<features>
HSTS
proxy
https
Debug
</features>
<setenv>
CURL_HSTS_HTTP=yes
CURL_TIME=2000000000
</setenv>

<name>
Changes to jni/curl/tests/data/test447.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</data>
</reply>

#
# Client-side
<client>
<features>
debug
</features>
<server>
http
</server>
<name>
HTTP PUT with growing file
</name>







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</data>
</reply>

#
# Client-side
<client>
<features>
Debug
</features>
<server>
http
</server>
<name>
HTTP PUT with growing file
</name>
Added jni/curl/tests/data/test472.






















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<testcase>
<info>
<keywords>
HTTP
aws-sigv4
</keywords>
</info>

#
# Server-side
<reply>
<data crlf="yes">
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
ETag: "21025-dc7-39462498"
Accept-Ranges: bytes
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-head: yesyes

-foo-
</data>
</reply>

#
# Client-side
<client>
<server>
http
</server>
<features>
Debug
Unicode
</features>
<name>
aws-sigv4 with query
</name>
<command>
"http://fake.fake.fake:8000/%TESTNUMBER/a=あ" -u user:secret --aws-sigv4 "aws:amz:us-east-2:es" --connect-to fake.fake.fake:8000:%HOSTIP:%HTTPPORT
</command>
</client>

#
# Verify data after the test has been "shot"
<verify>
<protocol crlf="yes">
GET /472/a=%e3%81%82 HTTP/1.1
Host: fake.fake.fake:8000
Authorization: AWS4-HMAC-SHA256 Credential=user/19700101/us-east-2/es/aws4_request, SignedHeaders=host;x-amz-date, Signature=c63315c199922f7ee00141869a250389405d19e205057249fb74726d940b1fc3
X-Amz-Date: 19700101T000000Z
User-Agent: curl/%VERSION
Accept: */*

</protocol>
</verify>
</testcase>
Added jni/curl/tests/data/test473.




























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<testcase>
<info>
<keywords>
HTTP
HTTP GET
</keywords>
</info>
#
# Server-side
<reply>
<data nocheck="yes">
HTTP/1.1 301 funky chunky!
Server: fakeit/0.9 fakeitbad/1.0
Location: /redirected
Transfer-Encoding: chunked
Trailer: chunky-trailer
Connection: mooo
ETag: W/"asdf"

40
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
30
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
21;heresatest=moooo
cccccccccccccccccccccccccccccccc

0
chunky-trailer: header data

</data>
</reply>

#
# Client-side
<client>
<server>
http
</server>
<name>
Check if --etag-save saved correct etag to a file on 301
</name>
<command>
http://%HOSTIP:%HTTPPORT/%TESTNUMBER --etag-save %LOGDIR/etag%TESTNUMBER
</command>
</client>

#
# Verify data after the test has been "shot"
<verify>
<protocol>
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*

</protocol>
<file name="%LOGDIR/etag%TESTNUMBER">
W/"asdf"
</file>
</verify>

</testcase>
Changes to jni/curl/tests/data/test508.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
http://%HOSTIP:%HTTPPORT/%TESTNUMBER
</command>
</client>

#
# Verify data after the test has been "shot"
<verify>
<strippart>
# remove CR that CURLOPT_TRANSFERTEXT added, when CharConv enabled:
s/^(this is what we post to the silly web server)\r\n/$1\n/ if($has_charconv)
</strippart>
<protocol>
POST /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Content-Length: 45
Content-Type: application/x-www-form-urlencoded








<
<
<
<







37
38
39
40
41
42
43




44
45
46
47
48
49
50
http://%HOSTIP:%HTTPPORT/%TESTNUMBER
</command>
</client>

#
# Verify data after the test has been "shot"
<verify>




<protocol>
POST /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
Content-Length: 45
Content-Type: application/x-www-form-urlencoded

Changes to jni/curl/tests/data/test558.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Client-side
<client>
<server>
none
</server>
<features>
TrackMemory
ipv6
</features>
# tool is what to use instead of 'curl'
<tool>
lib%TESTNUMBER
</tool>

<name>







|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# Client-side
<client>
<server>
none
</server>
<features>
TrackMemory
IPv6
</features>
# tool is what to use instead of 'curl'
<tool>
lib%TESTNUMBER
</tool>

<name>
Changes to jni/curl/tests/data/test644.
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#
# Client-side
<client>
<server>
http
</server>
<features>
debug
xattr
</features>
# simulate the xattr operations
<setenv>
CURL_FAKE_XATTR=1
</setenv>
<name>







|







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#
# Client-side
<client>
<server>
http
</server>
<features>
Debug
xattr
</features>
# simulate the xattr operations
<setenv>
CURL_FAKE_XATTR=1
</setenv>
<name>
Changes to jni/curl/tests/data/test687.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#
# Client-side
<client>
<server>
http
</server>
<features>
debug
xattr
</features>
# simulate the xattr operations
<setenv>
CURL_FAKE_XATTR=1
</setenv>
<name>







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#
# Client-side
<client>
<server>
http
</server>
<features>
Debug
xattr
</features>
# simulate the xattr operations
<setenv>
CURL_FAKE_XATTR=1
</setenv>
<name>
Changes to jni/curl/tests/data/test688.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#
# Client-side
<client>
<server>
http
</server>
<features>
debug
xattr
</features>
# simulate the xattr operations
<setenv>
CURL_FAKE_XATTR=1
</setenv>
<name>







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#
# Client-side
<client>
<server>
http
</server>
<features>
Debug
xattr
</features>
# simulate the xattr operations
<setenv>
CURL_FAKE_XATTR=1
</setenv>
<name>
Changes to jni/curl/tests/data/test719.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</data>
</reply>

#
# Client-side
<client>
<features>
ipv6
proxy
</features>
<server>
http
socks5
</server>
<name>







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</data>
</reply>

#
# Client-side
<client>
<features>
IPv6
proxy
</features>
<server>
http
socks5
</server>
<name>
Changes to jni/curl/tests/data/test823.
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Client-side
<client>
<server>
imap
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
IMAP DIGEST-MD5 authentication
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/;MAILINDEX=1' -u user:secret







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Client-side
<client>
<server>
imap
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
IMAP DIGEST-MD5 authentication
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/;MAILINDEX=1' -u user:secret
Changes to jni/curl/tests/data/test832.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Client-side
<client>
<server>
imap
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
IMAP DIGEST-MD5 graceful cancellation
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/;MAILINDEX=1' -u user:secret







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Client-side
<client>
<server>
imap
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
IMAP DIGEST-MD5 graceful cancellation
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/;MAILINDEX=1' -u user:secret
Changes to jni/curl/tests/data/test835.
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Client-side
<client>
<server>
imap
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
IMAP DIGEST-MD5 authentication with SASL downgrade
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/;MAILINDEX=1' -u user:secret







|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Client-side
<client>
<server>
imap
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
IMAP DIGEST-MD5 authentication with SASL downgrade
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/;MAILINDEX=1' -u user:secret
Changes to jni/curl/tests/data/test869.
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Client-side
<client>
<server>
pop3
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
POP3 DIGEST-MD5 authentication
</name>
<command>
pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret







|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Client-side
<client>
<server>
pop3
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
POP3 DIGEST-MD5 authentication
</name>
<command>
pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret
Changes to jni/curl/tests/data/test878.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Client-side
<client>
<server>
pop3
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
POP3 DIGEST-MD5 graceful cancellation
</name>
<command>
pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Client-side
<client>
<server>
pop3
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
POP3 DIGEST-MD5 graceful cancellation
</name>
<command>
pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret
Changes to jni/curl/tests/data/test881.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# Client-side
<client>
<server>
pop3
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
POP3 DIGEST-MD5 authentication with SASL downgrade
</name>
<command>
pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# Client-side
<client>
<server>
pop3
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
POP3 DIGEST-MD5 authentication with SASL downgrade
</name>
<command>
pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret
Changes to jni/curl/tests/data/test907.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Client-side
<client>
<server>
smtp
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
SMTP DIGEST-MD5 authentication
</name>
<stdin>
mail body







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Client-side
<client>
<server>
smtp
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
SMTP DIGEST-MD5 authentication
</name>
<stdin>
mail body
Changes to jni/curl/tests/data/test934.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Client-side
<client>
<server>
smtp
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
SMTP DIGEST-MD5 graceful cancellation
</name>
<command>
smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -u user:secret -T -







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Client-side
<client>
<server>
smtp
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
SMTP DIGEST-MD5 graceful cancellation
</name>
<command>
smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -u user:secret -T -
Changes to jni/curl/tests/data/test937.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Client-side
<client>
<server>
smtp
</server>
<features>
!SSPI
debug
crypto
</features>
<name>
SMTP DIGEST-MD5 authentication with SASL downgrade
</name>
<stdin>
mail body







|







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# Client-side
<client>
<server>
smtp
</server>
<features>
!SSPI
Debug
crypto
</features>
<name>
SMTP DIGEST-MD5 authentication with SASL downgrade
</name>
<stdin>
mail body
Changes to jni/curl/tests/data/test941.
28
29
30
31
32
33
34

35
36
37
38
39
40
41
headers and body
with unix newlines
meant to be
converted
with
the
--crlf option

</file>
<command>
smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -T %LOGDIR/upload%TESTNUMBER --crlf
</command>
</client>

#







>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
headers and body
with unix newlines
meant to be
converted
with
the
--crlf option
%repeat[650 x 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%0a]%
</file>
<command>
smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -T %LOGDIR/upload%TESTNUMBER --crlf
</command>
</client>

#
56
57
58
59
60
61
62

63
64
65
66
headers and body
with unix newlines
meant to be
converted
with
the
--crlf option

.
</upload>
</verify>
</testcase>







>




57
58
59
60
61
62
63
64
65
66
67
68
headers and body
with unix newlines
meant to be
converted
with
the
--crlf option
%repeat[650 x 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 %0a]%
.
</upload>
</verify>
</testcase>
Changes to jni/curl/tests/data/test959.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#
# Client-side
<client>
<server>
smtp
</server>
<features>
!idn
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#
# Client-side
<client>
<server>
smtp
</server>
<features>
!IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test960.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#
# Client-side
<client>
<server>
smtp
</server>
<features>
!idn
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#
# Client-side
<client>
<server>
smtp
</server>
<features>
!IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test961.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#
# Client-side
<client>
<server>
smtp
</server>
<features>
!idn
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#
# Client-side
<client>
<server>
smtp
</server>
<features>
!IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test962.
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
#
# Client-side
<client>
<server>
smtp
</server>
<features>
idn

!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
#
# Client-side
<client>
<server>
smtp
</server>
<features>

IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test963.
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
#
# Client-side
<client>
<server>
smtp
</server>
<features>
idn

!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
#
# Client-side
<client>
<server>
smtp
</server>
<features>

IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test964.
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
#
# Client-side
<client>
<server>
smtp
</server>
<features>
idn

!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
#
# Client-side
<client>
<server>
smtp
</server>
<features>

IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test965.
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
#
# Client-side
<client>
<server>
smtp
</server>
<features>
idn

!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
#
# Client-side
<client>
<server>
smtp
</server>
<features>

IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test966.
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
#
# Client-side
<client>
<server>
smtp
</server>
<features>
idn

!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







17
18
19
20
21
22
23

24
25
26
27
28
29
30
31
#
# Client-side
<client>
<server>
smtp
</server>
<features>

IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test967.
21
22
23
24
25
26
27
28

29
30
31
32
33
34
35
#
# Client-side
<client>
<server>
smtp
</server>
<features>
idn

!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







21
22
23
24
25
26
27

28
29
30
31
32
33
34
35
#
# Client-side
<client>
<server>
smtp
</server>
<features>

IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test968.
18
19
20
21
22
23
24
25

26
27
28
29
30
31
32
#
# Client-side
<client>
<server>
smtp
</server>
<features>
idn

!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>







<
>







18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
#
# Client-side
<client>
<server>
smtp
</server>
<features>

IDN
!win32
</features>
<setenv>
LC_ALL=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
</setenv>
<precheck>
Changes to jni/curl/tests/data/test969.
24
25
26
27
28
29
30
31

32
33
34
35
36
37
38
#
# Client-side
<client>
<server>
smtp
</server>
<features>
idn

!win32
</features>
<name>
SMTP mailing list EXPN (CUSTOMREQUEST) with SMTPUTF8 support
</name>
<command>
smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt Friends -X EXPN







<
>







24
25
26
27
28
29
30

31
32
33
34
35
36
37
38
#
# Client-side
<client>
<server>
smtp
</server>
<features>

IDN
!win32
</features>
<name>
SMTP mailing list EXPN (CUSTOMREQUEST) with SMTPUTF8 support
</name>
<command>
smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt Friends -X EXPN
Changes to jni/curl/tests/data/test970.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#
# Client-side
<client>
<server>
http
</server>
<features>
debug
proxy
</features>
<setenv>
CURL_TIME=13
CURL_DEBUG_SIZE=4019
CURL_VERSION=curl-unit-test-fake-version
</setenv>







|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#
# Client-side
<client>
<server>
http
</server>
<features>
Debug
proxy
</features>
<setenv>
CURL_TIME=13
CURL_DEBUG_SIZE=4019
CURL_VERSION=curl-unit-test-fake-version
</setenv>
55
56
57
58
59
60
61
62
63
64
65
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*

</protocol>
<stdout nonewline="yes">
{"certs":"","content_type":"text/html","conn_id":0,"errormsg":null,"exitcode":0,"filename_effective":"%LOGDIR/out%TESTNUMBER","ftp_entry_path":null,"http_code":200,"http_connect":0,"http_version":"1.1","local_ip":"127.0.0.1","local_port":13,"method":"GET","num_certs":0,"num_connects":1,"num_headers":9,"num_redirects":0,"proxy_ssl_verify_result":0,"proxy_used":0,"redirect_url":null,"referer":null,"remote_ip":"%HOSTIP","remote_port":%HTTPPORT,"response_code":200,"scheme":"http","size_download":445,"size_header":4019,"size_request":4019,"size_upload":0,"speed_download":13,"speed_upload":13,"ssl_verify_result":0,"time_appconnect":0.000013,"time_connect":0.000013,"time_namelookup":0.000013,"time_pretransfer":0.000013,"time_redirect":0.000013,"time_starttransfer":0.000013,"time_total":0.000013,"url":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","url.scheme":"http","url.user":null,"url.password":null,"url.options":null,"url.host":"%HOSTIP","url.port":"%HTTPPORT","url.path":"/%TESTNUMBER","url.query":null,"url.fragment":null,"url.zoneid":null,"urle.scheme":"http","urle.user":null,"urle.password":null,"urle.options":null,"urle.host":"%HOSTIP","urle.port":"%HTTPPORT","urle.path":"/%TESTNUMBER","urle.query":null,"urle.fragment":null,"urle.zoneid":null,"url_effective":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","urlnum":0,"xfer_id":0,"curl_version":"curl-unit-test-fake-version"}
</stdout>
</verify>
</testcase>







|



55
56
57
58
59
60
61
62
63
64
65
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*

</protocol>
<stdout nonewline="yes">
{"certs":"","conn_id":0,"content_type":"text/html","errormsg":null,"exitcode":0,"filename_effective":"%LOGDIR/out%TESTNUMBER","ftp_entry_path":null,"http_code":200,"http_connect":0,"http_version":"1.1","local_ip":"127.0.0.1","local_port":13,"method":"GET","num_certs":0,"num_connects":1,"num_headers":9,"num_redirects":0,"num_retries":0,"proxy_ssl_verify_result":0,"proxy_used":0,"redirect_url":null,"referer":null,"remote_ip":"%HOSTIP","remote_port":%HTTPPORT,"response_code":200,"scheme":"http","size_download":445,"size_header":4019,"size_request":4019,"size_upload":0,"speed_download":13,"speed_upload":13,"ssl_verify_result":0,"time_appconnect":0.000013,"time_connect":0.000013,"time_namelookup":0.000013,"time_pretransfer":0.000013,"time_redirect":0.000013,"time_starttransfer":0.000013,"time_total":0.000013,"url":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","url.fragment":null,"url.host":"127.0.0.1","url.options":null,"url.password":null,"url.path":"/%TESTNUMBER","url.port":"%HTTPPORT","url.query":null,"url.scheme":"http","url.user":null,"url.zoneid":null,"url_effective":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","urle.fragment":null,"urle.host":"127.0.0.1","urle.options":null,"urle.password":null,"urle.path":"/%TESTNUMBER","urle.port":"%HTTPPORT","urle.query":null,"urle.scheme":"http","urle.user":null,"urle.zoneid":null,"urlnum":0,"xfer_id":0,"curl_version":"curl-unit-test-fake-version"}
</stdout>
</verify>
</testcase>
Changes to jni/curl/tests/data/test972.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Client-side
<client>

<server>
http
</server>
<features>
debug
proxy
</features>
<setenv>
CURL_TIME=13
CURL_DEBUG_SIZE=4019
CURL_VERSION=curl-unit-test-fake-version
</setenv>







|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Client-side
<client>

<server>
http
</server>
<features>
Debug
proxy
</features>
<setenv>
CURL_TIME=13
CURL_DEBUG_SIZE=4019
CURL_VERSION=curl-unit-test-fake-version
</setenv>
56
57
58
59
60
61
62
63
64
65
66
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*

</protocol>
<stdout mode="text">
{"certs":"","content_type":"text/html","conn_id":0,"errormsg":null,"exitcode":0,"filename_effective":"%LOGDIR/out972","ftp_entry_path":null,"http_code":200,"http_connect":0,"http_version":"1.1","local_ip":"%HOSTIP","local_port":13,"method":"GET","num_certs":0,"num_connects":1,"num_headers":9,"num_redirects":0,"proxy_ssl_verify_result":0,"proxy_used":0,"redirect_url":null,"referer":null,"remote_ip":"%HOSTIP","remote_port":%HTTPPORT,"response_code":200,"scheme":"http","size_download":445,"size_header":4019,"size_request":4019,"size_upload":0,"speed_download":13,"speed_upload":13,"ssl_verify_result":0,"time_appconnect":0.000013,"time_connect":0.000013,"time_namelookup":0.000013,"time_pretransfer":0.000013,"time_redirect":0.000013,"time_starttransfer":0.000013,"time_total":0.000013,"url":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","url.scheme":"http","url.user":null,"url.password":null,"url.options":null,"url.host":"%HOSTIP","url.port":"%HTTPPORT","url.path":"/%TESTNUMBER","url.query":null,"url.fragment":null,"url.zoneid":null,"urle.scheme":"http","urle.user":null,"urle.password":null,"urle.options":null,"urle.host":"%HOSTIP","urle.port":"%HTTPPORT","urle.path":"/%TESTNUMBER","urle.query":null,"urle.fragment":null,"urle.zoneid":null,"url_effective":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","urlnum":0,"xfer_id":0,"curl_version":"curl-unit-test-fake-version"}
</stdout>
</verify>
</testcase>







|



56
57
58
59
60
61
62
63
64
65
66
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*

</protocol>
<stdout mode="text">
{"certs":"","conn_id":0,"content_type":"text/html","errormsg":null,"exitcode":0,"filename_effective":"%LOGDIR/out%TESTNUMBER","ftp_entry_path":null,"http_code":200,"http_connect":0,"http_version":"1.1","local_ip":"127.0.0.1","local_port":13,"method":"GET","num_certs":0,"num_connects":1,"num_headers":9,"num_redirects":0,"num_retries":0,"proxy_ssl_verify_result":0,"proxy_used":0,"redirect_url":null,"referer":null,"remote_ip":"%HOSTIP","remote_port":%HTTPPORT,"response_code":200,"scheme":"http","size_download":445,"size_header":4019,"size_request":4019,"size_upload":0,"speed_download":13,"speed_upload":13,"ssl_verify_result":0,"time_appconnect":0.000013,"time_connect":0.000013,"time_namelookup":0.000013,"time_pretransfer":0.000013,"time_redirect":0.000013,"time_starttransfer":0.000013,"time_total":0.000013,"url":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","url.fragment":null,"url.host":"127.0.0.1","url.options":null,"url.password":null,"url.path":"/%TESTNUMBER","url.port":"%HTTPPORT","url.query":null,"url.scheme":"http","url.user":null,"url.zoneid":null,"url_effective":"http://%HOSTIP:%HTTPPORT/%TESTNUMBER","urle.fragment":null,"urle.host":"127.0.0.1","urle.options":null,"urle.password":null,"urle.path":"/%TESTNUMBER","urle.port":"%HTTPPORT","urle.query":null,"urle.scheme":"http","urle.user":null,"urle.zoneid":null,"urlnum":0,"xfer_id":0,"curl_version":"curl-unit-test-fake-version"}
</stdout>
</verify>
</testcase>
Changes to jni/curl/tests/data/test99.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
</datacheck>
</reply>

#
# Client-side
<client>
<features>
large_file
</features>
<server>
http
</server>
<name>
HTTP GET with large-file resume point and failed resume
</name>







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
</datacheck>
</reply>

#
# Client-side
<client>
<features>
Largefile
</features>
<server>
http
</server>
<name>
HTTP GET with large-file resume point and failed resume
</name>
Changes to jni/curl/tests/ech_tests.sh.
64
65
66
67
68
69
70

71
72
73
74
75
76
77
78
    [draft-13.esni.defo.ie:9413]=""
    [draft-13.esni.defo.ie:10413]=""
    [draft-13.esni.defo.ie:11413]=""
    [draft-13.esni.defo.ie:12413]=""
    [draft-13.esni.defo.ie:12414]=""
    [crypto.cloudflare.com]="cdn-cgi/trace"
    [tls-ech.dev]=""

    [epochbelt.com]=""
)

# Targets we expect not to be ECH-enabled servers
# but for which an HTTPS RR is published.
declare -A httpsrr_targets=(
    [ietf.org]=""
    [rte.ie]=""







>
|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    [draft-13.esni.defo.ie:9413]=""
    [draft-13.esni.defo.ie:10413]=""
    [draft-13.esni.defo.ie:11413]=""
    [draft-13.esni.defo.ie:12413]=""
    [draft-13.esni.defo.ie:12414]=""
    [crypto.cloudflare.com]="cdn-cgi/trace"
    [tls-ech.dev]=""
    # this one's gone away for now (possibly temporarily)
    # [epochbelt.com]=""
)

# Targets we expect not to be ECH-enabled servers
# but for which an HTTPS RR is published.
declare -A httpsrr_targets=(
    [ietf.org]=""
    [rte.ie]=""
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# place to stash outputs when things go wrong
: "${BTOP:=$LTOP}"

# time to wait for a remote access to work, 10 seconds
: "${tout:=10s}"

# Where we find OpenSSL .so's
: "${OSSL:=$HOME/code/openssl}"

# Where we find WolfSSL .so's
: "${WSSL:=$HOME/code/wolfssl/inst/lib}"

# Where we find boringssl .so's
: "${BSSL:=$HOME/code/boringssl/inst/lib}"

# Where we send DoH queries when using kdig or curl
: "${DOHSERVER:=one.one.one.one}"
: "${DOHPATH:=dns-query}"

# Whether to send mail when bad things happen (mostly for cronjob)







|

|


|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# place to stash outputs when things go wrong
: "${BTOP:=$LTOP}"

# time to wait for a remote access to work, 10 seconds
: "${tout:=10s}"

# Where we find OpenSSL .so's
: "${OSSL:=$HOME/code/openssl-local-inst}"

# Where we find wolfSSL .so's
: "${WSSL:=$HOME/code/wolfssl/inst/lib}"

# Where we find BoringSSL .so's
: "${BSSL:=$HOME/code/boringssl/inst/lib}"

# Where we send DoH queries when using kdig or curl
: "${DOHSERVER:=one.one.one.one}"
: "${DOHPATH:=dns-query}"

# Whether to send mail when bad things happen (mostly for cronjob)
407
408
409
410
411
412
413





414
415
416
417
418
419
420
    do
        host=$(hostport2host "$targ")
        port=$(hostport2port "$targ")
        if [[ "$port" != "443" && "$have_portsblocked" == "yes" ]]
        then
            echo "Skipping $targ as ports != 443 seem blocked"
            continue





        fi
        path=${ech_targets[$targ]}
        turl="https://$host:$port/$path"
        echo "PN override check for $turl"
        {
            echo ""
            echo "PN override check for $turl"







>
>
>
>
>







408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
    do
        host=$(hostport2host "$targ")
        port=$(hostport2port "$targ")
        if [[ "$port" != "443" && "$have_portsblocked" == "yes" ]]
        then
            echo "Skipping $targ as ports != 443 seem blocked"
            continue
        fi
        if [[ "$host" == "crypto.cloudflare.com" ]]
        then
            echo "Skipping $host as they've blocked PN override"
            continue
        fi
        path=${ech_targets[$targ]}
        turl="https://$host:$port/$path"
        echo "PN override check for $turl"
        {
            echo ""
            echo "PN override check for $turl"
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
    cli_test "$turl" 1 1 --ech ecl:"$echconfiglist"
    cli_test "$turl" 1 0 --ech ecl:
fi

fi # skip

# Check combinations of command line options, if we're good so far
# Most of this only works for openssl, which is ok, as we're checking
# the argument handling here, not the ECH protocol
if [[ "$using_ossl" == "yes" && "$allgood" == "yes" ]]
then
    # ech can be hard, true, grease or false
    # ecl:ecl can be correct, incorrect or missing
    # ech:pn can be correct, incorrect or missing
    # in all cases the "last" argument provided should "win"







|







535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
    cli_test "$turl" 1 1 --ech ecl:"$echconfiglist"
    cli_test "$turl" 1 0 --ech ecl:
fi

fi # skip

# Check combinations of command line options, if we're good so far
# Most of this only works for OpenSSL, which is ok, as we're checking
# the argument handling here, not the ECH protocol
if [[ "$using_ossl" == "yes" && "$allgood" == "yes" ]]
then
    # ech can be hard, true, grease or false
    # ecl:ecl can be correct, incorrect or missing
    # ech:pn can be correct, incorrect or missing
    # in all cases the "last" argument provided should "win"
Changes to jni/curl/tests/ftpserver.pl.
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695

696
697
698
699
700
701
702
            '220-   / __| | | | |_) | |    '."\r\n",
            '220-  | (__| |_| |  _ {| |___ '."\r\n",
            '220    \___|\___/|_| \_\_____|'."\r\n")
        );
    }
}

# Perform the disconnecgt handshake with sockfilt on the secondary connection
# (the only connection we actively disconnect).
# This involves waiting for the disconnect acknowledgment after the DISC
# command, while throwing away anything else that might come in before
# that.
sub disc_handshake {
    print DWRITE "DISC\n";
    my $line;
    my $nr;
    while (5 == ($nr = sysread DREAD, $line, 5)) {
        if($line eq "DATA\n") {
            # Must read the data bytes to stay in sync
            my $i;
            sysread DREAD, $i, 5;

            my $size = 0;
            if($i =~ /^([0-9a-fA-F]{4})\n/) {
                $size = hex($1);
            }

            read_datasockf(\$line, $size);

            logmsg "> Throwing away $size bytes on closed connection\n";

        }
        elsif($line eq "DISC\n") {
            logmsg "Fancy that; client wants to DISC, too\n";
            printf DWRITE "ACKD\n";
        }
        elsif($line eq "ACKD\n") {
            # Got the ack we were waiting for







|



















<
<

>







666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692


693
694
695
696
697
698
699
700
701
            '220-   / __| | | | |_) | |    '."\r\n",
            '220-  | (__| |_| |  _ {| |___ '."\r\n",
            '220    \___|\___/|_| \_\_____|'."\r\n")
        );
    }
}

# Perform the disconnect handshake with sockfilt on the secondary connection
# (the only connection we actively disconnect).
# This involves waiting for the disconnect acknowledgment after the DISC
# command, while throwing away anything else that might come in before
# that.
sub disc_handshake {
    print DWRITE "DISC\n";
    my $line;
    my $nr;
    while (5 == ($nr = sysread DREAD, $line, 5)) {
        if($line eq "DATA\n") {
            # Must read the data bytes to stay in sync
            my $i;
            sysread DREAD, $i, 5;

            my $size = 0;
            if($i =~ /^([0-9a-fA-F]{4})\n/) {
                $size = hex($1);
            }



            logmsg "> Throwing away $size bytes on closed connection\n";
            read_datasockf(\$line, $size);
        }
        elsif($line eq "DISC\n") {
            logmsg "Fancy that; client wants to DISC, too\n";
            printf DWRITE "ACKD\n";
        }
        elsif($line eq "ACKD\n") {
            # Got the ack we were waiting for
Changes to jni/curl/tests/globalconfig.pm.
34
35
36
37
38
39
40


41
42
43
44
45
46
47
    use base qw(Exporter);

    our @EXPORT = qw(
        $anyway
        $automakestyle
        $CURL
        $CURLVERSION


        $has_shared
        $LIBDIR
        $listonly
        $LOCKDIR
        $LOGDIR
        $memanalyze
        $MEMDUMP







>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    use base qw(Exporter);

    our @EXPORT = qw(
        $anyway
        $automakestyle
        $CURL
        $CURLVERSION
        $CURLVERNUM
        $DATE
        $has_shared
        $LIBDIR
        $listonly
        $LOCKDIR
        $LOGDIR
        $memanalyze
        $MEMDUMP
78
79
80
81
82
83
84

85
86
87
88
89
90
91
92
93
94
95
96
97
our $torture;         # 1 to enable torture testing
our $proxy_address;   # external HTTP proxy address
our $listonly;        # only list the tests
our $run_event_based; # run curl with --test-event to test the event API
our $automakestyle;   # use automake-like test status output format
our $anyway;          # continue anyway, even if a test fail
our $CURLVERSION="";  # curl's reported version number

our $randseed = 0;    # random number seed

# paths
our $pwd = getcwd();  # current working directory
our $srcdir = $ENV{'srcdir'} || '.';  # root of the test source code
our $perl="perl -I$srcdir"; # invoke perl like this
our $LOGDIR="log";  # root of the log directory; this will be different for
                    # each runner in multiprocess mode
our $LIBDIR="./libtest";
our $TESTDIR="$srcdir/data";
our $CURL="../src/curl".exe_ext('TOOL'); # what curl binary to run on the tests
our $VCURL=$CURL;  # what curl binary to use to verify the servers with
                   # VCURL is handy to set to the system one when the one you







>





|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
our $torture;         # 1 to enable torture testing
our $proxy_address;   # external HTTP proxy address
our $listonly;        # only list the tests
our $run_event_based; # run curl with --test-event to test the event API
our $automakestyle;   # use automake-like test status output format
our $anyway;          # continue anyway, even if a test fail
our $CURLVERSION="";  # curl's reported version number
our $CURLVERNUM="";   # curl's reported version number (without -DEV)
our $randseed = 0;    # random number seed

# paths
our $pwd = getcwd();  # current working directory
our $srcdir = $ENV{'srcdir'} || '.';  # root of the test source code
our $perl="perl -I. -I$srcdir"; # invoke perl like this
our $LOGDIR="log";  # root of the log directory; this will be different for
                    # each runner in multiprocess mode
our $LIBDIR="./libtest";
our $TESTDIR="$srcdir/data";
our $CURL="../src/curl".exe_ext('TOOL'); # what curl binary to run on the tests
our $VCURL=$CURL;  # what curl binary to use to verify the servers with
                   # VCURL is handy to set to the system one when the one you
Changes to jni/curl/tests/http/Makefile.am.
31
32
33
34
35
36
37

38
39
40
41
42
43
44
testenv/client.py                     \
testenv/curl.py                       \
testenv/env.py                        \
testenv/httpd.py                      \
testenv/mod_curltest/mod_curltest.c   \
testenv/nghttpx.py                    \
testenv/ports.py                      \

testenv/ws_echo_server.py

EXTRA_DIST =           \
config.ini.in          \
conftest.py            \
requirements.txt       \
scorecard.py           \







>







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
testenv/client.py                     \
testenv/curl.py                       \
testenv/env.py                        \
testenv/httpd.py                      \
testenv/mod_curltest/mod_curltest.c   \
testenv/nghttpx.py                    \
testenv/ports.py                      \
testenv/vsftpd.py                     \
testenv/ws_echo_server.py

EXTRA_DIST =           \
config.ini.in          \
conftest.py            \
requirements.txt       \
scorecard.py           \
Changes to jni/curl/tests/http/Makefile.in.
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







129
130
131
132
133
134
135

136
137
138
139
140
141
142
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
312
313
314
315
316
317
318


319
320
321
322
323
324
325
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@







>
>







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
459
460
461
462
463
464
465

466
467
468
469
470
471
472
testenv/client.py                     \
testenv/curl.py                       \
testenv/env.py                        \
testenv/httpd.py                      \
testenv/mod_curltest/mod_curltest.c   \
testenv/nghttpx.py                    \
testenv/ports.py                      \

testenv/ws_echo_server.py

EXTRA_DIST = \
config.ini.in          \
conftest.py            \
requirements.txt       \
scorecard.py           \







>







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
testenv/client.py                     \
testenv/curl.py                       \
testenv/env.py                        \
testenv/httpd.py                      \
testenv/mod_curltest/mod_curltest.c   \
testenv/nghttpx.py                    \
testenv/ports.py                      \
testenv/vsftpd.py                     \
testenv/ws_echo_server.py

EXTRA_DIST = \
config.ini.in          \
conftest.py            \
requirements.txt       \
scorecard.py           \
Changes to jni/curl/tests/http/clients/Makefile.in.
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







158
159
160
161
162
163
164

165
166
167
168
169
170
171
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
392
393
394
395
396
397
398


399
400
401
402
403
404
405
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@







>
>







391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
Changes to jni/curl/tests/http/clients/h2-download.c.
155
156
157
158
159
160
161

162
163
164
165
166
167
168
  int paused;
  int resumed;
  int done;
};

static size_t transfer_count = 1;
static struct transfer *transfers;


static struct transfer *get_transfer_for_easy(CURL *easy)
{
  size_t i;
  for(i = 0; i < transfer_count; ++i) {
    if(easy == transfers[i].easy)
      return &transfers[i];







>







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  int paused;
  int resumed;
  int done;
};

static size_t transfer_count = 1;
static struct transfer *transfers;
static int forbid_reuse = 0;

static struct transfer *get_transfer_for_easy(CURL *easy)
{
  size_t i;
  for(i = 0; i < transfer_count; ++i) {
    if(easy == transfers[i].easy)
      return &transfers[i];
235
236
237
238
239
240
241


242
243
244
245
246
247
248
  curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
  curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, (long)(128 * 1024));
  curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, my_write_cb);
  curl_easy_setopt(hnd, CURLOPT_WRITEDATA, t);
  curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 0L);
  curl_easy_setopt(hnd, CURLOPT_XFERINFOFUNCTION, my_progress_cb);
  curl_easy_setopt(hnd, CURLOPT_XFERINFODATA, t);



  /* please be verbose */
  if(verbose) {
    curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
    curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, debug_cb);
  }








>
>







236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
  curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, (long)(128 * 1024));
  curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, my_write_cb);
  curl_easy_setopt(hnd, CURLOPT_WRITEDATA, t);
  curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 0L);
  curl_easy_setopt(hnd, CURLOPT_XFERINFOFUNCTION, my_progress_cb);
  curl_easy_setopt(hnd, CURLOPT_XFERINFODATA, t);
  if(forbid_reuse)
    curl_easy_setopt(hnd, CURLOPT_FORBID_REUSE, 1L);

  /* please be verbose */
  if(verbose) {
    curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
    curl_easy_setopt(hnd, CURLOPT_DEBUGFUNCTION, debug_cb);
  }

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298



299
300
301
302
303
304
305
  size_t abort_offset = 0;
  size_t fail_offset = 0;
  int abort_paused = 0;
  struct transfer *t;
  int http_version = CURL_HTTP_VERSION_2_0;
  int ch;

  while((ch = getopt(argc, argv, "ahm:n:A:F:P:V:")) != -1) {
    switch(ch) {
    case 'h':
      usage(NULL);
      return 2;
    case 'a':
      abort_paused = 1;
      break;



    case 'm':
      max_parallel = (size_t)strtol(optarg, NULL, 10);
      break;
    case 'n':
      transfer_count = (size_t)strtol(optarg, NULL, 10);
      break;
    case 'A':







|







>
>
>







287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  size_t abort_offset = 0;
  size_t fail_offset = 0;
  int abort_paused = 0;
  struct transfer *t;
  int http_version = CURL_HTTP_VERSION_2_0;
  int ch;

  while((ch = getopt(argc, argv, "afhm:n:A:F:P:V:")) != -1) {
    switch(ch) {
    case 'h':
      usage(NULL);
      return 2;
    case 'a':
      abort_paused = 1;
      break;
    case 'f':
      forbid_reuse = 1;
      break;
    case 'm':
      max_parallel = (size_t)strtol(optarg, NULL, 10);
      break;
    case 'n':
      transfer_count = (size_t)strtol(optarg, NULL, 10);
      break;
    case 'A':
Changes to jni/curl/tests/http/clients/upload-pausing.c.
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

146
147
148
149
150

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165




166
167



168
169
170
171
172
173
174
    traced_data = 1;
    break;
  }

  return 0;
}

#define PAUSE_READ_AFTER  10
static size_t total_read = 0;

static size_t read_callback(char *ptr, size_t size, size_t nmemb,
                            void *userdata)
{
  (void)size;
  (void)nmemb;
  (void)userdata;
  if(total_read >= PAUSE_READ_AFTER) {

    return CURL_READFUNC_PAUSE;
  }
  else {
    ptr[0] = '\n';
    ++total_read;

    return 1;
  }
}

static int progress_callback(void *clientp,
                             double dltotal,
                             double dlnow,
                             double ultotal,
                             double ulnow)
{
  CURL *curl;
  (void)dltotal;
  (void)dlnow;
  (void)ultotal;
  (void)ulnow;




  curl = (CURL *)clientp;
  curl_easy_pause(curl, CURLPAUSE_CONT);



  return 0;
}

static int err(void)
{
  fprintf(stderr, "something unexpected went wrong - bailing out!\n");
  exit(2);







|









>





>










<




>
>
>
>
|
|
>
>
>







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
    traced_data = 1;
    break;
  }

  return 0;
}

#define PAUSE_READ_AFTER  1
static size_t total_read = 0;

static size_t read_callback(char *ptr, size_t size, size_t nmemb,
                            void *userdata)
{
  (void)size;
  (void)nmemb;
  (void)userdata;
  if(total_read >= PAUSE_READ_AFTER) {
    fprintf(stderr, "read_callback, return PAUSE\n");
    return CURL_READFUNC_PAUSE;
  }
  else {
    ptr[0] = '\n';
    ++total_read;
    fprintf(stderr, "read_callback, return 1 byte\n");
    return 1;
  }
}

static int progress_callback(void *clientp,
                             double dltotal,
                             double dlnow,
                             double ultotal,
                             double ulnow)
{

  (void)dltotal;
  (void)dlnow;
  (void)ultotal;
  (void)ulnow;
  (void)clientp;
#if 0
  /* Used to unpause on progress, but keeping for now. */
  {
    CURL *curl = (CURL *)clientp;
    curl_easy_pause(curl, CURLPAUSE_CONT);
    /* curl_easy_pause(curl, CURLPAUSE_RECV_CONT); */
  }
#endif
  return 0;
}

static int err(void)
{
  fprintf(stderr, "something unexpected went wrong - bailing out!\n");
  exit(2);
229
230
231
232
233
234
235

236
237
238
239
240
241
242
  curl_easy_setopt(curl, CURLOPT_XFERINFODATA, curl);
  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);

  /* It will help us to ensure that keepalive does not help. */
  curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
  curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 1L);
  curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 1L);


  /* Enable uploading. */
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
  curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

  if(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L) != CURLE_OK ||
     curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debug_cb)







>







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  curl_easy_setopt(curl, CURLOPT_XFERINFODATA, curl);
  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);

  /* It will help us to ensure that keepalive does not help. */
  curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
  curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 1L);
  curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 1L);
  curl_easy_setopt(curl, CURLOPT_TCP_KEEPCNT, 1L);

  /* Enable uploading. */
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
  curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

  if(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L) != CURLE_OK ||
     curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debug_cb)
Changes to jni/curl/tests/http/scorecard.py.
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
        fpath = os.path.join(docs_dir, fname)
        data1k = 1024*'x'
        flen = 0
        with open(fpath, 'w') as fd:
            while flen < fsize:
                fd.write(data1k)
                flen += len(data1k)
        return flen

    def _check_downloads(self, r: ExecResult, count: int):
        error = ''
        if r.exit_code != 0:
            error += f'exit={r.exit_code} '
        if r.exit_code != 0 or len(r.stats) != count:
            error += f'stats={len(r.stats)}/{count} '







|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
        fpath = os.path.join(docs_dir, fname)
        data1k = 1024*'x'
        flen = 0
        with open(fpath, 'w') as fd:
            while flen < fsize:
                fd.write(data1k)
                flen += len(data1k)
        return fpath

    def _check_downloads(self, r: ExecResult, count: int):
        error = ''
        if r.exit_code != 0:
            error += f'exit={r.exit_code} '
        if r.exit_code != 0 or len(r.stats) != count:
            error += f'stats={len(r.stats)}/{count} '
256
257
258
259
260
261
262





























































































































































263
264
265
266
267
268
269
                self._make_docs_file(docs_dir=self.caddy.docs_dir,
                                     fname=fname, fsize=fsize)
                url = f'https://{self.env.domain1}:{port}/{fname}'
                results = self.download_url(label=label, url=url,
                                            proto=proto, count=count)
                scores[via][label] = results
        return scores






























































































































































    def do_requests(self, url: str, proto: str, count: int,
                    max_parallel: int = 1):
        sample_size = 1
        samples = []
        errors = []
        profiles = []







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
                self._make_docs_file(docs_dir=self.caddy.docs_dir,
                                     fname=fname, fsize=fsize)
                url = f'https://{self.env.domain1}:{port}/{fname}'
                results = self.download_url(label=label, url=url,
                                            proto=proto, count=count)
                scores[via][label] = results
        return scores

    def _check_uploads(self, r: ExecResult, count: int):
        error = ''
        if r.exit_code != 0:
            error += f'exit={r.exit_code} '
        if r.exit_code != 0 or len(r.stats) != count:
            error += f'stats={len(r.stats)}/{count} '
        fails = [s for s in r.stats if s['response_code'] != 200]
        if len(fails) > 0:
            error += f'{len(fails)} failed'
        for f in fails:
            error += f'[{f["response_code"]}]'
        return error if len(error) > 0 else None

    def upload_single(self, url: str, proto: str, fpath: str, count: int):
        sample_size = count
        count = 1
        samples = []
        errors = []
        profiles = []
        self.info(f'single...')
        for i in range(sample_size):
            curl = CurlClient(env=self.env, silent=self._silent_curl)
            r = curl.http_put(urls=[url], fdata=fpath, alpn_proto=proto,
                              with_headers=False, with_profile=True)
            err = self._check_uploads(r, count)
            if err:
                errors.append(err)
            else:
                total_size = sum([s['size_upload'] for s in r.stats])
                samples.append(total_size / r.duration.total_seconds())
                profiles.append(r.profile)
        return {
            'count': count,
            'samples': sample_size,
            'max-parallel': 1,
            'speed': mean(samples) if len(samples) else -1,
            'errors': errors,
            'stats': RunProfile.AverageStats(profiles) if len(profiles) else {},
        }

    def upload_serial(self, url: str, proto: str, fpath: str, count: int):
        sample_size = 1
        samples = []
        errors = []
        profiles = []
        url = f'{url}?id=[0-{count - 1}]'
        self.info(f'serial...')
        for i in range(sample_size):
            curl = CurlClient(env=self.env, silent=self._silent_curl)
            r = curl.http_put(urls=[url], fdata=fpath, alpn_proto=proto,
                              with_headers=False, with_profile=True)
            err = self._check_uploads(r, count)
            if err:
                errors.append(err)
            else:
                total_size = sum([s['size_upload'] for s in r.stats])
                samples.append(total_size / r.duration.total_seconds())
                profiles.append(r.profile)
        return {
            'count': count,
            'samples': sample_size,
            'max-parallel': 1,
            'speed': mean(samples) if len(samples) else -1,
            'errors': errors,
            'stats': RunProfile.AverageStats(profiles) if len(profiles) else {},
        }

    def upload_parallel(self, url: str, proto: str, fpath: str, count: int):
        sample_size = 1
        samples = []
        errors = []
        profiles = []
        max_parallel = count
        url = f'{url}?id=[0-{count - 1}]'
        self.info(f'parallel...')
        for i in range(sample_size):
            curl = CurlClient(env=self.env, silent=self._silent_curl)
            r = curl.http_put(urls=[url], fdata=fpath, alpn_proto=proto,
                              with_headers=False, with_profile=True,
                              extra_args=[
                                   '--parallel',
                                    '--parallel-max', str(max_parallel)
                              ])
            err = self._check_uploads(r, count)
            if err:
                errors.append(err)
            else:
                total_size = sum([s['size_upload'] for s in r.stats])
                samples.append(total_size / r.duration.total_seconds())
                profiles.append(r.profile)
        return {
            'count': count,
            'samples': sample_size,
            'max-parallel': max_parallel,
            'speed': mean(samples) if len(samples) else -1,
            'errors': errors,
            'stats': RunProfile.AverageStats(profiles) if len(profiles) else {},
        }

    def upload_url(self, label: str, url: str, fpath: str, proto: str, count: int):
        self.info(f'  {count}x{label}: ')
        props = {
            'single': self.upload_single(url=url, proto=proto, fpath=fpath,
                                         count=10),
        }
        if count > 1:
            props['serial'] = self.upload_serial(url=url, proto=proto,
                                                 fpath=fpath, count=count)
            props['parallel'] = self.upload_parallel(url=url, proto=proto,
                                                     fpath=fpath, count=count)
        self.info(f'ok.\n')
        return props

    def uploads(self, proto: str, count: int,
                  fsizes: List[int]) -> Dict[str, Any]:
        scores = {}
        if self.httpd:
            if proto == 'h3':
                port = self.env.h3_port
                via = 'nghttpx'
                descr = f'port {port}, proxying httpd'
            else:
                port = self.env.https_port
                via = 'httpd'
                descr = f'port {port}'
            self.info(f'{via} uploads\n')
            scores[via] = {
                'description': descr,
            }
            for fsize in fsizes:
                label = self.fmt_size(fsize)
                fname = f'upload{label}.data'
                fpath = self._make_docs_file(docs_dir=self.env.gen_dir,
                                             fname=fname, fsize=fsize)
                url = f'https://{self.env.domain1}:{port}/curltest/put'
                results = self.upload_url(label=label, url=url, fpath=fpath,
                                          proto=proto, count=count)
                scores[via][label] = results
        if self.caddy:
            port = self.caddy.port
            via = 'caddy'
            descr = f'port {port}'
            self.info('caddy uploads\n')
            scores[via] = {
                'description': descr,
            }
            for fsize in fsizes:
                label = self.fmt_size(fsize)
                fname = f'upload{label}.data'
                fpath = self._make_docs_file(docs_dir=self.env.gen_dir,
                                             fname=fname, fsize=fsize)
                url = f'https://{self.env.domain2}:{port}/curltest/put'
                results = self.upload_url(label=label, url=url, fpath=fpath,
                                          proto=proto, count=count)
                scores[via][label] = results
        return scores

    def do_requests(self, url: str, proto: str, count: int,
                    max_parallel: int = 1):
        sample_size = 1
        samples = []
        errors = []
        profiles = []
342
343
344
345
346
347
348


349
350
351
352
353
354
355
            }
        return scores

    def score_proto(self, proto: str,
                    handshakes: bool = True,
                    downloads: Optional[List[int]] = None,
                    download_count: int = 50,


                    req_count=5000,
                    requests: bool = True):
        self.info(f"scoring {proto}\n")
        p = {}
        if proto == 'h3':
            p['name'] = 'h3'
            if not self.env.have_h3_curl():







>
>







499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
            }
        return scores

    def score_proto(self, proto: str,
                    handshakes: bool = True,
                    downloads: Optional[List[int]] = None,
                    download_count: int = 50,
                    uploads: Optional[List[int]] = None,
                    upload_count: int = 50,
                    req_count=5000,
                    requests: bool = True):
        self.info(f"scoring {proto}\n")
        p = {}
        if proto == 'h3':
            p['name'] = 'h3'
            if not self.env.have_h3_curl():
385
386
387
388
389
390
391




392
393
394
395
396
397
398
        }
        if handshakes:
            score['handshakes'] = self.handshakes(proto=proto)
        if downloads and len(downloads) > 0:
            score['downloads'] = self.downloads(proto=proto,
                                                count=download_count,
                                                fsizes=downloads)




        if requests:
            score['requests'] = self.requests(proto=proto, req_count=req_count)
        self.info("\n")
        return score

    def fmt_ms(self, tval):
        return f'{int(tval*1000)} ms' if tval >= 0 else '--'







>
>
>
>







544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
        }
        if handshakes:
            score['handshakes'] = self.handshakes(proto=proto)
        if downloads and len(downloads) > 0:
            score['downloads'] = self.downloads(proto=proto,
                                                count=download_count,
                                                fsizes=downloads)
        if uploads and len(uploads) > 0:
            score['uploads'] = self.uploads(proto=proto,
                                                count=upload_count,
                                                fsizes=uploads)
        if requests:
            score['requests'] = self.requests(proto=proto, req_count=req_count)
        self.info("\n")
        return score

    def fmt_ms(self, tval):
        return f'{int(tval*1000)} ms' if tval >= 0 else '--'
460
461
462
463
464
465
466















































467
468
469
470
471
472
473
                    for m in measures:
                        if m in size_score:
                            print(f' {self.fmt_mbs(size_score[m]["speed"]):>{mcol_width}}', end='')
                            s = f'[{size_score[m]["stats"]["cpu"]:>.1f}%'\
                                f'/{self.fmt_size(size_score[m]["stats"]["rss"])}]'
                            print(f' {s:<{mcol_sw}}', end='')
                        else:















































                            print(' '*mcol_width, end='')
                    if len(errors):
                        print(f' {"/".join(errors):<20}')
                    else:
                        print(f' {"-":^20}')

        if 'requests' in score:







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
                    for m in measures:
                        if m in size_score:
                            print(f' {self.fmt_mbs(size_score[m]["speed"]):>{mcol_width}}', end='')
                            s = f'[{size_score[m]["stats"]["cpu"]:>.1f}%'\
                                f'/{self.fmt_size(size_score[m]["stats"]["rss"])}]'
                            print(f' {s:<{mcol_sw}}', end='')
                        else:
                            print(' '*mcol_width, end='')
                    if len(errors):
                        print(f' {"/".join(errors):<20}')
                    else:
                        print(f' {"-":^20}')

        if 'uploads' in score:
            # get the key names of all sizes and measurements made
            sizes = []
            measures = []
            m_names = {}
            mcol_width = 12
            mcol_sw = 17
            for server, server_score in score['uploads'].items():
                for sskey, ssval in server_score.items():
                    if isinstance(ssval, str):
                        continue
                    if sskey not in sizes:
                        sizes.append(sskey)
                    for mkey, mval in server_score[sskey].items():
                        if mkey not in measures:
                            measures.append(mkey)
                            m_names[mkey] = f'{mkey}({mval["count"]}x{mval["max-parallel"]})'

            print('Uploads')
            print(f'  {"Server":<8} {"Size":>8}', end='')
            for m in measures: print(f' {m_names[m]:>{mcol_width}} {"[cpu/rss]":<{mcol_sw}}', end='')
            print(f' {"Errors":^20}')

            for server in score['uploads']:
                for size in sizes:
                    size_score = score['uploads'][server][size]
                    print(f'  {server:<8} {size:>8}', end='')
                    errors = []
                    for key, val in size_score.items():
                        if 'errors' in val:
                            errors.extend(val['errors'])
                    for m in measures:
                        if m in size_score:
                            print(f' {self.fmt_mbs(size_score[m]["speed"]):>{mcol_width}}', end='')
                            stats = size_score[m]["stats"]
                            if 'cpu' in stats:
                                s = f'[{stats["cpu"]:>.1f}%/{self.fmt_size(stats["rss"])}]'
                            else:
                                s = '[???/???]'
                            print(f' {s:<{mcol_sw}}', end='')
                        else:
                            print(' '*mcol_width, end='')
                    if len(errors):
                        print(f' {"/".join(errors):<20}')
                    else:
                        print(f' {"-":^20}')

        if 'requests' in score:
547
548
549
550
551
552
553






554
555
556
557
558
559
560
                        default=False, help="evaluate downloads")
    parser.add_argument("--download", action='append', type=str,
                        default=None, help="evaluate download size")
    parser.add_argument("--download-count", action='store', type=int,
                        default=50, help="perform that many downloads")
    parser.add_argument("--download-parallel", action='store', type=int,
                        default=0, help="perform that many downloads in parallel (default all)")






    parser.add_argument("-r", "--requests", action='store_true',
                        default=False, help="evaluate requests")
    parser.add_argument("--request-count", action='store', type=int,
                        default=5000, help="perform that many requests")
    parser.add_argument("--httpd", action='store_true', default=False,
                        help="evaluate httpd server only")
    parser.add_argument("--caddy", action='store_true', default=False,







>
>
>
>
>
>







757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
                        default=False, help="evaluate downloads")
    parser.add_argument("--download", action='append', type=str,
                        default=None, help="evaluate download size")
    parser.add_argument("--download-count", action='store', type=int,
                        default=50, help="perform that many downloads")
    parser.add_argument("--download-parallel", action='store', type=int,
                        default=0, help="perform that many downloads in parallel (default all)")
    parser.add_argument("-u", "--uploads", action='store_true',
                        default=False, help="evaluate uploads")
    parser.add_argument("--upload", action='append', type=str,
                        default=None, help="evaluate upload size")
    parser.add_argument("--upload-count", action='store', type=int,
                        default=50, help="perform that many uploads")
    parser.add_argument("-r", "--requests", action='store_true',
                        default=False, help="evaluate requests")
    parser.add_argument("--request-count", action='store', type=int,
                        default=5000, help="perform that many requests")
    parser.add_argument("--httpd", action='store_true', default=False,
                        help="evaluate httpd server only")
    parser.add_argument("--caddy", action='store_true', default=False,
574
575
576
577
578
579
580







581
582
583
584
585


586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602

603
604
605
606
607
608
609
610
611
612

613
614
615
616
617

618
619
620
621
622
623


624
625
626
627
628
629
630
    protocol = args.protocol
    handshakes = True
    downloads = [1024 * 1024, 10 * 1024 * 1024, 100 * 1024 * 1024]
    if args.download is not None:
        downloads = []
        for x in args.download:
            downloads.extend([parse_size(s) for s in x.split(',')])







    requests = True
    if args.downloads or args.requests or args.handshakes:
        handshakes = args.handshakes
        if not args.downloads:
            downloads = None


        requests = args.requests

    test_httpd = protocol != 'h3'
    test_caddy = True
    if args.caddy or args.httpd:
        test_caddy = args.caddy
        test_httpd = args.httpd

    rv = 0
    env = Env()
    env.setup()
    env.test_timeout = None
    httpd = None
    nghttpx = None
    caddy = None
    try:
        if test_httpd:

            httpd = Httpd(env=env)
            assert httpd.exists(), \
                f'httpd not found: {env.httpd}'
            httpd.clear_logs()
            assert httpd.start()
            if 'h3' == protocol:
                nghttpx = NghttpxQuic(env=env)
                nghttpx.clear_logs()
                assert nghttpx.start()
        if test_caddy and env.caddy:

            caddy = Caddy(env=env)
            caddy.clear_logs()
            assert caddy.start()

        card = ScoreCard(env=env, httpd=httpd, nghttpx=nghttpx, caddy=caddy,

                         verbose=args.verbose, curl_verbose=args.curl_verbose,
                         download_parallel=args.download_parallel)
        score = card.score_proto(proto=protocol,
                                 handshakes=handshakes,
                                 downloads=downloads,
                                 download_count=args.download_count,


                                 req_count=args.request_count,
                                 requests=requests)
        if args.json:
            print(json.JSONEncoder(indent=2).encode(score))
        else:
            card.print_score(score)








>
>
>
>
>
>
>

|



>
>
















|
>





|




>




|
>






>
>







790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
    protocol = args.protocol
    handshakes = True
    downloads = [1024 * 1024, 10 * 1024 * 1024, 100 * 1024 * 1024]
    if args.download is not None:
        downloads = []
        for x in args.download:
            downloads.extend([parse_size(s) for s in x.split(',')])

    uploads = [1024 * 1024, 10 * 1024 * 1024, 100 * 1024 * 1024]
    if args.upload is not None:
        uploads = []
        for x in args.upload:
            uploads.extend([parse_size(s) for s in x.split(',')])

    requests = True
    if args.downloads or args.uploads or args.requests or args.handshakes:
        handshakes = args.handshakes
        if not args.downloads:
            downloads = None
        if not args.uploads:
            uploads = None
        requests = args.requests

    test_httpd = protocol != 'h3'
    test_caddy = True
    if args.caddy or args.httpd:
        test_caddy = args.caddy
        test_httpd = args.httpd

    rv = 0
    env = Env()
    env.setup()
    env.test_timeout = None
    httpd = None
    nghttpx = None
    caddy = None
    try:
        if test_httpd or (test_caddy and uploads):
            print(f'httpd: {env.httpd_version()}, http:{env.http_port} https:{env.https_port}')
            httpd = Httpd(env=env)
            assert httpd.exists(), \
                f'httpd not found: {env.httpd}'
            httpd.clear_logs()
            assert httpd.start()
            if test_httpd and 'h3' == protocol:
                nghttpx = NghttpxQuic(env=env)
                nghttpx.clear_logs()
                assert nghttpx.start()
        if test_caddy and env.caddy:
            print(f'Caddy: {env.caddy_version()}, http:{env.caddy_http_port} https:{env.caddy_https_port}')
            caddy = Caddy(env=env)
            caddy.clear_logs()
            assert caddy.start()

        card = ScoreCard(env=env, httpd=httpd if test_httpd else None,
                         nghttpx=nghttpx, caddy=caddy if test_caddy else None,
                         verbose=args.verbose, curl_verbose=args.curl_verbose,
                         download_parallel=args.download_parallel)
        score = card.score_proto(proto=protocol,
                                 handshakes=handshakes,
                                 downloads=downloads,
                                 download_count=args.download_count,
                                 uploads=uploads,
                                 upload_count=args.upload_count,
                                 req_count=args.request_count,
                                 requests=requests)
        if args.json:
            print(json.JSONEncoder(indent=2).encode(score))
        else:
            card.print_score(score)

Changes to jni/curl/tests/http/test_07_upload.py.
460
461
462
463
464
465
466
467
468
469
470




























471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
                diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(),
                                                    b=open(dfile).readlines(),
                                                    fromfile=srcfile,
                                                    tofile=dfile,
                                                    n=1))
                assert False, f'download {dfile} differs:\n{diff}'

    # upload large data, let connection die while doing it
    # issues #11769 #13260
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_07_42_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto):




























        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 fails here")
        client = LocalClient(name='upload-pausing', env=env, timeout=60)
        if not client.exists():
            pytest.skip(f'example client not built: {client.name}')
        url = f'http://{env.domain1}:{env.http_port}/curltest/echo?id=[0-0]&die_after=10'
        r = client.run([url])
        r.check_exit_code(18)  # PARTIAL_FILE

    # speed limited on put handler
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_07_50_put_speed_limit(self, env: Env, httpd, nghttpx, proto, repeat):
        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        count = 1







|


|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







|

|







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
                diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(),
                                                    b=open(dfile).readlines(),
                                                    fromfile=srcfile,
                                                    tofile=dfile,
                                                    n=1))
                assert False, f'download {dfile} differs:\n{diff}'

    # upload data, pause, let connection die with an incomplete response
    # issues #11769 #13260
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_07_42a_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto):
        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 fails here")
        client = LocalClient(name='upload-pausing', env=env, timeout=60)
        if not client.exists():
            pytest.skip(f'example client not built: {client.name}')
        url = f'http://{env.domain1}:{env.http_port}/curltest/echo?id=[0-0]&die_after=0'
        r = client.run([url])
        r.check_exit_code(18)  # PARTIAL_FILE

    # upload data, pause, let connection die without any response at all
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_07_42b_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto):
        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 fails here")
        client = LocalClient(name='upload-pausing', env=env, timeout=60)
        if not client.exists():
            pytest.skip(f'example client not built: {client.name}')
        url = f'http://{env.domain1}:{env.http_port}/curltest/echo?id=[0-0]&just_die=1'
        r = client.run([url])
        r.check_exit_code(52)  # GOT_NOTHING

    # upload data, pause, let connection die after 100 continue
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_07_42c_upload_disconnect(self, env: Env, httpd, nghttpx, repeat, proto):
        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 fails here")
        client = LocalClient(name='upload-pausing', env=env, timeout=60)
        if not client.exists():
            pytest.skip(f'example client not built: {client.name}')
        url = f'http://{env.domain1}:{env.http_port}/curltest/echo?id=[0-0]&die_after_100=1'
        r = client.run([url])
        r.check_exit_code(52)  # GOT_NOTHING

    # speed limited on put handler
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_07_50_put_speed_limit(self, env: Env, httpd, nghttpx, proto, repeat):
        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        count = 1
Changes to jni/curl/tests/http/test_08_caddy.py.
57
58
59
60
61
62
63

64
65
66
67
68
69
70

    @pytest.fixture(autouse=True, scope='class')
    def _class_scope(self, env, caddy):
        self._make_docs_file(docs_dir=caddy.docs_dir, fname='data1.data', fsize=1024*1024)
        self._make_docs_file(docs_dir=caddy.docs_dir, fname='data5.data', fsize=5*1024*1024)
        self._make_docs_file(docs_dir=caddy.docs_dir, fname='data10.data', fsize=10*1024*1024)
        self._make_docs_file(docs_dir=caddy.docs_dir, fname='data100.data', fsize=100*1024*1024)


    # download 1 file
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_08_01_download_1(self, env: Env, caddy: Caddy, repeat, proto):
        if proto == 'h3' and not env.have_h3_curl():
            pytest.skip("h3 not supported in curl")
        if proto == 'h3' and env.curl_uses_lib('msh3'):







>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

    @pytest.fixture(autouse=True, scope='class')
    def _class_scope(self, env, caddy):
        self._make_docs_file(docs_dir=caddy.docs_dir, fname='data1.data', fsize=1024*1024)
        self._make_docs_file(docs_dir=caddy.docs_dir, fname='data5.data', fsize=5*1024*1024)
        self._make_docs_file(docs_dir=caddy.docs_dir, fname='data10.data', fsize=10*1024*1024)
        self._make_docs_file(docs_dir=caddy.docs_dir, fname='data100.data', fsize=100*1024*1024)
        env.make_data_file(indir=env.gen_dir, fname="data-10m", fsize=10*1024*1024)

    # download 1 file
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_08_01_download_1(self, env: Env, caddy: Caddy, repeat, proto):
        if proto == 'h3' and not env.have_h3_curl():
            pytest.skip("h3 not supported in curl")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
147
148
149
150
151
152
153



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183






















    @pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
    def test_08_05_download_1mb_parallel(self, env: Env, caddy: Caddy,
                                         repeat, proto):
        if proto == 'h3' and not env.have_h3_curl():
            pytest.skip("h3 not supported in curl")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 itself crashes")



        count = 50
        curl = CurlClient(env=env)
        urln = f'https://{env.domain1}:{caddy.port}/data10.data?[0-{count-1}]'
        r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[
            '--parallel'
        ])
        r.check_response(count=count, http_status=200)
        if proto == 'http/1.1':
            # http/1.1 parallel transfers will open multiple connections
            assert r.total_connects > 1, r.dump_logs()
        else:
            assert r.total_connects == 1, r.dump_logs()

    # upload data parallel, check that they were echoed
    @pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
    @pytest.mark.parametrize("proto", ['h2', 'h3'])
    def test_08_06_upload_parallel(self, env: Env, caddy, repeat, proto):
        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 stalls here")
        # limit since we use a separate connection in h1
        count = 20
        data = '0123456789'
        curl = CurlClient(env=env)
        url = f'https://{env.domain1}:{caddy.port}/data10.data?[0-{count-1}]'
        r = curl.http_upload(urls=[url], data=data, alpn_proto=proto,
                             extra_args=['--parallel'])
        exp_status = 405 if env.caddy_is_at_least('2.7.0') else 200
        r.check_stats(count=count, http_status=exp_status, exitcode=0)





























>
>
>













|
<
|
|








|


<
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
    @pytest.mark.skipif(condition=Env().ci_run, reason="not suitable for CI runs")
    def test_08_05_download_1mb_parallel(self, env: Env, caddy: Caddy,
                                         repeat, proto):
        if proto == 'h3' and not env.have_h3_curl():
            pytest.skip("h3 not supported in curl")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 itself crashes")
        if proto == 'http/1.1' and env.curl_uses_lib('mbedtls'):
            pytest.skip("mbedtls 3.6.0 fails on 50 connections with: "\
                "ssl_handshake returned: (-0x7F00) SSL - Memory allocation failed")
        count = 50
        curl = CurlClient(env=env)
        urln = f'https://{env.domain1}:{caddy.port}/data10.data?[0-{count-1}]'
        r = curl.http_download(urls=[urln], alpn_proto=proto, extra_args=[
            '--parallel'
        ])
        r.check_response(count=count, http_status=200)
        if proto == 'http/1.1':
            # http/1.1 parallel transfers will open multiple connections
            assert r.total_connects > 1, r.dump_logs()
        else:
            assert r.total_connects == 1, r.dump_logs()

    # post data parallel, check that they were echoed

    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_08_06_post_parallel(self, env: Env, httpd, caddy, repeat, proto):
        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 stalls here")
        # limit since we use a separate connection in h1
        count = 20
        data = '0123456789'
        curl = CurlClient(env=env)
        url = f'https://{env.domain2}:{caddy.port}/curltest/echo?id=[0-{count-1}]'
        r = curl.http_upload(urls=[url], data=data, alpn_proto=proto,
                             extra_args=['--parallel'])

        r.check_stats(count=count, http_status=200, exitcode=0)
        for i in range(0,count):
            respdata = open(curl.response_file(i)).readlines()
            assert respdata == [data]

    # put large file, check that they length were echoed
    @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
    def test_08_07_put_large(self, env: Env, httpd, caddy, repeat, proto):
        if proto == 'h3' and not env.have_h3():
            pytest.skip("h3 not supported")
        if proto == 'h3' and env.curl_uses_lib('msh3'):
            pytest.skip("msh3 stalls here")
        # limit since we use a separate connection in h1<
        count = 1
        fdata = os.path.join(env.gen_dir, 'data-10m')
        curl = CurlClient(env=env)
        url = f'https://{env.domain2}:{caddy.port}/curltest/put?id=[0-{count-1}]'
        r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto)
        exp_data = [f'{os.path.getsize(fdata)}']
        r.check_response(count=count, http_status=200)
        for i in range(count):
            respdata = open(curl.response_file(i)).readlines()
            assert respdata == exp_data
Changes to jni/curl/tests/http/testenv/caddy.py.
137
138
139
140
141
142
143


144
145
146
147
148
149
150
    def _mkpath(self, path):
        if not os.path.exists(path):
            return os.makedirs(path)

    def _write_config(self):
        domain1 = self.env.domain1
        creds1 = self.env.get_credentials(domain1)


        self._mkpath(self._docs_dir)
        self._mkpath(self._tmp_dir)
        with open(os.path.join(self._docs_dir, 'data.json'), 'w') as fd:
            data = {
                'server': f'{domain1}',
            }
            fd.write(JSONEncoder().encode(data))







>
>







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    def _mkpath(self, path):
        if not os.path.exists(path):
            return os.makedirs(path)

    def _write_config(self):
        domain1 = self.env.domain1
        creds1 = self.env.get_credentials(domain1)
        domain2 = self.env.domain2
        creds2 = self.env.get_credentials(domain2)
        self._mkpath(self._docs_dir)
        self._mkpath(self._tmp_dir)
        with open(os.path.join(self._docs_dir, 'data.json'), 'w') as fd:
            data = {
                'server': f'{domain1}',
            }
            fd.write(JSONEncoder().encode(data))
159
160
161
162
163
164
165





166
167
                f'}}',
                f'{domain1}:{self.env.caddy_https_port} {{',
                f'  file_server * {{',
                f'    root {self._docs_dir}',
                f'  }}',
                f'  tls {creds1.cert_file} {creds1.pkey_file}',
                f'}}',





            ]
            fd.write("\n".join(conf))







>
>
>
>
>


161
162
163
164
165
166
167
168
169
170
171
172
173
174
                f'}}',
                f'{domain1}:{self.env.caddy_https_port} {{',
                f'  file_server * {{',
                f'    root {self._docs_dir}',
                f'  }}',
                f'  tls {creds1.cert_file} {creds1.pkey_file}',
                f'}}',
                f'{domain2} {{',
                f'  reverse_proxy /* http://localhost:{self.env.http_port} {{',
                f'  }}',
                f'  tls {creds2.cert_file} {creds2.pkey_file}',
                f'}}',
            ]
            fd.write("\n".join(conf))
Changes to jni/curl/tests/http/testenv/curl.py.
23
24
25
26
27
28
29




30
31
32
33
34
35
36
# SPDX-License-Identifier: curl
#
###########################################################################
#
import json
import logging
import os




import psutil
import re
import shutil
import subprocess
from statistics import mean, fmean
from datetime import timedelta, datetime
from typing import List, Optional, Dict, Union, Any







>
>
>
>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# SPDX-License-Identifier: curl
#
###########################################################################
#
import json
import logging
import os
import sys
import time
from threading import Thread

import psutil
import re
import shutil
import subprocess
from statistics import mean, fmean
from datetime import timedelta, datetime
from typing import List, Optional, Dict, Union, Any
98
99
100
101
102
103
104
105















































































106
107
108
109
110
111
112
113

114
115
116
117
118
119

120
121
122
123
124
125
126
        self._psu = None

    def __repr__(self):
        return f'RunProfile[pid={self._pid}, '\
               f'duration={self.duration.total_seconds():.3f}s, '\
               f'stats={self.stats}]'

















































































class ExecResult:

    def __init__(self, args: List[str], exit_code: int,
                 stdout: List[str], stderr: List[str],
                 duration: Optional[timedelta] = None,
                 with_stats: bool = False,
                 exception: Optional[str] = None,
                 profile: Optional[RunProfile] = None):

        self._args = args
        self._exit_code = exit_code
        self._exception = exception
        self._stdout = stdout
        self._stderr = stderr
        self._profile = profile

        self._duration = duration if duration is not None else timedelta()
        self._response = None
        self._responses = []
        self._results = {}
        self._assets = []
        self._stats = []
        self._json_out = None








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







|
>






>







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        self._psu = None

    def __repr__(self):
        return f'RunProfile[pid={self._pid}, '\
               f'duration={self.duration.total_seconds():.3f}s, '\
               f'stats={self.stats}]'


class RunTcpDump:

    def __init__(self, env, run_dir):
        self._env = env
        self._run_dir = run_dir
        self._proc = None
        self._stdoutfile = os.path.join(self._run_dir, 'tcpdump.out')
        self._stderrfile = os.path.join(self._run_dir, 'tcpdump.err')

    @property
    def stats(self) -> Optional[List[str]]:
        if self._proc:
            raise Exception('tcpdump still running')
        lines = []
        for l in open(self._stdoutfile).readlines():
            if re.match(r'.* IP 127\.0\.0\.1\.\d+ [<>] 127\.0\.0\.1\.\d+:.*', l):
                lines.append(l)
        return lines

    def stats_excluding(self, src_port) -> Optional[List[str]]:
        if self._proc:
            raise Exception('tcpdump still running')
        lines = []
        for l in self.stats:
            if not re.match(r'.* IP 127\.0\.0\.1\.' + str(src_port) + ' >.*', l):
                lines.append(l)
        return lines

    @property
    def stderr(self) -> List[str]:
        if self._proc:
            raise Exception('tcpdump still running')
        lines = []
        return open(self._stderrfile).readlines()

    def sample(self):
        # not sure how to make that detection reliable for all platforms
        local_if = 'lo0' if sys.platform.startswith('darwin') else 'lo'
        try:
            tcpdump = self._env.tcpdump()
            if tcpdump is None:
                raise Exception('tcpdump not available')
            # look with tcpdump for TCP RST packets which indicate
            # we did not shut down connections cleanly
            args = []
            # at least on Linux, we need root permissions to run tcpdump
            if sys.platform.startswith('linux'):
                args.append('sudo')
            args.extend([
                tcpdump, '-i', local_if, '-n', 'tcp[tcpflags] & (tcp-rst)!=0'
            ])
            with open(self._stdoutfile, 'w') as cout:
                with open(self._stderrfile, 'w') as cerr:
                    self._proc = subprocess.Popen(args, stdout=cout, stderr=cerr,
                                                  text=True, cwd=self._run_dir,
                                                  shell=False)
                    assert self._proc
                    assert self._proc.returncode is None
                    while self._proc:
                        try:
                            self._proc.wait(timeout=1)
                        except subprocess.TimeoutExpired:
                            pass
        except Exception as e:
            log.error(f'Tcpdump: {e}')

    def start(self):
        def do_sample():
            self.sample()
        t = Thread(target=do_sample)
        t.start()

    def finish(self):
        if self._proc:
            time.sleep(1)
            self._proc.terminate()
            self._proc = None


class ExecResult:

    def __init__(self, args: List[str], exit_code: int,
                 stdout: List[str], stderr: List[str],
                 duration: Optional[timedelta] = None,
                 with_stats: bool = False,
                 exception: Optional[str] = None,
                 profile: Optional[RunProfile] = None,
                 tcpdump: Optional[RunTcpDump] = None):
        self._args = args
        self._exit_code = exit_code
        self._exception = exception
        self._stdout = stdout
        self._stderr = stderr
        self._profile = profile
        self._tcpdump = tcpdump
        self._duration = duration if duration is not None else timedelta()
        self._response = None
        self._responses = []
        self._results = {}
        self._assets = []
        self._stats = []
        self._json_out = None
181
182
183
184
185
186
187




188
189
190
191
192
193
194
    def duration(self) -> timedelta:
        return self._duration

    @property
    def profile(self) -> Optional[RunProfile]:
        return self._profile





    @property
    def response(self) -> Optional[Dict]:
        return self._response

    @property
    def responses(self) -> List[Dict]:
        return self._responses







>
>
>
>







266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
    def duration(self) -> timedelta:
        return self._duration

    @property
    def profile(self) -> Optional[RunProfile]:
        return self._profile

    @property
    def tcpdump(self) -> Optional[RunTcpDump]:
        return self._tcpdump

    @property
    def response(self) -> Optional[Dict]:
        return self._response

    @property
    def responses(self) -> List[Dict]:
        return self._responses
355
356
357
358
359
360
361
362

363


364
365
366
367
368
369
370
371
372

373
374
375
376
377
378
379
        'http/1.0': '--http1.0',
        'http/1.1': '--http1.1',
        'h2': '--http2',
        'h2c': '--http2',
        'h3': '--http3-only',
    }

    def __init__(self, env: Env, run_dir: Optional[str] = None,

                 timeout: Optional[float] = None, silent: bool = False):


        self.env = env
        self._timeout = timeout if timeout else env.test_timeout
        self._curl = os.environ['CURL'] if 'CURL' in os.environ else env.curl
        self._run_dir = run_dir if run_dir else os.path.join(env.gen_dir, 'curl')
        self._stdoutfile = f'{self._run_dir}/curl.stdout'
        self._stderrfile = f'{self._run_dir}/curl.stderr'
        self._headerfile = f'{self._run_dir}/curl.headers'
        self._log_path = f'{self._run_dir}/curl.log'
        self._silent = silent

        self._rmrf(self._run_dir)
        self._mkpath(self._run_dir)

    @property
    def run_dir(self) -> str:
        return self._run_dir








|
>
|
>
>









>







444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
        'http/1.0': '--http1.0',
        'http/1.1': '--http1.1',
        'h2': '--http2',
        'h2c': '--http2',
        'h3': '--http3-only',
    }

    def __init__(self, env: Env,
                 run_dir: Optional[str] = None,
                 timeout: Optional[float] = None,
                 silent: bool = False,
                 run_env: Optional[Dict[str, str]] = None):
        self.env = env
        self._timeout = timeout if timeout else env.test_timeout
        self._curl = os.environ['CURL'] if 'CURL' in os.environ else env.curl
        self._run_dir = run_dir if run_dir else os.path.join(env.gen_dir, 'curl')
        self._stdoutfile = f'{self._run_dir}/curl.stdout'
        self._stderrfile = f'{self._run_dir}/curl.stderr'
        self._headerfile = f'{self._run_dir}/curl.headers'
        self._log_path = f'{self._run_dir}/curl.log'
        self._silent = silent
        self._run_env = run_env
        self._rmrf(self._run_dir)
        self._mkpath(self._run_dir)

    @property
    def run_dir(self) -> str:
        return self._run_dir

414
415
416
417
418
419
420
421

422
423
424
425
426

427
428
429
430
431
432

433
434
435
436
437
438
439
            xargs.append('--proxytunnel')
        return xargs

    def http_get(self, url: str, extra_args: Optional[List[str]] = None,
                 alpn_proto: Optional[str] = None,
                 def_tracing: bool = True,
                 with_stats: bool = False,
                 with_profile: bool = False):

        return self._raw(url, options=extra_args,
                         with_stats=with_stats,
                         alpn_proto=alpn_proto,
                         def_tracing=def_tracing,
                         with_profile=with_profile)


    def http_download(self, urls: List[str],
                      alpn_proto: Optional[str] = None,
                      with_stats: bool = True,
                      with_headers: bool = False,
                      with_profile: bool = False,

                      no_save: bool = False,
                      extra_args: List[str] = None):
        if extra_args is None:
            extra_args = []
        if no_save:
            extra_args.extend([
                '-o', '/dev/null',







|
>




|
>






>







507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
            xargs.append('--proxytunnel')
        return xargs

    def http_get(self, url: str, extra_args: Optional[List[str]] = None,
                 alpn_proto: Optional[str] = None,
                 def_tracing: bool = True,
                 with_stats: bool = False,
                 with_profile: bool = False,
                 with_tcpdump: bool = False):
        return self._raw(url, options=extra_args,
                         with_stats=with_stats,
                         alpn_proto=alpn_proto,
                         def_tracing=def_tracing,
                         with_profile=with_profile,
                         with_tcpdump=with_tcpdump)

    def http_download(self, urls: List[str],
                      alpn_proto: Optional[str] = None,
                      with_stats: bool = True,
                      with_headers: bool = False,
                      with_profile: bool = False,
                      with_tcpdump: bool = False,
                      no_save: bool = False,
                      extra_args: List[str] = None):
        if extra_args is None:
            extra_args = []
        if no_save:
            extra_args.extend([
                '-o', '/dev/null',
448
449
450
451
452
453
454
455

456
457
458
459
460
461

462
463
464
465
466
467
468
469
470
471
472
473
474
475

476
477
478
479
480
481
482
        if with_stats:
            extra_args.extend([
                '-w', '%{json}\\n'
            ])
        return self._raw(urls, alpn_proto=alpn_proto, options=extra_args,
                         with_stats=with_stats,
                         with_headers=with_headers,
                         with_profile=with_profile)


    def http_upload(self, urls: List[str], data: str,
                    alpn_proto: Optional[str] = None,
                    with_stats: bool = True,
                    with_headers: bool = False,
                    with_profile: bool = False,

                    extra_args: Optional[List[str]] = None):
        if extra_args is None:
            extra_args = []
        extra_args.extend([
            '--data-binary', data, '-o', 'download_#1.data',
        ])
        if with_stats:
            extra_args.extend([
                '-w', '%{json}\\n'
            ])
        return self._raw(urls, alpn_proto=alpn_proto, options=extra_args,
                         with_stats=with_stats,
                         with_headers=with_headers,
                         with_profile=with_profile)


    def http_delete(self, urls: List[str],
                    alpn_proto: Optional[str] = None,
                    with_stats: bool = True,
                    with_profile: bool = False,
                    extra_args: Optional[List[str]] = None):
        if extra_args is None:







|
>






>













|
>







544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
        if with_stats:
            extra_args.extend([
                '-w', '%{json}\\n'
            ])
        return self._raw(urls, alpn_proto=alpn_proto, options=extra_args,
                         with_stats=with_stats,
                         with_headers=with_headers,
                         with_profile=with_profile,
                         with_tcpdump=with_tcpdump)

    def http_upload(self, urls: List[str], data: str,
                    alpn_proto: Optional[str] = None,
                    with_stats: bool = True,
                    with_headers: bool = False,
                    with_profile: bool = False,
                    with_tcpdump: bool = False,
                    extra_args: Optional[List[str]] = None):
        if extra_args is None:
            extra_args = []
        extra_args.extend([
            '--data-binary', data, '-o', 'download_#1.data',
        ])
        if with_stats:
            extra_args.extend([
                '-w', '%{json}\\n'
            ])
        return self._raw(urls, alpn_proto=alpn_proto, options=extra_args,
                         with_stats=with_stats,
                         with_headers=with_headers,
                         with_profile=with_profile,
                         with_tcpdump=with_tcpdump)

    def http_delete(self, urls: List[str],
                    alpn_proto: Optional[str] = None,
                    with_stats: bool = True,
                    with_profile: bool = False,
                    extra_args: Optional[List[str]] = None):
        if extra_args is None:
537
538
539
540
541
542
543

544
545
546
547
548
549
550
        return self._raw(urls, alpn_proto=alpn_proto, options=extra_args,
                         with_stats=with_stats,
                         with_headers=with_headers)

    def ftp_get(self, urls: List[str],
                      with_stats: bool = True,
                      with_profile: bool = False,

                      no_save: bool = False,
                      extra_args: List[str] = None):
        if extra_args is None:
            extra_args = []
        if no_save:
            extra_args.extend([
                '-o', '/dev/null',







>







636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
        return self._raw(urls, alpn_proto=alpn_proto, options=extra_args,
                         with_stats=with_stats,
                         with_headers=with_headers)

    def ftp_get(self, urls: List[str],
                      with_stats: bool = True,
                      with_profile: bool = False,
                      with_tcpdump: bool = False,
                      no_save: bool = False,
                      extra_args: List[str] = None):
        if extra_args is None:
            extra_args = []
        if no_save:
            extra_args.extend([
                '-o', '/dev/null',
559
560
561
562
563
564
565
566

567
568
569
570

571
572
573
574
575
576
577
578
579

580
581



































582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597

598
599
600
601
602
603

604



605
606
607
608
609
610
611
612
613

614
615
616
617
618
619
620
        if with_stats:
            extra_args.extend([
                '-w', '%{json}\\n'
            ])
        return self._raw(urls, options=extra_args,
                         with_stats=with_stats,
                         with_headers=False,
                         with_profile=with_profile)


    def ftp_ssl_get(self, urls: List[str],
                      with_stats: bool = True,
                      with_profile: bool = False,

                      no_save: bool = False,
                      extra_args: List[str] = None):
        if extra_args is None:
            extra_args = []
        extra_args.extend([
            '--ssl-reqd',
        ])
        return self.ftp_get(urls=urls, with_stats=with_stats,
                            with_profile=with_profile, no_save=no_save,

                            extra_args=extra_args)




































    def response_file(self, idx: int):
        return os.path.join(self._run_dir, f'download_{idx}.data')

    def run_direct(self, args, with_stats: bool = False, with_profile: bool = False):
        my_args = [self._curl]
        if with_stats:
            my_args.extend([
                '-w', '%{json}\\n'
            ])
        my_args.extend([
            '-o', 'download.data',
        ])
        my_args.extend(args)
        return self._run(args=my_args, with_stats=with_stats, with_profile=with_profile)

    def _run(self, args, intext='', with_stats: bool = False, with_profile: bool = True):

        self._rmf(self._stdoutfile)
        self._rmf(self._stderrfile)
        self._rmf(self._headerfile)
        started_at = datetime.now()
        exception = None
        profile = None

        started_at = datetime.now()



        try:
            with open(self._stdoutfile, 'w') as cout:
                with open(self._stderrfile, 'w') as cerr:
                    if with_profile:
                        end_at = started_at + timedelta(seconds=self._timeout) \
                            if self._timeout else None
                        log.info(f'starting: {args}')
                        p = subprocess.Popen(args, stderr=cerr, stdout=cout,
                                             cwd=self._run_dir, shell=False)

                        profile = RunProfile(p.pid, started_at, self._run_dir)
                        if intext is not None and False:
                            p.communicate(input=intext.encode(), timeout=1)
                        ptimeout = 0.0
                        while True:
                            try:
                                p.wait(timeout=ptimeout)







|
>




>









>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>















|
>



<


>

>
>
>








|
>







659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739

740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
        if with_stats:
            extra_args.extend([
                '-w', '%{json}\\n'
            ])
        return self._raw(urls, options=extra_args,
                         with_stats=with_stats,
                         with_headers=False,
                         with_profile=with_profile,
                         with_tcpdump=with_tcpdump)

    def ftp_ssl_get(self, urls: List[str],
                      with_stats: bool = True,
                      with_profile: bool = False,
                      with_tcpdump: bool = False,
                      no_save: bool = False,
                      extra_args: List[str] = None):
        if extra_args is None:
            extra_args = []
        extra_args.extend([
            '--ssl-reqd',
        ])
        return self.ftp_get(urls=urls, with_stats=with_stats,
                            with_profile=with_profile, no_save=no_save,
                            with_tcpdump=with_tcpdump,
                            extra_args=extra_args)

    def ftp_upload(self, urls: List[str], fupload,
                   with_stats: bool = True,
                   with_profile: bool = False,
                   with_tcpdump: bool = False,
                   extra_args: List[str] = None):
        if extra_args is None:
            extra_args = []
        extra_args.extend([
            '--upload-file', fupload
        ])
        if with_stats:
            extra_args.extend([
                '-w', '%{json}\\n'
            ])
        return self._raw(urls, options=extra_args,
                         with_stats=with_stats,
                         with_headers=False,
                         with_profile=with_profile,
                         with_tcpdump=with_tcpdump)

    def ftp_ssl_upload(self, urls: List[str], fupload,
                       with_stats: bool = True,
                       with_profile: bool = False,
                       with_tcpdump: bool = False,
                       extra_args: List[str] = None):
        if extra_args is None:
            extra_args = []
        extra_args.extend([
            '--ssl-reqd',
        ])
        return self.ftp_upload(urls=urls, fupload=fupload,
                               with_stats=with_stats, with_profile=with_profile,
                               with_tcpdump=with_tcpdump,
                               extra_args=extra_args)

    def response_file(self, idx: int):
        return os.path.join(self._run_dir, f'download_{idx}.data')

    def run_direct(self, args, with_stats: bool = False, with_profile: bool = False):
        my_args = [self._curl]
        if with_stats:
            my_args.extend([
                '-w', '%{json}\\n'
            ])
        my_args.extend([
            '-o', 'download.data',
        ])
        my_args.extend(args)
        return self._run(args=my_args, with_stats=with_stats, with_profile=with_profile)

    def _run(self, args, intext='', with_stats: bool = False,
             with_profile: bool = True, with_tcpdump: bool = False):
        self._rmf(self._stdoutfile)
        self._rmf(self._stderrfile)
        self._rmf(self._headerfile)

        exception = None
        profile = None
        tcpdump = None
        started_at = datetime.now()
        if with_tcpdump:
            tcpdump = RunTcpDump(self.env, self._run_dir)
            tcpdump.start()
        try:
            with open(self._stdoutfile, 'w') as cout:
                with open(self._stderrfile, 'w') as cerr:
                    if with_profile:
                        end_at = started_at + timedelta(seconds=self._timeout) \
                            if self._timeout else None
                        log.info(f'starting: {args}')
                        p = subprocess.Popen(args, stderr=cerr, stdout=cout,
                                             cwd=self._run_dir, shell=False,
                                             env=self._run_env)
                        profile = RunProfile(p.pid, started_at, self._run_dir)
                        if intext is not None and False:
                            p.communicate(input=intext.encode(), timeout=1)
                        ptimeout = 0.0
                        while True:
                            try:
                                p.wait(timeout=ptimeout)
628
629
630
631
632
633
634
635

636
637
638
639
640
641
642
643


644
645
646
647
648
649
650
651
652
653
654
655
656
657
658

659
660
661
662
663
664
665
666
667
668
669
670
671
                        exitcode = p.returncode
                        profile.finish()
                        log.info(f'done: exit={exitcode}, profile={profile}')
                    else:
                        p = subprocess.run(args, stderr=cerr, stdout=cout,
                                           cwd=self._run_dir, shell=False,
                                           input=intext.encode() if intext else None,
                                           timeout=self._timeout)

                        exitcode = p.returncode
        except subprocess.TimeoutExpired:
            now = datetime.now()
            duration = now - started_at
            log.warning(f'Timeout at {now} after {duration.total_seconds()}s '
                        f'(configured {self._timeout}s): {args}')
            exitcode = -1
            exception = 'TimeoutExpired'


        coutput = open(self._stdoutfile).readlines()
        cerrput = open(self._stderrfile).readlines()
        return ExecResult(args=args, exit_code=exitcode, exception=exception,
                          stdout=coutput, stderr=cerrput,
                          duration=datetime.now() - started_at,
                          with_stats=with_stats,
                          profile=profile)

    def _raw(self, urls, intext='', timeout=None, options=None, insecure=False,
             alpn_proto: Optional[str] = None,
             force_resolve=True,
             with_stats=False,
             with_headers=True,
             def_tracing=True,
             with_profile=False):

        args = self._complete_args(
            urls=urls, timeout=timeout, options=options, insecure=insecure,
            alpn_proto=alpn_proto, force_resolve=force_resolve,
            with_headers=with_headers, def_tracing=def_tracing)
        r = self._run(args, intext=intext, with_stats=with_stats,
                      with_profile=with_profile)
        if r.exit_code == 0 and with_headers:
            self._parse_headerfile(self._headerfile, r=r)
            if r.json:
                r.response["json"] = r.json
        return r

    def _complete_args(self, urls, timeout=None, options=None,







|
>








>
>






|







|
>





|







771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
                        exitcode = p.returncode
                        profile.finish()
                        log.info(f'done: exit={exitcode}, profile={profile}')
                    else:
                        p = subprocess.run(args, stderr=cerr, stdout=cout,
                                           cwd=self._run_dir, shell=False,
                                           input=intext.encode() if intext else None,
                                           timeout=self._timeout,
                                           env=self._run_env)
                        exitcode = p.returncode
        except subprocess.TimeoutExpired:
            now = datetime.now()
            duration = now - started_at
            log.warning(f'Timeout at {now} after {duration.total_seconds()}s '
                        f'(configured {self._timeout}s): {args}')
            exitcode = -1
            exception = 'TimeoutExpired'
        if tcpdump:
            tcpdump.finish()
        coutput = open(self._stdoutfile).readlines()
        cerrput = open(self._stderrfile).readlines()
        return ExecResult(args=args, exit_code=exitcode, exception=exception,
                          stdout=coutput, stderr=cerrput,
                          duration=datetime.now() - started_at,
                          with_stats=with_stats,
                          profile=profile, tcpdump=tcpdump)

    def _raw(self, urls, intext='', timeout=None, options=None, insecure=False,
             alpn_proto: Optional[str] = None,
             force_resolve=True,
             with_stats=False,
             with_headers=True,
             def_tracing=True,
             with_profile=False,
             with_tcpdump=False):
        args = self._complete_args(
            urls=urls, timeout=timeout, options=options, insecure=insecure,
            alpn_proto=alpn_proto, force_resolve=force_resolve,
            with_headers=with_headers, def_tracing=def_tracing)
        r = self._run(args, intext=intext, with_stats=with_stats,
                      with_profile=with_profile, with_tcpdump=with_tcpdump)
        if r.exit_code == 0 and with_headers:
            self._parse_headerfile(self._headerfile, r=r)
            if r.json:
                r.response["json"] = r.json
        return r

    def _complete_args(self, urls, timeout=None, options=None,
Changes to jni/curl/tests/http/testenv/env.py.
23
24
25
26
27
28
29

30
31
32
33
34
35
36
# SPDX-License-Identifier: curl
#
###########################################################################
#
import logging
import os
import re

import socket
import subprocess
import sys
from configparser import ConfigParser, ExtendedInterpolation
from datetime import timedelta
from typing import Optional








>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# SPDX-License-Identifier: curl
#
###########################################################################
#
import logging
import os
import re
import shutil
import socket
import subprocess
import sys
from configparser import ConfigParser, ExtendedInterpolation
from datetime import timedelta
from typing import Optional

199
200
201
202
203
204
205


206
207
208
209
210
211
212
                    # vsftp does not use stdout or stderr for printing its version... -.-
                    self._vsftpd_version = 'unknown'
                else:
                    raise Exception(f'Unable to determine VsFTPD version from: {p.stderr}')
            except Exception as e:
                self.vsftpd = None



    @property
    def httpd_version(self):
        if self._httpd_version is None and self.apxs is not None:
            try:
                p = subprocess.run(args=[self.apxs, '-q', 'HTTPD_VERSION'],
                                   capture_output=True, text=True)
                if p.returncode != 0:







>
>







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
                    # vsftp does not use stdout or stderr for printing its version... -.-
                    self._vsftpd_version = 'unknown'
                else:
                    raise Exception(f'Unable to determine VsFTPD version from: {p.stderr}')
            except Exception as e:
                self.vsftpd = None

        self._tcpdump = shutil.which('tcpdump')

    @property
    def httpd_version(self):
        if self._httpd_version is None and self.apxs is not None:
            try:
                p = subprocess.run(args=[self.apxs, '-q', 'HTTPD_VERSION'],
                                   capture_output=True, text=True)
                if p.returncode != 0:
260
261
262
263
264
265
266




267
268
269
270
271
272
273
    def caddy_version(self):
        return self._caddy_version

    @property
    def vsftpd_version(self):
        return self._vsftpd_version






class Env:

    CONFIG = EnvConfig()

    @staticmethod
    def setup_incomplete() -> bool:







>
>
>
>







263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
    def caddy_version(self):
        return self._caddy_version

    @property
    def vsftpd_version(self):
        return self._vsftpd_version

    @property
    def tcpdmp(self) -> Optional[str]:
        return self._tcpdump


class Env:

    CONFIG = EnvConfig()

    @staticmethod
    def setup_incomplete() -> bool:
379
380
381
382
383
384
385




386
387
388
389
390
391
392
    def has_vsftpd() -> bool:
        return Env.CONFIG.vsftpd is not None

    @staticmethod
    def vsftpd_version() -> str:
        return Env.CONFIG.vsftpd_version





    def __init__(self, pytestconfig=None):
        self._verbose = pytestconfig.option.verbose \
            if pytestconfig is not None else 0
        self._ca = None
        self._test_timeout = 300.0 if self._verbose > 1 else 60.0  # seconds

    def issue_certs(self):







>
>
>
>







386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
    def has_vsftpd() -> bool:
        return Env.CONFIG.vsftpd is not None

    @staticmethod
    def vsftpd_version() -> str:
        return Env.CONFIG.vsftpd_version

    @staticmethod
    def tcpdump() -> Optional[str]:
        return Env.CONFIG.tcpdmp

    def __init__(self, pytestconfig=None):
        self._verbose = pytestconfig.option.verbose \
            if pytestconfig is not None else 0
        self._ca = None
        self._test_timeout = 300.0 if self._verbose > 1 else 60.0  # seconds

    def issue_certs(self):
Changes to jni/curl/tests/http/testenv/httpd.py.

1
2
3
4
5
6
7

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
>







1
2
3
4
5
6
7
8
#!/usr/bin/env python3
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
242
243
244
245
246
247
248

249
250
251
252
253
254
255
256
257







258
259
260
261
262
263
264
            conf = [   # base server config
                f'ServerRoot "{self._apache_dir}"',
                f'DefaultRuntimeDir logs',
                f'PidFile httpd.pid',
                f'ErrorLog {self._error_log}',
                f'LogLevel {self._get_log_level()}',
                f'StartServers 4',

                f'H2MinWorkers 16',
                f'H2MaxWorkers 256',
                f'H2Direct on',
                f'Listen {self.env.http_port}',
                f'Listen {self.env.https_port}',
                f'Listen {self.env.proxy_port}',
                f'Listen {self.env.proxys_port}',
                f'TypesConfig "{self._conf_dir}/mime.types',
                f'SSLSessionCache "shmcb:ssl_gcache_data(32000)"',







            ]
            if 'base' in self._extra_configs:
                conf.extend(self._extra_configs['base'])
            conf.extend([  # plain http host for domain1
                f'<VirtualHost *:{self.env.http_port}>',
                f'    ServerName {domain1}',
                f'    ServerAlias localhost',







>









>
>
>
>
>
>
>







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
            conf = [   # base server config
                f'ServerRoot "{self._apache_dir}"',
                f'DefaultRuntimeDir logs',
                f'PidFile httpd.pid',
                f'ErrorLog {self._error_log}',
                f'LogLevel {self._get_log_level()}',
                f'StartServers 4',
                f'ReadBufferSize 16000',
                f'H2MinWorkers 16',
                f'H2MaxWorkers 256',
                f'H2Direct on',
                f'Listen {self.env.http_port}',
                f'Listen {self.env.https_port}',
                f'Listen {self.env.proxy_port}',
                f'Listen {self.env.proxys_port}',
                f'TypesConfig "{self._conf_dir}/mime.types',
                f'SSLSessionCache "shmcb:ssl_gcache_data(32000)"',
                (f'SSLCipherSuite SSL'
                 f' ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'
                 f':ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305'
                ),
                (f'SSLCipherSuite TLSv1.3'
                 f' TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256'
                ),
            ]
            if 'base' in self._extra_configs:
                conf.extend(self._extra_configs['base'])
            conf.extend([  # plain http host for domain1
                f'<VirtualHost *:{self.env.http_port}>',
                f'    ServerName {domain1}',
                f'    ServerAlias localhost',
300
301
302
303
304
305
306












307
308
309
310
311
312
313
            ])
            conf.extend(self._curltest_conf(domain1))
            if domain1 in self._extra_configs:
                conf.extend(self._extra_configs[domain1])
            conf.extend([
                f'</VirtualHost>',
                f'',












            ])
            conf.extend([  # https host for domain2, no h2
                f'<VirtualHost *:{self.env.https_port}>',
                f'    ServerName {domain2}',
                f'    Protocols http/1.1',
                f'    SSLEngine on',
                f'    SSLCertificateFile {creds2.cert_file}',







>
>
>
>
>
>
>
>
>
>
>
>







309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
            ])
            conf.extend(self._curltest_conf(domain1))
            if domain1 in self._extra_configs:
                conf.extend(self._extra_configs[domain1])
            conf.extend([
                f'</VirtualHost>',
                f'',
            ])
            conf.extend([  # plain http host for domain2
                f'<VirtualHost *:{self.env.http_port}>',
                f'    ServerName {domain2}',
                f'    ServerAlias localhost',
                f'    DocumentRoot "{self._docs_dir}"',
                f'    Protocols h2c http/1.1',
            ])
            conf.extend(self._curltest_conf(domain2))
            conf.extend([
                f'</VirtualHost>',
                f'',
            ])
            conf.extend([  # https host for domain2, no h2
                f'<VirtualHost *:{self.env.https_port}>',
                f'    ServerName {domain2}',
                f'    Protocols http/1.1',
                f'    SSLEngine on',
                f'    SSLCertificateFile {creds2.cert_file}',
Changes to jni/curl/tests/http/testenv/mod_curltest/mod_curltest.c.
182
183
184
185
186
187
188

189
190
191
192
193
194
195
  conn_rec *c = r->connection;
  apr_bucket_brigade *bb;
  apr_bucket *b;
  apr_status_t rv;
  char buffer[8192];
  const char *ct;
  apr_off_t die_after_len = -1, total_read_len = 0;

  long l;

  if(strcmp(r->handler, "curltest-echo")) {
    return DECLINED;
  }
  if(r->method_number != M_GET && r->method_number != M_POST) {
    return DECLINED;







>







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  conn_rec *c = r->connection;
  apr_bucket_brigade *bb;
  apr_bucket *b;
  apr_status_t rv;
  char buffer[8192];
  const char *ct;
  apr_off_t die_after_len = -1, total_read_len = 0;
  int just_die = 0, die_after_100 = 0;
  long l;

  if(strcmp(r->handler, "curltest-echo")) {
    return DECLINED;
  }
  if(r->method_number != M_GET && r->method_number != M_POST) {
    return DECLINED;
204
205
206
207
208
209
210









211
212
213
214









215
216
217
218
219
220

221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237








238
239
240
241
242
243
244


245
246
247
248
249
250
251
      char *s, *val, *arg = APR_ARRAY_IDX(args, i, char*);
      s = strchr(arg, '=');
      if(s) {
        *s = '\0';
        val = s + 1;
        if(!strcmp("die_after", arg)) {
          die_after_len = (apr_off_t)apr_atoi64(val);









        }
      }
    }
  }










  r->status = 200;
  if(die_after_len >= 0) {
    r->clength = die_after_len + 1;
    r->chunked = 0;
    apr_table_set(r->headers_out, "Content-Length", apr_ltoa(r->pool, (long)r->clength));

  }
  else {
    r->clength = -1;
    r->chunked = 1;
    apr_table_unset(r->headers_out, "Content-Length");
  }
  /* Discourage content-encodings */
  apr_table_unset(r->headers_out, "Content-Encoding");
  apr_table_setn(r->subprocess_env, "no-brotli", "1");
  apr_table_setn(r->subprocess_env, "no-gzip", "1");

  ct = apr_table_get(r->headers_in, "content-type");
  ap_set_content_type(r, ct? ct : "application/octet-stream");

  bb = apr_brigade_create(r->pool, c->bucket_alloc);
  /* copy any request body into the response */
  if((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) goto cleanup;








  if(ap_should_client_block(r)) {
    while(0 < (l = ap_get_client_block(r, &buffer[0], sizeof(buffer)))) {
      total_read_len += l;
      if(die_after_len >= 0 && total_read_len >= die_after_len) {
        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
                      "echo_handler: dying after %ld bytes as requested",
                      (long)total_read_len);


        r->connection->keepalive = AP_CONN_CLOSE;
        return DONE;
      }
      ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
                    "echo_handler: copying %ld bytes from request body", l);
      rv = apr_brigade_write(bb, NULL, NULL, buffer, l);
      if (APR_SUCCESS != rv) goto cleanup;







>
>
>
>
>
>
>
>
>




>
>
>
>
>
>
>
>
>





|
>

















>
>
>
>
>
>
>
>







>
>







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
      char *s, *val, *arg = APR_ARRAY_IDX(args, i, char*);
      s = strchr(arg, '=');
      if(s) {
        *s = '\0';
        val = s + 1;
        if(!strcmp("die_after", arg)) {
          die_after_len = (apr_off_t)apr_atoi64(val);
          continue;
        }
        else if(!strcmp("just_die", arg)) {
          just_die = 1;
          continue;
        }
        else if(!strcmp("die_after_100", arg)) {
          die_after_100 = 1;
          continue;
        }
      }
    }
  }

  if(just_die) {
    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
                  "echo_handler: dying right away");
    /* Generate no HTTP response at all. */
    ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
    r->connection->keepalive = AP_CONN_CLOSE;
    return AP_FILTER_ERROR;
  }

  r->status = 200;
  if(die_after_len >= 0) {
    r->clength = die_after_len + 1;
    r->chunked = 0;
    apr_table_set(r->headers_out, "Content-Length",
                  apr_ltoa(r->pool, (long)r->clength));
  }
  else {
    r->clength = -1;
    r->chunked = 1;
    apr_table_unset(r->headers_out, "Content-Length");
  }
  /* Discourage content-encodings */
  apr_table_unset(r->headers_out, "Content-Encoding");
  apr_table_setn(r->subprocess_env, "no-brotli", "1");
  apr_table_setn(r->subprocess_env, "no-gzip", "1");

  ct = apr_table_get(r->headers_in, "content-type");
  ap_set_content_type(r, ct? ct : "application/octet-stream");

  bb = apr_brigade_create(r->pool, c->bucket_alloc);
  /* copy any request body into the response */
  if((rv = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK))) goto cleanup;
  if(die_after_100) {
    ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
                  "echo_handler: dying after 100-continue");
    /* Generate no HTTP response at all. */
    ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
    r->connection->keepalive = AP_CONN_CLOSE;
    return AP_FILTER_ERROR;
  }
  if(ap_should_client_block(r)) {
    while(0 < (l = ap_get_client_block(r, &buffer[0], sizeof(buffer)))) {
      total_read_len += l;
      if(die_after_len >= 0 && total_read_len >= die_after_len) {
        ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
                      "echo_handler: dying after %ld bytes as requested",
                      (long)total_read_len);
        ap_pass_brigade(r->output_filters, bb);
        ap_remove_output_filter_byhandle(r->output_filters, "HTTP_HEADER");
        r->connection->keepalive = AP_CONN_CLOSE;
        return DONE;
      }
      ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
                    "echo_handler: copying %ld bytes from request body", l);
      rv = apr_brigade_write(bb, NULL, NULL, buffer, l);
      if (APR_SUCCESS != rv) goto cleanup;
290
291
292
293
294
295
296
297
298
299
300

301
302
303
304
305
306
307
  apr_bucket_brigade *bb;
  apr_bucket *b;
  apr_status_t rv;
  char buffer[16*1024];
  int i, chunks = 3, error_bucket = 1;
  size_t chunk_size = sizeof(buffer);
  const char *request_id = "none";
  apr_time_t delay = 0, chunk_delay = 0;
  apr_array_header_t *args = NULL;
  int http_status = 200;
  apr_status_t error = APR_SUCCESS, body_error = APR_SUCCESS;


  if(strcmp(r->handler, "curltest-tweak")) {
    return DECLINED;
  }
  if(r->method_number == M_DELETE) {
    http_status = 204;
    chunks = 0;







|



>







320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  apr_bucket_brigade *bb;
  apr_bucket *b;
  apr_status_t rv;
  char buffer[16*1024];
  int i, chunks = 3, error_bucket = 1;
  size_t chunk_size = sizeof(buffer);
  const char *request_id = "none";
  apr_time_t delay = 0, chunk_delay = 0, close_delay = 0;
  apr_array_header_t *args = NULL;
  int http_status = 200;
  apr_status_t error = APR_SUCCESS, body_error = APR_SUCCESS;
  int close_conn = 0, with_cl = 0;

  if(strcmp(r->handler, "curltest-tweak")) {
    return DECLINED;
  }
  if(r->method_number == M_DELETE) {
    http_status = 204;
    chunks = 0;
371
372
373
374
375
376
377















378
379
380
381
382
383
384
385
386
387
388
389
390
391
392





393
394
395
396
397
398
399
400
        }
        else if(!strcmp("chunk_delay", arg)) {
          rv = duration_parse(&chunk_delay, val, "s");
          if(APR_SUCCESS == rv) {
            continue;
          }
        }















      }
      ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "query parameter not "
                    "understood: '%s' in %s",
                    arg, r->args);
      ap_die(HTTP_BAD_REQUEST, r);
      return OK;
    }
  }

  ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "error_handler: processing "
                "request, %s", r->args? r->args : "(no args)");
  r->status = http_status;
  r->clength = -1;
  r->chunked = (r->proto_num >= HTTP_VERSION(1,1));
  apr_table_setn(r->headers_out, "request-id", request_id);





  apr_table_unset(r->headers_out, "Content-Length");
  /* Discourage content-encodings */
  apr_table_unset(r->headers_out, "Content-Encoding");
  apr_table_setn(r->subprocess_env, "no-brotli", "1");
  apr_table_setn(r->subprocess_env, "no-gzip", "1");

  ap_set_content_type(r, "application/octet-stream");
  bb = apr_brigade_create(r->pool, c->bucket_alloc);







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>












|
|

>
>
>
>
>
|







402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
        }
        else if(!strcmp("chunk_delay", arg)) {
          rv = duration_parse(&chunk_delay, val, "s");
          if(APR_SUCCESS == rv) {
            continue;
          }
        }
        else if(!strcmp("close_delay", arg)) {
          rv = duration_parse(&close_delay, val, "s");
          if(APR_SUCCESS == rv) {
            continue;
          }
        }
      }
      else if(!strcmp("close", arg)) {
        /* we are asked to close the connection */
        close_conn = 1;
        continue;
      }
      else if(!strcmp("with_cl", arg)) {
        with_cl = 1;
        continue;
      }
      ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "query parameter not "
                    "understood: '%s' in %s",
                    arg, r->args);
      ap_die(HTTP_BAD_REQUEST, r);
      return OK;
    }
  }

  ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "error_handler: processing "
                "request, %s", r->args? r->args : "(no args)");
  r->status = http_status;
  r->clength = with_cl? (chunks * chunk_size) : -1;
  r->chunked = (r->proto_num >= HTTP_VERSION(1,1)) && !with_cl;
  apr_table_setn(r->headers_out, "request-id", request_id);
  if(r->clength >= 0) {
    apr_table_set(r->headers_out, "Content-Length",
                  apr_ltoa(r->pool, (long)r->clength));
  }
  else
    apr_table_unset(r->headers_out, "Content-Length");
  /* Discourage content-encodings */
  apr_table_unset(r->headers_out, "Content-Encoding");
  apr_table_setn(r->subprocess_env, "no-brotli", "1");
  apr_table_setn(r->subprocess_env, "no-gzip", "1");

  ap_set_content_type(r, "application/octet-stream");
  bb = apr_brigade_create(r->pool, c->bucket_alloc);
433
434
435
436
437
438
439










440
441
442
443
444
445
446
447
448
449
  APR_BRIGADE_INSERT_TAIL(bb, b);
  rv = ap_pass_brigade(r->output_filters, bb);
  apr_brigade_cleanup(bb);
  ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
                "error_handler: response passed");

cleanup:










  ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
                "error_handler: request cleanup, r->status=%d, aborted=%d",
                r->status, c->aborted);
  if(rv == APR_SUCCESS) {
    return OK;
  }
  if(error_bucket) {
    http_status = ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
    b = ap_bucket_error_create(http_status, NULL, r->pool, c->bucket_alloc);
    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,







>
>
>
>
>
>
>
>
>
>

|
|







484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  APR_BRIGADE_INSERT_TAIL(bb, b);
  rv = ap_pass_brigade(r->output_filters, bb);
  apr_brigade_cleanup(bb);
  ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
                "error_handler: response passed");

cleanup:
  if(close_conn) {
    if(close_delay) {
      b = apr_bucket_flush_create(c->bucket_alloc);
      APR_BRIGADE_INSERT_TAIL(bb, b);
      rv = ap_pass_brigade(r->output_filters, bb);
      apr_brigade_cleanup(bb);
      apr_sleep(close_delay);
    }
    r->connection->keepalive = AP_CONN_CLOSE;
  }
  ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
                "error_handler: request cleanup, r->status=%d, aborted=%d, "
                "close=%d", r->status, c->aborted, close_conn);
  if(rv == APR_SUCCESS) {
    return OK;
  }
  if(error_bucket) {
    http_status = ap_map_http_request_error(rv, HTTP_BAD_REQUEST);
    b = ap_bucket_error_create(http_status, NULL, r->pool, c->bucket_alloc);
    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r,
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471

static int curltest_put_handler(request_rec *r)
{
  conn_rec *c = r->connection;
  apr_bucket_brigade *bb;
  apr_bucket *b;
  apr_status_t rv;
  char buffer[16*1024];
  const char *ct;
  apr_off_t rbody_len = 0;
  const char *s_rbody_len;
  const char *request_id = "none";
  apr_time_t read_delay = 0, chunk_delay = 0;
  apr_array_header_t *args = NULL;
  long l;







|







518
519
520
521
522
523
524
525
526
527
528
529
530
531
532

static int curltest_put_handler(request_rec *r)
{
  conn_rec *c = r->connection;
  apr_bucket_brigade *bb;
  apr_bucket *b;
  apr_status_t rv;
  char buffer[128*1024];
  const char *ct;
  apr_off_t rbody_len = 0;
  const char *s_rbody_len;
  const char *request_id = "none";
  apr_time_t read_delay = 0, chunk_delay = 0;
  apr_array_header_t *args = NULL;
  long l;
Added jni/curl/tests/http/testenv/vsftpd.py.












































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
#                             \___|\___/|_| \_\_____|
#
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
import inspect
import logging
import os
import subprocess
from datetime import timedelta, datetime
from json import JSONEncoder
import time
from typing import List, Union, Optional

from .curl import CurlClient, ExecResult
from .env import Env


log = logging.getLogger(__name__)


class VsFTPD:

    def __init__(self, env: Env, with_ssl=False):
        self.env = env
        self._cmd = env.vsftpd
        self._scheme = 'ftp'
        self._with_ssl = with_ssl
        if self._with_ssl:
            self._port = self.env.ftps_port
            name = 'vsftpds'
        else:
            self._port = self.env.ftp_port
            name = 'vsftpd'
        self._vsftpd_dir = os.path.join(env.gen_dir, name)
        self._run_dir = os.path.join(self._vsftpd_dir, 'run')
        self._docs_dir = os.path.join(self._vsftpd_dir, 'docs')
        self._tmp_dir = os.path.join(self._vsftpd_dir, 'tmp')
        self._conf_file = os.path.join(self._vsftpd_dir, 'test.conf')
        self._pid_file = os.path.join(self._vsftpd_dir, 'vsftpd.pid')
        self._error_log = os.path.join(self._vsftpd_dir, 'vsftpd.log')
        self._process = None

        self.clear_logs()

    @property
    def domain(self):
        return self.env.ftp_domain

    @property
    def docs_dir(self):
        return self._docs_dir

    @property
    def port(self) -> str:
        return self._port

    def clear_logs(self):
        self._rmf(self._error_log)

    def exists(self):
        return os.path.exists(self._cmd)

    def is_running(self):
        if self._process:
            self._process.poll()
            return self._process.returncode is None
        return False

    def start_if_needed(self):
        if not self.is_running():
            return self.start()
        return True

    def start(self, wait_live=True):
        pass

    def stop_if_running(self):
        if self.is_running():
            return self.stop()
        return True

    def stop(self, wait_dead=True):
        self._mkpath(self._tmp_dir)
        if self._process:
            self._process.terminate()
            self._process.wait(timeout=2)
            self._process = None
            return not wait_dead or self.wait_dead(timeout=timedelta(seconds=5))
        return True

    def restart(self):
        self.stop()
        return self.start()

    def start(self, wait_live=True):
        self._mkpath(self._tmp_dir)
        if self._process:
            self.stop()
        self._write_config()
        args = [
            self._cmd,
            f'{self._conf_file}',
        ]
        procerr = open(self._error_log, 'a')
        self._process = subprocess.Popen(args=args, stderr=procerr)
        if self._process.returncode is not None:
            return False
        return not wait_live or self.wait_live(timeout=timedelta(seconds=5))

    def wait_dead(self, timeout: timedelta):
        curl = CurlClient(env=self.env, run_dir=self._tmp_dir)
        try_until = datetime.now() + timeout
        while datetime.now() < try_until:
            check_url = f'{self._scheme}://{self.domain}:{self.port}/'
            r = curl.ftp_get(urls=[check_url], extra_args=['-v'])
            if r.exit_code != 0:
                return True
            log.debug(f'waiting for vsftpd to stop responding: {r}')
            time.sleep(.1)
        log.debug(f"Server still responding after {timeout}")
        return False

    def wait_live(self, timeout: timedelta):
        curl = CurlClient(env=self.env, run_dir=self._tmp_dir)
        try_until = datetime.now() + timeout
        while datetime.now() < try_until:
            check_url = f'{self._scheme}://{self.domain}:{self.port}/'
            r = curl.ftp_get(urls=[check_url], extra_args=[
                '--trace', 'curl-start.trace', '--trace-time'
            ])
            if r.exit_code == 0:
                return True
            log.debug(f'waiting for vsftpd to become responsive: {r}')
            time.sleep(.1)
        log.error(f"Server still not responding after {timeout}")
        return False

    def _run(self, args, intext=''):
        env = {}
        for key, val in os.environ.items():
            env[key] = val
        with open(self._error_log, 'w') as cerr:
            self._process = subprocess.run(args, stderr=cerr, stdout=cerr,
                                           cwd=self._vsftpd_dir,
                                           input=intext.encode() if intext else None,
                                           env=env)
            start = datetime.now()
            return ExecResult(args=args, exit_code=self._process.returncode,
                              duration=datetime.now() - start)

    def _rmf(self, path):
        if os.path.exists(path):
            return os.remove(path)

    def _mkpath(self, path):
        if not os.path.exists(path):
            return os.makedirs(path)

    def _write_config(self):
        self._mkpath(self._docs_dir)
        self._mkpath(self._tmp_dir)
        conf = [  # base server config
            f'listen=YES',
            f'run_as_launching_user=YES',
            f'#listen_address=127.0.0.1',
            f'listen_port={self.port}',
            f'local_enable=NO',
            f'anonymous_enable=YES',
            f'anon_root={self._docs_dir}',
            f'dirmessage_enable=YES',
            f'write_enable=YES',
            f'anon_upload_enable=YES',
            f'log_ftp_protocol=YES',
            f'xferlog_enable=YES',
            f'xferlog_std_format=NO',
            f'vsftpd_log_file={self._error_log}',
            f'\n',
        ]
        if self._with_ssl:
            creds = self.env.get_credentials(self.domain)
            conf.extend([
                f'ssl_enable=YES',
                f'debug_ssl=YES',
                f'allow_anon_ssl=YES',
                f'rsa_cert_file={creds.cert_file}',
                f'rsa_private_key_file={creds.pkey_file}',
                # require_ssl_reuse=YES means ctrl and data connection need to use the same session
                f'require_ssl_reuse=NO',
            ])

        with open(self._conf_file, 'w') as fd:
            fd.write("\n".join(conf))
Changes to jni/curl/tests/http2-server.pl.
112
113
114
115
116
117
118
119
    "--frontend=\"*,$listenport2\" ".
    "--log-level=INFO ".
    "--pid-file=$pidfile ".
    "--conf=$conf ".
    "--errorlog-file=$logfile ".
    "$keyfile $certfile";
print "RUN: $cmdline\n" if($verbose);
system("$cmdline 2>/dev/null");







|
112
113
114
115
116
117
118
119
    "--frontend=\"*,$listenport2\" ".
    "--log-level=INFO ".
    "--pid-file=$pidfile ".
    "--conf=$conf ".
    "--errorlog-file=$logfile ".
    "$keyfile $certfile";
print "RUN: $cmdline\n" if($verbose);
exec("exec $cmdline 2>/dev/null");
Changes to jni/curl/tests/http3-server.pl.
112
113
114
115
116
117
118
119
    "--frontend=\"*,$listenport;quic\" ".
    "--log-level=INFO ".
    "--pid-file=$pidfile ".
    "--errorlog-file=$logfile ".
    "--conf=$conf ".
    "$keyfile $certfile";
print "RUN: $cmdline\n" if($verbose);
system("$cmdline 2>/dev/null");







|
112
113
114
115
116
117
118
119
    "--frontend=\"*,$listenport;quic\" ".
    "--log-level=INFO ".
    "--pid-file=$pidfile ".
    "--errorlog-file=$logfile ".
    "--conf=$conf ".
    "$keyfile $certfile";
print "RUN: $cmdline\n" if($verbose);
exec("exec $cmdline 2>/dev/null");
Changes to jni/curl/tests/libtest/CMakeLists.txt.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
set(TARGET_LABEL_PREFIX "Test ")

function(setup_test TEST_NAME)          # ARGN are the files in the test

  if(LIB_SELECTED STREQUAL LIB_STATIC)
    # These are part of the libcurl static lib. Do not compile/link them again.
    list(REMOVE_ITEM ARGN ${WARNLESS} ${MULTIBYTE} ${TIMEDIFF})
  endif()

  add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${ARGN})
  add_dependencies(testdeps ${TEST_NAME})
  string(TOUPPER ${TEST_NAME} UPPER_TEST_NAME)

  include_directories(
    ${CURL_SOURCE_DIR}/lib          # To be able to reach "curl_setup_once.h"
    ${CURL_BINARY_DIR}/lib          # To be able to reach "curl_config.h"
    ${CURL_BINARY_DIR}/include      # To be able to reach "curl/curl.h"
    ${CURL_SOURCE_DIR}/tests/libtest # To be able to build generated tests
    )
  if(USE_ARES)
    include_directories(${CARES_INCLUDE_DIR})
  endif()

  target_link_libraries(${TEST_NAME} ${LIB_SELECTED} ${CURL_LIBS})








|











|
|
|
|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
set(TARGET_LABEL_PREFIX "Test ")

function(setup_test TEST_NAME)  # ARGN are the files in the test

  if(LIB_SELECTED STREQUAL LIB_STATIC)
    # These are part of the libcurl static lib. Do not compile/link them again.
    list(REMOVE_ITEM ARGN ${WARNLESS} ${MULTIBYTE} ${TIMEDIFF})
  endif()

  add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${ARGN})
  add_dependencies(testdeps ${TEST_NAME})
  string(TOUPPER ${TEST_NAME} UPPER_TEST_NAME)

  include_directories(
    ${CURL_SOURCE_DIR}/lib            # for "curl_setup_once.h"
    ${CURL_BINARY_DIR}/lib            # for "curl_config.h"
    ${CURL_BINARY_DIR}/include        # for "curl/curl.h"
    ${CURL_SOURCE_DIR}/tests/libtest  # to be able to build generated tests
    )
  if(USE_ARES)
    include_directories(${CARES_INCLUDE_DIR})
  endif()

  target_link_libraries(${TEST_NAME} ${LIB_SELECTED} ${CURL_LIBS})

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# TODO this cmake build assumes a shared build, detect static linking here!
if(NOT WIN32)
  add_library(hostname MODULE EXCLUDE_FROM_ALL sethostname.c)
  add_dependencies(testdeps hostname)
  # Output to .libs for compatibility with autotools, the test data expects a
  # library at (tests)/libtest/.libs/libhostname.so
  set_target_properties(hostname PROPERTIES
      LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.libs)
  if(HIDES_CURL_PRIVATE_SYMBOLS)
    set_property(TARGET hostname APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
    set_property(TARGET hostname APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE})
  endif()
endif()

add_custom_command(
  OUTPUT lib1521.c
  COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/mk-lib1521.pl < ${CURL_SOURCE_DIR}/include/curl/curl.h > lib1521.c
  DEPENDS
    "${CMAKE_CURRENT_SOURCE_DIR}/mk-lib1521.pl"
    "${CURL_SOURCE_DIR}/include/curl/curl.h"
  VERBATIM)







|













68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# TODO this cmake build assumes a shared build, detect static linking here!
if(NOT WIN32)
  add_library(hostname MODULE EXCLUDE_FROM_ALL sethostname.c)
  add_dependencies(testdeps hostname)
  # Output to .libs for compatibility with autotools, the test data expects a
  # library at (tests)/libtest/.libs/libhostname.so
  set_target_properties(hostname PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.libs)
  if(HIDES_CURL_PRIVATE_SYMBOLS)
    set_property(TARGET hostname APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
    set_property(TARGET hostname APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE})
  endif()
endif()

add_custom_command(
  OUTPUT lib1521.c
  COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/mk-lib1521.pl < ${CURL_SOURCE_DIR}/include/curl/curl.h > lib1521.c
  DEPENDS
    "${CMAKE_CURRENT_SOURCE_DIR}/mk-lib1521.pl"
    "${CURL_SOURCE_DIR}/include/curl/curl.h"
  VERBATIM)
Changes to jni/curl/tests/libtest/Makefile.am.
130
131
132
133
134
135
136
137
138
139
140
CS_0 = @echo "  RUN     " $@;
CS_1 =
CS_ = $(CS_0)

checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(srcdir)/*.[ch]

if CURLDEBUG
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif







|



130
131
132
133
134
135
136
137
138
139
140
CS_0 = @echo "  RUN     " $@;
CS_1 =
CS_ = $(CS_0)

checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(srcdir)/*.[ch]

if DEBUGBUILD
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif
Changes to jni/curl/tests/libtest/Makefile.in.
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169

170
171
172
173
174
175
176
	lib650$(EXEEXT) lib651$(EXEEXT) lib652$(EXEEXT) \
	lib653$(EXEEXT) lib654$(EXEEXT) lib655$(EXEEXT) \
	lib658$(EXEEXT) lib659$(EXEEXT) lib661$(EXEEXT) \
	lib666$(EXEEXT) lib667$(EXEEXT) lib668$(EXEEXT) \
	lib670$(EXEEXT) lib671$(EXEEXT) lib672$(EXEEXT) \
	lib673$(EXEEXT) lib674$(EXEEXT) lib676$(EXEEXT) \
	lib677$(EXEEXT) lib678$(EXEEXT) lib1156$(EXEEXT) \
	lib1301$(EXEEXT) lib1500$(EXEEXT) lib1501$(EXEEXT) \
	lib1502$(EXEEXT) lib1503$(EXEEXT) lib1504$(EXEEXT) \
	lib1505$(EXEEXT) lib1506$(EXEEXT) lib1507$(EXEEXT) \
	lib1508$(EXEEXT) lib1509$(EXEEXT) lib1510$(EXEEXT) \
	lib1511$(EXEEXT) lib1512$(EXEEXT) lib1513$(EXEEXT) \
	lib1514$(EXEEXT) lib1515$(EXEEXT) lib1517$(EXEEXT) \
	lib1518$(EXEEXT) lib1520$(EXEEXT) lib1521$(EXEEXT) \
	lib1522$(EXEEXT) lib1523$(EXEEXT) lib1525$(EXEEXT) \
	lib1526$(EXEEXT) lib1527$(EXEEXT) lib1528$(EXEEXT) \
	lib1529$(EXEEXT) lib1530$(EXEEXT) lib1531$(EXEEXT) \
	lib1532$(EXEEXT) lib1533$(EXEEXT) lib1534$(EXEEXT) \
	lib1535$(EXEEXT) lib1536$(EXEEXT) lib1537$(EXEEXT) \
	lib1538$(EXEEXT) lib1539$(EXEEXT) lib1540$(EXEEXT) \
	lib1541$(EXEEXT) lib1542$(EXEEXT) lib1543$(EXEEXT) \
	lib1545$(EXEEXT) lib1550$(EXEEXT) lib1551$(EXEEXT) \
	lib1552$(EXEEXT) lib1553$(EXEEXT) lib1554$(EXEEXT) \
	lib1555$(EXEEXT) lib1556$(EXEEXT) lib1557$(EXEEXT) \
	lib1558$(EXEEXT) lib1559$(EXEEXT) lib1560$(EXEEXT) \
	lib1564$(EXEEXT) lib1565$(EXEEXT) lib1567$(EXEEXT) \
	lib1568$(EXEEXT) lib1569$(EXEEXT) lib1591$(EXEEXT) \
	lib1592$(EXEEXT) lib1593$(EXEEXT) lib1594$(EXEEXT) \
	lib1596$(EXEEXT) lib1597$(EXEEXT) lib1598$(EXEEXT) \
	lib1662$(EXEEXT) lib1900$(EXEEXT) lib1901$(EXEEXT) \
	lib1903$(EXEEXT) lib1905$(EXEEXT) lib1906$(EXEEXT) \
	lib1907$(EXEEXT) lib1908$(EXEEXT) lib1910$(EXEEXT) \
	lib1911$(EXEEXT) lib1912$(EXEEXT) lib1913$(EXEEXT) \
	lib1915$(EXEEXT) lib1916$(EXEEXT) lib1917$(EXEEXT) \
	lib1918$(EXEEXT) lib1919$(EXEEXT) lib1933$(EXEEXT) \
	lib1934$(EXEEXT) lib1935$(EXEEXT) lib1936$(EXEEXT) \
	lib1937$(EXEEXT) lib1938$(EXEEXT) lib1939$(EXEEXT) \
	lib1940$(EXEEXT) lib1945$(EXEEXT) lib1946$(EXEEXT) \
	lib1947$(EXEEXT) lib1948$(EXEEXT) lib1955$(EXEEXT) \
	lib1956$(EXEEXT) lib1957$(EXEEXT) lib1958$(EXEEXT) \
	lib1959$(EXEEXT) lib1960$(EXEEXT) lib1964$(EXEEXT) \
	lib1970$(EXEEXT) lib1971$(EXEEXT) lib1972$(EXEEXT) \
	lib1973$(EXEEXT) lib1974$(EXEEXT) lib1975$(EXEEXT) \
	lib2301$(EXEEXT) lib2302$(EXEEXT) lib2304$(EXEEXT) \
	lib2305$(EXEEXT) lib2306$(EXEEXT) lib2308$(EXEEXT) \
	lib2402$(EXEEXT) lib2404$(EXEEXT) lib2405$(EXEEXT) \
	lib2502$(EXEEXT) lib3010$(EXEEXT) lib3025$(EXEEXT) \
	lib3026$(EXEEXT) lib3027$(EXEEXT) lib3100$(EXEEXT) \
	lib3101$(EXEEXT) lib3102$(EXEEXT) lib3103$(EXEEXT)

@USE_CPPFLAG_CURL_STATICLIB_TRUE@am__append_1 = -DCURL_STATICLIB
@CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_2 = -no-undefined
@CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_3 = -no-undefined
@CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE@am__append_4 = -mimpure-text
@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_5 = -DCURL_HIDDEN_SYMBOLS
@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_6 = $(CFLAG_CURL_SYMBOL_HIDING)








|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
	lib650$(EXEEXT) lib651$(EXEEXT) lib652$(EXEEXT) \
	lib653$(EXEEXT) lib654$(EXEEXT) lib655$(EXEEXT) \
	lib658$(EXEEXT) lib659$(EXEEXT) lib661$(EXEEXT) \
	lib666$(EXEEXT) lib667$(EXEEXT) lib668$(EXEEXT) \
	lib670$(EXEEXT) lib671$(EXEEXT) lib672$(EXEEXT) \
	lib673$(EXEEXT) lib674$(EXEEXT) lib676$(EXEEXT) \
	lib677$(EXEEXT) lib678$(EXEEXT) lib1156$(EXEEXT) \
	lib1301$(EXEEXT) lib1485$(EXEEXT) lib1500$(EXEEXT) \
	lib1501$(EXEEXT) lib1502$(EXEEXT) lib1503$(EXEEXT) \
	lib1504$(EXEEXT) lib1505$(EXEEXT) lib1506$(EXEEXT) \
	lib1507$(EXEEXT) lib1508$(EXEEXT) lib1509$(EXEEXT) \
	lib1510$(EXEEXT) lib1511$(EXEEXT) lib1512$(EXEEXT) \
	lib1513$(EXEEXT) lib1514$(EXEEXT) lib1515$(EXEEXT) \
	lib1517$(EXEEXT) lib1518$(EXEEXT) lib1520$(EXEEXT) \
	lib1521$(EXEEXT) lib1522$(EXEEXT) lib1523$(EXEEXT) \
	lib1525$(EXEEXT) lib1526$(EXEEXT) lib1527$(EXEEXT) \
	lib1528$(EXEEXT) lib1529$(EXEEXT) lib1530$(EXEEXT) \
	lib1531$(EXEEXT) lib1532$(EXEEXT) lib1533$(EXEEXT) \
	lib1534$(EXEEXT) lib1535$(EXEEXT) lib1536$(EXEEXT) \
	lib1537$(EXEEXT) lib1538$(EXEEXT) lib1539$(EXEEXT) \
	lib1540$(EXEEXT) lib1541$(EXEEXT) lib1542$(EXEEXT) \
	lib1543$(EXEEXT) lib1545$(EXEEXT) lib1550$(EXEEXT) \
	lib1551$(EXEEXT) lib1552$(EXEEXT) lib1553$(EXEEXT) \
	lib1554$(EXEEXT) lib1555$(EXEEXT) lib1556$(EXEEXT) \
	lib1557$(EXEEXT) lib1558$(EXEEXT) lib1559$(EXEEXT) \
	lib1560$(EXEEXT) lib1564$(EXEEXT) lib1565$(EXEEXT) \
	lib1567$(EXEEXT) lib1568$(EXEEXT) lib1569$(EXEEXT) \
	lib1591$(EXEEXT) lib1592$(EXEEXT) lib1593$(EXEEXT) \
	lib1594$(EXEEXT) lib1596$(EXEEXT) lib1597$(EXEEXT) \
	lib1598$(EXEEXT) lib1662$(EXEEXT) lib1900$(EXEEXT) \
	lib1901$(EXEEXT) lib1903$(EXEEXT) lib1905$(EXEEXT) \
	lib1906$(EXEEXT) lib1907$(EXEEXT) lib1908$(EXEEXT) \
	lib1910$(EXEEXT) lib1911$(EXEEXT) lib1912$(EXEEXT) \
	lib1913$(EXEEXT) lib1915$(EXEEXT) lib1916$(EXEEXT) \
	lib1917$(EXEEXT) lib1918$(EXEEXT) lib1919$(EXEEXT) \
	lib1933$(EXEEXT) lib1934$(EXEEXT) lib1935$(EXEEXT) \
	lib1936$(EXEEXT) lib1937$(EXEEXT) lib1938$(EXEEXT) \
	lib1939$(EXEEXT) lib1940$(EXEEXT) lib1945$(EXEEXT) \
	lib1946$(EXEEXT) lib1947$(EXEEXT) lib1948$(EXEEXT) \
	lib1955$(EXEEXT) lib1956$(EXEEXT) lib1957$(EXEEXT) \
	lib1958$(EXEEXT) lib1959$(EXEEXT) lib1960$(EXEEXT) \
	lib1964$(EXEEXT) lib1970$(EXEEXT) lib1971$(EXEEXT) \
	lib1972$(EXEEXT) lib1973$(EXEEXT) lib1974$(EXEEXT) \
	lib1975$(EXEEXT) lib2301$(EXEEXT) lib2302$(EXEEXT) \
	lib2304$(EXEEXT) lib2305$(EXEEXT) lib2306$(EXEEXT) \
	lib2308$(EXEEXT) lib2402$(EXEEXT) lib2404$(EXEEXT) \
	lib2405$(EXEEXT) lib2502$(EXEEXT) lib3010$(EXEEXT) \
	lib3025$(EXEEXT) lib3026$(EXEEXT) lib3027$(EXEEXT) \
	lib3100$(EXEEXT) lib3101$(EXEEXT) lib3102$(EXEEXT) \
	lib3103$(EXEEXT)
@USE_CPPFLAG_CURL_STATICLIB_TRUE@am__append_1 = -DCURL_STATICLIB
@CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_2 = -no-undefined
@CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_3 = -no-undefined
@CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE@am__append_4 = -mimpure-text
@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_5 = -DCURL_HIDDEN_SYMBOLS
@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_6 = $(CFLAG_CURL_SYMBOL_HIDING)

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







196
197
198
199
200
201
202

203
204
205
206
207
208
209
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
250
251
252
253
254
255
256




257
258
259
260
261
262
263
@USE_EXPLICIT_LIB_DEPS_TRUE@am__DEPENDENCIES_1 =  \
@USE_EXPLICIT_LIB_DEPS_TRUE@	$(top_builddir)/lib/libcurl.la
lib1156_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1301_OBJECTS = lib1301.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3)
lib1301_OBJECTS = $(am_lib1301_OBJECTS)
lib1301_DEPENDENCIES = $(am__DEPENDENCIES_1)




am_lib1500_OBJECTS = lib1500.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3)
lib1500_OBJECTS = $(am_lib1500_OBJECTS)
lib1500_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1501_OBJECTS = lib1501.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3) $(am__objects_4)
lib1501_OBJECTS = $(am_lib1501_OBJECTS)







>
>
>
>







250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
@USE_EXPLICIT_LIB_DEPS_TRUE@am__DEPENDENCIES_1 =  \
@USE_EXPLICIT_LIB_DEPS_TRUE@	$(top_builddir)/lib/libcurl.la
lib1156_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1301_OBJECTS = lib1301.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3)
lib1301_OBJECTS = $(am_lib1301_OBJECTS)
lib1301_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1485_OBJECTS = lib1485.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3) $(am__objects_4)
lib1485_OBJECTS = $(am_lib1485_OBJECTS)
lib1485_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1500_OBJECTS = lib1500.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3)
lib1500_OBJECTS = $(am_lib1500_OBJECTS)
lib1500_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1501_OBJECTS = lib1501.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3) $(am__objects_4)
lib1501_OBJECTS = $(am_lib1501_OBJECTS)
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
lib1551_LDADD = $(LDADD)
lib1551_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1552_OBJECTS = lib1552.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3)
lib1552_OBJECTS = $(am_lib1552_OBJECTS)
lib1552_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1553_OBJECTS = lib1553.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3)
lib1553_OBJECTS = $(am_lib1553_OBJECTS)
lib1553_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1554_OBJECTS = lib1554.$(OBJEXT) $(am__objects_2)
lib1554_OBJECTS = $(am_lib1554_OBJECTS)
lib1554_LDADD = $(LDADD)
lib1554_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1555_OBJECTS = lib1555.$(OBJEXT) $(am__objects_2) \







|







462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
lib1551_LDADD = $(LDADD)
lib1551_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1552_OBJECTS = lib1552.$(OBJEXT) $(am__objects_2) \
	$(am__objects_3)
lib1552_OBJECTS = $(am_lib1552_OBJECTS)
lib1552_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1553_OBJECTS = lib1553.$(OBJEXT) $(am__objects_2) \
	$(am__objects_23) $(am__objects_3)
lib1553_OBJECTS = $(am_lib1553_OBJECTS)
lib1553_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1554_OBJECTS = lib1554.$(OBJEXT) $(am__objects_2)
lib1554_OBJECTS = $(am_lib1554_OBJECTS)
lib1554_LDADD = $(LDADD)
lib1554_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_lib1555_OBJECTS = lib1555.$(OBJEXT) $(am__objects_2) \
1315
1316
1317
1318
1319
1320
1321
1322

1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354

1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388

1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422

1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
	../../lib/$(DEPDIR)/lib671-timediff.Po \
	../../lib/$(DEPDIR)/lib671-warnless.Po \
	../../lib/$(DEPDIR)/lib672-timediff.Po \
	../../lib/$(DEPDIR)/lib672-warnless.Po \
	../../lib/$(DEPDIR)/timediff.Po \
	../../lib/$(DEPDIR)/warnless.Po ./$(DEPDIR)/chkhostname.Po \
	./$(DEPDIR)/first.Po ./$(DEPDIR)/lib1156.Po \
	./$(DEPDIR)/lib1301.Po ./$(DEPDIR)/lib1500.Po \

	./$(DEPDIR)/lib1501.Po ./$(DEPDIR)/lib1502-first.Po \
	./$(DEPDIR)/lib1502-lib1502.Po ./$(DEPDIR)/lib1502-testutil.Po \
	./$(DEPDIR)/lib1503-first.Po ./$(DEPDIR)/lib1503-lib1502.Po \
	./$(DEPDIR)/lib1503-testutil.Po ./$(DEPDIR)/lib1504-first.Po \
	./$(DEPDIR)/lib1504-lib1502.Po ./$(DEPDIR)/lib1504-testutil.Po \
	./$(DEPDIR)/lib1505-first.Po ./$(DEPDIR)/lib1505-lib1502.Po \
	./$(DEPDIR)/lib1505-testutil.Po ./$(DEPDIR)/lib1506.Po \
	./$(DEPDIR)/lib1507.Po ./$(DEPDIR)/lib1508.Po \
	./$(DEPDIR)/lib1509.Po ./$(DEPDIR)/lib1510.Po \
	./$(DEPDIR)/lib1511.Po ./$(DEPDIR)/lib1512.Po \
	./$(DEPDIR)/lib1513.Po ./$(DEPDIR)/lib1514.Po \
	./$(DEPDIR)/lib1515.Po ./$(DEPDIR)/lib1517.Po \
	./$(DEPDIR)/lib1518.Po ./$(DEPDIR)/lib1520.Po \
	./$(DEPDIR)/lib1521-first.Po ./$(DEPDIR)/lib1521-lib1521.Po \
	./$(DEPDIR)/lib1522.Po ./$(DEPDIR)/lib1523.Po \
	./$(DEPDIR)/lib1525.Po ./$(DEPDIR)/lib1526.Po \
	./$(DEPDIR)/lib1527.Po ./$(DEPDIR)/lib1528.Po \
	./$(DEPDIR)/lib1529.Po ./$(DEPDIR)/lib1530.Po \
	./$(DEPDIR)/lib1531.Po ./$(DEPDIR)/lib1532.Po \
	./$(DEPDIR)/lib1533.Po ./$(DEPDIR)/lib1534.Po \
	./$(DEPDIR)/lib1535.Po ./$(DEPDIR)/lib1536.Po \
	./$(DEPDIR)/lib1537.Po ./$(DEPDIR)/lib1538.Po \
	./$(DEPDIR)/lib1539-first.Po ./$(DEPDIR)/lib1539-lib1514.Po \
	./$(DEPDIR)/lib1539-testutil.Po ./$(DEPDIR)/lib1540.Po \
	./$(DEPDIR)/lib1541.Po ./$(DEPDIR)/lib1542.Po \
	./$(DEPDIR)/lib1543-first.Po ./$(DEPDIR)/lib1543-lib1518.Po \
	./$(DEPDIR)/lib1545-first.Po ./$(DEPDIR)/lib1545-lib1545.Po \
	./$(DEPDIR)/lib1550.Po ./$(DEPDIR)/lib1551.Po \
	./$(DEPDIR)/lib1552.Po ./$(DEPDIR)/lib1553.Po \
	./$(DEPDIR)/lib1554.Po ./$(DEPDIR)/lib1555.Po \
	./$(DEPDIR)/lib1556.Po ./$(DEPDIR)/lib1557.Po \
	./$(DEPDIR)/lib1558.Po ./$(DEPDIR)/lib1559.Po \

	./$(DEPDIR)/lib1560.Po ./$(DEPDIR)/lib1564.Po \
	./$(DEPDIR)/lib1565.Po ./$(DEPDIR)/lib1567.Po \
	./$(DEPDIR)/lib1568.Po ./$(DEPDIR)/lib1569.Po \
	./$(DEPDIR)/lib1591.Po ./$(DEPDIR)/lib1592.Po \
	./$(DEPDIR)/lib1593.Po ./$(DEPDIR)/lib1594.Po \
	./$(DEPDIR)/lib1596-first.Po ./$(DEPDIR)/lib1596-lib1594.Po \
	./$(DEPDIR)/lib1596-testutil.Po ./$(DEPDIR)/lib1597.Po \
	./$(DEPDIR)/lib1598.Po ./$(DEPDIR)/lib1662.Po \
	./$(DEPDIR)/lib1900.Po ./$(DEPDIR)/lib1901.Po \
	./$(DEPDIR)/lib1903.Po ./$(DEPDIR)/lib1905.Po \
	./$(DEPDIR)/lib1906.Po ./$(DEPDIR)/lib1907.Po \
	./$(DEPDIR)/lib1908.Po ./$(DEPDIR)/lib1910.Po \
	./$(DEPDIR)/lib1911.Po ./$(DEPDIR)/lib1912.Po \
	./$(DEPDIR)/lib1913.Po ./$(DEPDIR)/lib1915.Po \
	./$(DEPDIR)/lib1916.Po ./$(DEPDIR)/lib1917-first.Po \
	./$(DEPDIR)/lib1917-lib1916.Po ./$(DEPDIR)/lib1918.Po \
	./$(DEPDIR)/lib1919.Po ./$(DEPDIR)/lib1933.Po \
	./$(DEPDIR)/lib1934.Po ./$(DEPDIR)/lib1935.Po \
	./$(DEPDIR)/lib1936.Po ./$(DEPDIR)/lib1937.Po \
	./$(DEPDIR)/lib1938.Po ./$(DEPDIR)/lib1939.Po \
	./$(DEPDIR)/lib1940.Po ./$(DEPDIR)/lib1945.Po \
	./$(DEPDIR)/lib1946-first.Po ./$(DEPDIR)/lib1946-lib1940.Po \
	./$(DEPDIR)/lib1947.Po ./$(DEPDIR)/lib1948.Po \
	./$(DEPDIR)/lib1955.Po ./$(DEPDIR)/lib1956.Po \
	./$(DEPDIR)/lib1957.Po ./$(DEPDIR)/lib1958.Po \
	./$(DEPDIR)/lib1959.Po ./$(DEPDIR)/lib1960.Po \
	./$(DEPDIR)/lib1964.Po ./$(DEPDIR)/lib1970.Po \
	./$(DEPDIR)/lib1971.Po ./$(DEPDIR)/lib1972.Po \
	./$(DEPDIR)/lib1973.Po ./$(DEPDIR)/lib1974.Po \
	./$(DEPDIR)/lib1975.Po ./$(DEPDIR)/lib2301.Po \
	./$(DEPDIR)/lib2302.Po ./$(DEPDIR)/lib2304.Po \
	./$(DEPDIR)/lib2305.Po ./$(DEPDIR)/lib2306.Po \
	./$(DEPDIR)/lib2308.Po ./$(DEPDIR)/lib2402.Po \
	./$(DEPDIR)/lib2404.Po ./$(DEPDIR)/lib2405.Po \

	./$(DEPDIR)/lib2502.Po ./$(DEPDIR)/lib3010.Po \
	./$(DEPDIR)/lib3025.Po ./$(DEPDIR)/lib3026.Po \
	./$(DEPDIR)/lib3027.Po ./$(DEPDIR)/lib3100.Po \
	./$(DEPDIR)/lib3101.Po ./$(DEPDIR)/lib3102.Po \
	./$(DEPDIR)/lib3103.Po ./$(DEPDIR)/lib500.Po \
	./$(DEPDIR)/lib501.Po ./$(DEPDIR)/lib502.Po \
	./$(DEPDIR)/lib503.Po ./$(DEPDIR)/lib504.Po \
	./$(DEPDIR)/lib505.Po ./$(DEPDIR)/lib506.Po \
	./$(DEPDIR)/lib507.Po ./$(DEPDIR)/lib508.Po \
	./$(DEPDIR)/lib509.Po ./$(DEPDIR)/lib510.Po \
	./$(DEPDIR)/lib511.Po ./$(DEPDIR)/lib512.Po \
	./$(DEPDIR)/lib513.Po ./$(DEPDIR)/lib514.Po \
	./$(DEPDIR)/lib515.Po ./$(DEPDIR)/lib516.Po \
	./$(DEPDIR)/lib517.Po ./$(DEPDIR)/lib518.Po \
	./$(DEPDIR)/lib519.Po ./$(DEPDIR)/lib520.Po \
	./$(DEPDIR)/lib521.Po ./$(DEPDIR)/lib523.Po \
	./$(DEPDIR)/lib524.Po ./$(DEPDIR)/lib525.Po \
	./$(DEPDIR)/lib526-first.Po ./$(DEPDIR)/lib526-lib526.Po \
	./$(DEPDIR)/lib526-testutil.Po ./$(DEPDIR)/lib527-first.Po \
	./$(DEPDIR)/lib527-lib526.Po ./$(DEPDIR)/lib527-testutil.Po \
	./$(DEPDIR)/lib529-first.Po ./$(DEPDIR)/lib529-lib525.Po \
	./$(DEPDIR)/lib529-testutil.Po ./$(DEPDIR)/lib530.Po \
	./$(DEPDIR)/lib532-first.Po ./$(DEPDIR)/lib532-lib526.Po \
	./$(DEPDIR)/lib532-testutil.Po ./$(DEPDIR)/lib533.Po \
	./$(DEPDIR)/lib536.Po ./$(DEPDIR)/lib537.Po \
	./$(DEPDIR)/lib539.Po ./$(DEPDIR)/lib540.Po \
	./$(DEPDIR)/lib541.Po ./$(DEPDIR)/lib542.Po \
	./$(DEPDIR)/lib543.Po ./$(DEPDIR)/lib544.Po \
	./$(DEPDIR)/lib545-first.Po ./$(DEPDIR)/lib545-lib544.Po \
	./$(DEPDIR)/lib547.Po ./$(DEPDIR)/lib548-first.Po \
	./$(DEPDIR)/lib548-lib547.Po ./$(DEPDIR)/lib549.Po \
	./$(DEPDIR)/lib552.Po ./$(DEPDIR)/lib553.Po \
	./$(DEPDIR)/lib554.Po ./$(DEPDIR)/lib555.Po \
	./$(DEPDIR)/lib556.Po ./$(DEPDIR)/lib557.Po \

	./$(DEPDIR)/lib558.Po ./$(DEPDIR)/lib559.Po \
	./$(DEPDIR)/lib560.Po ./$(DEPDIR)/lib562.Po \
	./$(DEPDIR)/lib564.Po ./$(DEPDIR)/lib565-first.Po \
	./$(DEPDIR)/lib565-lib510.Po ./$(DEPDIR)/lib566.Po \
	./$(DEPDIR)/lib567.Po ./$(DEPDIR)/lib568.Po \
	./$(DEPDIR)/lib569.Po ./$(DEPDIR)/lib570.Po \
	./$(DEPDIR)/lib571.Po ./$(DEPDIR)/lib572.Po \
	./$(DEPDIR)/lib573.Po ./$(DEPDIR)/lib574.Po \
	./$(DEPDIR)/lib575.Po ./$(DEPDIR)/lib576.Po \
	./$(DEPDIR)/lib578.Po ./$(DEPDIR)/lib579.Po \
	./$(DEPDIR)/lib582.Po ./$(DEPDIR)/lib583.Po \
	./$(DEPDIR)/lib584-first.Po ./$(DEPDIR)/lib584-lib589.Po \
	./$(DEPDIR)/lib585-first.Po ./$(DEPDIR)/lib585-lib500.Po \
	./$(DEPDIR)/lib585-testtrace.Po ./$(DEPDIR)/lib585-testutil.Po \
	./$(DEPDIR)/lib586.Po ./$(DEPDIR)/lib587-first.Po \
	./$(DEPDIR)/lib587-lib554.Po ./$(DEPDIR)/lib589.Po \
	./$(DEPDIR)/lib590.Po ./$(DEPDIR)/lib591.Po \
	./$(DEPDIR)/lib597.Po ./$(DEPDIR)/lib598.Po \
	./$(DEPDIR)/lib599.Po ./$(DEPDIR)/lib643.Po \
	./$(DEPDIR)/lib645-first.Po ./$(DEPDIR)/lib645-lib643.Po \
	./$(DEPDIR)/lib650.Po ./$(DEPDIR)/lib651.Po \
	./$(DEPDIR)/lib652.Po ./$(DEPDIR)/lib653.Po \
	./$(DEPDIR)/lib654.Po ./$(DEPDIR)/lib655.Po \
	./$(DEPDIR)/lib658.Po ./$(DEPDIR)/lib659.Po \
	./$(DEPDIR)/lib661.Po ./$(DEPDIR)/lib666.Po \
	./$(DEPDIR)/lib667.Po ./$(DEPDIR)/lib668.Po \
	./$(DEPDIR)/lib670-first.Po ./$(DEPDIR)/lib670-lib670.Po \
	./$(DEPDIR)/lib670-testutil.Po ./$(DEPDIR)/lib670.Po \
	./$(DEPDIR)/lib671-first.Po ./$(DEPDIR)/lib671-lib670.Po \
	./$(DEPDIR)/lib671-testutil.Po ./$(DEPDIR)/lib672-first.Po \
	./$(DEPDIR)/lib672-lib670.Po ./$(DEPDIR)/lib672-testutil.Po \
	./$(DEPDIR)/lib674.Po ./$(DEPDIR)/lib676.Po \
	./$(DEPDIR)/lib677.Po ./$(DEPDIR)/lib678.Po \
	./$(DEPDIR)/libauthretry.Po \
	./$(DEPDIR)/libhostname_la-sethostname.Plo \
	./$(DEPDIR)/libntlmconnect.Po ./$(DEPDIR)/libprereq.Po \
	./$(DEPDIR)/libstubgss_la-stub_gssapi.Plo \
	./$(DEPDIR)/testtrace.Po ./$(DEPDIR)/testutil.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)







|
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
|







1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358

1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392

1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426

1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459

1460
1461
1462
1463
1464
1465
1466
1467
	../../lib/$(DEPDIR)/lib671-timediff.Po \
	../../lib/$(DEPDIR)/lib671-warnless.Po \
	../../lib/$(DEPDIR)/lib672-timediff.Po \
	../../lib/$(DEPDIR)/lib672-warnless.Po \
	../../lib/$(DEPDIR)/timediff.Po \
	../../lib/$(DEPDIR)/warnless.Po ./$(DEPDIR)/chkhostname.Po \
	./$(DEPDIR)/first.Po ./$(DEPDIR)/lib1156.Po \
	./$(DEPDIR)/lib1301.Po ./$(DEPDIR)/lib1485.Po \
	./$(DEPDIR)/lib1500.Po ./$(DEPDIR)/lib1501.Po \
	./$(DEPDIR)/lib1502-first.Po ./$(DEPDIR)/lib1502-lib1502.Po \
	./$(DEPDIR)/lib1502-testutil.Po ./$(DEPDIR)/lib1503-first.Po \
	./$(DEPDIR)/lib1503-lib1502.Po ./$(DEPDIR)/lib1503-testutil.Po \
	./$(DEPDIR)/lib1504-first.Po ./$(DEPDIR)/lib1504-lib1502.Po \
	./$(DEPDIR)/lib1504-testutil.Po ./$(DEPDIR)/lib1505-first.Po \
	./$(DEPDIR)/lib1505-lib1502.Po ./$(DEPDIR)/lib1505-testutil.Po \
	./$(DEPDIR)/lib1506.Po ./$(DEPDIR)/lib1507.Po \
	./$(DEPDIR)/lib1508.Po ./$(DEPDIR)/lib1509.Po \
	./$(DEPDIR)/lib1510.Po ./$(DEPDIR)/lib1511.Po \
	./$(DEPDIR)/lib1512.Po ./$(DEPDIR)/lib1513.Po \
	./$(DEPDIR)/lib1514.Po ./$(DEPDIR)/lib1515.Po \
	./$(DEPDIR)/lib1517.Po ./$(DEPDIR)/lib1518.Po \
	./$(DEPDIR)/lib1520.Po ./$(DEPDIR)/lib1521-first.Po \
	./$(DEPDIR)/lib1521-lib1521.Po ./$(DEPDIR)/lib1522.Po \
	./$(DEPDIR)/lib1523.Po ./$(DEPDIR)/lib1525.Po \
	./$(DEPDIR)/lib1526.Po ./$(DEPDIR)/lib1527.Po \
	./$(DEPDIR)/lib1528.Po ./$(DEPDIR)/lib1529.Po \
	./$(DEPDIR)/lib1530.Po ./$(DEPDIR)/lib1531.Po \
	./$(DEPDIR)/lib1532.Po ./$(DEPDIR)/lib1533.Po \
	./$(DEPDIR)/lib1534.Po ./$(DEPDIR)/lib1535.Po \
	./$(DEPDIR)/lib1536.Po ./$(DEPDIR)/lib1537.Po \
	./$(DEPDIR)/lib1538.Po ./$(DEPDIR)/lib1539-first.Po \
	./$(DEPDIR)/lib1539-lib1514.Po ./$(DEPDIR)/lib1539-testutil.Po \
	./$(DEPDIR)/lib1540.Po ./$(DEPDIR)/lib1541.Po \
	./$(DEPDIR)/lib1542.Po ./$(DEPDIR)/lib1543-first.Po \
	./$(DEPDIR)/lib1543-lib1518.Po ./$(DEPDIR)/lib1545-first.Po \
	./$(DEPDIR)/lib1545-lib1545.Po ./$(DEPDIR)/lib1550.Po \
	./$(DEPDIR)/lib1551.Po ./$(DEPDIR)/lib1552.Po \
	./$(DEPDIR)/lib1553.Po ./$(DEPDIR)/lib1554.Po \
	./$(DEPDIR)/lib1555.Po ./$(DEPDIR)/lib1556.Po \
	./$(DEPDIR)/lib1557.Po ./$(DEPDIR)/lib1558.Po \

	./$(DEPDIR)/lib1559.Po ./$(DEPDIR)/lib1560.Po \
	./$(DEPDIR)/lib1564.Po ./$(DEPDIR)/lib1565.Po \
	./$(DEPDIR)/lib1567.Po ./$(DEPDIR)/lib1568.Po \
	./$(DEPDIR)/lib1569.Po ./$(DEPDIR)/lib1591.Po \
	./$(DEPDIR)/lib1592.Po ./$(DEPDIR)/lib1593.Po \
	./$(DEPDIR)/lib1594.Po ./$(DEPDIR)/lib1596-first.Po \
	./$(DEPDIR)/lib1596-lib1594.Po ./$(DEPDIR)/lib1596-testutil.Po \
	./$(DEPDIR)/lib1597.Po ./$(DEPDIR)/lib1598.Po \
	./$(DEPDIR)/lib1662.Po ./$(DEPDIR)/lib1900.Po \
	./$(DEPDIR)/lib1901.Po ./$(DEPDIR)/lib1903.Po \
	./$(DEPDIR)/lib1905.Po ./$(DEPDIR)/lib1906.Po \
	./$(DEPDIR)/lib1907.Po ./$(DEPDIR)/lib1908.Po \
	./$(DEPDIR)/lib1910.Po ./$(DEPDIR)/lib1911.Po \
	./$(DEPDIR)/lib1912.Po ./$(DEPDIR)/lib1913.Po \
	./$(DEPDIR)/lib1915.Po ./$(DEPDIR)/lib1916.Po \
	./$(DEPDIR)/lib1917-first.Po ./$(DEPDIR)/lib1917-lib1916.Po \
	./$(DEPDIR)/lib1918.Po ./$(DEPDIR)/lib1919.Po \
	./$(DEPDIR)/lib1933.Po ./$(DEPDIR)/lib1934.Po \
	./$(DEPDIR)/lib1935.Po ./$(DEPDIR)/lib1936.Po \
	./$(DEPDIR)/lib1937.Po ./$(DEPDIR)/lib1938.Po \
	./$(DEPDIR)/lib1939.Po ./$(DEPDIR)/lib1940.Po \
	./$(DEPDIR)/lib1945.Po ./$(DEPDIR)/lib1946-first.Po \
	./$(DEPDIR)/lib1946-lib1940.Po ./$(DEPDIR)/lib1947.Po \
	./$(DEPDIR)/lib1948.Po ./$(DEPDIR)/lib1955.Po \
	./$(DEPDIR)/lib1956.Po ./$(DEPDIR)/lib1957.Po \
	./$(DEPDIR)/lib1958.Po ./$(DEPDIR)/lib1959.Po \
	./$(DEPDIR)/lib1960.Po ./$(DEPDIR)/lib1964.Po \
	./$(DEPDIR)/lib1970.Po ./$(DEPDIR)/lib1971.Po \
	./$(DEPDIR)/lib1972.Po ./$(DEPDIR)/lib1973.Po \
	./$(DEPDIR)/lib1974.Po ./$(DEPDIR)/lib1975.Po \
	./$(DEPDIR)/lib2301.Po ./$(DEPDIR)/lib2302.Po \
	./$(DEPDIR)/lib2304.Po ./$(DEPDIR)/lib2305.Po \
	./$(DEPDIR)/lib2306.Po ./$(DEPDIR)/lib2308.Po \
	./$(DEPDIR)/lib2402.Po ./$(DEPDIR)/lib2404.Po \

	./$(DEPDIR)/lib2405.Po ./$(DEPDIR)/lib2502.Po \
	./$(DEPDIR)/lib3010.Po ./$(DEPDIR)/lib3025.Po \
	./$(DEPDIR)/lib3026.Po ./$(DEPDIR)/lib3027.Po \
	./$(DEPDIR)/lib3100.Po ./$(DEPDIR)/lib3101.Po \
	./$(DEPDIR)/lib3102.Po ./$(DEPDIR)/lib3103.Po \
	./$(DEPDIR)/lib500.Po ./$(DEPDIR)/lib501.Po \
	./$(DEPDIR)/lib502.Po ./$(DEPDIR)/lib503.Po \
	./$(DEPDIR)/lib504.Po ./$(DEPDIR)/lib505.Po \
	./$(DEPDIR)/lib506.Po ./$(DEPDIR)/lib507.Po \
	./$(DEPDIR)/lib508.Po ./$(DEPDIR)/lib509.Po \
	./$(DEPDIR)/lib510.Po ./$(DEPDIR)/lib511.Po \
	./$(DEPDIR)/lib512.Po ./$(DEPDIR)/lib513.Po \
	./$(DEPDIR)/lib514.Po ./$(DEPDIR)/lib515.Po \
	./$(DEPDIR)/lib516.Po ./$(DEPDIR)/lib517.Po \
	./$(DEPDIR)/lib518.Po ./$(DEPDIR)/lib519.Po \
	./$(DEPDIR)/lib520.Po ./$(DEPDIR)/lib521.Po \
	./$(DEPDIR)/lib523.Po ./$(DEPDIR)/lib524.Po \
	./$(DEPDIR)/lib525.Po ./$(DEPDIR)/lib526-first.Po \
	./$(DEPDIR)/lib526-lib526.Po ./$(DEPDIR)/lib526-testutil.Po \
	./$(DEPDIR)/lib527-first.Po ./$(DEPDIR)/lib527-lib526.Po \
	./$(DEPDIR)/lib527-testutil.Po ./$(DEPDIR)/lib529-first.Po \
	./$(DEPDIR)/lib529-lib525.Po ./$(DEPDIR)/lib529-testutil.Po \
	./$(DEPDIR)/lib530.Po ./$(DEPDIR)/lib532-first.Po \
	./$(DEPDIR)/lib532-lib526.Po ./$(DEPDIR)/lib532-testutil.Po \
	./$(DEPDIR)/lib533.Po ./$(DEPDIR)/lib536.Po \
	./$(DEPDIR)/lib537.Po ./$(DEPDIR)/lib539.Po \
	./$(DEPDIR)/lib540.Po ./$(DEPDIR)/lib541.Po \
	./$(DEPDIR)/lib542.Po ./$(DEPDIR)/lib543.Po \
	./$(DEPDIR)/lib544.Po ./$(DEPDIR)/lib545-first.Po \
	./$(DEPDIR)/lib545-lib544.Po ./$(DEPDIR)/lib547.Po \
	./$(DEPDIR)/lib548-first.Po ./$(DEPDIR)/lib548-lib547.Po \
	./$(DEPDIR)/lib549.Po ./$(DEPDIR)/lib552.Po \
	./$(DEPDIR)/lib553.Po ./$(DEPDIR)/lib554.Po \
	./$(DEPDIR)/lib555.Po ./$(DEPDIR)/lib556.Po \

	./$(DEPDIR)/lib557.Po ./$(DEPDIR)/lib558.Po \
	./$(DEPDIR)/lib559.Po ./$(DEPDIR)/lib560.Po \
	./$(DEPDIR)/lib562.Po ./$(DEPDIR)/lib564.Po \
	./$(DEPDIR)/lib565-first.Po ./$(DEPDIR)/lib565-lib510.Po \
	./$(DEPDIR)/lib566.Po ./$(DEPDIR)/lib567.Po \
	./$(DEPDIR)/lib568.Po ./$(DEPDIR)/lib569.Po \
	./$(DEPDIR)/lib570.Po ./$(DEPDIR)/lib571.Po \
	./$(DEPDIR)/lib572.Po ./$(DEPDIR)/lib573.Po \
	./$(DEPDIR)/lib574.Po ./$(DEPDIR)/lib575.Po \
	./$(DEPDIR)/lib576.Po ./$(DEPDIR)/lib578.Po \
	./$(DEPDIR)/lib579.Po ./$(DEPDIR)/lib582.Po \
	./$(DEPDIR)/lib583.Po ./$(DEPDIR)/lib584-first.Po \
	./$(DEPDIR)/lib584-lib589.Po ./$(DEPDIR)/lib585-first.Po \
	./$(DEPDIR)/lib585-lib500.Po ./$(DEPDIR)/lib585-testtrace.Po \
	./$(DEPDIR)/lib585-testutil.Po ./$(DEPDIR)/lib586.Po \
	./$(DEPDIR)/lib587-first.Po ./$(DEPDIR)/lib587-lib554.Po \
	./$(DEPDIR)/lib589.Po ./$(DEPDIR)/lib590.Po \
	./$(DEPDIR)/lib591.Po ./$(DEPDIR)/lib597.Po \
	./$(DEPDIR)/lib598.Po ./$(DEPDIR)/lib599.Po \
	./$(DEPDIR)/lib643.Po ./$(DEPDIR)/lib645-first.Po \
	./$(DEPDIR)/lib645-lib643.Po ./$(DEPDIR)/lib650.Po \
	./$(DEPDIR)/lib651.Po ./$(DEPDIR)/lib652.Po \
	./$(DEPDIR)/lib653.Po ./$(DEPDIR)/lib654.Po \
	./$(DEPDIR)/lib655.Po ./$(DEPDIR)/lib658.Po \
	./$(DEPDIR)/lib659.Po ./$(DEPDIR)/lib661.Po \
	./$(DEPDIR)/lib666.Po ./$(DEPDIR)/lib667.Po \
	./$(DEPDIR)/lib668.Po ./$(DEPDIR)/lib670-first.Po \
	./$(DEPDIR)/lib670-lib670.Po ./$(DEPDIR)/lib670-testutil.Po \
	./$(DEPDIR)/lib670.Po ./$(DEPDIR)/lib671-first.Po \
	./$(DEPDIR)/lib671-lib670.Po ./$(DEPDIR)/lib671-testutil.Po \
	./$(DEPDIR)/lib672-first.Po ./$(DEPDIR)/lib672-lib670.Po \
	./$(DEPDIR)/lib672-testutil.Po ./$(DEPDIR)/lib674.Po \
	./$(DEPDIR)/lib676.Po ./$(DEPDIR)/lib677.Po \

	./$(DEPDIR)/lib678.Po ./$(DEPDIR)/libauthretry.Po \
	./$(DEPDIR)/libhostname_la-sethostname.Plo \
	./$(DEPDIR)/libntlmconnect.Po ./$(DEPDIR)/libprereq.Po \
	./$(DEPDIR)/libstubgss_la-stub_gssapi.Plo \
	./$(DEPDIR)/testtrace.Po ./$(DEPDIR)/testutil.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
1475
1476
1477
1478
1479
1480
1481

















































































1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
	$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo "  CCLD    " $@;
am__v_CCLD_1 = 
SOURCES = $(libhostname_la_SOURCES) $(libstubgss_la_SOURCES) \
	$(chkhostname_SOURCES) $(lib1156_SOURCES) $(lib1301_SOURCES) \

















































































	$(lib1500_SOURCES) $(lib1501_SOURCES) $(lib1502_SOURCES) \
	$(lib1503_SOURCES) $(lib1504_SOURCES) $(lib1505_SOURCES) \
	$(lib1506_SOURCES) $(lib1507_SOURCES) $(lib1508_SOURCES) \
	$(lib1509_SOURCES) $(lib1510_SOURCES) $(lib1511_SOURCES) \
	$(lib1512_SOURCES) $(lib1513_SOURCES) $(lib1514_SOURCES) \
	$(lib1515_SOURCES) $(lib1517_SOURCES) $(lib1518_SOURCES) \
	$(lib1520_SOURCES) $(nodist_lib1521_SOURCES) \
	$(lib1522_SOURCES) $(lib1523_SOURCES) $(lib1525_SOURCES) \
	$(lib1526_SOURCES) $(lib1527_SOURCES) $(lib1528_SOURCES) \
	$(lib1529_SOURCES) $(lib1530_SOURCES) $(lib1531_SOURCES) \
	$(lib1532_SOURCES) $(lib1533_SOURCES) $(lib1534_SOURCES) \
	$(lib1535_SOURCES) $(lib1536_SOURCES) $(lib1537_SOURCES) \
	$(lib1538_SOURCES) $(lib1539_SOURCES) $(lib1540_SOURCES) \
	$(lib1541_SOURCES) $(lib1542_SOURCES) $(lib1543_SOURCES) \
	$(lib1545_SOURCES) $(lib1550_SOURCES) $(lib1551_SOURCES) \
	$(lib1552_SOURCES) $(lib1553_SOURCES) $(lib1554_SOURCES) \
	$(lib1555_SOURCES) $(lib1556_SOURCES) $(lib1557_SOURCES) \
	$(lib1558_SOURCES) $(lib1559_SOURCES) $(lib1560_SOURCES) \
	$(lib1564_SOURCES) $(lib1565_SOURCES) $(lib1567_SOURCES) \
	$(lib1568_SOURCES) $(lib1569_SOURCES) $(lib1591_SOURCES) \
	$(lib1592_SOURCES) $(lib1593_SOURCES) $(lib1594_SOURCES) \
	$(lib1596_SOURCES) $(lib1597_SOURCES) $(lib1598_SOURCES) \
	$(lib1662_SOURCES) $(lib1900_SOURCES) $(lib1901_SOURCES) \
	$(lib1903_SOURCES) $(lib1905_SOURCES) $(lib1906_SOURCES) \
	$(lib1907_SOURCES) $(lib1908_SOURCES) $(lib1910_SOURCES) \
	$(lib1911_SOURCES) $(lib1912_SOURCES) $(lib1913_SOURCES) \
	$(lib1915_SOURCES) $(lib1916_SOURCES) $(lib1917_SOURCES) \
	$(lib1918_SOURCES) $(lib1919_SOURCES) $(lib1933_SOURCES) \
	$(lib1934_SOURCES) $(lib1935_SOURCES) $(lib1936_SOURCES) \
	$(lib1937_SOURCES) $(lib1938_SOURCES) $(lib1939_SOURCES) \
	$(lib1940_SOURCES) $(lib1945_SOURCES) $(lib1946_SOURCES) \
	$(lib1947_SOURCES) $(lib1948_SOURCES) $(lib1955_SOURCES) \
	$(lib1956_SOURCES) $(lib1957_SOURCES) $(lib1958_SOURCES) \
	$(lib1959_SOURCES) $(lib1960_SOURCES) $(lib1964_SOURCES) \
	$(lib1970_SOURCES) $(lib1971_SOURCES) $(lib1972_SOURCES) \
	$(lib1973_SOURCES) $(lib1974_SOURCES) $(lib1975_SOURCES) \
	$(lib2301_SOURCES) $(lib2302_SOURCES) $(lib2304_SOURCES) \
	$(lib2305_SOURCES) $(lib2306_SOURCES) $(lib2308_SOURCES) \
	$(lib2402_SOURCES) $(lib2404_SOURCES) $(lib2405_SOURCES) \
	$(lib2502_SOURCES) $(lib3010_SOURCES) $(lib3025_SOURCES) \
	$(lib3026_SOURCES) $(lib3027_SOURCES) $(lib3100_SOURCES) \
	$(lib3101_SOURCES) $(lib3102_SOURCES) $(lib3103_SOURCES) \
	$(lib500_SOURCES) $(lib501_SOURCES) $(lib502_SOURCES) \
	$(lib503_SOURCES) $(lib504_SOURCES) $(lib505_SOURCES) \
	$(lib506_SOURCES) $(lib507_SOURCES) $(lib508_SOURCES) \
	$(lib509_SOURCES) $(lib510_SOURCES) $(lib511_SOURCES) \
	$(lib512_SOURCES) $(lib513_SOURCES) $(lib514_SOURCES) \
	$(lib515_SOURCES) $(lib516_SOURCES) $(lib517_SOURCES) \
	$(lib518_SOURCES) $(lib519_SOURCES) $(lib520_SOURCES) \
	$(lib521_SOURCES) $(lib523_SOURCES) $(lib524_SOURCES) \
	$(lib525_SOURCES) $(lib526_SOURCES) $(lib527_SOURCES) \
	$(lib529_SOURCES) $(lib530_SOURCES) $(lib532_SOURCES) \
	$(lib533_SOURCES) $(lib536_SOURCES) $(lib537_SOURCES) \
	$(lib539_SOURCES) $(lib540_SOURCES) $(lib541_SOURCES) \
	$(lib542_SOURCES) $(lib543_SOURCES) $(lib544_SOURCES) \
	$(lib545_SOURCES) $(lib547_SOURCES) $(lib548_SOURCES) \
	$(lib549_SOURCES) $(lib552_SOURCES) $(lib553_SOURCES) \
	$(lib554_SOURCES) $(lib555_SOURCES) $(lib556_SOURCES) \
	$(lib557_SOURCES) $(lib558_SOURCES) $(lib559_SOURCES) \
	$(lib560_SOURCES) $(lib562_SOURCES) $(lib564_SOURCES) \
	$(lib565_SOURCES) $(lib566_SOURCES) $(lib567_SOURCES) \
	$(lib568_SOURCES) $(lib569_SOURCES) $(lib570_SOURCES) \
	$(lib571_SOURCES) $(lib572_SOURCES) $(lib573_SOURCES) \
	$(lib574_SOURCES) $(lib575_SOURCES) $(lib576_SOURCES) \
	$(lib578_SOURCES) $(lib579_SOURCES) $(lib582_SOURCES) \
	$(lib583_SOURCES) $(lib584_SOURCES) $(lib585_SOURCES) \
	$(lib586_SOURCES) $(lib587_SOURCES) $(lib589_SOURCES) \
	$(lib590_SOURCES) $(lib591_SOURCES) $(lib597_SOURCES) \
	$(lib598_SOURCES) $(lib599_SOURCES) $(lib643_SOURCES) \
	$(lib645_SOURCES) $(lib650_SOURCES) $(lib651_SOURCES) \
	$(lib652_SOURCES) $(lib653_SOURCES) $(lib654_SOURCES) \
	$(lib655_SOURCES) $(lib658_SOURCES) $(lib659_SOURCES) \
	$(lib661_SOURCES) $(lib666_SOURCES) $(lib667_SOURCES) \
	$(lib668_SOURCES) $(lib670_SOURCES) $(lib671_SOURCES) \
	$(lib672_SOURCES) $(lib673_SOURCES) $(lib674_SOURCES) \
	$(lib676_SOURCES) $(lib677_SOURCES) $(lib678_SOURCES) \
	$(libauthretry_SOURCES) $(libntlmconnect_SOURCES) \
	$(libprereq_SOURCES)
DIST_SOURCES = $(libhostname_la_SOURCES) \
	$(am__libstubgss_la_SOURCES_DIST) $(chkhostname_SOURCES) \
	$(lib1156_SOURCES) $(lib1301_SOURCES) $(lib1500_SOURCES) \
	$(lib1501_SOURCES) $(lib1502_SOURCES) $(lib1503_SOURCES) \
	$(lib1504_SOURCES) $(lib1505_SOURCES) $(lib1506_SOURCES) \
	$(lib1507_SOURCES) $(lib1508_SOURCES) $(lib1509_SOURCES) \
	$(lib1510_SOURCES) $(lib1511_SOURCES) $(lib1512_SOURCES) \
	$(lib1513_SOURCES) $(lib1514_SOURCES) $(lib1515_SOURCES) \
	$(lib1517_SOURCES) $(lib1518_SOURCES) $(lib1520_SOURCES) \
	$(lib1522_SOURCES) $(lib1523_SOURCES) $(lib1525_SOURCES) \
	$(lib1526_SOURCES) $(lib1527_SOURCES) $(lib1528_SOURCES) \
	$(lib1529_SOURCES) $(lib1530_SOURCES) $(lib1531_SOURCES) \
	$(lib1532_SOURCES) $(lib1533_SOURCES) $(lib1534_SOURCES) \
	$(lib1535_SOURCES) $(lib1536_SOURCES) $(lib1537_SOURCES) \
	$(lib1538_SOURCES) $(lib1539_SOURCES) $(lib1540_SOURCES) \
	$(lib1541_SOURCES) $(lib1542_SOURCES) $(lib1543_SOURCES) \
	$(lib1545_SOURCES) $(lib1550_SOURCES) $(lib1551_SOURCES) \
	$(lib1552_SOURCES) $(lib1553_SOURCES) $(lib1554_SOURCES) \
	$(lib1555_SOURCES) $(lib1556_SOURCES) $(lib1557_SOURCES) \
	$(lib1558_SOURCES) $(lib1559_SOURCES) $(lib1560_SOURCES) \
	$(lib1564_SOURCES) $(lib1565_SOURCES) $(lib1567_SOURCES) \
	$(lib1568_SOURCES) $(lib1569_SOURCES) $(lib1591_SOURCES) \
	$(lib1592_SOURCES) $(lib1593_SOURCES) $(lib1594_SOURCES) \
	$(lib1596_SOURCES) $(lib1597_SOURCES) $(lib1598_SOURCES) \
	$(lib1662_SOURCES) $(lib1900_SOURCES) $(lib1901_SOURCES) \
	$(lib1903_SOURCES) $(lib1905_SOURCES) $(lib1906_SOURCES) \
	$(lib1907_SOURCES) $(lib1908_SOURCES) $(lib1910_SOURCES) \
	$(lib1911_SOURCES) $(lib1912_SOURCES) $(lib1913_SOURCES) \
	$(lib1915_SOURCES) $(lib1916_SOURCES) $(lib1917_SOURCES) \
	$(lib1918_SOURCES) $(lib1919_SOURCES) $(lib1933_SOURCES) \
	$(lib1934_SOURCES) $(lib1935_SOURCES) $(lib1936_SOURCES) \
	$(lib1937_SOURCES) $(lib1938_SOURCES) $(lib1939_SOURCES) \
	$(lib1940_SOURCES) $(lib1945_SOURCES) $(lib1946_SOURCES) \
	$(lib1947_SOURCES) $(lib1948_SOURCES) $(lib1955_SOURCES) \
	$(lib1956_SOURCES) $(lib1957_SOURCES) $(lib1958_SOURCES) \
	$(lib1959_SOURCES) $(lib1960_SOURCES) $(lib1964_SOURCES) \
	$(lib1970_SOURCES) $(lib1971_SOURCES) $(lib1972_SOURCES) \
	$(lib1973_SOURCES) $(lib1974_SOURCES) $(lib1975_SOURCES) \
	$(lib2301_SOURCES) $(lib2302_SOURCES) $(lib2304_SOURCES) \
	$(lib2305_SOURCES) $(lib2306_SOURCES) $(lib2308_SOURCES) \
	$(lib2402_SOURCES) $(lib2404_SOURCES) $(lib2405_SOURCES) \
	$(lib2502_SOURCES) $(lib3010_SOURCES) $(lib3025_SOURCES) \
	$(lib3026_SOURCES) $(lib3027_SOURCES) $(lib3100_SOURCES) \
	$(lib3101_SOURCES) $(lib3102_SOURCES) $(lib3103_SOURCES) \
	$(lib500_SOURCES) $(lib501_SOURCES) $(lib502_SOURCES) \
	$(lib503_SOURCES) $(lib504_SOURCES) $(lib505_SOURCES) \
	$(lib506_SOURCES) $(lib507_SOURCES) $(lib508_SOURCES) \
	$(lib509_SOURCES) $(lib510_SOURCES) $(lib511_SOURCES) \
	$(lib512_SOURCES) $(lib513_SOURCES) $(lib514_SOURCES) \
	$(lib515_SOURCES) $(lib516_SOURCES) $(lib517_SOURCES) \
	$(lib518_SOURCES) $(lib519_SOURCES) $(lib520_SOURCES) \
	$(lib521_SOURCES) $(lib523_SOURCES) $(lib524_SOURCES) \
	$(lib525_SOURCES) $(lib526_SOURCES) $(lib527_SOURCES) \
	$(lib529_SOURCES) $(lib530_SOURCES) $(lib532_SOURCES) \
	$(lib533_SOURCES) $(lib536_SOURCES) $(lib537_SOURCES) \
	$(lib539_SOURCES) $(lib540_SOURCES) $(lib541_SOURCES) \
	$(lib542_SOURCES) $(lib543_SOURCES) $(lib544_SOURCES) \
	$(lib545_SOURCES) $(lib547_SOURCES) $(lib548_SOURCES) \
	$(lib549_SOURCES) $(lib552_SOURCES) $(lib553_SOURCES) \
	$(lib554_SOURCES) $(lib555_SOURCES) $(lib556_SOURCES) \
	$(lib557_SOURCES) $(lib558_SOURCES) $(lib559_SOURCES) \
	$(lib560_SOURCES) $(lib562_SOURCES) $(lib564_SOURCES) \
	$(lib565_SOURCES) $(lib566_SOURCES) $(lib567_SOURCES) \
	$(lib568_SOURCES) $(lib569_SOURCES) $(lib570_SOURCES) \
	$(lib571_SOURCES) $(lib572_SOURCES) $(lib573_SOURCES) \
	$(lib574_SOURCES) $(lib575_SOURCES) $(lib576_SOURCES) \
	$(lib578_SOURCES) $(lib579_SOURCES) $(lib582_SOURCES) \
	$(lib583_SOURCES) $(lib584_SOURCES) $(lib585_SOURCES) \
	$(lib586_SOURCES) $(lib587_SOURCES) $(lib589_SOURCES) \
	$(lib590_SOURCES) $(lib591_SOURCES) $(lib597_SOURCES) \
	$(lib598_SOURCES) $(lib599_SOURCES) $(lib643_SOURCES) \
	$(lib645_SOURCES) $(lib650_SOURCES) $(lib651_SOURCES) \
	$(lib652_SOURCES) $(lib653_SOURCES) $(lib654_SOURCES) \
	$(lib655_SOURCES) $(lib658_SOURCES) $(lib659_SOURCES) \
	$(lib661_SOURCES) $(lib666_SOURCES) $(lib667_SOURCES) \
	$(lib668_SOURCES) $(lib670_SOURCES) $(lib671_SOURCES) \
	$(lib672_SOURCES) $(lib673_SOURCES) $(lib674_SOURCES) \
	$(lib676_SOURCES) $(lib677_SOURCES) $(lib678_SOURCES) \
	$(libauthretry_SOURCES) $(libntlmconnect_SOURCES) \
	$(libprereq_SOURCES)
am__can_run_installinfo = \
  case $$AM_UPDATE_INFO_DIR in \
    n|no|NO) false;; \
    *) (install-info --version) >/dev/null 2>&1;; \
  esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
<
|
|
<
<
|
|
<
|
<
|
|
|
<
<
|
|
<
|
<
<
|
|
<
|
|
<
<
<
|
<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572

1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589




















1590
1591
1592

1593
1594


1595
1596

1597

1598
1599
1600


1601
1602

1603


1604
1605

1606
1607



1608




1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626










































1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
	$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo "  CCLD    " $@;
am__v_CCLD_1 = 
SOURCES = $(libhostname_la_SOURCES) $(libstubgss_la_SOURCES) \
	$(chkhostname_SOURCES) $(lib1156_SOURCES) $(lib1301_SOURCES) \
	$(lib1485_SOURCES) $(lib1500_SOURCES) $(lib1501_SOURCES) \
	$(lib1502_SOURCES) $(lib1503_SOURCES) $(lib1504_SOURCES) \
	$(lib1505_SOURCES) $(lib1506_SOURCES) $(lib1507_SOURCES) \
	$(lib1508_SOURCES) $(lib1509_SOURCES) $(lib1510_SOURCES) \
	$(lib1511_SOURCES) $(lib1512_SOURCES) $(lib1513_SOURCES) \
	$(lib1514_SOURCES) $(lib1515_SOURCES) $(lib1517_SOURCES) \
	$(lib1518_SOURCES) $(lib1520_SOURCES) \
	$(nodist_lib1521_SOURCES) $(lib1522_SOURCES) \
	$(lib1523_SOURCES) $(lib1525_SOURCES) $(lib1526_SOURCES) \
	$(lib1527_SOURCES) $(lib1528_SOURCES) $(lib1529_SOURCES) \
	$(lib1530_SOURCES) $(lib1531_SOURCES) $(lib1532_SOURCES) \
	$(lib1533_SOURCES) $(lib1534_SOURCES) $(lib1535_SOURCES) \
	$(lib1536_SOURCES) $(lib1537_SOURCES) $(lib1538_SOURCES) \
	$(lib1539_SOURCES) $(lib1540_SOURCES) $(lib1541_SOURCES) \
	$(lib1542_SOURCES) $(lib1543_SOURCES) $(lib1545_SOURCES) \
	$(lib1550_SOURCES) $(lib1551_SOURCES) $(lib1552_SOURCES) \
	$(lib1553_SOURCES) $(lib1554_SOURCES) $(lib1555_SOURCES) \
	$(lib1556_SOURCES) $(lib1557_SOURCES) $(lib1558_SOURCES) \
	$(lib1559_SOURCES) $(lib1560_SOURCES) $(lib1564_SOURCES) \
	$(lib1565_SOURCES) $(lib1567_SOURCES) $(lib1568_SOURCES) \
	$(lib1569_SOURCES) $(lib1591_SOURCES) $(lib1592_SOURCES) \
	$(lib1593_SOURCES) $(lib1594_SOURCES) $(lib1596_SOURCES) \
	$(lib1597_SOURCES) $(lib1598_SOURCES) $(lib1662_SOURCES) \
	$(lib1900_SOURCES) $(lib1901_SOURCES) $(lib1903_SOURCES) \
	$(lib1905_SOURCES) $(lib1906_SOURCES) $(lib1907_SOURCES) \
	$(lib1908_SOURCES) $(lib1910_SOURCES) $(lib1911_SOURCES) \
	$(lib1912_SOURCES) $(lib1913_SOURCES) $(lib1915_SOURCES) \
	$(lib1916_SOURCES) $(lib1917_SOURCES) $(lib1918_SOURCES) \
	$(lib1919_SOURCES) $(lib1933_SOURCES) $(lib1934_SOURCES) \
	$(lib1935_SOURCES) $(lib1936_SOURCES) $(lib1937_SOURCES) \
	$(lib1938_SOURCES) $(lib1939_SOURCES) $(lib1940_SOURCES) \
	$(lib1945_SOURCES) $(lib1946_SOURCES) $(lib1947_SOURCES) \
	$(lib1948_SOURCES) $(lib1955_SOURCES) $(lib1956_SOURCES) \
	$(lib1957_SOURCES) $(lib1958_SOURCES) $(lib1959_SOURCES) \
	$(lib1960_SOURCES) $(lib1964_SOURCES) $(lib1970_SOURCES) \
	$(lib1971_SOURCES) $(lib1972_SOURCES) $(lib1973_SOURCES) \
	$(lib1974_SOURCES) $(lib1975_SOURCES) $(lib2301_SOURCES) \
	$(lib2302_SOURCES) $(lib2304_SOURCES) $(lib2305_SOURCES) \
	$(lib2306_SOURCES) $(lib2308_SOURCES) $(lib2402_SOURCES) \
	$(lib2404_SOURCES) $(lib2405_SOURCES) $(lib2502_SOURCES) \
	$(lib3010_SOURCES) $(lib3025_SOURCES) $(lib3026_SOURCES) \
	$(lib3027_SOURCES) $(lib3100_SOURCES) $(lib3101_SOURCES) \
	$(lib3102_SOURCES) $(lib3103_SOURCES) $(lib500_SOURCES) \
	$(lib501_SOURCES) $(lib502_SOURCES) $(lib503_SOURCES) \
	$(lib504_SOURCES) $(lib505_SOURCES) $(lib506_SOURCES) \
	$(lib507_SOURCES) $(lib508_SOURCES) $(lib509_SOURCES) \
	$(lib510_SOURCES) $(lib511_SOURCES) $(lib512_SOURCES) \
	$(lib513_SOURCES) $(lib514_SOURCES) $(lib515_SOURCES) \
	$(lib516_SOURCES) $(lib517_SOURCES) $(lib518_SOURCES) \
	$(lib519_SOURCES) $(lib520_SOURCES) $(lib521_SOURCES) \
	$(lib523_SOURCES) $(lib524_SOURCES) $(lib525_SOURCES) \
	$(lib526_SOURCES) $(lib527_SOURCES) $(lib529_SOURCES) \
	$(lib530_SOURCES) $(lib532_SOURCES) $(lib533_SOURCES) \
	$(lib536_SOURCES) $(lib537_SOURCES) $(lib539_SOURCES) \
	$(lib540_SOURCES) $(lib541_SOURCES) $(lib542_SOURCES) \
	$(lib543_SOURCES) $(lib544_SOURCES) $(lib545_SOURCES) \
	$(lib547_SOURCES) $(lib548_SOURCES) $(lib549_SOURCES) \
	$(lib552_SOURCES) $(lib553_SOURCES) $(lib554_SOURCES) \
	$(lib555_SOURCES) $(lib556_SOURCES) $(lib557_SOURCES) \
	$(lib558_SOURCES) $(lib559_SOURCES) $(lib560_SOURCES) \
	$(lib562_SOURCES) $(lib564_SOURCES) $(lib565_SOURCES) \
	$(lib566_SOURCES) $(lib567_SOURCES) $(lib568_SOURCES) \
	$(lib569_SOURCES) $(lib570_SOURCES) $(lib571_SOURCES) \
	$(lib572_SOURCES) $(lib573_SOURCES) $(lib574_SOURCES) \
	$(lib575_SOURCES) $(lib576_SOURCES) $(lib578_SOURCES) \
	$(lib579_SOURCES) $(lib582_SOURCES) $(lib583_SOURCES) \
	$(lib584_SOURCES) $(lib585_SOURCES) $(lib586_SOURCES) \
	$(lib587_SOURCES) $(lib589_SOURCES) $(lib590_SOURCES) \
	$(lib591_SOURCES) $(lib597_SOURCES) $(lib598_SOURCES) \
	$(lib599_SOURCES) $(lib643_SOURCES) $(lib645_SOURCES) \
	$(lib650_SOURCES) $(lib651_SOURCES) $(lib652_SOURCES) \
	$(lib653_SOURCES) $(lib654_SOURCES) $(lib655_SOURCES) \
	$(lib658_SOURCES) $(lib659_SOURCES) $(lib661_SOURCES) \
	$(lib666_SOURCES) $(lib667_SOURCES) $(lib668_SOURCES) \
	$(lib670_SOURCES) $(lib671_SOURCES) $(lib672_SOURCES) \
	$(lib673_SOURCES) $(lib674_SOURCES) $(lib676_SOURCES) \
	$(lib677_SOURCES) $(lib678_SOURCES) $(libauthretry_SOURCES) \
	$(libntlmconnect_SOURCES) $(libprereq_SOURCES)
DIST_SOURCES = $(libhostname_la_SOURCES) \
	$(am__libstubgss_la_SOURCES_DIST) $(chkhostname_SOURCES) \
	$(lib1156_SOURCES) $(lib1301_SOURCES) $(lib1485_SOURCES) \
	$(lib1500_SOURCES) $(lib1501_SOURCES) $(lib1502_SOURCES) \
	$(lib1503_SOURCES) $(lib1504_SOURCES) $(lib1505_SOURCES) \
	$(lib1506_SOURCES) $(lib1507_SOURCES) $(lib1508_SOURCES) \
	$(lib1509_SOURCES) $(lib1510_SOURCES) $(lib1511_SOURCES) \
	$(lib1512_SOURCES) $(lib1513_SOURCES) $(lib1514_SOURCES) \
	$(lib1515_SOURCES) $(lib1517_SOURCES) $(lib1518_SOURCES) \

	$(lib1520_SOURCES) $(lib1522_SOURCES) $(lib1523_SOURCES) \
	$(lib1525_SOURCES) $(lib1526_SOURCES) $(lib1527_SOURCES) \
	$(lib1528_SOURCES) $(lib1529_SOURCES) $(lib1530_SOURCES) \
	$(lib1531_SOURCES) $(lib1532_SOURCES) $(lib1533_SOURCES) \
	$(lib1534_SOURCES) $(lib1535_SOURCES) $(lib1536_SOURCES) \
	$(lib1537_SOURCES) $(lib1538_SOURCES) $(lib1539_SOURCES) \
	$(lib1540_SOURCES) $(lib1541_SOURCES) $(lib1542_SOURCES) \
	$(lib1543_SOURCES) $(lib1545_SOURCES) $(lib1550_SOURCES) \
	$(lib1551_SOURCES) $(lib1552_SOURCES) $(lib1553_SOURCES) \
	$(lib1554_SOURCES) $(lib1555_SOURCES) $(lib1556_SOURCES) \
	$(lib1557_SOURCES) $(lib1558_SOURCES) $(lib1559_SOURCES) \
	$(lib1560_SOURCES) $(lib1564_SOURCES) $(lib1565_SOURCES) \
	$(lib1567_SOURCES) $(lib1568_SOURCES) $(lib1569_SOURCES) \
	$(lib1591_SOURCES) $(lib1592_SOURCES) $(lib1593_SOURCES) \
	$(lib1594_SOURCES) $(lib1596_SOURCES) $(lib1597_SOURCES) \
	$(lib1598_SOURCES) $(lib1662_SOURCES) $(lib1900_SOURCES) \
	$(lib1901_SOURCES) $(lib1903_SOURCES) $(lib1905_SOURCES) \




















	$(lib1906_SOURCES) $(lib1907_SOURCES) $(lib1908_SOURCES) \
	$(lib1910_SOURCES) $(lib1911_SOURCES) $(lib1912_SOURCES) \
	$(lib1913_SOURCES) $(lib1915_SOURCES) $(lib1916_SOURCES) \

	$(lib1917_SOURCES) $(lib1918_SOURCES) $(lib1919_SOURCES) \
	$(lib1933_SOURCES) $(lib1934_SOURCES) $(lib1935_SOURCES) \


	$(lib1936_SOURCES) $(lib1937_SOURCES) $(lib1938_SOURCES) \
	$(lib1939_SOURCES) $(lib1940_SOURCES) $(lib1945_SOURCES) \

	$(lib1946_SOURCES) $(lib1947_SOURCES) $(lib1948_SOURCES) \

	$(lib1955_SOURCES) $(lib1956_SOURCES) $(lib1957_SOURCES) \
	$(lib1958_SOURCES) $(lib1959_SOURCES) $(lib1960_SOURCES) \
	$(lib1964_SOURCES) $(lib1970_SOURCES) $(lib1971_SOURCES) \


	$(lib1972_SOURCES) $(lib1973_SOURCES) $(lib1974_SOURCES) \
	$(lib1975_SOURCES) $(lib2301_SOURCES) $(lib2302_SOURCES) \

	$(lib2304_SOURCES) $(lib2305_SOURCES) $(lib2306_SOURCES) \


	$(lib2308_SOURCES) $(lib2402_SOURCES) $(lib2404_SOURCES) \
	$(lib2405_SOURCES) $(lib2502_SOURCES) $(lib3010_SOURCES) \

	$(lib3025_SOURCES) $(lib3026_SOURCES) $(lib3027_SOURCES) \
	$(lib3100_SOURCES) $(lib3101_SOURCES) $(lib3102_SOURCES) \



	$(lib3103_SOURCES) $(lib500_SOURCES) $(lib501_SOURCES) \




	$(lib502_SOURCES) $(lib503_SOURCES) $(lib504_SOURCES) \
	$(lib505_SOURCES) $(lib506_SOURCES) $(lib507_SOURCES) \
	$(lib508_SOURCES) $(lib509_SOURCES) $(lib510_SOURCES) \
	$(lib511_SOURCES) $(lib512_SOURCES) $(lib513_SOURCES) \
	$(lib514_SOURCES) $(lib515_SOURCES) $(lib516_SOURCES) \
	$(lib517_SOURCES) $(lib518_SOURCES) $(lib519_SOURCES) \
	$(lib520_SOURCES) $(lib521_SOURCES) $(lib523_SOURCES) \
	$(lib524_SOURCES) $(lib525_SOURCES) $(lib526_SOURCES) \
	$(lib527_SOURCES) $(lib529_SOURCES) $(lib530_SOURCES) \
	$(lib532_SOURCES) $(lib533_SOURCES) $(lib536_SOURCES) \
	$(lib537_SOURCES) $(lib539_SOURCES) $(lib540_SOURCES) \
	$(lib541_SOURCES) $(lib542_SOURCES) $(lib543_SOURCES) \
	$(lib544_SOURCES) $(lib545_SOURCES) $(lib547_SOURCES) \
	$(lib548_SOURCES) $(lib549_SOURCES) $(lib552_SOURCES) \
	$(lib553_SOURCES) $(lib554_SOURCES) $(lib555_SOURCES) \
	$(lib556_SOURCES) $(lib557_SOURCES) $(lib558_SOURCES) \
	$(lib559_SOURCES) $(lib560_SOURCES) $(lib562_SOURCES) \
	$(lib564_SOURCES) $(lib565_SOURCES) $(lib566_SOURCES) \










































	$(lib567_SOURCES) $(lib568_SOURCES) $(lib569_SOURCES) \
	$(lib570_SOURCES) $(lib571_SOURCES) $(lib572_SOURCES) \
	$(lib573_SOURCES) $(lib574_SOURCES) $(lib575_SOURCES) \
	$(lib576_SOURCES) $(lib578_SOURCES) $(lib579_SOURCES) \
	$(lib582_SOURCES) $(lib583_SOURCES) $(lib584_SOURCES) \
	$(lib585_SOURCES) $(lib586_SOURCES) $(lib587_SOURCES) \
	$(lib589_SOURCES) $(lib590_SOURCES) $(lib591_SOURCES) \
	$(lib597_SOURCES) $(lib598_SOURCES) $(lib599_SOURCES) \
	$(lib643_SOURCES) $(lib645_SOURCES) $(lib650_SOURCES) \
	$(lib651_SOURCES) $(lib652_SOURCES) $(lib653_SOURCES) \
	$(lib654_SOURCES) $(lib655_SOURCES) $(lib658_SOURCES) \
	$(lib659_SOURCES) $(lib661_SOURCES) $(lib666_SOURCES) \
	$(lib667_SOURCES) $(lib668_SOURCES) $(lib670_SOURCES) \
	$(lib671_SOURCES) $(lib672_SOURCES) $(lib673_SOURCES) \
	$(lib674_SOURCES) $(lib676_SOURCES) $(lib677_SOURCES) \
	$(lib678_SOURCES) $(libauthretry_SOURCES) \
	$(libntlmconnect_SOURCES) $(libprereq_SOURCES)
am__can_run_installinfo = \
  case $$AM_UPDATE_INFO_DIR in \
    n|no|NO) false;; \
    *) (install-info --version) >/dev/null 2>&1;; \
  esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
1747
1748
1749
1750
1751
1752
1753


1754
1755
1756
1757
1758
1759
1760
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@







>
>







1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
2130
2131
2132
2133
2134
2135
2136


2137
2138
2139
2140
2141
2142
2143
lib676_LDADD = $(TESTUTIL_LIBS)
lib677_SOURCES = lib677.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) $(MULTIBYTE)
lib677_LDADD = $(TESTUTIL_LIBS)
lib678_SOURCES = lib678.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) $(MULTIBYTE)
lib678_LDADD = $(TESTUTIL_LIBS)
lib1301_SOURCES = lib1301.c $(SUPPORTFILES) $(TESTUTIL)
lib1301_LDADD = $(TESTUTIL_LIBS)


lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL)
lib1500_LDADD = $(TESTUTIL_LIBS)
lib1501_SOURCES = lib1501.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1501_LDADD = $(TESTUTIL_LIBS)
lib1502_SOURCES = lib1502.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1502_LDADD = $(TESTUTIL_LIBS)
lib1502_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1502







>
>







2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
lib676_LDADD = $(TESTUTIL_LIBS)
lib677_SOURCES = lib677.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) $(MULTIBYTE)
lib677_LDADD = $(TESTUTIL_LIBS)
lib678_SOURCES = lib678.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) $(MULTIBYTE)
lib678_LDADD = $(TESTUTIL_LIBS)
lib1301_SOURCES = lib1301.c $(SUPPORTFILES) $(TESTUTIL)
lib1301_LDADD = $(TESTUTIL_LIBS)
lib1485_SOURCES = lib1485.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1485_LDADD = $(TESTUTIL_LIBS)
lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL)
lib1500_LDADD = $(TESTUTIL_LIBS)
lib1501_SOURCES = lib1501.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1501_LDADD = $(TESTUTIL_LIBS)
lib1502_SOURCES = lib1502.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1502_LDADD = $(TESTUTIL_LIBS)
lib1502_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1502
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
lib1543_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1543
lib1545_SOURCES = lib1545.c $(SUPPORTFILES)
lib1545_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_DISABLE_DEPRECATION
lib1550_SOURCES = lib1550.c $(SUPPORTFILES)
lib1551_SOURCES = lib1551.c $(SUPPORTFILES)
lib1552_SOURCES = lib1552.c $(SUPPORTFILES) $(TESTUTIL)
lib1552_LDADD = $(TESTUTIL_LIBS)
lib1553_SOURCES = lib1553.c $(SUPPORTFILES) $(TESTUTIL)
lib1553_LDADD = $(TESTUTIL_LIBS)
lib1554_SOURCES = lib1554.c $(SUPPORTFILES)
lib1555_SOURCES = lib1555.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1555_LDADD = $(TESTUTIL_LIBS)
lib1556_SOURCES = lib1556.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1556_LDADD = $(TESTUTIL_LIBS)
lib1557_SOURCES = lib1557.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)







|







2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
lib1543_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1543
lib1545_SOURCES = lib1545.c $(SUPPORTFILES)
lib1545_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_DISABLE_DEPRECATION
lib1550_SOURCES = lib1550.c $(SUPPORTFILES)
lib1551_SOURCES = lib1551.c $(SUPPORTFILES)
lib1552_SOURCES = lib1552.c $(SUPPORTFILES) $(TESTUTIL)
lib1552_LDADD = $(TESTUTIL_LIBS)
lib1553_SOURCES = lib1553.c $(SUPPORTFILES) $(TSTTRACE) $(TESTUTIL)
lib1553_LDADD = $(TESTUTIL_LIBS)
lib1554_SOURCES = lib1554.c $(SUPPORTFILES)
lib1555_SOURCES = lib1555.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1555_LDADD = $(TESTUTIL_LIBS)
lib1556_SOURCES = lib1556.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1556_LDADD = $(TESTUTIL_LIBS)
lib1557_SOURCES = lib1557.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
2490
2491
2492
2493
2494
2495
2496




2497
2498
2499
2500
2501
2502
2503
lib1156$(EXEEXT): $(lib1156_OBJECTS) $(lib1156_DEPENDENCIES) $(EXTRA_lib1156_DEPENDENCIES) 
	@rm -f lib1156$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(lib1156_OBJECTS) $(lib1156_LDADD) $(LIBS)

lib1301$(EXEEXT): $(lib1301_OBJECTS) $(lib1301_DEPENDENCIES) $(EXTRA_lib1301_DEPENDENCIES) 
	@rm -f lib1301$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(lib1301_OBJECTS) $(lib1301_LDADD) $(LIBS)





lib1500$(EXEEXT): $(lib1500_OBJECTS) $(lib1500_DEPENDENCIES) $(EXTRA_lib1500_DEPENDENCIES) 
	@rm -f lib1500$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(lib1500_OBJECTS) $(lib1500_LDADD) $(LIBS)

lib1501$(EXEEXT): $(lib1501_OBJECTS) $(lib1501_DEPENDENCIES) $(EXTRA_lib1501_DEPENDENCIES) 
	@rm -f lib1501$(EXEEXT)







>
>
>
>







2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
lib1156$(EXEEXT): $(lib1156_OBJECTS) $(lib1156_DEPENDENCIES) $(EXTRA_lib1156_DEPENDENCIES) 
	@rm -f lib1156$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(lib1156_OBJECTS) $(lib1156_LDADD) $(LIBS)

lib1301$(EXEEXT): $(lib1301_OBJECTS) $(lib1301_DEPENDENCIES) $(EXTRA_lib1301_DEPENDENCIES) 
	@rm -f lib1301$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(lib1301_OBJECTS) $(lib1301_LDADD) $(LIBS)

lib1485$(EXEEXT): $(lib1485_OBJECTS) $(lib1485_DEPENDENCIES) $(EXTRA_lib1485_DEPENDENCIES) 
	@rm -f lib1485$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(lib1485_OBJECTS) $(lib1485_LDADD) $(LIBS)

lib1500$(EXEEXT): $(lib1500_OBJECTS) $(lib1500_DEPENDENCIES) $(EXTRA_lib1500_DEPENDENCIES) 
	@rm -f lib1500$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(lib1500_OBJECTS) $(lib1500_LDADD) $(LIBS)

lib1501$(EXEEXT): $(lib1501_OBJECTS) $(lib1501_DEPENDENCIES) $(EXTRA_lib1501_DEPENDENCIES) 
	@rm -f lib1501$(EXEEXT)
3551
3552
3553
3554
3555
3556
3557

3558
3559
3560
3561
3562
3563
3564
@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib672-warnless.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/timediff.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/warnless.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chkhostname.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/first.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1156.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1301.Po@am__quote@ # am--include-marker

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1500.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1501.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1502-first.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1502-lib1502.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1502-testutil.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1503-first.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1503-lib1502.Po@am__quote@ # am--include-marker







>







3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/lib672-warnless.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/timediff.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@../../lib/$(DEPDIR)/warnless.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chkhostname.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/first.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1156.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1301.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1485.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1500.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1501.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1502-first.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1502-lib1502.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1502-testutil.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1503-first.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib1503-lib1502.Po@am__quote@ # am--include-marker
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
@CURLDEBUG_FALSE@all-local:
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) all-local
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am








|







5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
@DEBUGBUILD_FALSE@all-local:
all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) all-local
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am

5537
5538
5539
5540
5541
5542
5543

5544
5545
5546
5547
5548
5549
5550
	-rm -f ../../lib/$(DEPDIR)/lib672-warnless.Po
	-rm -f ../../lib/$(DEPDIR)/timediff.Po
	-rm -f ../../lib/$(DEPDIR)/warnless.Po
	-rm -f ./$(DEPDIR)/chkhostname.Po
	-rm -f ./$(DEPDIR)/first.Po
	-rm -f ./$(DEPDIR)/lib1156.Po
	-rm -f ./$(DEPDIR)/lib1301.Po

	-rm -f ./$(DEPDIR)/lib1500.Po
	-rm -f ./$(DEPDIR)/lib1501.Po
	-rm -f ./$(DEPDIR)/lib1502-first.Po
	-rm -f ./$(DEPDIR)/lib1502-lib1502.Po
	-rm -f ./$(DEPDIR)/lib1502-testutil.Po
	-rm -f ./$(DEPDIR)/lib1503-first.Po
	-rm -f ./$(DEPDIR)/lib1503-lib1502.Po







>







5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
	-rm -f ../../lib/$(DEPDIR)/lib672-warnless.Po
	-rm -f ../../lib/$(DEPDIR)/timediff.Po
	-rm -f ../../lib/$(DEPDIR)/warnless.Po
	-rm -f ./$(DEPDIR)/chkhostname.Po
	-rm -f ./$(DEPDIR)/first.Po
	-rm -f ./$(DEPDIR)/lib1156.Po
	-rm -f ./$(DEPDIR)/lib1301.Po
	-rm -f ./$(DEPDIR)/lib1485.Po
	-rm -f ./$(DEPDIR)/lib1500.Po
	-rm -f ./$(DEPDIR)/lib1501.Po
	-rm -f ./$(DEPDIR)/lib1502-first.Po
	-rm -f ./$(DEPDIR)/lib1502-lib1502.Po
	-rm -f ./$(DEPDIR)/lib1502-testutil.Po
	-rm -f ./$(DEPDIR)/lib1503-first.Po
	-rm -f ./$(DEPDIR)/lib1503-lib1502.Po
5905
5906
5907
5908
5909
5910
5911

5912
5913
5914
5915
5916
5917
5918
	-rm -f ../../lib/$(DEPDIR)/lib672-warnless.Po
	-rm -f ../../lib/$(DEPDIR)/timediff.Po
	-rm -f ../../lib/$(DEPDIR)/warnless.Po
	-rm -f ./$(DEPDIR)/chkhostname.Po
	-rm -f ./$(DEPDIR)/first.Po
	-rm -f ./$(DEPDIR)/lib1156.Po
	-rm -f ./$(DEPDIR)/lib1301.Po

	-rm -f ./$(DEPDIR)/lib1500.Po
	-rm -f ./$(DEPDIR)/lib1501.Po
	-rm -f ./$(DEPDIR)/lib1502-first.Po
	-rm -f ./$(DEPDIR)/lib1502-lib1502.Po
	-rm -f ./$(DEPDIR)/lib1502-testutil.Po
	-rm -f ./$(DEPDIR)/lib1503-first.Po
	-rm -f ./$(DEPDIR)/lib1503-lib1502.Po







>







5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
	-rm -f ../../lib/$(DEPDIR)/lib672-warnless.Po
	-rm -f ../../lib/$(DEPDIR)/timediff.Po
	-rm -f ../../lib/$(DEPDIR)/warnless.Po
	-rm -f ./$(DEPDIR)/chkhostname.Po
	-rm -f ./$(DEPDIR)/first.Po
	-rm -f ./$(DEPDIR)/lib1156.Po
	-rm -f ./$(DEPDIR)/lib1301.Po
	-rm -f ./$(DEPDIR)/lib1485.Po
	-rm -f ./$(DEPDIR)/lib1500.Po
	-rm -f ./$(DEPDIR)/lib1501.Po
	-rm -f ./$(DEPDIR)/lib1502-first.Po
	-rm -f ./$(DEPDIR)/lib1502-lib1502.Po
	-rm -f ./$(DEPDIR)/lib1502-testutil.Po
	-rm -f ./$(DEPDIR)/lib1503-first.Po
	-rm -f ./$(DEPDIR)/lib1503-lib1502.Po
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
lib1521.c: $(top_srcdir)/tests/libtest/mk-lib1521.pl $(top_srcdir)/include/curl/curl.h
	@PERL@ $(top_srcdir)/tests/libtest/mk-lib1521.pl < $(top_srcdir)/include/curl/curl.h > lib1521.c

checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(srcdir)/*.[ch]

# for debug builds, we scan the sources on all regular make invokes
@CURLDEBUG_TRUE@all-local: checksrc

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:







|




6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
lib1521.c: $(top_srcdir)/tests/libtest/mk-lib1521.pl $(top_srcdir)/include/curl/curl.h
	@PERL@ $(top_srcdir)/tests/libtest/mk-lib1521.pl < $(top_srcdir)/include/curl/curl.h > lib1521.c

checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) $(srcdir)/*.[ch]

# for debug builds, we scan the sources on all regular make invokes
@DEBUGBUILD_TRUE@all-local: checksrc

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
Changes to jni/curl/tests/libtest/Makefile.inc.
50
51
52
53
54
55
56

57
58
59
60
61
62
63
 lib583 lib584 lib585 lib586 lib587 lib589 lib590 lib591 lib597 lib598   \
 lib599 \
 lib643        lib645 lib650 lib651 lib652 lib653 lib654 lib655 lib658   \
 lib659 lib661 lib666 lib667 lib668 \
 lib670 lib671 lib672 lib673 lib674 lib676 lib677 lib678 \
 lib1156 \
 lib1301 \

 lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \
 lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515         lib1517 \
 lib1518         lib1520 lib1521 lib1522 lib1523 \
 lib1525 lib1526 lib1527 lib1528 lib1529 lib1530 lib1531 lib1532 lib1533 \
 lib1534 lib1535 lib1536 lib1537 lib1538 lib1539 \
 lib1540 lib1541 lib1542 lib1543         lib1545 \
 lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \







>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 lib583 lib584 lib585 lib586 lib587 lib589 lib590 lib591 lib597 lib598   \
 lib599 \
 lib643        lib645 lib650 lib651 lib652 lib653 lib654 lib655 lib658   \
 lib659 lib661 lib666 lib667 lib668 \
 lib670 lib671 lib672 lib673 lib674 lib676 lib677 lib678 \
 lib1156 \
 lib1301 \
 lib1485 \
 lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \
 lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515         lib1517 \
 lib1518         lib1520 lib1521 lib1522 lib1523 \
 lib1525 lib1526 lib1527 lib1528 lib1529 lib1530 lib1531 lib1532 lib1533 \
 lib1534 lib1535 lib1536 lib1537 lib1538 lib1539 \
 lib1540 lib1541 lib1542 lib1543         lib1545 \
 lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 lib1556 lib1557 \
341
342
343
344
345
346
347



348
349
350
351
352
353
354
lib677_LDADD = $(TESTUTIL_LIBS)

lib678_SOURCES = lib678.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) $(MULTIBYTE)
lib678_LDADD = $(TESTUTIL_LIBS)

lib1301_SOURCES = lib1301.c $(SUPPORTFILES) $(TESTUTIL)
lib1301_LDADD = $(TESTUTIL_LIBS)




lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL)
lib1500_LDADD = $(TESTUTIL_LIBS)

lib1501_SOURCES = lib1501.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1501_LDADD = $(TESTUTIL_LIBS)








>
>
>







342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
lib677_LDADD = $(TESTUTIL_LIBS)

lib678_SOURCES = lib678.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) $(MULTIBYTE)
lib678_LDADD = $(TESTUTIL_LIBS)

lib1301_SOURCES = lib1301.c $(SUPPORTFILES) $(TESTUTIL)
lib1301_LDADD = $(TESTUTIL_LIBS)

lib1485_SOURCES = lib1485.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1485_LDADD = $(TESTUTIL_LIBS)

lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL)
lib1500_LDADD = $(TESTUTIL_LIBS)

lib1501_SOURCES = lib1501.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1501_LDADD = $(TESTUTIL_LIBS)

479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
lib1550_SOURCES = lib1550.c $(SUPPORTFILES)

lib1551_SOURCES = lib1551.c $(SUPPORTFILES)

lib1552_SOURCES = lib1552.c $(SUPPORTFILES) $(TESTUTIL)
lib1552_LDADD = $(TESTUTIL_LIBS)

lib1553_SOURCES = lib1553.c $(SUPPORTFILES) $(TESTUTIL)
lib1553_LDADD = $(TESTUTIL_LIBS)

lib1554_SOURCES = lib1554.c $(SUPPORTFILES)

lib1555_SOURCES = lib1555.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1555_LDADD = $(TESTUTIL_LIBS)








|







483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
lib1550_SOURCES = lib1550.c $(SUPPORTFILES)

lib1551_SOURCES = lib1551.c $(SUPPORTFILES)

lib1552_SOURCES = lib1552.c $(SUPPORTFILES) $(TESTUTIL)
lib1552_LDADD = $(TESTUTIL_LIBS)

lib1553_SOURCES = lib1553.c $(SUPPORTFILES) $(TSTTRACE) $(TESTUTIL)
lib1553_LDADD = $(TESTUTIL_LIBS)

lib1554_SOURCES = lib1554.c $(SUPPORTFILES)

lib1555_SOURCES = lib1555.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1555_LDADD = $(TESTUTIL_LIBS)

Added jni/curl/tests/libtest/lib1485.c.
















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "test.h"

#include "testutil.h"
#include "warnless.h"
#include "memdebug.h"

struct transfer_status {
  CURL *easy;
  curl_off_t out_len;
  size_t hd_line;
  CURLcode result;
  int http_status;
};

static size_t header_callback(void *ptr, size_t size, size_t nmemb,
                              void *userp)
{
  struct transfer_status *st = (struct transfer_status *)userp;
  const char *hd = ptr;
  size_t len = size * nmemb;
  CURLcode result;

  (void)fwrite(ptr, size, nmemb, stdout);
  ++st->hd_line;
  if(len == 2 && hd[0] == '\r' && hd[1] == '\n') {
    curl_off_t clen;
    long httpcode = 0;
    /* end of a response */
    result = curl_easy_getinfo(st->easy, CURLINFO_RESPONSE_CODE, &httpcode);
    fprintf(stderr, "header_callback, get status: %ld, %d\n",
            httpcode, result);
    if(httpcode < 100 || httpcode >= 1000) {
      fprintf(stderr, "header_callback, invalid status: %ld, %d\n",
              httpcode, result);
      return CURLE_WRITE_ERROR;
    }
    st->http_status = (int)httpcode;
    if(st->http_status >= 200 && st->http_status < 300) {
      result = curl_easy_getinfo(st->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,
                                 &clen);
      fprintf(stderr, "header_callback, info Content-Length: %ld, %d\n",
              (long)clen, result);
      if(result) {
        st->result = result;
        return CURLE_WRITE_ERROR;
      }
      if(clen < 0) {
        fprintf(stderr, "header_callback, expected known Content-Length, "
                "got: %ld\n", (long)clen);
        return CURLE_WRITE_ERROR;
      }
    }
  }
  return len;
}

static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
  struct transfer_status *st = (struct transfer_status *)userp;
  size_t len = size * nmemb;
  fwrite(ptr, size, nmemb, stdout);
  st->out_len += (curl_off_t)len;
  return len;
}

CURLcode test(char *URL)
{
  CURL *curls = NULL;
  CURLcode res = CURLE_OK;
  struct transfer_status st;

  start_test_timing();

  memset(&st, 0, sizeof(st));

  global_init(CURL_GLOBAL_ALL);

  easy_init(curls);
  st.easy = curls; /* to allow callbacks access */

  easy_setopt(curls, CURLOPT_URL, URL);
  easy_setopt(curls, CURLOPT_WRITEFUNCTION, write_callback);
  easy_setopt(curls, CURLOPT_WRITEDATA, &st);
  easy_setopt(curls, CURLOPT_HEADERFUNCTION, header_callback);
  easy_setopt(curls, CURLOPT_HEADERDATA, &st);

  easy_setopt(curls, CURLOPT_NOPROGRESS, 1L);

  res = curl_easy_perform(curls);

test_cleanup:

  curl_easy_cleanup(curls);
  curl_global_cleanup();

  return res; /* return the final return code */
}
Changes to jni/curl/tests/libtest/lib1553.c.
20
21
22
23
24
25
26

27
28
29
30
31
32
33
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "test.h"

#include "testutil.h"

#include "warnless.h"
#include "memdebug.h"

#define TEST_HANG_TIMEOUT 60 * 1000

static int xferinfo(void *p,
                    curl_off_t dltotal, curl_off_t dlnow,







>







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "test.h"

#include "testutil.h"
#include "testtrace.h"
#include "warnless.h"
#include "memdebug.h"

#define TEST_HANG_TIMEOUT 60 * 1000

static int xferinfo(void *p,
                    curl_off_t dltotal, curl_off_t dlnow,
70
71
72
73
74
75
76






77
78
79
80
81
82
83
  easy_setopt(curls, CURLOPT_HEADER, 1L);
  easy_setopt(curls, CURLOPT_VERBOSE, 1L);
  easy_setopt(curls, CURLOPT_MIMEPOST, mime);
  easy_setopt(curls, CURLOPT_USERPWD, "u:s");
  easy_setopt(curls, CURLOPT_XFERINFOFUNCTION, xferinfo);
  easy_setopt(curls, CURLOPT_NOPROGRESS, 1L);







  multi_add_handle(multi, curls);

  multi_perform(multi, &still_running);

  abort_on_test_timeout();

  while(still_running && counter--) {







>
>
>
>
>
>







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  easy_setopt(curls, CURLOPT_HEADER, 1L);
  easy_setopt(curls, CURLOPT_VERBOSE, 1L);
  easy_setopt(curls, CURLOPT_MIMEPOST, mime);
  easy_setopt(curls, CURLOPT_USERPWD, "u:s");
  easy_setopt(curls, CURLOPT_XFERINFOFUNCTION, xferinfo);
  easy_setopt(curls, CURLOPT_NOPROGRESS, 1L);

  libtest_debug_config.nohex = 1;
  libtest_debug_config.tracetime = 1;
  test_setopt(curls, CURLOPT_DEBUGDATA, &libtest_debug_config);
  easy_setopt(curls, CURLOPT_DEBUGFUNCTION, libtest_debug_cb);
  easy_setopt(curls, CURLOPT_VERBOSE, 1L);

  multi_add_handle(multi, curls);

  multi_perform(multi, &still_running);

  abort_on_test_timeout();

  while(still_running && counter--) {
Changes to jni/curl/tests/libtest/lib1560.c.
147
148
149
150
151
152
153



154
155
156
157
158
159
160
  CURLUPart part;
  const char *in;
  const char *out;
  CURLUcode ucode;
};

static const struct testcase get_parts_list[] ={



  {"https://curl.se:0/#",
   "https | [11] | [12] | [13] | curl.se | 0 | / | [16] | ",
   0, CURLU_GET_EMPTY, CURLUE_OK},
  {"https://curl.se/#",
   "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | ",
   0, CURLU_GET_EMPTY, CURLUE_OK},
  {"https://curl.se/?#",







>
>
>







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  CURLUPart part;
  const char *in;
  const char *out;
  CURLUcode ucode;
};

static const struct testcase get_parts_list[] ={
  {"curl.se",
   "[10] | [11] | [12] | [13] | curl.se | [15] | / | [16] | [17]",
   CURLU_GUESS_SCHEME, CURLU_NO_GUESS_SCHEME, CURLUE_OK},
  {"https://curl.se:0/#",
   "https | [11] | [12] | [13] | curl.se | 0 | / | [16] | ",
   0, CURLU_GET_EMPTY, CURLUE_OK},
  {"https://curl.se/#",
   "https | [11] | [12] | [13] | curl.se | [15] | / | [16] | ",
   0, CURLU_GET_EMPTY, CURLUE_OK},
  {"https://curl.se/?#",
522
523
524
525
526
527
528



529
530
531
532
533
534
535
  {"http:////user:password@example.com:1234/path/html?query=name#anchor",
   "",
   CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_SLASHES},
  {NULL, NULL, 0, 0, CURLUE_OK},
};

static const struct urltestcase get_url_list[] = {



  {"http://user@example.com?#",
   "http://user@example.com/?#",
   0, CURLU_GET_EMPTY, CURLUE_OK},
  /* WHATWG disgrees, it wants "https:/0.0.0.0/" */
  {"https://0x.0x.0", "https://0x.0x.0/", 0, 0, CURLUE_OK},

  {"https://example.com:000000000000000000000443/foo",







>
>
>







525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  {"http:////user:password@example.com:1234/path/html?query=name#anchor",
   "",
   CURLU_DEFAULT_SCHEME, 0, CURLUE_BAD_SLASHES},
  {NULL, NULL, 0, 0, CURLUE_OK},
};

static const struct urltestcase get_url_list[] = {
  {"example.com",
   "example.com/",
   CURLU_GUESS_SCHEME, CURLU_NO_GUESS_SCHEME, CURLUE_OK},
  {"http://user@example.com?#",
   "http://user@example.com/?#",
   0, CURLU_GET_EMPTY, CURLUE_OK},
  /* WHATWG disgrees, it wants "https:/0.0.0.0/" */
  {"https://0x.0x.0", "https://0x.0x.0/", 0, 0, CURLUE_OK},

  {"https://example.com:000000000000000000000443/foo",
Changes to jni/curl/tests/libtest/lib3026.c.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

#include "testutil.h"
#include "warnless.h"

#define NUM_THREADS 100

#ifdef _WIN32
#ifdef _WIN32_WCE
static DWORD WINAPI run_thread(LPVOID ptr)
#else
#include <process.h>
static unsigned int WINAPI run_thread(void *ptr)
#endif
{
  CURLcode *result = ptr;

  *result = curl_global_init(CURL_GLOBAL_ALL);
  if(*result == CURLE_OK)
    curl_global_cleanup();

  return 0;
}

CURLcode test(char *URL)
{
#ifdef _WIN32_WCE
  typedef HANDLE curl_win_thread_handle_t;
#else
  typedef uintptr_t curl_win_thread_handle_t;
#endif
  CURLcode results[NUM_THREADS];
  curl_win_thread_handle_t ths[NUM_THREADS];
  unsigned tid_count = NUM_THREADS, i;







|

















|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

#include "testutil.h"
#include "warnless.h"

#define NUM_THREADS 100

#ifdef _WIN32
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
static DWORD WINAPI run_thread(LPVOID ptr)
#else
#include <process.h>
static unsigned int WINAPI run_thread(void *ptr)
#endif
{
  CURLcode *result = ptr;

  *result = curl_global_init(CURL_GLOBAL_ALL);
  if(*result == CURLE_OK)
    curl_global_cleanup();

  return 0;
}

CURLcode test(char *URL)
{
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
  typedef HANDLE curl_win_thread_handle_t;
#else
  typedef uintptr_t curl_win_thread_handle_t;
#endif
  CURLcode results[NUM_THREADS];
  curl_win_thread_handle_t ths[NUM_THREADS];
  unsigned tid_count = NUM_THREADS, i;
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
     which would affect the test runtime. */
  (void)win32_load_system_library(TEXT("secur32.dll"));
  (void)win32_load_system_library(TEXT("iphlpapi.dll"));

  for(i = 0; i < tid_count; i++) {
    curl_win_thread_handle_t th;
    results[i] = CURL_LAST; /* initialize with invalid value */
#ifdef _WIN32_WCE
    th = CreateThread(NULL, 0, run_thread, &results[i], 0, NULL);
#else
    th = _beginthreadex(NULL, 0, run_thread, &results[i], 0, NULL);
#endif
    if(!th) {
      fprintf(stderr, "%s:%d Couldn't create thread, errno %lu\n",
              __FILE__, __LINE__, GetLastError());







|







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
     which would affect the test runtime. */
  (void)win32_load_system_library(TEXT("secur32.dll"));
  (void)win32_load_system_library(TEXT("iphlpapi.dll"));

  for(i = 0; i < tid_count; i++) {
    curl_win_thread_handle_t th;
    results[i] = CURL_LAST; /* initialize with invalid value */
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
    th = CreateThread(NULL, 0, run_thread, &results[i], 0, NULL);
#else
    th = _beginthreadex(NULL, 0, run_thread, &results[i], 0, NULL);
#endif
    if(!th) {
      fprintf(stderr, "%s:%d Couldn't create thread, errno %lu\n",
              __FILE__, __LINE__, GetLastError());
jni/curl/tests/libtest/mk-lib1521.pl became executable.
Changes to jni/curl/tests/libtest/test1013.pl.
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    $curl_protocols = lc($_) if ( /$what:/i );
}
close CURL;

$curl_protocols =~ s/\r//;
$curl_protocols =~ /\w+: (.*)$/;
@curl = split / /,$1;

# These features are not supported by curl-config
@curl = grep(!/^(Debug|TrackMemory|CharConv)$/i, @curl);
@curl = sort @curl;

# Read the output of curl-config
my @curl_config;
open(CURLCONFIG, "sh $ARGV[0] --$what|") || die "Can't get curl-config $what list\n";
while( <CURLCONFIG> )
{







<
<
<







40
41
42
43
44
45
46



47
48
49
50
51
52
53
    $curl_protocols = lc($_) if ( /$what:/i );
}
close CURL;

$curl_protocols =~ s/\r//;
$curl_protocols =~ /\w+: (.*)$/;
@curl = split / /,$1;



@curl = sort @curl;

# Read the output of curl-config
my @curl_config;
open(CURLCONFIG, "sh $ARGV[0] --$what|") || die "Can't get curl-config $what list\n";
while( <CURLCONFIG> )
{
Changes to jni/curl/tests/libtest/testutil.c.
129
130
131
132
133
134
135




136
137
138
139
140
141
142
      (double)(newer.tv_usec-older.tv_usec)/1000000.0;
  return (double)(newer.tv_usec-older.tv_usec)/1000000.0;
}

#ifdef _WIN32
HMODULE win32_load_system_library(const TCHAR *filename)
{




  size_t filenamelen = _tcslen(filename);
  size_t systemdirlen = GetSystemDirectory(NULL, 0);
  size_t written;
  TCHAR *path;

  if(!filenamelen || filenamelen > 32768 ||
     !systemdirlen || systemdirlen > 32768)







>
>
>
>







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
      (double)(newer.tv_usec-older.tv_usec)/1000000.0;
  return (double)(newer.tv_usec-older.tv_usec)/1000000.0;
}

#ifdef _WIN32
HMODULE win32_load_system_library(const TCHAR *filename)
{
#ifdef CURL_WINDOWS_APP
  (void)filename;
  return NULL;
#else
  size_t filenamelen = _tcslen(filename);
  size_t systemdirlen = GetSystemDirectory(NULL, 0);
  size_t written;
  TCHAR *path;

  if(!filenamelen || filenamelen > 32768 ||
     !systemdirlen || systemdirlen > 32768)
154
155
156
157
158
159
160

161
162

  if(path[written - 1] != _T('\\'))
    path[written++] = _T('\\');

  _tcscpy(path + written, filename);

  return LoadLibrary(path);

}
#endif







>


158
159
160
161
162
163
164
165
166
167

  if(path[written - 1] != _T('\\'))
    path[written++] = _T('\\');

  _tcscpy(path + written, filename);

  return LoadLibrary(path);
#endif
}
#endif
Changes to jni/curl/tests/runner.pm.
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
                $content = $1;

                if($var =~ /^LD_PRELOAD/) {
                    if(exe_ext('TOOL') && (exe_ext('TOOL') eq '.exe')) {
                        logmsg "Skipping LD_PRELOAD due to lack of OS support\n" if($verbose);
                        next;
                    }
                    if($feature{"debug"} || !$has_shared) {
                        logmsg "Skipping LD_PRELOAD due to no release shared build\n" if($verbose);
                        next;
                    }
                }
                $ENV{$var} = "$content";
                logmsg "setenv $var = $content\n" if($verbose);
            }







|







658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
                $content = $1;

                if($var =~ /^LD_PRELOAD/) {
                    if(exe_ext('TOOL') && (exe_ext('TOOL') eq '.exe')) {
                        logmsg "Skipping LD_PRELOAD due to lack of OS support\n" if($verbose);
                        next;
                    }
                    if($feature{"Debug"} || !$has_shared) {
                        logmsg "Skipping LD_PRELOAD due to no release shared build\n" if($verbose);
                        next;
                    }
                }
                $ENV{$var} = "$content";
                logmsg "setenv $var = $content\n" if($verbose);
            }
853
854
855
856
857
858
859

860
861
862
863
864
865
866

        if($cmdhash{'option'} && ($cmdhash{'option'} =~ /binary-trace/)) {
            $cmdargs .= "--trace $LOGDIR/trace$testnum ";
        }
        else {
            $cmdargs .= "--trace-ascii $LOGDIR/trace$testnum ";
        }

        $cmdargs .= "--trace-time ";
        if($run_event_based) {
            $cmdargs .= "--test-event ";
            $fail_due_event_based--;
        }
        $cmdargs .= $cmd;
        if ($proxy_address) {







>







853
854
855
856
857
858
859
860
861
862
863
864
865
866
867

        if($cmdhash{'option'} && ($cmdhash{'option'} =~ /binary-trace/)) {
            $cmdargs .= "--trace $LOGDIR/trace$testnum ";
        }
        else {
            $cmdargs .= "--trace-ascii $LOGDIR/trace$testnum ";
        }
        $cmdargs .= "--trace-config all ";
        $cmdargs .= "--trace-time ";
        if($run_event_based) {
            $cmdargs .= "--test-event ";
            $fail_due_event_based--;
        }
        $cmdargs .= $cmd;
        if ($proxy_address) {
Changes to jni/curl/tests/runtests.pl.
56
57
58
59
60
61
62

63
64
65
66
67
68
69
# fixed. As long as the -g option is never given, and the -n is always
# given, this won't be a problem.

use strict;
# Promote all warnings to fatal
use warnings FATAL => 'all';
use 5.006;


# These should be the only variables that might be needed to get edited:

BEGIN {
    # Define srcdir to the location of the tests source directory. This is
    # usually set by the Makefile, but for out-of-tree builds with direct
    # invocation of runtests.pl, it may not be set.







>







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# fixed. As long as the -g option is never given, and the -n is always
# given, this won't be a problem.

use strict;
# Promote all warnings to fatal
use warnings FATAL => 'all';
use 5.006;
use POSIX qw(strftime);

# These should be the only variables that might be needed to get edited:

BEGIN {
    # Define srcdir to the location of the tests source directory. This is
    # usually set by the Makefile, but for out-of-tree builds with direct
    # invocation of runtests.pl, it may not be set.
442
443
444
445
446
447
448







449
450
451
452
453
454
455
        else {
            # automakestyle
            logmsg "FAIL: $testnum - $testname - $subject\n";
        }
    }
    return $result;
}








#######################################################################
# Parse and store the protocols in curl's Protocols: line
sub parseprotocols {
    my ($line)=@_;

    @protocols = split(' ', lc($line));







>
>
>
>
>
>
>







443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
        else {
            # automakestyle
            logmsg "FAIL: $testnum - $testname - $subject\n";
        }
    }
    return $result;
}

#######################################################################
# Numeric-sort words in a string
sub numsortwords {
    my ($string)=@_;
    return join(' ', sort { $a <=> $b } split(' ', $string));
}

#######################################################################
# Parse and store the protocols in curl's Protocols: line
sub parseprotocols {
    my ($line)=@_;

    @protocols = split(' ', lc($line));
488
489
490
491
492
493
494




495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514


515
516
517
518
519
520
521

    unlink($curlverout);
    unlink($curlvererr);

    $versretval = runclient($versioncmd);
    $versnoexec = $!;





    open(my $versout, "<", "$curlverout");
    @version = <$versout>;
    close($versout);

    open(my $disabledh, "-|", "server/disabled".exe_ext('TOOL'));
    @disabled = <$disabledh>;
    close($disabledh);

    if($disabled[0]) {
        s/[\r\n]//g for @disabled;
        $dis = join(", ", @disabled);
    }

    $resolver="stock";
    for(@version) {
        chomp;

        if($_ =~ /^curl ([^ ]*)/) {
            $curl = $_;
            $CURLVERSION = $1;


            $curl =~ s/^(.*)(libcurl.*)/$1/g || die "Failure determining curl binary version";

            $libcurl = $2;
            if($curl =~ /linux|bsd|solaris/) {
                # system support LD_PRELOAD; may be disabled later
                $feature{"ld_preload"} = 1;
            }







>
>
>
>




















>
>







496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535

    unlink($curlverout);
    unlink($curlvererr);

    $versretval = runclient($versioncmd);
    $versnoexec = $!;

    my $current_time = int(time());
    $ENV{'SOURCE_DATE_EPOCH'} = $current_time;
    $DATE = strftime "%Y-%m-%d", gmtime($current_time);

    open(my $versout, "<", "$curlverout");
    @version = <$versout>;
    close($versout);

    open(my $disabledh, "-|", "server/disabled".exe_ext('TOOL'));
    @disabled = <$disabledh>;
    close($disabledh);

    if($disabled[0]) {
        s/[\r\n]//g for @disabled;
        $dis = join(", ", @disabled);
    }

    $resolver="stock";
    for(@version) {
        chomp;

        if($_ =~ /^curl ([^ ]*)/) {
            $curl = $_;
            $CURLVERSION = $1;
            $CURLVERNUM = $CURLVERSION;
            $CURLVERNUM =~ s/^([0-9.]+)(.*)/$1/; # leading dots and numbers
            $curl =~ s/^(.*)(libcurl.*)/$1/g || die "Failure determining curl binary version";

            $libcurl = $2;
            if($curl =~ /linux|bsd|solaris/) {
                # system support LD_PRELOAD; may be disabled later
                $feature{"ld_preload"} = 1;
            }
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
        }
        elsif($_ =~ /^Features: (.*)/i) {
            $feat = $1;

            # built with memory tracking support (--enable-curldebug); may be disabled later
            $feature{"TrackMemory"} = $feat =~ /TrackMemory/i;
            # curl was built with --enable-debug
            $feature{"debug"} = $feat =~ /debug/i;
            # ssl enabled
            $feature{"SSL"} = $feat =~ /SSL/i;
            # multiple ssl backends available.
            $feature{"MultiSSL"} = $feat =~ /MultiSSL/i;
            # large file support
            $feature{"large_file"} = $feat =~ /Largefile/i;
            # IDN support
            $feature{"idn"} = $feat =~ /IDN/i;
            # IPv6 support
            $feature{"ipv6"} = $feat =~ /IPv6/i;
            # Unix sockets support
            $feature{"unix-sockets"} = $feat =~ /UnixSockets/i;
            # libz compression
            $feature{"libz"} = $feat =~ /libz/i;
            # Brotli compression
            $feature{"brotli"} = $feat =~ /brotli/i;
            # Zstd compression
            $feature{"zstd"} = $feat =~ /zstd/i;
            # NTLM enabled
            $feature{"NTLM"} = $feat =~ /NTLM/i;
            # NTLM delegation to winbind daemon ntlm_auth helper enabled
            $feature{"NTLM_WB"} = $feat =~ /NTLM_WB/i;
            # SSPI enabled
            $feature{"SSPI"} = $feat =~ /SSPI/i;
            # GSS-API enabled
            $feature{"GSS-API"} = $feat =~ /GSS-API/i;
            # Kerberos enabled
            $feature{"Kerberos"} = $feat =~ /Kerberos/i;
            # SPNEGO enabled
            $feature{"SPNEGO"} = $feat =~ /SPNEGO/i;
            # CharConv enabled
            $feature{"CharConv"} = $feat =~ /CharConv/i;
            # TLS-SRP enabled
            $feature{"TLS-SRP"} = $feat =~ /TLS-SRP/i;
            # PSL enabled
            $feature{"PSL"} = $feat =~ /PSL/i;
            # alt-svc enabled
            $feature{"alt-svc"} = $feat =~ /alt-svc/i;
            # HSTS support







|





|

|

|

|


















<
<







616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653


654
655
656
657
658
659
660
        }
        elsif($_ =~ /^Features: (.*)/i) {
            $feat = $1;

            # built with memory tracking support (--enable-curldebug); may be disabled later
            $feature{"TrackMemory"} = $feat =~ /TrackMemory/i;
            # curl was built with --enable-debug
            $feature{"Debug"} = $feat =~ /Debug/i;
            # ssl enabled
            $feature{"SSL"} = $feat =~ /SSL/i;
            # multiple ssl backends available.
            $feature{"MultiSSL"} = $feat =~ /MultiSSL/i;
            # large file support
            $feature{"Largefile"} = $feat =~ /Largefile/i;
            # IDN support
            $feature{"IDN"} = $feat =~ /IDN/i;
            # IPv6 support
            $feature{"IPv6"} = $feat =~ /IPv6/i;
            # Unix sockets support
            $feature{"UnixSockets"} = $feat =~ /UnixSockets/i;
            # libz compression
            $feature{"libz"} = $feat =~ /libz/i;
            # Brotli compression
            $feature{"brotli"} = $feat =~ /brotli/i;
            # Zstd compression
            $feature{"zstd"} = $feat =~ /zstd/i;
            # NTLM enabled
            $feature{"NTLM"} = $feat =~ /NTLM/i;
            # NTLM delegation to winbind daemon ntlm_auth helper enabled
            $feature{"NTLM_WB"} = $feat =~ /NTLM_WB/i;
            # SSPI enabled
            $feature{"SSPI"} = $feat =~ /SSPI/i;
            # GSS-API enabled
            $feature{"GSS-API"} = $feat =~ /GSS-API/i;
            # Kerberos enabled
            $feature{"Kerberos"} = $feat =~ /Kerberos/i;
            # SPNEGO enabled
            $feature{"SPNEGO"} = $feat =~ /SPNEGO/i;


            # TLS-SRP enabled
            $feature{"TLS-SRP"} = $feat =~ /TLS-SRP/i;
            # PSL enabled
            $feature{"PSL"} = $feat =~ /PSL/i;
            # alt-svc enabled
            $feature{"alt-svc"} = $feat =~ /alt-svc/i;
            # HSTS support
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
            }
            # http3 enabled
            $feature{"http/3"} = $feat =~ /HTTP3/;
            if($feature{"http/3"}) {
                push @protocols, 'http/3';
            }
            # https proxy support
            $feature{"https-proxy"} = $feat =~ /HTTPS-proxy/;
            if($feature{"https-proxy"}) {
                # 'https-proxy' is used as "server" so consider it a protocol
                push @protocols, 'https-proxy';
            }
            # UNICODE support
            $feature{"Unicode"} = $feat =~ /Unicode/i;
            # Thread-safe init
            $feature{"threadsafe"} = $feat =~ /threadsafe/i;







|
|







673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
            }
            # http3 enabled
            $feature{"http/3"} = $feat =~ /HTTP3/;
            if($feature{"http/3"}) {
                push @protocols, 'http/3';
            }
            # https proxy support
            $feature{"HTTPS-proxy"} = $feat =~ /HTTPS-proxy/;
            if($feature{"HTTPS-proxy"}) {
                # 'https-proxy' is used as "server" so consider it a protocol
                push @protocols, 'https-proxy';
            }
            # UNICODE support
            $feature{"Unicode"} = $feat =~ /Unicode/i;
            # Thread-safe init
            $feature{"threadsafe"} = $feat =~ /threadsafe/i;
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
                $feature{"getrlimit"} = 1;
            }
        }
        close($conf);
    }

    # allow this feature only if debug mode is disabled
    $feature{"ld_preload"} = $feature{"ld_preload"} && !$feature{"debug"};

    if($feature{"ipv6"}) {
        # client has IPv6 support

        # check if the HTTP server has it!
        my $cmd = "server/sws".exe_ext('SRV')." --version";
        my @sws = `$cmd`;
        if($sws[0] =~ /IPv6/) {
            # HTTP server has IPv6 support!
            $http_ipv6 = 1;
        }

        # check if the FTP server has it!
        $cmd = "server/sockfilt".exe_ext('SRV')." --version";
        @sws = `$cmd`;
        if($sws[0] =~ /IPv6/) {
            # FTP server has IPv6 support!
            $ftp_ipv6 = 1;
        }
    }

    if($feature{"unix-sockets"}) {
        # client has Unix sockets support, check whether the HTTP server has it
        my $cmd = "server/sws".exe_ext('SRV')." --version";
        my @sws = `$cmd`;
        $http_unix = 1 if($sws[0] =~ /unix/);
    }

    open(my $manh, "-|", shell_quote($CURL) . " -M 2>&1");
    while(my $s = <$manh>) {
        if($s =~ /built-in manual was disabled at build-time/) {
            $feature{"manual"} = 0;
            last;
        }
        $feature{"manual"} = 1;
        last;
    }
    close($manh);

    $feature{"unittest"} = $feature{"debug"};
    $feature{"nghttpx"} = !!$ENV{'NGHTTPX'};
    $feature{"nghttpx-h3"} = !!$nghttpx_h3;

    #
    # strings that must exactly match the names used in server/disabled.c
    #
    $feature{"cookies"} = 1;







|

|



















|

















|







740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
                $feature{"getrlimit"} = 1;
            }
        }
        close($conf);
    }

    # allow this feature only if debug mode is disabled
    $feature{"ld_preload"} = $feature{"ld_preload"} && !$feature{"Debug"};

    if($feature{"IPv6"}) {
        # client has IPv6 support

        # check if the HTTP server has it!
        my $cmd = "server/sws".exe_ext('SRV')." --version";
        my @sws = `$cmd`;
        if($sws[0] =~ /IPv6/) {
            # HTTP server has IPv6 support!
            $http_ipv6 = 1;
        }

        # check if the FTP server has it!
        $cmd = "server/sockfilt".exe_ext('SRV')." --version";
        @sws = `$cmd`;
        if($sws[0] =~ /IPv6/) {
            # FTP server has IPv6 support!
            $ftp_ipv6 = 1;
        }
    }

    if($feature{"UnixSockets"}) {
        # client has Unix sockets support, check whether the HTTP server has it
        my $cmd = "server/sws".exe_ext('SRV')." --version";
        my @sws = `$cmd`;
        $http_unix = 1 if($sws[0] =~ /unix/);
    }

    open(my $manh, "-|", shell_quote($CURL) . " -M 2>&1");
    while(my $s = <$manh>) {
        if($s =~ /built-in manual was disabled at build-time/) {
            $feature{"manual"} = 0;
            last;
        }
        $feature{"manual"} = 1;
        last;
    }
    close($manh);

    $feature{"unittest"} = $feature{"Debug"};
    $feature{"nghttpx"} = !!$ENV{'NGHTTPX'};
    $feature{"nghttpx-h3"} = !!$nghttpx_h3;

    #
    # strings that must exactly match the names used in server/disabled.c
    #
    $feature{"cookies"} = 1;
1299
1300
1301
1302
1303
1304
1305




1306
1307
1308
1309
1310
1311
1312
        }

        if($hash{'nonewline'}) {
            # Yes, we must cut off the final newline from the final line
            # of the protocol data
            chomp($validstderr[-1]);
        }





        $res = compare($runnerid, $testnum, $testname, "stderr", \@actual, \@validstderr);
        if($res) {
            return -1;
        }
        $ok .= "r";
    }







>
>
>
>







1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
        }

        if($hash{'nonewline'}) {
            # Yes, we must cut off the final newline from the final line
            # of the protocol data
            chomp($validstderr[-1]);
        }

        if($hash{'crlf'}) {
            subnewlines(0, \$_) for @validstderr;
        }

        $res = compare($runnerid, $testnum, $testname, "stderr", \@actual, \@validstderr);
        if($res) {
            return -1;
        }
        $ok .= "r";
    }
1441
1442
1443
1444
1445
1446
1447



1448
1449
1450
1451
1452
1453
1454
    # if this section exists, we verify upload
    my @upload = getpart("verify", "upload");
    if(@upload) {
        my %hash = getpartattr("verify", "upload");
        if($hash{'nonewline'}) {
            # cut off the final newline from the final line of the upload data
            chomp($upload[-1]);



        }

        # verify uploaded data
        my @out = loadarray("$logdir/upload.$testnum");
        for my $strip (@strippart) {
            chomp $strip;
            for(@out) {







>
>
>







1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
    # if this section exists, we verify upload
    my @upload = getpart("verify", "upload");
    if(@upload) {
        my %hash = getpartattr("verify", "upload");
        if($hash{'nonewline'}) {
            # cut off the final newline from the final line of the upload data
            chomp($upload[-1]);
        }
        for my $line (@upload) {
            subbase64(\$line);
        }

        # verify uploaded data
        my @out = loadarray("$logdir/upload.$testnum");
        for my $strip (@strippart) {
            chomp $strip;
            for(@out) {
3015
3016
3017
3018
3019
3020
3021
3022




















3023
3024


3025
3026
3027
3028
3029
3030



3031
3032
3033
3034
3035
3036
3037
3038
        $log_line .= ")\n";
        $restraints{$log_line} = $skip_count;
    }
    foreach my $log_line (sort {$restraints{$b} <=> $restraints{$a}} keys %restraints) {
        logmsg $log_line;
    }
}





















if($total) {
    if($failedign) {


        logmsg "IGNORED: failed tests: $failedign\n";
    }
    logmsg sprintf("TESTDONE: $ok tests out of $total reported OK: %d%%\n",
                   $ok/$total*100);

    if($failed && ($ok != $total)) {



        logmsg "\nTESTFAIL: These test cases failed: $failed\n\n";
    }
}
else {
    logmsg "\nTESTFAIL: No tests were performed\n\n";
    if(scalar(keys %enabled_keywords)) {
        logmsg "TESTFAIL: Nothing matched these keywords: ";
        for(keys %enabled_keywords) {








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


>
>
|





>
>
>
|







3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
        $log_line .= ")\n";
        $restraints{$log_line} = $skip_count;
    }
    foreach my $log_line (sort {$restraints{$b} <=> $restraints{$a}} keys %restraints) {
        logmsg $log_line;
    }
}

sub testnumdetails {
    my ($desc, $numlist) = @_;
    foreach my $testnum (split(' ', $numlist)) {
        if(!loadtest("${TESTDIR}/test${testnum}")) {
            my @info_keywords = getpart("info", "keywords");
            my $testname = (getpart("client", "name"))[0];
            chomp $testname;
            logmsg "$desc $testnum: '$testname'";
            my $first = 1;
            for my $k (@info_keywords) {
                chomp $k;
                my $sep = ($first == 1) ? " " : ", ";
                logmsg "$sep$k";
                $first = 0;
            }
            logmsg "\n";
        }
    }
}

if($total) {
    if($failedign) {
        my $failedignsorted = numsortwords($failedign);
        testnumdetails("FAIL-IGNORED", $failedignsorted);
        logmsg "IGNORED: failed tests: $failedignsorted\n";
    }
    logmsg sprintf("TESTDONE: $ok tests out of $total reported OK: %d%%\n",
                   $ok/$total*100);

    if($failed && ($ok != $total)) {
        my $failedsorted = numsortwords($failed);
        logmsg "\n";
        testnumdetails("FAIL", $failedsorted);
        logmsg "\nTESTFAIL: These test cases failed: $failedsorted\n\n";
    }
}
else {
    logmsg "\nTESTFAIL: No tests were performed\n\n";
    if(scalar(keys %enabled_keywords)) {
        logmsg "TESTFAIL: Nothing matched these keywords: ";
        for(keys %enabled_keywords) {
Changes to jni/curl/tests/server/CMakeLists.txt.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
###########################################################################
set(TARGET_LABEL_PREFIX "Test server ")

if(MSVC)
  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4306")
endif()

function(SETUP_EXECUTABLE TEST_NAME)    # ARGN are the files in the test
  add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${ARGN})
  add_dependencies(testdeps ${TEST_NAME})
  string(TOUPPER ${TEST_NAME} UPPER_TEST_NAME)

  include_directories(
    ${CURL_SOURCE_DIR}/lib      # To be able to reach "curl_setup_once.h"
    ${CURL_BINARY_DIR}/lib      # To be able to reach "curl_config.h"
    ${CURL_BINARY_DIR}/include  # To be able to reach "curl/curl.h"
    ${CURL_SOURCE_DIR}/src      # To be able to reach "tool_xattr.h"
    )
  if(USE_ARES)
    include_directories(${CARES_INCLUDE_DIR})
  endif()

  target_link_libraries(${TEST_NAME} ${CURL_LIBS})

  # Test servers simply are standalone programs that do not use libcurl
  # library.  For convenience and to ease portability of these servers,
  # some source code files from the libcurl subdirectory are also used
  # to build the servers.  In order to achieve proper linkage of these
  # files on Win32 targets it is necessary to build the test servers
  # with CURL_STATICLIB defined, independently of how libcurl is built.
  set_target_properties(${TEST_NAME} PROPERTIES
    COMPILE_DEFINITIONS CURL_STATICLIB)       # ${UPPER_TEST_NAME}
  set_target_properties(${TEST_NAME} PROPERTIES
    PROJECT_LABEL "${TARGET_LABEL_PREFIX}${TEST_NAME}")
endfunction()


transform_makefile_inc("Makefile.inc"
  "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)

foreach(EXECUTABLE_NAME ${noinst_PROGRAMS})
  setup_executable(${EXECUTABLE_NAME} ${${EXECUTABLE_NAME}_SOURCES})
endforeach()


# SET(useful
# getpart.c getpart.h
# ${CURL_SOURCE_DIR}/lib/strequal.c
# ${CURL_SOURCE_DIR}/lib/base64.c
# ${CURL_SOURCE_DIR}/lib/mprintf.c
# ${CURL_SOURCE_DIR}/lib/memdebug.c
# ${CURL_SOURCE_DIR}/lib/timeval.c
# )

# SETUP_EXECUTABLE(sws sws.c util.c util.h ${useful})
# SETUP_EXECUTABLE(resolve resolve.c util.c util.h ${useful})
# SETUP_EXECUTABLE(sockfilt sockfilt.c util.c util.h ${useful} ${CURL_SOURCE_DIR}/lib/inet_pton.c)
# SETUP_EXECUTABLE(getpart testpart.c ${useful})
# SETUP_EXECUTABLE(tftpd tftpd.c util.c util.h ${useful} tftp.h)







|





|
|
|
|














|














|
|
|
|
|
|
|


|
|
|
|
|
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
###########################################################################
set(TARGET_LABEL_PREFIX "Test server ")

if(MSVC)
  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4306")
endif()

function(SETUP_EXECUTABLE TEST_NAME)  # ARGN are the files in the test
  add_executable(${TEST_NAME} EXCLUDE_FROM_ALL ${ARGN})
  add_dependencies(testdeps ${TEST_NAME})
  string(TOUPPER ${TEST_NAME} UPPER_TEST_NAME)

  include_directories(
    ${CURL_SOURCE_DIR}/lib      # for "curl_setup_once.h"
    ${CURL_BINARY_DIR}/lib      # for "curl_config.h"
    ${CURL_BINARY_DIR}/include  # for "curl/curl.h"
    ${CURL_SOURCE_DIR}/src      # for "tool_xattr.h"
    )
  if(USE_ARES)
    include_directories(${CARES_INCLUDE_DIR})
  endif()

  target_link_libraries(${TEST_NAME} ${CURL_LIBS})

  # Test servers simply are standalone programs that do not use libcurl
  # library.  For convenience and to ease portability of these servers,
  # some source code files from the libcurl subdirectory are also used
  # to build the servers.  In order to achieve proper linkage of these
  # files on Win32 targets it is necessary to build the test servers
  # with CURL_STATICLIB defined, independently of how libcurl is built.
  set_target_properties(${TEST_NAME} PROPERTIES
    COMPILE_DEFINITIONS CURL_STATICLIB)  # ${UPPER_TEST_NAME}
  set_target_properties(${TEST_NAME} PROPERTIES
    PROJECT_LABEL "${TARGET_LABEL_PREFIX}${TEST_NAME}")
endfunction()


transform_makefile_inc("Makefile.inc"
  "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)

foreach(EXECUTABLE_NAME ${noinst_PROGRAMS})
  setup_executable(${EXECUTABLE_NAME} ${${EXECUTABLE_NAME}_SOURCES})
endforeach()


# set(useful
#   getpart.c getpart.h
#   ${CURL_SOURCE_DIR}/lib/strequal.c
#   ${CURL_SOURCE_DIR}/lib/base64.c
#   ${CURL_SOURCE_DIR}/lib/mprintf.c
#   ${CURL_SOURCE_DIR}/lib/memdebug.c
#   ${CURL_SOURCE_DIR}/lib/timeval.c
# )

# setup_executable(sws sws.c util.c util.h ${useful})
# setup_executable(resolve resolve.c util.c util.h ${useful})
# setup_executable(sockfilt sockfilt.c util.c util.h ${useful} ${CURL_SOURCE_DIR}/lib/inet_pton.c)
# setup_executable(getpart testpart.c ${useful})
# setup_executable(tftpd tftpd.c util.c util.h ${useful} tftp.h)
Changes to jni/curl/tests/server/Makefile.am.
55
56
57
58
59
60
61
62
63
64
65
CS_0 = @echo "  RUN     " $@;
CS_1 =
CS_ = $(CS_0)

checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl $(srcdir)/*.[ch]

if CURLDEBUG
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif







|



55
56
57
58
59
60
61
62
63
64
65
CS_0 = @echo "  RUN     " $@;
CS_1 =
CS_ = $(CS_0)

checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl $(srcdir)/*.[ch]

if DEBUGBUILD
# for debug builds, we scan the sources on all regular make invokes
all-local: checksrc
endif
Changes to jni/curl/tests/server/Makefile.in.
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







135
136
137
138
139
140
141

142
143
144
145
146
147
148
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
615
616
617
618
619
620
621


622
623
624
625
626
627
628
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@







>
>







614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
@CURLDEBUG_FALSE@all-local:
all-am: Makefile $(PROGRAMS) all-local
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am








|







3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
	    test -f "$(distdir)/$$file" \
	    || cp -p $$d/$$file "$(distdir)/$$file" \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
@DEBUGBUILD_FALSE@all-local:
all-am: Makefile $(PROGRAMS) all-local
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am

3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
.PRECIOUS: Makefile


checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl $(srcdir)/*.[ch]

# for debug builds, we scan the sources on all regular make invokes
@CURLDEBUG_TRUE@all-local: checksrc

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:







|




3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
.PRECIOUS: Makefile


checksrc:
	$(CHECKSRC)@PERL@ $(top_srcdir)/scripts/checksrc.pl $(srcdir)/*.[ch]

# for debug builds, we scan the sources on all regular make invokes
@DEBUGBUILD_TRUE@all-local: checksrc

# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
Changes to jni/curl/tests/server/sockfilt.c.
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
enum sockmode {
  PASSIVE_LISTEN,    /* as a server waiting for connections */
  PASSIVE_CONNECT,   /* as a server, connected to a client */
  ACTIVE,            /* as a client, connected to a server */
  ACTIVE_DISCONNECT  /* as a client, disconnected from server */
};

#ifdef _WIN32
/*
 * read-wrapper to support reading from stdin on Windows.
 */
static ssize_t read_wincon(int fd, void *buf, size_t count)
{
  HANDLE handle = NULL;
  DWORD mode, rcount = 0;







|







148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
enum sockmode {
  PASSIVE_LISTEN,    /* as a server waiting for connections */
  PASSIVE_CONNECT,   /* as a server, connected to a client */
  ACTIVE,            /* as a client, connected to a server */
  ACTIVE_DISCONNECT  /* as a client, disconnected from server */
};

#if defined(_WIN32) && !defined(CURL_WINDOWS_APP)
/*
 * read-wrapper to support reading from stdin on Windows.
 */
static ssize_t read_wincon(int fd, void *buf, size_t count)
{
  HANDLE handle = NULL;
  DWORD mode, rcount = 0;
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430

  lograw(buffer, *buffer_len);

  return TRUE;
}


#ifdef USE_WINSOCK
/*
 * WinSock select() does not support standard file descriptors,
 * it can only check SOCKETs. The following function is an attempt
 * to re-create a select() function with support for other handle types.
 *
 * select() function with support for WINSOCK2 sockets and all
 * other handle types supported by WaitForMultipleObjectsEx() as







|







416
417
418
419
420
421
422
423
424
425
426
427
428
429
430

  lograw(buffer, *buffer_len);

  return TRUE;
}


#if defined(USE_WINSOCK) && !defined(CURL_WINDOWS_APP)
/*
 * WinSock select() does not support standard file descriptors,
 * it can only check SOCKETs. The following function is an attempt
 * to re-create a select() function with support for other handle types.
 *
 * select() function with support for WINSOCK2 sockets and all
 * other handle types supported by WaitForMultipleObjectsEx() as
917
918
919
920
921
922
923

924
925
926
927
928
929
930
931
932
933
934
935
      else if(!memcmp("DISC", buffer, 4)) {
        logmsg("Crikey! Client also wants to disconnect");
        if(!write_stdout("ACKD\n", 5))
          return FALSE;
      }
      else if(!memcmp("DATA", buffer, 4)) {
        /* We must read more data to stay in sync */

        if(!read_data_block(buffer, sizeof(buffer), &buffer_len))
          return FALSE;

        logmsg("Throwing again %zd data bytes", buffer_len);

      }
      else if(!memcmp("QUIT", buffer, 4)) {
        /* just die */
        logmsg("quits");
        return FALSE;
      }
      else {







>



<
<







917
918
919
920
921
922
923
924
925
926
927


928
929
930
931
932
933
934
      else if(!memcmp("DISC", buffer, 4)) {
        logmsg("Crikey! Client also wants to disconnect");
        if(!write_stdout("ACKD\n", 5))
          return FALSE;
      }
      else if(!memcmp("DATA", buffer, 4)) {
        /* We must read more data to stay in sync */
        logmsg("Throwing away data bytes");
        if(!read_data_block(buffer, sizeof(buffer), &buffer_len))
          return FALSE;



      }
      else if(!memcmp("QUIT", buffer, 4)) {
        /* just die */
        logmsg("quits");
        return FALSE;
      }
      else {
Changes to jni/curl/tests/server/util.c.
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  } while(res && ((error = errno) == EINTR));
  if(res)
    logmsg("Error removing lock file %s error: %d %s",
           filename, error, strerror(error));
}


#if defined(_WIN32) && !defined(MSDOS)

static struct timeval tvnow(void)
{
  /*
  ** GetTickCount() is available on _all_ Windows versions from W95 up
  ** to nowadays. Returns milliseconds elapsed since last system boot,
  ** increases monotonically and wraps once 49.7 days have elapsed.







|







362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  } while(res && ((error = errno) == EINTR));
  if(res)
    logmsg("Error removing lock file %s error: %d %s",
           filename, error, strerror(error));
}


#if defined(_WIN32)

static struct timeval tvnow(void)
{
  /*
  ** GetTickCount() is available on _all_ Windows versions from W95 up
  ** to nowadays. Returns milliseconds elapsed since last system boot,
  ** increases monotonically and wraps once 49.7 days have elapsed.
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
#endif

#if defined(SIGBREAK) && defined(_WIN32)
static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
#endif

#ifdef _WIN32
#ifdef _WIN32_WCE
static DWORD thread_main_id = 0;
#else
static unsigned int thread_main_id = 0;
#endif
static HANDLE thread_main_window = NULL;
static HWND hidden_main_window = NULL;







|







489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
static SIGHANDLER_T old_sigterm_handler = SIG_ERR;
#endif

#if defined(SIGBREAK) && defined(_WIN32)
static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
#endif

#if defined(_WIN32) && !defined(CURL_WINDOWS_APP)
#ifdef _WIN32_WCE
static DWORD thread_main_id = 0;
#else
static unsigned int thread_main_id = 0;
#endif
static HANDLE thread_main_window = NULL;
static HWND hidden_main_window = NULL;
570
571
572
573
574
575
576



577
578
579
580
581
582
583
  }
  if(signum) {
    logmsg("ctrl_event_handler: %lu -> %d", dwCtrlType, signum);
    raise(signum);
  }
  return TRUE;
}



/* Window message handler for Windows applications to add support
 * for graceful process termination via taskkill (without /f) which
 * sends WM_CLOSE to all Windows of a process (even hidden ones).
 *
 * Therefore we create and run a hidden Window in a separate thread
 * to receive and handle the WM_CLOSE message as SIGTERM signal.
 */







>
>
>







570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  }
  if(signum) {
    logmsg("ctrl_event_handler: %lu -> %d", dwCtrlType, signum);
    raise(signum);
  }
  return TRUE;
}
#endif

#if defined(_WIN32) && !defined(CURL_WINDOWS_APP)
/* Window message handler for Windows applications to add support
 * for graceful process termination via taskkill (without /f) which
 * sends WM_CLOSE to all Windows of a process (even hidden ones).
 *
 * Therefore we create and run a hidden Window in a separate thread
 * to receive and handle the WM_CLOSE message as SIGTERM signal.
 */
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
  return oldhdlr;
#endif
}

void install_signal_handlers(bool keep_sigalrm)
{
#ifdef _WIN32
#ifdef _WIN32_WCE
  typedef HANDLE curl_win_thread_handle_t;
#else
  typedef uintptr_t curl_win_thread_handle_t;
#endif
  curl_win_thread_handle_t thread;
  /* setup windows exit event before any signal can trigger */
  exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
  if(!exit_event)
    logmsg("cannot create exit event");
#endif
#ifdef SIGHUP
  /* ignore SIGHUP signal */







<
<
<
<
<
<







686
687
688
689
690
691
692






693
694
695
696
697
698
699
  return oldhdlr;
#endif
}

void install_signal_handlers(bool keep_sigalrm)
{
#ifdef _WIN32






  /* setup windows exit event before any signal can trigger */
  exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
  if(!exit_event)
    logmsg("cannot create exit event");
#endif
#ifdef SIGHUP
  /* ignore SIGHUP signal */
737
738
739
740
741
742
743



744






745
746
747
748
749
750
751
752
753


754
755
756
757
758
759
760
  old_sigbreak_handler = set_signal(SIGBREAK, exit_signal_handler, TRUE);
  if(old_sigbreak_handler == SIG_ERR)
    logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
#endif
#ifdef _WIN32
  if(!SetConsoleCtrlHandler(ctrl_event_handler, TRUE))
    logmsg("cannot install CTRL event handler");



#ifdef _WIN32_WCE






  thread = CreateThread(NULL, 0, &main_window_loop,
                        (LPVOID)GetModuleHandle(NULL), 0, &thread_main_id);
#else
  thread = _beginthreadex(NULL, 0, &main_window_loop,
                          (void *)GetModuleHandle(NULL), 0, &thread_main_id);
#endif
  thread_main_window = (HANDLE)thread;
  if(!thread_main_window || !thread_main_id)
    logmsg("cannot start main window loop");


#endif
}

void restore_signal_handlers(bool keep_sigalrm)
{
#ifdef SIGHUP
  if(SIG_ERR != old_sighup_handler)







>
>
>

>
>
>
>
>
>
|
|

|
|

|
|
|
>
>







734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
  old_sigbreak_handler = set_signal(SIGBREAK, exit_signal_handler, TRUE);
  if(old_sigbreak_handler == SIG_ERR)
    logmsg("cannot install SIGBREAK handler: %s", strerror(errno));
#endif
#ifdef _WIN32
  if(!SetConsoleCtrlHandler(ctrl_event_handler, TRUE))
    logmsg("cannot install CTRL event handler");

#ifndef CURL_WINDOWS_APP
  {
#ifdef _WIN32_WCE
    typedef HANDLE curl_win_thread_handle_t;
#else
    typedef uintptr_t curl_win_thread_handle_t;
#endif
    curl_win_thread_handle_t thread;
#ifdef _WIN32_WCE
    thread = CreateThread(NULL, 0, &main_window_loop,
                          (LPVOID)GetModuleHandle(NULL), 0, &thread_main_id);
#else
    thread = _beginthreadex(NULL, 0, &main_window_loop,
                            (void *)GetModuleHandle(NULL), 0, &thread_main_id);
#endif
    thread_main_window = (HANDLE)thread;
    if(!thread_main_window || !thread_main_id)
      logmsg("cannot start main window loop");
  }
#endif
#endif
}

void restore_signal_handlers(bool keep_sigalrm)
{
#ifdef SIGHUP
  if(SIG_ERR != old_sighup_handler)
782
783
784
785
786
787
788

789
790
791
792
793
794
795
796
797
798
799
800
801
802
803

804
805
806
807
808
809
810
#endif
#if defined(SIGBREAK) && defined(_WIN32)
  if(SIG_ERR != old_sigbreak_handler)
    (void) set_signal(SIGBREAK, old_sigbreak_handler, FALSE);
#endif
#ifdef _WIN32
  (void)SetConsoleCtrlHandler(ctrl_event_handler, FALSE);

  if(thread_main_window && thread_main_id) {
    if(PostThreadMessage(thread_main_id, WM_APP, 0, 0)) {
      if(WaitForSingleObjectEx(thread_main_window, INFINITE, TRUE)) {
        if(CloseHandle(thread_main_window)) {
          thread_main_window = NULL;
          thread_main_id = 0;
        }
      }
    }
  }
  if(exit_event) {
    if(CloseHandle(exit_event)) {
      exit_event = NULL;
    }
  }

#endif
}

#ifdef USE_UNIX_SOCKETS

int bind_unix_socket(curl_socket_t sock, const char *unix_socket,
        struct sockaddr_un *sau) {







>















>







790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
#endif
#if defined(SIGBREAK) && defined(_WIN32)
  if(SIG_ERR != old_sigbreak_handler)
    (void) set_signal(SIGBREAK, old_sigbreak_handler, FALSE);
#endif
#ifdef _WIN32
  (void)SetConsoleCtrlHandler(ctrl_event_handler, FALSE);
#ifndef CURL_WINDOWS_APP
  if(thread_main_window && thread_main_id) {
    if(PostThreadMessage(thread_main_id, WM_APP, 0, 0)) {
      if(WaitForSingleObjectEx(thread_main_window, INFINITE, TRUE)) {
        if(CloseHandle(thread_main_window)) {
          thread_main_window = NULL;
          thread_main_id = 0;
        }
      }
    }
  }
  if(exit_event) {
    if(CloseHandle(exit_event)) {
      exit_event = NULL;
    }
  }
#endif
#endif
}

#ifdef USE_UNIX_SOCKETS

int bind_unix_socket(curl_socket_t sock, const char *unix_socket,
        struct sockaddr_un *sau) {
Changes to jni/curl/tests/servers.pm.
2966
2967
2968
2969
2970
2971
2972


2973
2974
2975
2976
2977
2978
2979

    # misc
    $$thing =~ s/${prefix}CURL/$CURL/g;
    $$thing =~ s/${prefix}LOGDIR/$LOGDIR/g;
    $$thing =~ s/${prefix}PWD/$pwd/g;
    $$thing =~ s/${prefix}POSIX_PWD/$posix_pwd/g;
    $$thing =~ s/${prefix}VERSION/$CURLVERSION/g;


    $$thing =~ s/${prefix}TESTNUMBER/$testnum/g;

    my $file_pwd = $pwd;
    if($file_pwd !~ /^\//) {
        $file_pwd = "/$file_pwd";
    }
    my $ssh_pwd = $posix_pwd;







>
>







2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981

    # misc
    $$thing =~ s/${prefix}CURL/$CURL/g;
    $$thing =~ s/${prefix}LOGDIR/$LOGDIR/g;
    $$thing =~ s/${prefix}PWD/$pwd/g;
    $$thing =~ s/${prefix}POSIX_PWD/$posix_pwd/g;
    $$thing =~ s/${prefix}VERSION/$CURLVERSION/g;
    $$thing =~ s/${prefix}VERNUM/$CURLVERNUM/g;
    $$thing =~ s/${prefix}DATE/$DATE/g;
    $$thing =~ s/${prefix}TESTNUMBER/$testnum/g;

    my $file_pwd = $pwd;
    if($file_pwd !~ /^\//) {
        $file_pwd = "/$file_pwd";
    }
    my $ssh_pwd = $posix_pwd;
Changes to jni/curl/tests/sshserver.pl.
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
if ($sshdid =~ /OpenSSH-Windows/) {
    # Ensure to use native Windows paths with OpenSSH for Windows
    $identity_config = pathhelp::sys_native_abs_path(pp($identity));
    $knownhosts_config = pathhelp::sys_native_abs_path(pp($knownhosts));
}
elsif (pathhelp::os_is_win()) {
    # Ensure to use MinGW/Cygwin paths
    $identity_config = pathhelp::build_sys_abs_path($identity_config);
    $knownhosts_config = pathhelp::build_sys_abs_path($knownhosts_config);
}
else {
    $identity_config = abs_path(pp($identity));
    $knownhosts_config = abs_path(pp($knownhosts));
}









|
|







843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
if ($sshdid =~ /OpenSSH-Windows/) {
    # Ensure to use native Windows paths with OpenSSH for Windows
    $identity_config = pathhelp::sys_native_abs_path(pp($identity));
    $knownhosts_config = pathhelp::sys_native_abs_path(pp($knownhosts));
}
elsif (pathhelp::os_is_win()) {
    # Ensure to use MinGW/Cygwin paths
    $identity_config = pathhelp::build_sys_abs_path($identity);
    $knownhosts_config = pathhelp::build_sys_abs_path($knownhosts);
}
else {
    $identity_config = abs_path(pp($identity));
    $knownhosts_config = abs_path(pp($knownhosts));
}


Changes to jni/curl/tests/stunnel.pem.
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
extensions = x509v3

[ x509v3 ]
subjectAltName = DNS:localhost
keyUsage	= keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage = serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid
basicConstraints = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits                    = 12048
distinguished_name              = req_DN
default_md			= sha256
string_mask			= utf8only

[ req_DN ]
countryName                     = "Country Name is Northern Nowhere"
countryName_value            = NN
organizationName              = "Organization Name"
organizationName_value     = Edel Curl Arctic Illudium Research Cloud
commonName                      = "Common Name"
commonName_value              = localhost

[something]
# The key
# the certificate
# some dhparam
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrCrAD0Hb+Xs4V
3mHV45FvfNa7yiaOeL4mNdGmWfHVPFU+CSzsoNSvDjxaorWweFGVYoCAcchOn1lZ
k0ASsqnOss0Xi58n8+PPI3gG0gYjX5sg7EJ3Zq2kXoK0TZRy6hNkcvzLgyzXoYv1
LkzTwYiyyJgZX++Y/GKAs2fMHyP8XzjNgm4tltk1k/4pomllwN9Fqz+sFxgAgEq3
ybq4Xym7xKwWl8xXNBDJNmVsPtiJRcilQoR8Xs0a6PE+VbMhD9A2E/LEL7lzQfqH
qtxE1mSW5FpQ+Uqf4KLnafStWs86IOWnCeLP6BmhAK6ouyICNFyzz7UkTHa/renx

>

|
|
|
|
|
|














|
|
|
|
>

|
|
|
|
|
|
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





36
37
38
39
40
41
42
extensions = x509v3

[ x509v3 ]
subjectAltName          = DNS:localhost
keyUsage                = keyEncipherment,digitalSignature,keyAgreement
extendedKeyUsage        = serverAuth
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid
basicConstraints        = CA:false
authorityInfoAccess     = @issuer_info
crlDistributionPoints   = @crl_info

[ crl_ext ]
authorityKeyIdentifier  = keyid:always
authorityInfoAccess     = @issuer_info

[ issuer_info ]
caIssuers;URI.0         = http://test.curl.se/ca/EdelCurlRoot.cer

[ crl_info ]
URI.0                   = http://test.curl.se/ca/EdelCurlRoot.crl

[ req ]
default_bits            = 12048
distinguished_name      = req_DN
default_md              = sha256
string_mask             = utf8only

[ req_DN ]
countryName             = "Country Name is Northern Nowhere"
countryName_value       = NN
organizationName        = "Organization Name"
organizationName_value  = Edel Curl Arctic Illudium Research Cloud
commonName              = "Common Name"
commonName_value        = localhost





-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrCrAD0Hb+Xs4V
3mHV45FvfNa7yiaOeL4mNdGmWfHVPFU+CSzsoNSvDjxaorWweFGVYoCAcchOn1lZ
k0ASsqnOss0Xi58n8+PPI3gG0gYjX5sg7EJ3Zq2kXoK0TZRy6hNkcvzLgyzXoYv1
LkzTwYiyyJgZX++Y/GKAs2fMHyP8XzjNgm4tltk1k/4pomllwN9Fqz+sFxgAgEq3
ybq4Xym7xKwWl8xXNBDJNmVsPtiJRcilQoR8Xs0a6PE+VbMhD9A2E/LEL7lzQfqH
qtxE1mSW5FpQ+Uqf4KLnafStWs86IOWnCeLP6BmhAK6ouyICNFyzz7UkTHa/renx
Changes to jni/curl/tests/test1119.pl.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
sub checkmanpage {
    my ($m) = @_;

    open(my $mh, "<", "$m");
    my $line = 1;
    while(<$mh>) {
        # strip off formatting
        $_ =~ s/\\f[BPRI]//;
        # detect global-looking 'CURL[BLABLA]_*' symbols
        while(s/\W(CURL(AUTH|E|H|MOPT|OPT|SHOPT|UE|M|SSH|SSLBACKEND|HEADER|FORM|FTP|PIPE|MIMEOPT|GSSAPI|ALTSVC|PROTO|PROXY|UPART|USESSL|_READFUNC|_WRITEFUNC|_CSELECT|_FORMADD|_IPRESOLVE|_REDIR|_RTSPREQ|_TIMECOND|_VERSION)_[a-zA-Z0-9_]+)//) {
            my $s = $1;
            # skip two "special" ones
            if($s !~ /^(CURLE_OBSOLETE|CURLOPT_TEMPLATE)/) {
                push @manrefs, "$1:$m:$line";
            }
        }
        $line++;
    }
    close($mh);
}

sub scanman3dir {
    my ($d) = @_;
    opendir(my $dh, $d) ||
        die "Can't opendir: $!";
    my @mans = grep { /.3\z/ } readdir($dh);
    closedir $dh;
    for my $m (@mans) {
        checkmanpage("$d/$m");
    }
}


scanallheaders();
scanman3dir("$root/docs/libcurl");
scanman3dir("$root/docs/libcurl/opts");

open my $s, "<", "$root/docs/libcurl/symbols-in-versions";
while(<$s>) {
    if(/(^[^ \n]+) +(.*)/) {
        my ($sym, $rest)=($1, $2);
        if($doc{$sym}) {
            print "Detected duplicate symbol: $sym\n";







|













|



|








|
|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
sub checkmanpage {
    my ($m) = @_;

    open(my $mh, "<", "$m");
    my $line = 1;
    while(<$mh>) {
        # strip off formatting
        $_ =~ s/(^|[^A-Z0-9])[*_]+/ /;
        # detect global-looking 'CURL[BLABLA]_*' symbols
        while(s/\W(CURL(AUTH|E|H|MOPT|OPT|SHOPT|UE|M|SSH|SSLBACKEND|HEADER|FORM|FTP|PIPE|MIMEOPT|GSSAPI|ALTSVC|PROTO|PROXY|UPART|USESSL|_READFUNC|_WRITEFUNC|_CSELECT|_FORMADD|_IPRESOLVE|_REDIR|_RTSPREQ|_TIMECOND|_VERSION)_[a-zA-Z0-9_]+)//) {
            my $s = $1;
            # skip two "special" ones
            if($s !~ /^(CURLE_OBSOLETE|CURLOPT_TEMPLATE)/) {
                push @manrefs, "$1:$m:$line";
            }
        }
        $line++;
    }
    close($mh);
}

sub scanman_md_dir {
    my ($d) = @_;
    opendir(my $dh, $d) ||
        die "Can't opendir: $!";
    my @mans = grep { /.md\z/ } readdir($dh);
    closedir $dh;
    for my $m (@mans) {
        checkmanpage("$d/$m");
    }
}


scanallheaders();
scanman_md_dir("$root/docs/libcurl");
scanman_md_dir("$root/docs/libcurl/opts");

open my $s, "<", "$root/docs/libcurl/symbols-in-versions";
while(<$s>) {
    if(/(^[^ \n]+) +(.*)/) {
        my ($sym, $rest)=($1, $2);
        if($doc{$sym}) {
            print "Detected duplicate symbol: $sym\n";
Changes to jni/curl/tests/test1139.pl.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
# Scan symbols-in-version (which is verified to be correct by test 1119), then
# verify that each option mention in there that should have its own man page
# actually does.
#
# In addition, make sure that every current option to curl_easy_setopt,
# curl_easy_getinfo and curl_multi_setopt are also mentioned in their
# corresponding main (index) man page.
#
# src/tool_getparam.c lists all options curl can parse
# docs/curl.1 documents all command line options
# src/tool_listhelp.c outputs all options with curl -h
# - make sure they're all in sync
#
# Output all deviances to stderr.







|




|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
# Scan symbols-in-version (which is verified to be correct by test 1119), then
# verify that each option mention in there that should have its own manpage
# actually does.
#
# In addition, make sure that every current option to curl_easy_setopt,
# curl_easy_getinfo and curl_multi_setopt are also mentioned in their
# corresponding main (index) manpage.
#
# src/tool_getparam.c lists all options curl can parse
# docs/curl.1 documents all command line options
# src/tool_listhelp.c outputs all options with curl -h
# - make sure they're all in sync
#
# Output all deviances to stderr.
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82









83
84
85
86
87
88
89
    'CURLINFO_LASTONE' => 'none',
    'CURLINFO_NONE' => 'none',
    'CURLINFO_SSL_DATA_IN' => 'none',
    'CURLINFO_SSL_DATA_OUT' => 'none',
    'CURLINFO_TEXT' => 'none'
    );

sub scanmanpage {
    my ($file, @words) = @_;

    open(my $mh, "<", "$file") ||
        die "could not open $file";
    my @m;
    while(<$mh>) {
        if($_ =~ /^\.IP (.*)/) {
            my $w = $1;
            # "unquote" minuses
            $w =~ s/\\-/-/g;
            push @m, $w;
        }
    }
    close($mh);










    foreach my $m (@words) {
        my @g = grep(/$m/, @m);
        if(!$g[0]) {
            print STDERR "Missing mention of $m in $file\n";
            $errors++;
        }
    }







|






|








>
>
>
>
>
>
>
>
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    'CURLINFO_LASTONE' => 'none',
    'CURLINFO_NONE' => 'none',
    'CURLINFO_SSL_DATA_IN' => 'none',
    'CURLINFO_SSL_DATA_OUT' => 'none',
    'CURLINFO_TEXT' => 'none'
    );

sub scanmdpage {
    my ($file, @words) = @_;

    open(my $mh, "<", "$file") ||
        die "could not open $file";
    my @m;
    while(<$mh>) {
        if($_ =~ /^## (.*)/) {
            my $w = $1;
            # "unquote" minuses
            $w =~ s/\\-/-/g;
            push @m, $w;
        }
    }
    close($mh);

    my @ms = sort @m;
    for my $i (0 .. $#m) {
        if($ms[$i] ne $m[$i]) {
            print STDERR "$file:1:ERROR: $m[$i] is not alphabetical (expected $ms[$i])\n";
            $errors++;
            # no point in reporting many
            last;
        }
    }
    foreach my $m (@words) {
        my @g = grep(/$m/, @m);
        if(!$g[0]) {
            print STDERR "Missing mention of $m in $file\n";
            $errors++;
        }
    }
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
            }
            elsif($type eq "INFO") {
                push @curlinfo, $opt,
            }
            elsif($type eq "MOPT") {
                push @curlmopt, $opt,
            }
            if(! -f "$buildroot/docs/libcurl/opts/$opt.3") {
                print STDERR "Missing $opt.3\n";
                $errors++;
            }
        }
    }
}
close($r);

scanmanpage("$buildroot/docs/libcurl/curl_easy_setopt.3", @curlopt);
scanmanpage("$buildroot/docs/libcurl/curl_easy_getinfo.3", @curlinfo);
scanmanpage("$buildroot/docs/libcurl/curl_multi_setopt.3", @curlmopt);

# using this hash array, we can skip specific options
my %opts = (
    # pretend these --no options exists in tool_getparam.c
    '--no-alpn' => 1,
    '--no-npn' => 1,
    '-N, --no-buffer' => 1,







|
|







|
|
|







134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
            }
            elsif($type eq "INFO") {
                push @curlinfo, $opt,
            }
            elsif($type eq "MOPT") {
                push @curlmopt, $opt,
            }
            if(! -f "$root/docs/libcurl/opts/$opt.md") {
                print STDERR "Missing $opt.md\n";
                $errors++;
            }
        }
    }
}
close($r);

scanmdpage("$root/docs/libcurl/curl_easy_setopt.md", @curlopt);
scanmdpage("$root/docs/libcurl/curl_easy_getinfo.md", @curlinfo);
scanmdpage("$root/docs/libcurl/curl_multi_setopt.md", @curlmopt);

# using this hash array, we can skip specific options
my %opts = (
    # pretend these --no options exists in tool_getparam.c
    '--no-alpn' => 1,
    '--no-npn' => 1,
    '-N, --no-buffer' => 1,
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
            $prevlong = $l;
        }
    }
}
close($r);

#########################################################################
# parse the curl.1 man page, extract all documented command line options
# The man page may or may not be rebuilt, so check both possible locations
open($r, "<", "$buildroot/docs/cmdline-opts/curl.1") || open($r, "<", "$root/docs/cmdline-opts/curl.1") ||
    die "failed getting curl.1";
my @manpage; # store all parsed parameters
while(<$r>) {
    chomp;
    my $l= $_;
    $l =~ s/\\-/-/g;







|
|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
            $prevlong = $l;
        }
    }
}
close($r);

#########################################################################
# parse the curl.1 manpage, extract all documented command line options
# The manpage may or may not be rebuilt, so check both possible locations
open($r, "<", "$buildroot/docs/cmdline-opts/curl.1") || open($r, "<", "$root/docs/cmdline-opts/curl.1") ||
    die "failed getting curl.1";
my @manpage; # store all parsed parameters
while(<$r>) {
    chomp;
    my $l= $_;
    $l =~ s/\\-/-/g;
Changes to jni/curl/tests/test1140.pl.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
# scan manpages to find basic syntactic problems such as unbalanced \f
# codes or references to non-existing curl man pages.

my $docsroot = $ARGV[0];

if(!$docsroot || ($docsroot eq "-g")) {
    print "Usage: test1140.pl <docs root dir> [manpages]\n";
    exit;
}







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
# scan manpages to find basic syntactic problems such as unbalanced \f
# codes or references to non-existing curl manpages.

my $docsroot = $ARGV[0];

if(!$docsroot || ($docsroot eq "-g")) {
    print "Usage: test1140.pl <docs root dir> [manpages]\n";
    exit;
}
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
                print "error: $f:$line: missing \\fP after $str\n";
                $errors++;
            }
            if($str =~ /((libcurl|curl)([^ ]*))\(3\)/i) {
                my $man = "$1.3";
                $man =~ s/\\//g; # cut off backslashes
                if(!manpresent($man)) {
                    print "error: $f:$line: referring to non-existing man page $man\n";
                    $errors++;
                }
                if($pre ne "I") {
                    print "error: $f:$line: use \\fI before $str\n";
                    $errors++;
                }
            }
        }
        if($l =~ /(curl([^ ]*)\(3\))/i) {
            print "error: $f:$line: non-referencing $1\n";
            $errors++;
        }
        if($l =~ /^\.BR (.*)/) {
            my $i= $1;
            while($i =~ s/((lib|)curl([^ ]*)) *\"\(3\)(,|) *\" *//i ) {
                my $man = "$1.3";
                $man =~ s/\\//g; # cut off backslashes
                if(!manpresent($man)) {
                    print "error: $f:$line: referring to non-existing man page $man\n";
                    $errors++;
                }
            }
        }
        $line++;
    }
    close($fh);







|


















|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
                print "error: $f:$line: missing \\fP after $str\n";
                $errors++;
            }
            if($str =~ /((libcurl|curl)([^ ]*))\(3\)/i) {
                my $man = "$1.3";
                $man =~ s/\\//g; # cut off backslashes
                if(!manpresent($man)) {
                    print "error: $f:$line: referring to non-existing manpage $man\n";
                    $errors++;
                }
                if($pre ne "I") {
                    print "error: $f:$line: use \\fI before $str\n";
                    $errors++;
                }
            }
        }
        if($l =~ /(curl([^ ]*)\(3\))/i) {
            print "error: $f:$line: non-referencing $1\n";
            $errors++;
        }
        if($l =~ /^\.BR (.*)/) {
            my $i= $1;
            while($i =~ s/((lib|)curl([^ ]*)) *\"\(3\)(,|) *\" *//i ) {
                my $man = "$1.3";
                $man =~ s/\\//g; # cut off backslashes
                if(!manpresent($man)) {
                    print "error: $f:$line: referring to non-existing manpage $man\n";
                    $errors++;
                }
            }
        }
        $line++;
    }
    close($fh);
Changes to jni/curl/tests/test1173.pl.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
# Scan man page(s) and detect some simple and yet common formatting mistakes.
#
# Output all deviances to stderr.

use strict;
use warnings;
use File::Basename;








|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
# Scan manpage(s) and detect some simple and yet common formatting mistakes.
#
# Output all deviances to stderr.

use strict;
use warnings;
use File::Basename;

133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    my $SH="";
    my @separators;
    my @sepline;

    open(my $m, "<", "$file") ||
        die "test1173.pl could not open $file";
    if($file =~ /[\/\\](CURL|curl_)([^\/\\]*).3/) {
        # This is a man page for libcurl. It requires an example unless it's
        # considered deprecated.
        $reqex = 1 unless defined $deprecated{'CURL'.$2};
        if($1 eq "CURL") {
            $optpage = 1;
        }
    }
    my $line = 1;
    while(<$m>) {
        chomp;
        if($_ =~ /^.so /) {
            # this man page is just a referral
            close($m);
            return;
        }
        if(($_ =~ /^\.SH SYNOPSIS/i) && ($reqex)) {
            # this is for libcurl man page SYNOPSIS checks
            $insynop = 1;
            $inex = 0;
        }
        elsif($_ =~ /^\.SH EXAMPLE/i) {
            $insynop = 0;
            $inex = 1;
        }







|










|




|







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    my $SH="";
    my @separators;
    my @sepline;

    open(my $m, "<", "$file") ||
        die "test1173.pl could not open $file";
    if($file =~ /[\/\\](CURL|curl_)([^\/\\]*).3/) {
        # This is a manpage for libcurl. It requires an example unless it's
        # considered deprecated.
        $reqex = 1 unless defined $deprecated{'CURL'.$2};
        if($1 eq "CURL") {
            $optpage = 1;
        }
    }
    my $line = 1;
    while(<$m>) {
        chomp;
        if($_ =~ /^.so /) {
            # this manpage is just a referral
            close($m);
            return;
        }
        if(($_ =~ /^\.SH SYNOPSIS/i) && ($reqex)) {
            # this is for libcurl manpage SYNOPSIS checks
            $insynop = 1;
            $inex = 0;
        }
        elsif($_ =~ /^\.SH EXAMPLE/i) {
            $insynop = 0;
            $inex = 1;
        }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
            print STDERR "$file:$line unrefed curl call: $2\n";
            $errors++;
        }


        if($optpage && $SH && ($SH !~ /^(SYNOPSIS|EXAMPLE|NAME|SEE ALSO)/i) &&
           ($_ =~ /(.*)(CURL(OPT_|MOPT_|INFO_|SHOPT_)[A-Z0-9_]*)/)) {
            # an option with its own man page, check that it is tagged
            # for linking
            my ($pref, $symbol) = ($1, $2);
            if($deprecated{$symbol}) {
                # let it be
            }
            elsif($pref !~ /\\fI\z/) {
                print STDERR "$file:$line option $symbol missing \\fI tagging\n";







|







250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
            print STDERR "$file:$line unrefed curl call: $2\n";
            $errors++;
        }


        if($optpage && $SH && ($SH !~ /^(SYNOPSIS|EXAMPLE|NAME|SEE ALSO)/i) &&
           ($_ =~ /(.*)(CURL(OPT_|MOPT_|INFO_|SHOPT_)[A-Z0-9_]*)/)) {
            # an option with its own manpage, check that it is tagged
            # for linking
            my ($pref, $symbol) = ($1, $2);
            if($deprecated{$symbol}) {
                # let it be
            }
            elsif($pref !~ /\\fI\z/) {
                print STDERR "$file:$line option $symbol missing \\fI tagging\n";
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
        my $shcount = scalar(@sh); # before @sh gets shifted
        if($exsize < 2) {
            print STDERR "$file:$line missing EXAMPLE section\n";
            $errors++;
        }

        if($shcount < 3) {
            print STDERR "$file:$line too few man page sections!\n";
            $errors++;
            return;
        }

        my $got = "start";
        my $i = 0;
        my $shused = 1;







|







299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
        my $shcount = scalar(@sh); # before @sh gets shifted
        if($exsize < 2) {
            print STDERR "$file:$line missing EXAMPLE section\n";
            $errors++;
        }

        if($shcount < 3) {
            print STDERR "$file:$line too few manpage sections!\n";
            $errors++;
            return;
        }

        my $got = "start";
        my $i = 0;
        my $shused = 1;
Changes to jni/curl/tests/test1175.pl.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# we may get the dir root pointed out
my $root=$ARGV[0] || ".";

my %error; # from the include file
my %docs; # from libcurl-errors.3

sub getdocserrors {
    open(my $f, "<", "$root/docs/libcurl/libcurl-errors.3");
    while(<$f>) {
        if($_ =~ /^.IP \"(CURL[EM]_[^ \t\"]*)/) {
            my ($symbol) = ($1);
            if($symbol =~ /OBSOLETE/) {
                ;
            }
            else {
                $docs{$symbol}=1;
            }







|

|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# we may get the dir root pointed out
my $root=$ARGV[0] || ".";

my %error; # from the include file
my %docs; # from libcurl-errors.3

sub getdocserrors {
    open(my $f, "<", "$root/docs/libcurl/libcurl-errors.md");
    while(<$f>) {
        if($_ =~ /^## (CURL[EM]_[^ ]*)/) {
            my ($symbol) = ($1);
            if($symbol =~ /OBSOLETE/) {
                ;
            }
            else {
                $docs{$symbol}=1;
            }
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
}

getincludeerrors();
getdocserrors();

for(sort keys %error) {
    if($error{$_} && !$docs{$_}) {
        print "$_ is not in libcurl-errors.3\n";
    }
}

for(sort keys %docs) {
    if($docs{$_} && !$error{$_}) {
        print "$_ is not in symbols-in-versions\n";
    }
}







|








67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
}

getincludeerrors();
getdocserrors();

for(sort keys %error) {
    if($error{$_} && !$docs{$_}) {
        print "$_ is not in libcurl-errors.md\n";
    }
}

for(sort keys %docs) {
    if($docs{$_} && !$error{$_}) {
        print "$_ is not in symbols-in-versions\n";
    }
}
Changes to jni/curl/tests/test1222.pl.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#
# SPDX-License-Identifier: curl
#
#
###########################################################################
#
# Check that the deprecated statuses of functions and enum values in header
# files, man pages and symbols-in-versions are in sync.

use strict;
use warnings;

use File::Basename;

my $root=$ARGV[0] || ".";
my $incdir = "$root/include/curl";
my $docdir = "$root/docs";
my $libdocdir = "$docdir/libcurl";
my $errcode = 0;

# Symbol-indexed hashes.
# Values are:
#     X       Not deprecated
#     ?       Deprecated in unknown version
#     x.yy.z  Deprecated in version x.yy.z
my %syminver;       # Symbols-in-versions deprecations.
my %hdr;            # Public header files deprecations.
my %funcman;        # Function man pages deprecations.
my %optman;         # Option man pages deprecations.


# Scan header file for public function and enum values. Flag them with
# the version they are deprecated in, if some.
sub scan_header {
    my ($f)=@_;
    my $line = "";







|



















|
|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#
# SPDX-License-Identifier: curl
#
#
###########################################################################
#
# Check that the deprecated statuses of functions and enum values in header
# files, manpages and symbols-in-versions are in sync.

use strict;
use warnings;

use File::Basename;

my $root=$ARGV[0] || ".";
my $incdir = "$root/include/curl";
my $docdir = "$root/docs";
my $libdocdir = "$docdir/libcurl";
my $errcode = 0;

# Symbol-indexed hashes.
# Values are:
#     X       Not deprecated
#     ?       Deprecated in unknown version
#     x.yy.z  Deprecated in version x.yy.z
my %syminver;       # Symbols-in-versions deprecations.
my %hdr;            # Public header files deprecations.
my %funcman;        # Function manpages deprecations.
my %optman;         # Option manpages deprecations.


# Scan header file for public function and enum values. Flag them with
# the version they are deprecated in, if some.
sub scan_header {
    my ($f)=@_;
    my $line = "";
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
      if($_ =~ /}/) {
        $inenum = 0;
      }
    }
    close $h;
}

# Scan function man page for options.
# Each option has to be declared as ".IP <option>" where <option> starts with
# the prefix. Flag each option with its deprecation version, if some.
sub scan_man_for_opts {
    my ($f, $prefix)=@_;
    my $opt = "";
    my $line = "";








|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
      if($_ =~ /}/) {
        $inenum = 0;
      }
    }
    close $h;
}

# Scan function manpage for options.
# Each option has to be declared as ".IP <option>" where <option> starts with
# the prefix. Flag each option with its deprecation version, if some.
sub scan_man_for_opts {
    my ($f, $prefix)=@_;
    my $opt = "";
    my $line = "";

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
        # Text line: accumulate.
        $line .= $_;
      }
    }
    close $m;
}

# Scan man page for deprecation in DESCRIPTION and/or AVAILABILITY sections.
sub scan_man_page {
    my ($path, $sym, $table)=@_;
    my $version = "X";

    if(open(my $fh, "<", "$path")) {
      my $section = "";
      my $line = "";

      while(<$fh>) {
        if($_ =~ /\.so\s+man3\/(.*\.3\b)/) {
          # Handle man page inclusion.
          scan_man_page(dirname($path) . "/$1", $sym, $table);
          $version = exists($$table{$sym})? $$table{$sym}: $version;
        }
        elsif($_ =~ /^\./) {
          # Line is a roff directive.
          if($_ =~ /^\.SH\b\s*(\w*)/) {
            # Section starts. End previous one.
            my $sh = $section;

            $section = $1;
            $_ = $line;     # Previous section text.
            $line = "";
            s/\\f.//g;
            s/\s+/ /g;
            s/\\f.//g;      # Remove font formatting.
            s/\s+/ /g;      # One line with single space only.
            if($sh =~ /DESCRIPTION|AVAILABILITY/) {
              while($_ =~ /(?:deprecated|obsoleted?)\b\s*(?:in\b|since\b)?\s*(?:version\b|curl\b|libcurl\b)?\s*(\d[0-9.]*\d)?\b\s*(.*)$/i) {
                # Flag deprecation status.
                if($version ne "X" && $version ne "?") {
                  if($1 && $1 ne $version) {
                    print "error: $sym man page lists unmatching deprecation versions $version and $1\n";
                    $errcode++;
                  }
                }
                else {
                  $version = $1 || "?";
                }
                $_ = $2;







|










|
















|




|







176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
        # Text line: accumulate.
        $line .= $_;
      }
    }
    close $m;
}

# Scan manpage for deprecation in DESCRIPTION and/or AVAILABILITY sections.
sub scan_man_page {
    my ($path, $sym, $table)=@_;
    my $version = "X";

    if(open(my $fh, "<", "$path")) {
      my $section = "";
      my $line = "";

      while(<$fh>) {
        if($_ =~ /\.so\s+man3\/(.*\.3\b)/) {
          # Handle manpage inclusion.
          scan_man_page(dirname($path) . "/$1", $sym, $table);
          $version = exists($$table{$sym})? $$table{$sym}: $version;
        }
        elsif($_ =~ /^\./) {
          # Line is a roff directive.
          if($_ =~ /^\.SH\b\s*(\w*)/) {
            # Section starts. End previous one.
            my $sh = $section;

            $section = $1;
            $_ = $line;     # Previous section text.
            $line = "";
            s/\\f.//g;
            s/\s+/ /g;
            s/\\f.//g;      # Remove font formatting.
            s/\s+/ /g;      # One line with single space only.
            if($sh =~ /DESCRIPTION|DEPRECATED/) {
              while($_ =~ /(?:deprecated|obsoleted?)\b\s*(?:in\b|since\b)?\s*(?:version\b|curl\b|libcurl\b)?\s*(\d[0-9.]*\d)?\b\s*(.*)$/i) {
                # Flag deprecation status.
                if($version ne "X" && $version ne "?") {
                  if($1 && $1 ne $version) {
                    print "error: $sym manpage lists unmatching deprecation versions $version and $1\n";
                    $errcode++;
                  }
                }
                else {
                  $version = $1 || "?";
                }
                $_ = $2;
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
closedir $dh;

# Get functions and enum symbols from header files.
for(@hfiles) {
  scan_header("$incdir/$_");
}

# Get function statuses from man pages.
foreach my $sym (keys %hdr) {
  if($sym =~/^(?:curl|curlx)_\w/) {
    scan_man_page("$libdocdir/$sym.3", $sym, \%funcman);
  }
}

# Get options from function man pages.
scan_man_for_opts("$libdocdir/curl_easy_setopt.3", "CURLOPT");
scan_man_for_opts("$libdocdir/curl_easy_getinfo.3", "CURLINFO");

# Get deprecation status from option man pages.
foreach my $sym (keys %syminver) {
  if($sym =~ /^(?:CURLOPT|CURLINFO)_\w+$/) {
    scan_man_page("$libdocdir/opts/$sym.3", $sym, \%optman);
  }
}

# Print results.







|






|



|







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
closedir $dh;

# Get functions and enum symbols from header files.
for(@hfiles) {
  scan_header("$incdir/$_");
}

# Get function statuses from manpages.
foreach my $sym (keys %hdr) {
  if($sym =~/^(?:curl|curlx)_\w/) {
    scan_man_page("$libdocdir/$sym.3", $sym, \%funcman);
  }
}

# Get options from function manpages.
scan_man_for_opts("$libdocdir/curl_easy_setopt.3", "CURLOPT");
scan_man_for_opts("$libdocdir/curl_easy_getinfo.3", "CURLINFO");

# Get deprecation status from option manpages.
foreach my $sym (keys %syminver) {
  if($sym =~ /^(?:CURLOPT|CURLINFO)_\w+$/) {
    scan_man_page("$libdocdir/opts/$sym.3", $sym, \%optman);
  }
}

# Print results.
Changes to jni/curl/tests/test1275.pl.
28
29
30
31
32
33
34

35
36
37
38
39
40
41
my @m = `git ls-files -- $root`;

my $errors;

my %accepted=('curl' => 1,
              'libcurl' => 1,
              'macOS' => 1,

              'c-ares' => 1);

sub checkfile {
    my ($f) = @_;
    chomp $f;
    if($f !~ /\.md\z/) {
        return;







>







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
my @m = `git ls-files -- $root`;

my $errors;

my %accepted=('curl' => 1,
              'libcurl' => 1,
              'macOS' => 1,
              'mbedTLS' => 1,
              'c-ares' => 1);

sub checkfile {
    my ($f) = @_;
    chomp $f;
    if($f !~ /\.md\z/) {
        return;
Changes to jni/curl/tests/test1477.pl.
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    scanheader("$curlh/$_");
}
scanmanpage($manpge);

print "Result\n";
for my $h (sort @hnames) {
    if(!$manfrom{$h}) {
        printf "$h from %s, not in man page\n", $wherefrom{$h};
    }
}

for my $m (sort @mnames) {
    if(!$wherefrom{$m}) {
        printf "$m from %s, not in any header\n", $manfrom{$m};
    }







|







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    scanheader("$curlh/$_");
}
scanmanpage($manpge);

print "Result\n";
for my $h (sort @hnames) {
    if(!$manfrom{$h}) {
        printf "$h from %s, not in manpage\n", $wherefrom{$h};
    }
}

for my $m (sort @mnames) {
    if(!$wherefrom{$m}) {
        printf "$m from %s, not in any header\n", $manfrom{$m};
    }
Added jni/curl/tests/test1486.pl.












































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env perl
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
#                             \___|\___/|_| \_\_____|
#
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
#

use strict;
use warnings;

# we may get the dir root pointed out
my $root=$ARGV[0] || ".";

my %insrc; # variable set in source
my %indocs; # variable described in docs

my $srccount = 1;
sub getsrcvars {
    open(my $f, "<", "$root/../src/tool_writeout.c");
    my $mode = 0;
    while(<$f>) {
        if(!$mode &&
           ($_ =~ /^static const struct writeoutvar/)) {
            $mode = 1;
        }
        if($mode) {
            if($_ =~ /^}/) {
                last;
            }
            if($_ =~ /^  \{\"([^\"]*)/) {
                my $var = $1;
                $insrc{$var} = $srccount++;
            }
        }
    }
    close($f);
}

sub getdocsvars {
    open(my $f, "<", "$root/../docs/cmdline-opts/write-out.md");
    while(<$f>) {
        if($_ =~ /^\#\# \`([^\`]*)\`/) {
            $indocs{$1} = 1;
        }
    }
    close($f);
}

getsrcvars();
getdocsvars();

my $error = 0;

if((scalar(keys %indocs) < 10) || (scalar(keys %insrc) < 10)) {
    print "problems to extract variables\n";
    $error++;
}

# also verify that the source code lists them alphabetically
my $check = 1;
for(sort keys %insrc) {
    if($insrc{$_} && !$indocs{$_}) {
        print "$_ is not mentioned in write.out.md\n";
        $error++;
    }
    if($insrc{$_} ne $check) {
        print "$_ is not in alphabetical order\n";
        $error++;
    }
    $check++;
}

for(sort keys %indocs) {
    if($indocs{$_} && !$insrc{$_}) {
        print "$_ documented, but not used in source code\n";
        $error++;
    }
}

print "OK\n" if(!$error);

exit $error;
Added jni/curl/tests/test1488.pl.
































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env perl
#***************************************************************************
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
#                             \___|\___/|_| \_\_____|
#
# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################
#
# This script grew out of help from Przemyslaw Iskra and Balint Szilakszi
# a late evening in the #curl IRC channel.
#

use strict;
use warnings;
use vars qw($Cpreprocessor);

#
# configurehelp perl module is generated by configure script
#
my $rc = eval {
    require configurehelp;
    configurehelp->import(qw(
        $Cpreprocessor
    ));
    1;
};
# Set default values if configure has not generated a configurehelp.pm file.
# This is the case with cmake.
if (!$rc) {
    $Cpreprocessor = 'cpp';
}

# we may get the dir root pointed out
my $root=$ARGV[0] || ".";

# need an include directory when building out-of-tree
my $i = ($ARGV[1]) ? "-I$ARGV[1] " : '';
my $error;


my @syms;
my %manpage;
my %symadded;

sub checkmanpage {
    my ($m) = @_;

    open(my $mh, "<", "$m");
    my $line = 1;
    my $title;
    my $addedin;
    while(<$mh>) {
        if(/^Title: (.*)/i) {
            $title = $1;
        }
        elsif(/^Added-in: (.*)/i) {
            $addedin = $1;
        }
        if($addedin && $title) {
            if($manpage{$title}) {
                print "$title is a duplicate symbol in file $m\n";
                $error++;
            }
            $manpage{$title} = $addedin;
            last;
        }
        $line++;
    }
    close($mh);
}

sub scanman_md_dir {
    my ($d) = @_;
    opendir(my $dh, $d) ||
        die "Can't opendir: $!";
    my @mans = grep { /.md\z/ } readdir($dh);
    closedir $dh;
    for my $m (@mans) {
        checkmanpage("$d/$m");
    }
}

scanman_md_dir("$root/docs/libcurl");
scanman_md_dir("$root/docs/libcurl/opts");

open my $s, "<", "$root/docs/libcurl/symbols-in-versions";
while(<$s>) {
    if(/(^[^ \n]+) +(.*)/) {
        my ($sym, $rest)=($1, $2);
        my @a=split(/ +/, $rest);
        push @syms, $sym;

        $symadded{$sym}=$a[0];
    }
}
close $s;

my $ignored=0;
for my $e (sort @syms) {
    if( $manpage{$e} ) {

        if( $manpage{$e} ne $symadded{$e} ) {
            printf "%s.md says version %s, but SIV says %s\n",
                $e, $manpage{$e}, $symadded{$e};
            $error++;
        }

    }
}
print "OK\n" if(!$error);
exit $error;
Changes to jni/curl/tests/testutil.pm.
123
124
125
126
127
128
129

130
131
132
133
134
135
136
        $$thing =~ s/%%HEX%%/$d/;
    }
    # repeat
    while($$thing =~ s/%repeat\[(\d+) x (.*?)\]%/%%REPEAT%%/i) {
        # decode %NN characters
        my ($d, $n) = ($2, $1);
        $d =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;

        my $all = $d x $n;
        $$thing =~ s/%%REPEAT%%/$all/;
    }

    # include a file
    $$thing =~ s/%include ([^%]*)%[\n\r]+/includefile($1)/ge;
}







>







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
        $$thing =~ s/%%HEX%%/$d/;
    }
    # repeat
    while($$thing =~ s/%repeat\[(\d+) x (.*?)\]%/%%REPEAT%%/i) {
        # decode %NN characters
        my ($d, $n) = ($2, $1);
        $d =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
        $n =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
        my $all = $d x $n;
        $$thing =~ s/%%REPEAT%%/$all/;
    }

    # include a file
    $$thing =~ s/%include ([^%]*)%[\n\r]+/includefile($1)/ge;
}
Changes to jni/curl/tests/unit/CMakeLists.txt.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#
###########################################################################

transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)

include_directories(
  ${CURL_SOURCE_DIR}/lib          # To be able to reach "curl_setup_once.h"
  ${CURL_SOURCE_DIR}/tests/libtest
  ${CURL_SOURCE_DIR}/src
  ${CURL_BINARY_DIR}/lib          # To be able to reach "curl_config.h"
  ${CURL_BINARY_DIR}/include      # To be able to reach "curl/curl.h"
)

if(ENABLE_CURLDEBUG)  # running unittests require curl to compiled with CURLDEBUG
  foreach(_testfile ${UNITPROGS})
    add_executable(${_testfile} EXCLUDE_FROM_ALL ${_testfile}.c ${UNITFILES})
    add_dependencies(testdeps ${_testfile})
    target_link_libraries(${_testfile} curltool curlu)
  endforeach()
endif()







|


|
|


<
|
|
|
|
|
<
22
23
24
25
26
27
28
29
30
31
32
33
34
35

36
37
38
39
40

#
###########################################################################

transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)

include_directories(
  ${CURL_SOURCE_DIR}/lib          # for "curl_setup_once.h"
  ${CURL_SOURCE_DIR}/tests/libtest
  ${CURL_SOURCE_DIR}/src
  ${CURL_BINARY_DIR}/lib          # for "curl_config.h"
  ${CURL_BINARY_DIR}/include      # for "curl/curl.h"
)


foreach(_testfile ${UNITPROGS})
  add_executable(${_testfile} EXCLUDE_FROM_ALL ${_testfile}.c ${UNITFILES})
  add_dependencies(testdeps ${_testfile})
  target_link_libraries(${_testfile} curltool curlu)
endforeach()

Changes to jni/curl/tests/unit/Makefile.in.
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \
	$(top_srcdir)/m4/xc-translit.m4 \
	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)







<







133
134
135
136
137
138
139

140
141
142
143
144
145
146
	$(top_srcdir)/m4/curl-sysconfig.m4 \
	$(top_srcdir)/m4/curl-wolfssl.m4 $(top_srcdir)/m4/libtool.m4 \
	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
	$(top_srcdir)/m4/xc-am-iface.m4 \
	$(top_srcdir)/m4/xc-cc-check.m4 \
	$(top_srcdir)/m4/xc-lt-iface.m4 \

	$(top_srcdir)/m4/xc-val-flgs.m4 \
	$(top_srcdir)/m4/zz40-xc-ovr.m4 \
	$(top_srcdir)/m4/zz50-xc-ovr.m4 \
	$(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
	unit1605$(EXEEXT) unit1606$(EXEEXT) unit1607$(EXEEXT) \
	unit1608$(EXEEXT) unit1609$(EXEEXT) unit1610$(EXEEXT) \
	unit1611$(EXEEXT) unit1612$(EXEEXT) unit1614$(EXEEXT) \
	unit1615$(EXEEXT) unit1616$(EXEEXT) unit1620$(EXEEXT) \
	unit1621$(EXEEXT) unit1650$(EXEEXT) unit1651$(EXEEXT) \
	unit1652$(EXEEXT) unit1653$(EXEEXT) unit1654$(EXEEXT) \
	unit1655$(EXEEXT) unit1660$(EXEEXT) unit1661$(EXEEXT) \
	unit2600$(EXEEXT) unit2601$(EXEEXT) unit2602$(EXEEXT) \
	unit2603$(EXEEXT) unit2604$(EXEEXT) unit3200$(EXEEXT) \
	unit3205$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
am__dirstamp = $(am__leading_dot)dirstamp
am__objects_1 = ../libtest/first.$(OBJEXT)
am_unit1300_OBJECTS = unit1300.$(OBJEXT) $(am__objects_1)
unit1300_OBJECTS = $(am_unit1300_OBJECTS)
unit1300_LDADD = $(LDADD)
unit1300_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \







|
|
|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
	unit1605$(EXEEXT) unit1606$(EXEEXT) unit1607$(EXEEXT) \
	unit1608$(EXEEXT) unit1609$(EXEEXT) unit1610$(EXEEXT) \
	unit1611$(EXEEXT) unit1612$(EXEEXT) unit1614$(EXEEXT) \
	unit1615$(EXEEXT) unit1616$(EXEEXT) unit1620$(EXEEXT) \
	unit1621$(EXEEXT) unit1650$(EXEEXT) unit1651$(EXEEXT) \
	unit1652$(EXEEXT) unit1653$(EXEEXT) unit1654$(EXEEXT) \
	unit1655$(EXEEXT) unit1660$(EXEEXT) unit1661$(EXEEXT) \
	unit1663$(EXEEXT) unit2600$(EXEEXT) unit2601$(EXEEXT) \
	unit2602$(EXEEXT) unit2603$(EXEEXT) unit2604$(EXEEXT) \
	unit3200$(EXEEXT) unit3205$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
am__dirstamp = $(am__leading_dot)dirstamp
am__objects_1 = ../libtest/first.$(OBJEXT)
am_unit1300_OBJECTS = unit1300.$(OBJEXT) $(am__objects_1)
unit1300_OBJECTS = $(am_unit1300_OBJECTS)
unit1300_LDADD = $(LDADD)
unit1300_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \
380
381
382
383
384
385
386





387
388
389
390
391
392
393
unit1660_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \
	$(top_builddir)/lib/libcurlu.la
am_unit1661_OBJECTS = unit1661.$(OBJEXT) $(am__objects_1)
unit1661_OBJECTS = $(am_unit1661_OBJECTS)
unit1661_LDADD = $(LDADD)
unit1661_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \
	$(top_builddir)/lib/libcurlu.la





am_unit2600_OBJECTS = unit2600.$(OBJEXT) $(am__objects_1)
unit2600_OBJECTS = $(am_unit2600_OBJECTS)
unit2600_LDADD = $(LDADD)
unit2600_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \
	$(top_builddir)/lib/libcurlu.la
am_unit2601_OBJECTS = unit2601.$(OBJEXT) $(am__objects_1)
unit2601_OBJECTS = $(am_unit2601_OBJECTS)







>
>
>
>
>







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
unit1660_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \
	$(top_builddir)/lib/libcurlu.la
am_unit1661_OBJECTS = unit1661.$(OBJEXT) $(am__objects_1)
unit1661_OBJECTS = $(am_unit1661_OBJECTS)
unit1661_LDADD = $(LDADD)
unit1661_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \
	$(top_builddir)/lib/libcurlu.la
am_unit1663_OBJECTS = unit1663.$(OBJEXT) $(am__objects_1)
unit1663_OBJECTS = $(am_unit1663_OBJECTS)
unit1663_LDADD = $(LDADD)
unit1663_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \
	$(top_builddir)/lib/libcurlu.la
am_unit2600_OBJECTS = unit2600.$(OBJEXT) $(am__objects_1)
unit2600_OBJECTS = $(am_unit2600_OBJECTS)
unit2600_LDADD = $(LDADD)
unit2600_DEPENDENCIES = $(top_builddir)/src/libcurltool.la \
	$(top_builddir)/lib/libcurlu.la
am_unit2601_OBJECTS = unit2601.$(OBJEXT) $(am__objects_1)
unit2601_OBJECTS = $(am_unit2601_OBJECTS)
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
	./$(DEPDIR)/unit1612.Po ./$(DEPDIR)/unit1614.Po \
	./$(DEPDIR)/unit1615.Po ./$(DEPDIR)/unit1616.Po \
	./$(DEPDIR)/unit1620.Po ./$(DEPDIR)/unit1621.Po \
	./$(DEPDIR)/unit1650.Po ./$(DEPDIR)/unit1651.Po \
	./$(DEPDIR)/unit1652.Po ./$(DEPDIR)/unit1653.Po \
	./$(DEPDIR)/unit1654.Po ./$(DEPDIR)/unit1655.Po \
	./$(DEPDIR)/unit1660.Po ./$(DEPDIR)/unit1661.Po \
	./$(DEPDIR)/unit2600.Po ./$(DEPDIR)/unit2601.Po \
	./$(DEPDIR)/unit2602.Po ./$(DEPDIR)/unit2603.Po \
	./$(DEPDIR)/unit2604.Po ./$(DEPDIR)/unit3200.Po \
	./$(DEPDIR)/unit3205.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
	$(AM_CFLAGS) $(CFLAGS)







|
|
|
|







456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
	./$(DEPDIR)/unit1612.Po ./$(DEPDIR)/unit1614.Po \
	./$(DEPDIR)/unit1615.Po ./$(DEPDIR)/unit1616.Po \
	./$(DEPDIR)/unit1620.Po ./$(DEPDIR)/unit1621.Po \
	./$(DEPDIR)/unit1650.Po ./$(DEPDIR)/unit1651.Po \
	./$(DEPDIR)/unit1652.Po ./$(DEPDIR)/unit1653.Po \
	./$(DEPDIR)/unit1654.Po ./$(DEPDIR)/unit1655.Po \
	./$(DEPDIR)/unit1660.Po ./$(DEPDIR)/unit1661.Po \
	./$(DEPDIR)/unit1663.Po ./$(DEPDIR)/unit2600.Po \
	./$(DEPDIR)/unit2601.Po ./$(DEPDIR)/unit2602.Po \
	./$(DEPDIR)/unit2603.Po ./$(DEPDIR)/unit2604.Po \
	./$(DEPDIR)/unit3200.Po ./$(DEPDIR)/unit3205.Po
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
	$(AM_CFLAGS) $(CFLAGS)
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
	$(unit1605_SOURCES) $(unit1606_SOURCES) $(unit1607_SOURCES) \
	$(unit1608_SOURCES) $(unit1609_SOURCES) $(unit1610_SOURCES) \
	$(unit1611_SOURCES) $(unit1612_SOURCES) $(unit1614_SOURCES) \
	$(unit1615_SOURCES) $(unit1616_SOURCES) $(unit1620_SOURCES) \
	$(unit1621_SOURCES) $(unit1650_SOURCES) $(unit1651_SOURCES) \
	$(unit1652_SOURCES) $(unit1653_SOURCES) $(unit1654_SOURCES) \
	$(unit1655_SOURCES) $(unit1660_SOURCES) $(unit1661_SOURCES) \
	$(unit2600_SOURCES) $(unit2601_SOURCES) $(unit2602_SOURCES) \
	$(unit2603_SOURCES) $(unit2604_SOURCES) $(unit3200_SOURCES) \
	$(unit3205_SOURCES)
DIST_SOURCES = $(unit1300_SOURCES) $(unit1302_SOURCES) \
	$(unit1303_SOURCES) $(unit1304_SOURCES) $(unit1305_SOURCES) \
	$(unit1307_SOURCES) $(unit1308_SOURCES) $(unit1309_SOURCES) \
	$(unit1323_SOURCES) $(unit1330_SOURCES) $(unit1394_SOURCES) \
	$(unit1395_SOURCES) $(unit1396_SOURCES) $(unit1397_SOURCES) \
	$(unit1398_SOURCES) $(unit1399_SOURCES) $(unit1600_SOURCES) \
	$(unit1601_SOURCES) $(unit1602_SOURCES) $(unit1603_SOURCES) \
	$(unit1604_SOURCES) $(unit1605_SOURCES) $(unit1606_SOURCES) \
	$(unit1607_SOURCES) $(unit1608_SOURCES) $(unit1609_SOURCES) \
	$(unit1610_SOURCES) $(unit1611_SOURCES) $(unit1612_SOURCES) \
	$(unit1614_SOURCES) $(unit1615_SOURCES) $(unit1616_SOURCES) \
	$(unit1620_SOURCES) $(unit1621_SOURCES) $(unit1650_SOURCES) \
	$(unit1651_SOURCES) $(unit1652_SOURCES) $(unit1653_SOURCES) \
	$(unit1654_SOURCES) $(unit1655_SOURCES) $(unit1660_SOURCES) \
	$(unit1661_SOURCES) $(unit2600_SOURCES) $(unit2601_SOURCES) \
	$(unit2602_SOURCES) $(unit2603_SOURCES) $(unit2604_SOURCES) \
	$(unit3200_SOURCES) $(unit3205_SOURCES)
am__can_run_installinfo = \
  case $$AM_UPDATE_INFO_DIR in \
    n|no|NO) false;; \
    *) (install-info --version) >/dev/null 2>&1;; \
  esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,







|
|
|














|
|
|







493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
	$(unit1605_SOURCES) $(unit1606_SOURCES) $(unit1607_SOURCES) \
	$(unit1608_SOURCES) $(unit1609_SOURCES) $(unit1610_SOURCES) \
	$(unit1611_SOURCES) $(unit1612_SOURCES) $(unit1614_SOURCES) \
	$(unit1615_SOURCES) $(unit1616_SOURCES) $(unit1620_SOURCES) \
	$(unit1621_SOURCES) $(unit1650_SOURCES) $(unit1651_SOURCES) \
	$(unit1652_SOURCES) $(unit1653_SOURCES) $(unit1654_SOURCES) \
	$(unit1655_SOURCES) $(unit1660_SOURCES) $(unit1661_SOURCES) \
	$(unit1663_SOURCES) $(unit2600_SOURCES) $(unit2601_SOURCES) \
	$(unit2602_SOURCES) $(unit2603_SOURCES) $(unit2604_SOURCES) \
	$(unit3200_SOURCES) $(unit3205_SOURCES)
DIST_SOURCES = $(unit1300_SOURCES) $(unit1302_SOURCES) \
	$(unit1303_SOURCES) $(unit1304_SOURCES) $(unit1305_SOURCES) \
	$(unit1307_SOURCES) $(unit1308_SOURCES) $(unit1309_SOURCES) \
	$(unit1323_SOURCES) $(unit1330_SOURCES) $(unit1394_SOURCES) \
	$(unit1395_SOURCES) $(unit1396_SOURCES) $(unit1397_SOURCES) \
	$(unit1398_SOURCES) $(unit1399_SOURCES) $(unit1600_SOURCES) \
	$(unit1601_SOURCES) $(unit1602_SOURCES) $(unit1603_SOURCES) \
	$(unit1604_SOURCES) $(unit1605_SOURCES) $(unit1606_SOURCES) \
	$(unit1607_SOURCES) $(unit1608_SOURCES) $(unit1609_SOURCES) \
	$(unit1610_SOURCES) $(unit1611_SOURCES) $(unit1612_SOURCES) \
	$(unit1614_SOURCES) $(unit1615_SOURCES) $(unit1616_SOURCES) \
	$(unit1620_SOURCES) $(unit1621_SOURCES) $(unit1650_SOURCES) \
	$(unit1651_SOURCES) $(unit1652_SOURCES) $(unit1653_SOURCES) \
	$(unit1654_SOURCES) $(unit1655_SOURCES) $(unit1660_SOURCES) \
	$(unit1661_SOURCES) $(unit1663_SOURCES) $(unit2600_SOURCES) \
	$(unit2601_SOURCES) $(unit2602_SOURCES) $(unit2603_SOURCES) \
	$(unit2604_SOURCES) $(unit3200_SOURCES) $(unit3205_SOURCES)
am__can_run_installinfo = \
  case $$AM_UPDATE_INFO_DIR in \
    n|no|NO) false;; \
    *) (install-info --version) >/dev/null 2>&1;; \
  esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
623
624
625
626
627
628
629


630
631
632
633
634
635
636
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@


LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@







>
>







627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IPV6_ENABLED = @IPV6_ENABLED@
LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_NO_SHARED = @LIBCURL_NO_SHARED@
LIBCURL_PC_REQUIRES = @LIBCURL_PC_REQUIRES@
LIBCURL_PC_REQUIRES_PRIVATE = @LIBCURL_PC_REQUIRES_PRIVATE@
LIBOBJS = @LIBOBJS@

# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
 unit1308 unit1309 unit1323 \
 unit1330 unit1394 unit1395 unit1396 unit1397 unit1398 \
 unit1399 \
 unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
 unit1608 unit1609 unit1610 unit1611 unit1612 unit1614 unit1615 unit1616 \
 unit1620 unit1621 \
 unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
 unit1660 unit1661 \
 unit2600 unit2601 unit2602 unit2603 unit2604 \
 unit3200 \
 unit3205

unit1300_SOURCES = unit1300.c $(UNITFILES)
unit1302_SOURCES = unit1302.c $(UNITFILES)
unit1303_SOURCES = unit1303.c $(UNITFILES)







|







826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
 unit1308 unit1309 unit1323 \
 unit1330 unit1394 unit1395 unit1396 unit1397 unit1398 \
 unit1399 \
 unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
 unit1608 unit1609 unit1610 unit1611 unit1612 unit1614 unit1615 unit1616 \
 unit1620 unit1621 \
 unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
 unit1660 unit1661 unit1663 \
 unit2600 unit2601 unit2602 unit2603 unit2604 \
 unit3200 \
 unit3205

unit1300_SOURCES = unit1300.c $(UNITFILES)
unit1302_SOURCES = unit1302.c $(UNITFILES)
unit1303_SOURCES = unit1303.c $(UNITFILES)
867
868
869
870
871
872
873

874
875
876
877
878
879
880
unit1651_SOURCES = unit1651.c $(UNITFILES)
unit1652_SOURCES = unit1652.c $(UNITFILES)
unit1653_SOURCES = unit1653.c $(UNITFILES)
unit1654_SOURCES = unit1654.c $(UNITFILES)
unit1655_SOURCES = unit1655.c $(UNITFILES)
unit1660_SOURCES = unit1660.c $(UNITFILES)
unit1661_SOURCES = unit1661.c $(UNITFILES)

unit2600_SOURCES = unit2600.c $(UNITFILES)
unit2601_SOURCES = unit2601.c $(UNITFILES)
unit2602_SOURCES = unit2602.c $(UNITFILES)
unit2603_SOURCES = unit2603.c $(UNITFILES)
unit2604_SOURCES = unit2604.c $(UNITFILES)
unit3200_SOURCES = unit3200.c $(UNITFILES)
unit3205_SOURCES = unit3205.c $(UNITFILES)







>







873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
unit1651_SOURCES = unit1651.c $(UNITFILES)
unit1652_SOURCES = unit1652.c $(UNITFILES)
unit1653_SOURCES = unit1653.c $(UNITFILES)
unit1654_SOURCES = unit1654.c $(UNITFILES)
unit1655_SOURCES = unit1655.c $(UNITFILES)
unit1660_SOURCES = unit1660.c $(UNITFILES)
unit1661_SOURCES = unit1661.c $(UNITFILES)
unit1663_SOURCES = unit1663.c $(UNITFILES)
unit2600_SOURCES = unit2600.c $(UNITFILES)
unit2601_SOURCES = unit2601.c $(UNITFILES)
unit2602_SOURCES = unit2602.c $(UNITFILES)
unit2603_SOURCES = unit2603.c $(UNITFILES)
unit2604_SOURCES = unit2604.c $(UNITFILES)
unit3200_SOURCES = unit3200.c $(UNITFILES)
unit3205_SOURCES = unit3205.c $(UNITFILES)
1093
1094
1095
1096
1097
1098
1099




1100
1101
1102
1103
1104
1105
1106
unit1660$(EXEEXT): $(unit1660_OBJECTS) $(unit1660_DEPENDENCIES) $(EXTRA_unit1660_DEPENDENCIES) 
	@rm -f unit1660$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(unit1660_OBJECTS) $(unit1660_LDADD) $(LIBS)

unit1661$(EXEEXT): $(unit1661_OBJECTS) $(unit1661_DEPENDENCIES) $(EXTRA_unit1661_DEPENDENCIES) 
	@rm -f unit1661$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(unit1661_OBJECTS) $(unit1661_LDADD) $(LIBS)





unit2600$(EXEEXT): $(unit2600_OBJECTS) $(unit2600_DEPENDENCIES) $(EXTRA_unit2600_DEPENDENCIES) 
	@rm -f unit2600$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(unit2600_OBJECTS) $(unit2600_LDADD) $(LIBS)

unit2601$(EXEEXT): $(unit2601_OBJECTS) $(unit2601_DEPENDENCIES) $(EXTRA_unit2601_DEPENDENCIES) 
	@rm -f unit2601$(EXEEXT)







>
>
>
>







1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
unit1660$(EXEEXT): $(unit1660_OBJECTS) $(unit1660_DEPENDENCIES) $(EXTRA_unit1660_DEPENDENCIES) 
	@rm -f unit1660$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(unit1660_OBJECTS) $(unit1660_LDADD) $(LIBS)

unit1661$(EXEEXT): $(unit1661_OBJECTS) $(unit1661_DEPENDENCIES) $(EXTRA_unit1661_DEPENDENCIES) 
	@rm -f unit1661$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(unit1661_OBJECTS) $(unit1661_LDADD) $(LIBS)

unit1663$(EXEEXT): $(unit1663_OBJECTS) $(unit1663_DEPENDENCIES) $(EXTRA_unit1663_DEPENDENCIES) 
	@rm -f unit1663$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(unit1663_OBJECTS) $(unit1663_LDADD) $(LIBS)

unit2600$(EXEEXT): $(unit2600_OBJECTS) $(unit2600_DEPENDENCIES) $(EXTRA_unit2600_DEPENDENCIES) 
	@rm -f unit2600$(EXEEXT)
	$(AM_V_CCLD)$(LINK) $(unit2600_OBJECTS) $(unit2600_LDADD) $(LIBS)

unit2601$(EXEEXT): $(unit2601_OBJECTS) $(unit2601_DEPENDENCIES) $(EXTRA_unit2601_DEPENDENCIES) 
	@rm -f unit2601$(EXEEXT)
1172
1173
1174
1175
1176
1177
1178

1179
1180
1181
1182
1183
1184
1185
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1651.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1652.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1653.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1654.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1655.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1660.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1661.Po@am__quote@ # am--include-marker

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2600.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2601.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2602.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2603.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2604.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit3200.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit3205.Po@am__quote@ # am--include-marker







>







1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1651.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1652.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1653.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1654.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1655.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1660.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1661.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit1663.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2600.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2601.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2602.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2603.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit2604.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit3200.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unit3205.Po@am__quote@ # am--include-marker
1385
1386
1387
1388
1389
1390
1391

1392
1393
1394
1395
1396
1397
1398
	-rm -f ./$(DEPDIR)/unit1651.Po
	-rm -f ./$(DEPDIR)/unit1652.Po
	-rm -f ./$(DEPDIR)/unit1653.Po
	-rm -f ./$(DEPDIR)/unit1654.Po
	-rm -f ./$(DEPDIR)/unit1655.Po
	-rm -f ./$(DEPDIR)/unit1660.Po
	-rm -f ./$(DEPDIR)/unit1661.Po

	-rm -f ./$(DEPDIR)/unit2600.Po
	-rm -f ./$(DEPDIR)/unit2601.Po
	-rm -f ./$(DEPDIR)/unit2602.Po
	-rm -f ./$(DEPDIR)/unit2603.Po
	-rm -f ./$(DEPDIR)/unit2604.Po
	-rm -f ./$(DEPDIR)/unit3200.Po
	-rm -f ./$(DEPDIR)/unit3205.Po







>







1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
	-rm -f ./$(DEPDIR)/unit1651.Po
	-rm -f ./$(DEPDIR)/unit1652.Po
	-rm -f ./$(DEPDIR)/unit1653.Po
	-rm -f ./$(DEPDIR)/unit1654.Po
	-rm -f ./$(DEPDIR)/unit1655.Po
	-rm -f ./$(DEPDIR)/unit1660.Po
	-rm -f ./$(DEPDIR)/unit1661.Po
	-rm -f ./$(DEPDIR)/unit1663.Po
	-rm -f ./$(DEPDIR)/unit2600.Po
	-rm -f ./$(DEPDIR)/unit2601.Po
	-rm -f ./$(DEPDIR)/unit2602.Po
	-rm -f ./$(DEPDIR)/unit2603.Po
	-rm -f ./$(DEPDIR)/unit2604.Po
	-rm -f ./$(DEPDIR)/unit3200.Po
	-rm -f ./$(DEPDIR)/unit3205.Po
1480
1481
1482
1483
1484
1485
1486

1487
1488
1489
1490
1491
1492
1493
	-rm -f ./$(DEPDIR)/unit1651.Po
	-rm -f ./$(DEPDIR)/unit1652.Po
	-rm -f ./$(DEPDIR)/unit1653.Po
	-rm -f ./$(DEPDIR)/unit1654.Po
	-rm -f ./$(DEPDIR)/unit1655.Po
	-rm -f ./$(DEPDIR)/unit1660.Po
	-rm -f ./$(DEPDIR)/unit1661.Po

	-rm -f ./$(DEPDIR)/unit2600.Po
	-rm -f ./$(DEPDIR)/unit2601.Po
	-rm -f ./$(DEPDIR)/unit2602.Po
	-rm -f ./$(DEPDIR)/unit2603.Po
	-rm -f ./$(DEPDIR)/unit2604.Po
	-rm -f ./$(DEPDIR)/unit3200.Po
	-rm -f ./$(DEPDIR)/unit3205.Po







>







1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
	-rm -f ./$(DEPDIR)/unit1651.Po
	-rm -f ./$(DEPDIR)/unit1652.Po
	-rm -f ./$(DEPDIR)/unit1653.Po
	-rm -f ./$(DEPDIR)/unit1654.Po
	-rm -f ./$(DEPDIR)/unit1655.Po
	-rm -f ./$(DEPDIR)/unit1660.Po
	-rm -f ./$(DEPDIR)/unit1661.Po
	-rm -f ./$(DEPDIR)/unit1663.Po
	-rm -f ./$(DEPDIR)/unit2600.Po
	-rm -f ./$(DEPDIR)/unit2601.Po
	-rm -f ./$(DEPDIR)/unit2602.Po
	-rm -f ./$(DEPDIR)/unit2603.Po
	-rm -f ./$(DEPDIR)/unit2604.Po
	-rm -f ./$(DEPDIR)/unit3200.Po
	-rm -f ./$(DEPDIR)/unit3205.Po
Changes to jni/curl/tests/unit/Makefile.inc.
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 unit1308 unit1309 unit1323 \
 unit1330 unit1394 unit1395 unit1396 unit1397 unit1398 \
 unit1399 \
 unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
 unit1608 unit1609 unit1610 unit1611 unit1612 unit1614 unit1615 unit1616 \
 unit1620 unit1621 \
 unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
 unit1660 unit1661 \
 unit2600 unit2601 unit2602 unit2603 unit2604 \
 unit3200 \
 unit3205

unit1300_SOURCES = unit1300.c $(UNITFILES)

unit1302_SOURCES = unit1302.c $(UNITFILES)







|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 unit1308 unit1309 unit1323 \
 unit1330 unit1394 unit1395 unit1396 unit1397 unit1398 \
 unit1399 \
 unit1600 unit1601 unit1602 unit1603 unit1604 unit1605 unit1606 unit1607 \
 unit1608 unit1609 unit1610 unit1611 unit1612 unit1614 unit1615 unit1616 \
 unit1620 unit1621 \
 unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 \
 unit1660 unit1661 unit1663 \
 unit2600 unit2601 unit2602 unit2603 unit2604 \
 unit3200 \
 unit3205

unit1300_SOURCES = unit1300.c $(UNITFILES)

unit1302_SOURCES = unit1302.c $(UNITFILES)
121
122
123
124
125
126
127


128
129
130
131
132
133
134
unit1654_SOURCES = unit1654.c $(UNITFILES)

unit1655_SOURCES = unit1655.c $(UNITFILES)

unit1660_SOURCES = unit1660.c $(UNITFILES)

unit1661_SOURCES = unit1661.c $(UNITFILES)



unit2600_SOURCES = unit2600.c $(UNITFILES)

unit2601_SOURCES = unit2601.c $(UNITFILES)

unit2602_SOURCES = unit2602.c $(UNITFILES)








>
>







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
unit1654_SOURCES = unit1654.c $(UNITFILES)

unit1655_SOURCES = unit1655.c $(UNITFILES)

unit1660_SOURCES = unit1660.c $(UNITFILES)

unit1661_SOURCES = unit1661.c $(UNITFILES)

unit1663_SOURCES = unit1663.c $(UNITFILES)

unit2600_SOURCES = unit2600.c $(UNITFILES)

unit2601_SOURCES = unit2601.c $(UNITFILES)

unit2602_SOURCES = unit2602.c $(UNITFILES)

Changes to jni/curl/tests/unit/unit1603.c.
34
35
36
37
38
39
40










41
42
43
44
45
46
47
static const size_t slots = 3;

static void mydtor(void *p)
{
  /* Data are statically allocated */
 (void)p; /* unused */
}











static CURLcode unit_setup(void)
{
  Curl_hash_init(&hash_static, slots, Curl_hash_str,
                 Curl_str_key_compare, mydtor);
  return CURLE_OK;
}







>
>
>
>
>
>
>
>
>
>







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
static const size_t slots = 3;

static void mydtor(void *p)
{
  /* Data are statically allocated */
 (void)p; /* unused */
}

static size_t elem_dtor_calls;

static void my_elem_dtor(void *key, size_t key_len, void *p)
{
  (void)p; /* unused */
  (void)key; /* unused */
  (void)key_len; /* unused */
  ++elem_dtor_calls;
}

static CURLcode unit_setup(void)
{
  Curl_hash_init(&hash_static, slots, Curl_hash_str,
                 Curl_str_key_compare, mydtor);
  return CURLE_OK;
}
142
143
144
145
146
147
148
















149
150
151
152
153
  fail_unless(nodep == notakey, "hash retrieval failed");

  /* Make sure all remaining elements are still accessible */
  nodep = Curl_hash_pick(&hash_static, &key2, strlen(key2));
  fail_unless(nodep == key2, "hash retrieval failed");
  nodep = Curl_hash_pick(&hash_static, &key3, strlen(key3));
  fail_unless(nodep == key3, "hash retrieval failed");

















  /* Clean up */
  Curl_hash_clean(&hash_static);

UNITTEST_STOP







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  fail_unless(nodep == notakey, "hash retrieval failed");

  /* Make sure all remaining elements are still accessible */
  nodep = Curl_hash_pick(&hash_static, &key2, strlen(key2));
  fail_unless(nodep == key2, "hash retrieval failed");
  nodep = Curl_hash_pick(&hash_static, &key3, strlen(key3));
  fail_unless(nodep == key3, "hash retrieval failed");

  /* Add element with own destructor */
  nodep = Curl_hash_add2(&hash_static, &key1, strlen(key1), &key1,
                         my_elem_dtor);
  fail_unless(nodep, "add2 insertion into hash failed");
  fail_unless(elem_dtor_calls == 0, "element destructor count should be 0");
  /* Add it again, should invoke destructor on first */
  nodep = Curl_hash_add2(&hash_static, &key1, strlen(key1), &key1,
                         my_elem_dtor);
  fail_unless(nodep, "add2 again, insertion into hash failed");
  fail_unless(elem_dtor_calls == 1, "element destructor count should be 1");
  /* remove, should invoke destructor */
  rc = Curl_hash_delete(&hash_static, &key1, strlen(key1));
  fail_unless(rc == 0, "hash delete failed");
  fail_unless(elem_dtor_calls == 2, "element destructor count should be 1");


  /* Clean up */
  Curl_hash_clean(&hash_static);

UNITTEST_STOP
Changes to jni/curl/tests/unit/unit1614.c.
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  bool match;
};

struct noproxy {
  const char *a;
  const char *n;
  bool match;
  bool space; /* space separated */
};

UNITTEST_START
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_PROXY)
{
  int i;
  int err = 0;







<







42
43
44
45
46
47
48

49
50
51
52
53
54
55
  bool match;
};

struct noproxy {
  const char *a;
  const char *n;
  bool match;

};

UNITTEST_START
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_PROXY)
{
  int i;
  int err = 0;
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

115
116
117
118



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
    { "::1", "::1", 128, TRUE},
    { "::1", "0:0::1", 128, TRUE},
    { "::1", "0:0::1", 129, FALSE},
    { "fe80::ab47:4396:55c9:8474", "fe80::ab47:4396:55c9:8474", 64, TRUE},
    { NULL, NULL, 0, FALSE} /* end marker */
  };
  struct noproxy list[]= {
    { "www.example.com", "localhost .example.com .example.de", TRUE, TRUE},
    { "www.example.com", "localhost,.example.com,.example.de", TRUE, FALSE},
    { "www.example.com.", "localhost,.example.com,.example.de", TRUE, FALSE},
    { "example.com", "localhost,.example.com,.example.de", TRUE, FALSE},
    { "example.com.", "localhost,.example.com,.example.de", TRUE, FALSE},
    { "www.example.com", "localhost,.example.com.,.example.de", TRUE, FALSE},
    { "www.example.com", "localhost,www.example.com.,.example.de",
      TRUE, FALSE},
    { "example.com", "localhost,example.com,.example.de", TRUE, FALSE},
    { "example.com.", "localhost,example.com,.example.de", TRUE, FALSE},
    { "nexample.com", "localhost,example.com,.example.de", FALSE, FALSE},
    { "www.example.com", "localhost,example.com,.example.de", TRUE, FALSE},
    { "127.0.0.1", "127.0.0.1,localhost", TRUE, FALSE},
    { "127.0.0.1", "127.0.0.1,localhost,", TRUE, FALSE},
    { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE, FALSE},
    { "127.0.0.1", "127.0.0.1/28,localhost,", TRUE, FALSE},
    { "127.0.0.1", "127.0.0.1/31,localhost,", TRUE, FALSE},
    { "127.0.0.1", "localhost,127.0.0.1", TRUE, FALSE},
    { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
      "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
      "0.0.1.127.0.0.1.127.0.0." /* 128 bytes "address" */, FALSE, FALSE},
    { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
      "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
      "0.0.1.127.0.0.1.127.0.0" /* 127 bytes "address" */, FALSE, FALSE},
    { "localhost", "localhost,127.0.0.1", TRUE, FALSE},
    { "localhost", "127.0.0.1,localhost", TRUE, FALSE},
    { "foobar", "barfoo", FALSE, FALSE},
    { "foobar", "foobar", TRUE, FALSE},
    { "192.168.0.1", "foobar", FALSE, FALSE},
    { "192.168.0.1", "192.168.0.0/16", TRUE, FALSE},
    { "192.168.0.1", "192.168.0.0/24", TRUE, FALSE},
    { "192.168.0.1", "192.168.0.0/32", FALSE, FALSE},
    { "192.168.0.1", "192.168.0.0", FALSE, FALSE},
    { "192.168.1.1", "192.168.0.0/24", FALSE, FALSE},

    { "192.168.1.1", "foo, bar, 192.168.0.0/24", FALSE, FALSE},
    { "192.168.1.1", "foo, bar, 192.168.0.0/16", TRUE, FALSE},
    { "[::1]", "foo, bar, 192.168.0.0/16", FALSE, FALSE},
    { "[::1]", "foo, bar, ::1/64", TRUE, FALSE},



    { "bar", "foo, bar, ::1/64", TRUE, FALSE},
    { "BAr", "foo, bar, ::1/64", TRUE, FALSE},
    { "BAr", "foo,,,,,              bar, ::1/64", TRUE, FALSE},
    { "www.example.com", "foo, .example.com", TRUE, FALSE},
    { "www.example.com", "www2.example.com, .example.net", FALSE, FALSE},
    { "example.com", ".example.com, .example.net", TRUE, FALSE},
    { "nonexample.com", ".example.com, .example.net", FALSE, FALSE},
    { NULL, NULL, FALSE, FALSE}
  };
  for(i = 0; list4[i].a; i++) {
    bool match = Curl_cidr4_match(list4[i].a, list4[i].n, list4[i].bits);
    if(match != list4[i].match) {
      fprintf(stderr, "%s in %s/%u should %smatch\n",
              list4[i].a, list4[i].n, list4[i].bits,
              list4[i].match ? "": "not ");
      err++;
    }
  }
  for(i = 0; list6[i].a; i++) {
    bool match = Curl_cidr6_match(list6[i].a, list6[i].n, list6[i].bits);
    if(match != list6[i].match) {
      fprintf(stderr, "%s in %s/%u should %smatch\n",
              list6[i].a, list6[i].n, list6[i].bits,
              list6[i].match ? "": "not ");
      err++;
    }
  }
  for(i = 0; list[i].a; i++) {
    bool spacesep = FALSE;
    bool match = Curl_check_noproxy(list[i].a, list[i].n, &spacesep);
    if(match != list[i].match) {
      fprintf(stderr, "%s in %s should %smatch\n",
              list[i].a, list[i].n,
              list[i].match ? "": "not ");
      err++;
    }
    if(spacesep != list[i].space) {
      fprintf(stderr, "%s is claimed to be %sspace separated\n",
              list[i].n, list[i].space?"":"NOT ");
      err++;
    }
  }
  fail_if(err, "errors");
}
#endif
UNITTEST_STOP







|
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
|


|


|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
>
>
>
|
|
|
|
|
|
|
|




















<
|






<
<
<
<
<





73
74
75
76
77
78
79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151
152
153
154
155





156
157
158
159
160
    { "::1", "::1", 128, TRUE},
    { "::1", "0:0::1", 128, TRUE},
    { "::1", "0:0::1", 129, FALSE},
    { "fe80::ab47:4396:55c9:8474", "fe80::ab47:4396:55c9:8474", 64, TRUE},
    { NULL, NULL, 0, FALSE} /* end marker */
  };
  struct noproxy list[]= {
    { "www.example.com", "localhost .example.com .example.de", FALSE},
    { "www.example.com", "localhost,.example.com,.example.de", TRUE},
    { "www.example.com.", "localhost,.example.com,.example.de", TRUE},
    { "example.com", "localhost,.example.com,.example.de", TRUE},
    { "example.com.", "localhost,.example.com,.example.de", TRUE},
    { "www.example.com", "localhost,.example.com.,.example.de", TRUE},
    { "www.example.com", "localhost,www.example.com.,.example.de", TRUE},

    { "example.com", "localhost,example.com,.example.de", TRUE},
    { "example.com.", "localhost,example.com,.example.de", TRUE},
    { "nexample.com", "localhost,example.com,.example.de", FALSE},
    { "www.example.com", "localhost,example.com,.example.de", TRUE},
    { "127.0.0.1", "127.0.0.1,localhost", TRUE},
    { "127.0.0.1", "127.0.0.1,localhost,", TRUE},
    { "127.0.0.1", "127.0.0.1/8,localhost,", TRUE},
    { "127.0.0.1", "127.0.0.1/28,localhost,", TRUE},
    { "127.0.0.1", "127.0.0.1/31,localhost,", TRUE},
    { "127.0.0.1", "localhost,127.0.0.1", TRUE},
    { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
      "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
      "0.0.1.127.0.0.1.127.0.0." /* 128 bytes "address" */, FALSE},
    { "127.0.0.1", "localhost,127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1."
      "127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127.0.0.1.127."
      "0.0.1.127.0.0.1.127.0.0" /* 127 bytes "address" */, FALSE},
    { "localhost", "localhost,127.0.0.1", TRUE},
    { "localhost", "127.0.0.1,localhost", TRUE},
    { "foobar", "barfoo", FALSE},
    { "foobar", "foobar", TRUE},
    { "192.168.0.1", "foobar", FALSE},
    { "192.168.0.1", "192.168.0.0/16", TRUE},
    { "192.168.0.1", "192.168.0.0/24", TRUE},
    { "192.168.0.1", "192.168.0.0/32", FALSE},
    { "192.168.0.1", "192.168.0.0", FALSE},
    { "192.168.1.1", "192.168.0.0/24", FALSE},
    { "192.168.1.1", "192.168.0.0/33", FALSE},
    { "192.168.1.1", "foo, bar, 192.168.0.0/24", FALSE},
    { "192.168.1.1", "foo, bar, 192.168.0.0/16", TRUE},
    { "[::1]", "foo, bar, 192.168.0.0/16", FALSE},
    { "[::1]", "foo, bar, ::1/64", TRUE},
    { "[::1]", "::1/64", TRUE},
    { "[::1]", "::1/96", TRUE},
    { "[::1]", "::1/129", FALSE},
    { "bar", "foo, bar, ::1/64", TRUE},
    { "BAr", "foo, bar, ::1/64", TRUE},
    { "BAr", "foo,,,,,              bar, ::1/64", TRUE},
    { "www.example.com", "foo, .example.com", TRUE},
    { "www.example.com", "www2.example.com, .example.net", FALSE},
    { "example.com", ".example.com, .example.net", TRUE},
    { "nonexample.com", ".example.com, .example.net", FALSE},
    { NULL, NULL, FALSE}
  };
  for(i = 0; list4[i].a; i++) {
    bool match = Curl_cidr4_match(list4[i].a, list4[i].n, list4[i].bits);
    if(match != list4[i].match) {
      fprintf(stderr, "%s in %s/%u should %smatch\n",
              list4[i].a, list4[i].n, list4[i].bits,
              list4[i].match ? "": "not ");
      err++;
    }
  }
  for(i = 0; list6[i].a; i++) {
    bool match = Curl_cidr6_match(list6[i].a, list6[i].n, list6[i].bits);
    if(match != list6[i].match) {
      fprintf(stderr, "%s in %s/%u should %smatch\n",
              list6[i].a, list6[i].n, list6[i].bits,
              list6[i].match ? "": "not ");
      err++;
    }
  }
  for(i = 0; list[i].a; i++) {

    bool match = Curl_check_noproxy(list[i].a, list[i].n);
    if(match != list[i].match) {
      fprintf(stderr, "%s in %s should %smatch\n",
              list[i].a, list[i].n,
              list[i].match ? "": "not ");
      err++;
    }





  }
  fail_if(err, "errors");
}
#endif
UNITTEST_STOP
Changes to jni/curl/tests/unit/unit1620.c.
35
36
37
38
39
40
41































42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  return res;
}

static void unit_stop(void)
{
  curl_global_cleanup();
}
































UNITTEST_START
{
  CURLcode rc;
  struct Curl_easy *empty;
  const char *hostname = "hostname";
  enum dupstring i;
  char *userstr = NULL;
  char *passwdstr = NULL;

  bool async = FALSE;
  bool protocol_connect = FALSE;

  rc = Curl_open(&empty);
  if(rc)
    goto unit_test_abort;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





<

<
<







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

78


79
80
81
82
83
84
85
  return res;
}

static void unit_stop(void)
{
  curl_global_cleanup();
}

static void test_parse(
  const char *input,
  const char *exp_username,
  const char *exp_password,
  const char *exp_options)
{
  char *userstr = NULL;
  char *passwdstr = NULL;
  char *options = NULL;
  CURLcode rc = Curl_parse_login_details(input, strlen(input),
                                &userstr, &passwdstr, &options);
  fail_unless(rc == CURLE_OK, "Curl_parse_login_details() failed");

  fail_unless(!!exp_username == !!userstr, "username expectation failed");
  fail_unless(!!exp_password == !!passwdstr, "password expectation failed");
  fail_unless(!!exp_options == !!options, "options expectation failed");

  if(!unitfail) {
    fail_unless(!exp_username || strcmp(userstr, exp_username) == 0,
                "userstr should be equal to exp_username");
    fail_unless(!exp_password || strcmp(passwdstr, exp_password) == 0,
                "passwdstr should be equal to exp_password");
    fail_unless(!exp_options || strcmp(options, exp_options) == 0,
                "options should be equal to exp_options");
  }

  free(userstr);
  free(passwdstr);
  free(options);
}

UNITTEST_START
{
  CURLcode rc;
  struct Curl_easy *empty;

  enum dupstring i;



  bool async = FALSE;
  bool protocol_connect = FALSE;

  rc = Curl_open(&empty);
  if(rc)
    goto unit_test_abort;
71
72
73
74
75
76
77
78



79
80
81
82

83






84
85
86
87
88
89
90
91
92
93
94
95

  rc = Curl_init_userdefined(empty);
  fail_unless(rc == CURLE_OK, "Curl_userdefined() failed");

  rc = Curl_init_do(empty, empty->conn);
  fail_unless(rc == CURLE_OK, "Curl_init_do() failed");

  rc = Curl_parse_login_details(hostname, strlen(hostname),



                                &userstr, &passwdstr, NULL);
  fail_unless(rc == CURLE_OK,
              "Curl_parse_login_details() failed");
  free(userstr);

  free(passwdstr);







  Curl_freeset(empty);
  for(i = (enum dupstring)0; i < STRING_LAST; i++) {
    fail_unless(empty->set.str[i] == NULL,
                "Curl_free() did not set to NULL");
  }

  rc = Curl_close(&empty);
  fail_unless(rc == CURLE_OK, "Curl_close() failed");

}
UNITTEST_STOP







|
>
>
>
|
<
|
<
>
|
>
>
>
>
>
>












99
100
101
102
103
104
105
106
107
108
109
110

111

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

  rc = Curl_init_userdefined(empty);
  fail_unless(rc == CURLE_OK, "Curl_userdefined() failed");

  rc = Curl_init_do(empty, empty->conn);
  fail_unless(rc == CURLE_OK, "Curl_init_do() failed");

  test_parse("hostname", "hostname", NULL, NULL);
  test_parse("user:password", "user", "password", NULL);
  test_parse("user:password;options", "user", "password", "options");
  test_parse("user:password;options;more", "user", "password", "options;more");
  test_parse("", "", NULL, NULL);

  test_parse(":", "", "", NULL);

  test_parse(":;", "", "", NULL);
  test_parse(":password", "", "password", NULL);
  test_parse(":password;", "", "password", NULL);
  test_parse(";options", "", NULL, "options");
  test_parse("user;options", "user", NULL, "options");
  test_parse("user:;options", "user", "", "options");
  test_parse("user;options:password", "user", "password", "options");
  test_parse("user;options:", "user", "", "options");

  Curl_freeset(empty);
  for(i = (enum dupstring)0; i < STRING_LAST; i++) {
    fail_unless(empty->set.str[i] == NULL,
                "Curl_free() did not set to NULL");
  }

  rc = Curl_close(&empty);
  fail_unless(rc == CURLE_OK, "Curl_close() failed");

}
UNITTEST_STOP
Added jni/curl/tests/unit/unit1663.c.




































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at https://curl.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * SPDX-License-Identifier: curl
 *
 ***************************************************************************/
#include "curlcheck.h"

#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_NETINET_IN6_H
#include <netinet/in6.h>
#endif

#include <curl/curl.h>

#include "cf-socket.h"

#include "memdebug.h" /* LAST include file */

static CURLcode unit_setup(void)
{
  CURLcode res = CURLE_OK;
  global_init(CURL_GLOBAL_ALL);
  return res;
}

static void unit_stop(void)
{
  curl_global_cleanup();
}

static void test_parse(
  const char *input,
  const char *exp_dev,
  const char *exp_iface,
  const char *exp_host,
  CURLcode exp_rc)
{
  char *dev = NULL;
  char *iface = NULL;
  char *host = NULL;
  CURLcode rc = Curl_parse_interface(
    input, strlen(input), &dev, &iface, &host);
  fail_unless(rc == exp_rc, "Curl_parse_interface() failed");

  fail_unless(!!exp_dev == !!dev, "dev expectation failed.");
  fail_unless(!!exp_iface == !!iface, "iface expectation failed");
  fail_unless(!!exp_host == !!host, "host expectation failed");

  if(!unitfail) {
    fail_unless(!exp_dev || strcmp(dev, exp_dev) == 0,
                "dev should be equal to exp_dev");
    fail_unless(!exp_iface || strcmp(iface, exp_iface) == 0,
                "iface should be equal to exp_iface");
    fail_unless(!exp_host || strcmp(host, exp_host) == 0,
                "host should be equal to exp_host");
  }

  free(dev);
  free(iface);
  free(host);
}

UNITTEST_START
{
  test_parse("dev", "dev", NULL, NULL, CURLE_OK);
  test_parse("if!eth0", NULL, "eth0", NULL, CURLE_OK);
  test_parse("host!myname", NULL, NULL, "myname", CURLE_OK);
  test_parse("ifhost!eth0!myname", NULL, "eth0", "myname", CURLE_OK);
  test_parse("", NULL, NULL, NULL, CURLE_BAD_FUNCTION_ARGUMENT);
  test_parse("!", "!", NULL, NULL, CURLE_OK);
  test_parse("if!", NULL, NULL, NULL, CURLE_BAD_FUNCTION_ARGUMENT);
  test_parse("if!eth0!blubb", NULL, "eth0!blubb", NULL, CURLE_OK);
  test_parse("host!", NULL, NULL, NULL, CURLE_BAD_FUNCTION_ARGUMENT);
  test_parse("ifhost!", NULL, NULL, NULL, CURLE_BAD_FUNCTION_ARGUMENT);
  test_parse("ifhost!eth0", NULL, NULL, NULL, CURLE_BAD_FUNCTION_ARGUMENT);
  test_parse("ifhost!eth0!", NULL, NULL, NULL, CURLE_BAD_FUNCTION_ARGUMENT);
}
UNITTEST_STOP
Changes to jni/curl/tests/unit/unit2600.c.
43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <setjmp.h>
#include <signal.h>

#include "urldata.h"
#include "connect.h"
#include "cfilters.h"
#include "multiif.h"

#include "curl_trc.h"


static CURL *easy;

static CURLcode unit_setup(void)
{
  CURLcode res = CURLE_OK;

  global_init(CURL_GLOBAL_ALL);
  easy = curl_easy_init();
  if(!easy) {
    curl_global_cleanup();
    return CURLE_OUT_OF_MEMORY;
  }

  curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L);
  return res;
}

static void unit_stop(void)
{
  curl_easy_cleanup(easy);
  curl_global_cleanup();
}

#ifdef DEBUGBUILD

struct test_case {
  int id;
  const char *url;
  const char *resolve_info;
  unsigned char ip_version;
  timediff_t connect_timeout_ms;
  timediff_t he_timeout_ms;







>















>










<
<







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76


77
78
79
80
81
82
83
#include <setjmp.h>
#include <signal.h>

#include "urldata.h"
#include "connect.h"
#include "cfilters.h"
#include "multiif.h"
#include "select.h"
#include "curl_trc.h"


static CURL *easy;

static CURLcode unit_setup(void)
{
  CURLcode res = CURLE_OK;

  global_init(CURL_GLOBAL_ALL);
  easy = curl_easy_init();
  if(!easy) {
    curl_global_cleanup();
    return CURLE_OUT_OF_MEMORY;
  }
  curl_global_trace("all");
  curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L);
  return res;
}

static void unit_stop(void)
{
  curl_easy_cleanup(easy);
  curl_global_cleanup();
}



struct test_case {
  int id;
  const char *url;
  const char *resolve_info;
  unsigned char ip_version;
  timediff_t connect_timeout_ms;
  timediff_t he_timeout_ms;
144
145
146
147
148
149
150
151
152


153
154
155









156
157
158
159
160
161
162
163

164
165
166
167
168
169
170
171
172
  *done = FALSE;
  duration_ms = Curl_timediff(Curl_now(), ctx->started);
  if(duration_ms >= ctx->fail_delay_ms) {
    infof(data, "%04dms: cf[%s] fail delay reached",
          (int)duration_ms, ctx->id);
    return CURLE_COULDNT_CONNECT;
  }
  if(duration_ms)
    infof(data, "%04dms: cf[%s] continuing", (int)duration_ms, ctx->id);


  Curl_expire(data, ctx->fail_delay_ms - duration_ms, EXPIRE_RUN_NOW);
  return CURLE_OK;
}










static struct Curl_cftype cft_test = {
  "TEST",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_test_destroy,
  cf_test_connect,
  Curl_cf_def_close,

  Curl_cf_def_get_host,
  Curl_cf_def_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
  Curl_cf_def_conn_keep_alive,
  Curl_cf_def_query,







|

>
>



>
>
>
>
>
>
>
>
>








>

|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  *done = FALSE;
  duration_ms = Curl_timediff(Curl_now(), ctx->started);
  if(duration_ms >= ctx->fail_delay_ms) {
    infof(data, "%04dms: cf[%s] fail delay reached",
          (int)duration_ms, ctx->id);
    return CURLE_COULDNT_CONNECT;
  }
  if(duration_ms) {
    infof(data, "%04dms: cf[%s] continuing", (int)duration_ms, ctx->id);
    Curl_wait_ms(10);
  }
  Curl_expire(data, ctx->fail_delay_ms - duration_ms, EXPIRE_RUN_NOW);
  return CURLE_OK;
}

static void cf_test_adjust_pollset(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   struct easy_pollset *ps)
{
  /* just for testing, give one socket with events back */
  (void)cf;
  Curl_pollset_set(data, ps, 1, TRUE, TRUE);
}

static struct Curl_cftype cft_test = {
  "TEST",
  CF_TYPE_IP_CONNECT,
  CURL_LOG_LVL_NONE,
  cf_test_destroy,
  cf_test_connect,
  Curl_cf_def_close,
  Curl_cf_def_shutdown,
  Curl_cf_def_get_host,
  cf_test_adjust_pollset,
  Curl_cf_def_data_pending,
  Curl_cf_def_send,
  Curl_cf_def_recv,
  Curl_cf_def_cntrl,
  Curl_cf_def_conn_is_alive,
  Curl_cf_def_conn_keep_alive,
  Curl_cf_def_query,
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
  list = NULL;
  current_tc = NULL;
  current_tr = NULL;

  check_result(tc, &tr);
}

#endif /* DEBUGBUILD */

/*
 * How these test cases work:
 * - replace the creation of the TCP socket filter with our test filter
 * - test filter does nothing and reports failure after configured delay
 * - we feed addresses into the resolve cache to simulate different cases
 * - we monitor how many instances of ipv4/v6 attempts are made and when
 * - for mixed families, we expect HAPPY_EYEBALLS_TIMEOUT to trigger







<
<







337
338
339
340
341
342
343


344
345
346
347
348
349
350
  list = NULL;
  current_tc = NULL;
  current_tr = NULL;

  check_result(tc, &tr);
}



/*
 * How these test cases work:
 * - replace the creation of the TCP socket filter with our test filter
 * - test filter does nothing and reports failure after configured delay
 * - we feed addresses into the resolve cache to simulate different cases
 * - we monitor how many instances of ipv4/v6 attempts are made and when
 * - for mixed families, we expect HAPPY_EYEBALLS_TIMEOUT to trigger
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
  /* mixed ip4+6, but only use v6, check it uses full connect timeout,
     although another address of the 'wrong' family is available */
#endif
};

UNITTEST_START

#if defined(DEBUGBUILD)
  size_t i;

  for(i = 0; i < sizeof(TEST_CASES)/sizeof(TEST_CASES[0]); ++i) {
    test_connect(&TEST_CASES[i]);
  }
#else
  (void)TEST_CASES;
  (void)test_connect;
#endif

UNITTEST_STOP







<





<
<
<
<


391
392
393
394
395
396
397

398
399
400
401
402




403
404
  /* mixed ip4+6, but only use v6, check it uses full connect timeout,
     although another address of the 'wrong' family is available */
#endif
};

UNITTEST_START


  size_t i;

  for(i = 0; i < sizeof(TEST_CASES)/sizeof(TEST_CASES[0]); ++i) {
    test_connect(&TEST_CASES[i]);
  }





UNITTEST_STOP
Changes to jni/curl/tests/unit/unit2604.c.
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#ifdef USE_SSH
{
/* 60 a's */
#define SA60 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
/* 540 a's */
#define SA540 SA60 SA60 SA60 SA60 SA60 SA60 SA60 SA60 SA60
  int i;
  int error = 0;
  size_t too_long = 90720;
  struct set list[] = {
    { "-too-long-", "", "", "", CURLE_TOO_LARGE},
    { SA540 " c", SA540, "c", "/", CURLE_OK},
    { "\" " SA540 "\" c", " " SA540, "c", "/", CURLE_OK},
    { "a a", "a", "a", "/home/", CURLE_OK},
    { "b a", "b", "a", "/", CURLE_OK},







<







46
47
48
49
50
51
52

53
54
55
56
57
58
59
#ifdef USE_SSH
{
/* 60 a's */
#define SA60 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
/* 540 a's */
#define SA540 SA60 SA60 SA60 SA60 SA60 SA60 SA60 SA60 SA60
  int i;

  size_t too_long = 90720;
  struct set list[] = {
    { "-too-long-", "", "", "", CURLE_TOO_LARGE},
    { SA540 " c", SA540, "c", "/", CURLE_OK},
    { "\" " SA540 "\" c", " " SA540, "c", "/", CURLE_OK},
    { "a a", "a", "a", "/home/", CURLE_OK},
    { "b a", "b", "a", "/", CURLE_OK},
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
    char *path;
    const char *cp = list[i].cp;
    CURLcode result = Curl_get_pathname(&cp, &path, list[i].home);
    printf("%u - Curl_get_pathname(\"%s\", ... \"%s\") == %u\n", i,
           list[i].cp, list[i].home, list[i].result);
    if(result != list[i].result) {
      printf("... returned %d\n", result);
      error++;
    }
    if(!result) {
      if(cp && strcmp(cp, list[i].next)) {
        printf("... cp points to '%s', not '%s' as expected \n",
               cp, list[i].next);
        error++;
      }
      if(path && strcmp(path, list[i].expect)) {
        printf("... gave '%s', not '%s' as expected \n",
               path, list[i].expect);
        error++;
      }
      curl_free(path);

    }
  }

  free((void *)list[0].cp);
  return error == 0 ? CURLE_OK : TEST_ERR_FAILURE;
}
#endif

UNITTEST_STOP







|





|




|







<




80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

106
107
108
109
    char *path;
    const char *cp = list[i].cp;
    CURLcode result = Curl_get_pathname(&cp, &path, list[i].home);
    printf("%u - Curl_get_pathname(\"%s\", ... \"%s\") == %u\n", i,
           list[i].cp, list[i].home, list[i].result);
    if(result != list[i].result) {
      printf("... returned %d\n", result);
      unitfail++;
    }
    if(!result) {
      if(cp && strcmp(cp, list[i].next)) {
        printf("... cp points to '%s', not '%s' as expected \n",
               cp, list[i].next);
        unitfail++;
      }
      if(path && strcmp(path, list[i].expect)) {
        printf("... gave '%s', not '%s' as expected \n",
               path, list[i].expect);
        unitfail++;
      }
      curl_free(path);

    }
  }

  free((void *)list[0].cp);

}
#endif

UNITTEST_STOP
Changes to jni/curl/tests/unit/unit3205.c.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  return CURLE_OK;
}

static void unit_stop(void)
{
}

#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)

struct test_cs_entry {
  uint16_t id;
  const char *rfc;
  const char *openssl;
};
static const struct test_cs_entry test_cs_list[] = {







|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  return CURLE_OK;
}

static void unit_stop(void)
{
}

#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_BEARSSL)

struct test_cs_entry {
  uint16_t id;
  const char *rfc;
  const char *openssl;
};
static const struct test_cs_entry test_cs_list[] = {
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
            "ECDH-RSA-AES128-GCM-SHA256" },
  { 0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
            "ECDH-RSA-AES256-GCM-SHA384" },
  { 0xCCA8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
            "ECDHE-RSA-CHACHA20-POLY1305" },
  { 0xCCA9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
            "ECDHE-ECDSA-CHACHA20-POLY1305" },
#if defined(USE_MBEDTLS)
  { 0x0001, "TLS_RSA_WITH_NULL_MD5",
            "NULL-MD5" },
  { 0x0002, "TLS_RSA_WITH_NULL_SHA",
            "NULL-SHA" },
  { 0x002C, "TLS_PSK_WITH_NULL_SHA",
            "PSK-NULL-SHA" },
  { 0x002D, "TLS_DHE_PSK_WITH_NULL_SHA",







|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
            "ECDH-RSA-AES128-GCM-SHA256" },
  { 0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
            "ECDH-RSA-AES256-GCM-SHA384" },
  { 0xCCA8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
            "ECDHE-RSA-CHACHA20-POLY1305" },
  { 0xCCA9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
            "ECDHE-ECDSA-CHACHA20-POLY1305" },
#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS)
  { 0x0001, "TLS_RSA_WITH_NULL_MD5",
            "NULL-MD5" },
  { 0x0002, "TLS_RSA_WITH_NULL_SHA",
            "NULL-SHA" },
  { 0x002C, "TLS_PSK_WITH_NULL_SHA",
            "PSK-NULL-SHA" },
  { 0x002D, "TLS_DHE_PSK_WITH_NULL_SHA",
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218

219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234














































































































































235
236
237
238
239
240
241
242
243
  { 0xC035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
            "ECDHE-PSK-AES128-CBC-SHA" },
  { 0xC036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
            "ECDHE-PSK-AES256-CBC-SHA" },
  { 0xCCAB, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256",
            "PSK-CHACHA20-POLY1305" },
#endif
#if defined(USE_BEARSSL)
  { 0x000A, "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
            "DES-CBC3-SHA" },
  { 0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
            "ECDH-ECDSA-DES-CBC3-SHA" },
  { 0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
            "ECDHE-ECDSA-DES-CBC3-SHA" },
  { 0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
            "ECDH-RSA-DES-CBC3-SHA" },
  { 0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
            "ECDHE-RSA-DES-CBC3-SHA" },
#endif

  { 0xC09C, "TLS_RSA_WITH_AES_128_CCM",
            "AES128-CCM" },
  { 0xC09D, "TLS_RSA_WITH_AES_256_CCM",
            "AES256-CCM" },
  { 0xC0A0, "TLS_RSA_WITH_AES_128_CCM_8",
            "AES128-CCM8" },
  { 0xC0A1, "TLS_RSA_WITH_AES_256_CCM_8",
            "AES256-CCM8" },
  { 0xC0AC, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM",
            "ECDHE-ECDSA-AES128-CCM" },
  { 0xC0AD, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM",
            "ECDHE-ECDSA-AES256-CCM" },
  { 0xC0AE, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",
            "ECDHE-ECDSA-AES128-CCM8" },
  { 0xC0AF, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",
            "ECDHE-ECDSA-AES256-CCM8" },














































































































































#if defined(USE_MBEDTLS)
  /* entries marked ns are non-"standard", they are not in openssl */
  { 0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
            "CAMELLIA128-SHA" },
  { 0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
            "DHE-RSA-CAMELLIA128-SHA" },
  { 0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
            "CAMELLIA256-SHA" },
  { 0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",







|











>
















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  { 0xC035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
            "ECDHE-PSK-AES128-CBC-SHA" },
  { 0xC036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
            "ECDHE-PSK-AES256-CBC-SHA" },
  { 0xCCAB, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256",
            "PSK-CHACHA20-POLY1305" },
#endif
#if defined(USE_SECTRANSP)  || defined(USE_BEARSSL)
  { 0x000A, "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
            "DES-CBC3-SHA" },
  { 0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
            "ECDH-ECDSA-DES-CBC3-SHA" },
  { 0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
            "ECDHE-ECDSA-DES-CBC3-SHA" },
  { 0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
            "ECDH-RSA-DES-CBC3-SHA" },
  { 0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
            "ECDHE-RSA-DES-CBC3-SHA" },
#endif
#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
  { 0xC09C, "TLS_RSA_WITH_AES_128_CCM",
            "AES128-CCM" },
  { 0xC09D, "TLS_RSA_WITH_AES_256_CCM",
            "AES256-CCM" },
  { 0xC0A0, "TLS_RSA_WITH_AES_128_CCM_8",
            "AES128-CCM8" },
  { 0xC0A1, "TLS_RSA_WITH_AES_256_CCM_8",
            "AES256-CCM8" },
  { 0xC0AC, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM",
            "ECDHE-ECDSA-AES128-CCM" },
  { 0xC0AD, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM",
            "ECDHE-ECDSA-AES256-CCM" },
  { 0xC0AE, "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8",
            "ECDHE-ECDSA-AES128-CCM8" },
  { 0xC0AF, "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8",
            "ECDHE-ECDSA-AES256-CCM8" },
#endif
#if defined(USE_SECTRANSP)
  { 0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5",
            "EXP-RC4-MD5" },
  { 0x0004, "TLS_RSA_WITH_RC4_128_MD5",
            "RC4-MD5" },
  { 0x0005, "TLS_RSA_WITH_RC4_128_SHA",
            "RC4-SHA" },
  { 0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
            "EXP-RC2-CBC-MD5" },
  { 0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA",
            "IDEA-CBC-SHA" },
  { 0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
            "EXP-DES-CBC-SHA" },
  { 0x0009, "TLS_RSA_WITH_DES_CBC_SHA",
            "DES-CBC-SHA" },
  { 0x000B, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
            "EXP-DH-DSS-DES-CBC-SHA" },
  { 0x000C, "TLS_DH_DSS_WITH_DES_CBC_SHA",
            "DH-DSS-DES-CBC-SHA" },
  { 0x000D, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA",
            "DH-DSS-DES-CBC3-SHA" },
  { 0x000E, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
            "EXP-DH-RSA-DES-CBC-SHA" },
  { 0x000F, "TLS_DH_RSA_WITH_DES_CBC_SHA",
            "DH-RSA-DES-CBC-SHA" },
  { 0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA",
            "DH-RSA-DES-CBC3-SHA" },
  { 0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
            "EXP-DHE-DSS-DES-CBC-SHA" },
  { 0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA",
            "DHE-DSS-DES-CBC-SHA" },
  { 0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
            "DHE-DSS-DES-CBC3-SHA" },
  { 0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
            "EXP-DHE-RSA-DES-CBC-SHA" },
  { 0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA",
            "DHE-RSA-DES-CBC-SHA" },
  { 0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
            "DHE-RSA-DES-CBC3-SHA" },
  { 0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
            "EXP-ADH-RC4-MD5" },
  { 0x0018, "TLS_DH_anon_WITH_RC4_128_MD5",
            "ADH-RC4-MD5" },
  { 0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
            "EXP-ADH-DES-CBC-SHA" },
  { 0x001A, "TLS_DH_anon_WITH_DES_CBC_SHA",
            "ADH-DES-CBC-SHA" },
  { 0x001B, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
            "ADH-DES-CBC3-SHA" },
  { 0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA",
            "DH-DSS-AES128-SHA" },
  { 0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA",
            "DH-RSA-AES128-SHA" },
  { 0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
            "DHE-DSS-AES128-SHA" },
  { 0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA",
            "ADH-AES128-SHA" },
  { 0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA",
            "DH-DSS-AES256-SHA" },
  { 0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA",
            "DH-RSA-AES256-SHA" },
  { 0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
            "DHE-DSS-AES256-SHA" },
  { 0x003A, "TLS_DH_anon_WITH_AES_256_CBC_SHA",
            "ADH-AES256-SHA" },
  { 0x003E, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
            "DH-DSS-AES128-SHA256" },
  { 0x003F, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
            "DH-RSA-AES128-SHA256" },
  { 0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
            "DHE-DSS-AES128-SHA256" },
  { 0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256",
            "DH-DSS-AES256-SHA256" },
  { 0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256",
            "DH-RSA-AES256-SHA256" },
  { 0x006A, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
            "DHE-DSS-AES256-SHA256" },
  { 0x006C, "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
            "ADH-AES128-SHA256" },
  { 0x006D, "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
            "ADH-AES256-SHA256" },
  { 0x008A, "TLS_PSK_WITH_RC4_128_SHA",
            "PSK-RC4-SHA" },
  { 0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA",
            "PSK-3DES-EDE-CBC-SHA" },
  { 0x008E, "TLS_DHE_PSK_WITH_RC4_128_SHA",
            "DHE-PSK-RC4-SHA" },
  { 0x008F, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
            "DHE-PSK-3DES-EDE-CBC-SHA" },
  { 0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA",
            "RSA-PSK-RC4-SHA" },
  { 0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
            "RSA-PSK-3DES-EDE-CBC-SHA" },
  { 0x00A0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
            "DH-RSA-AES128-GCM-SHA256" },
  { 0x00A1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
            "DH-RSA-AES256-GCM-SHA384" },
  { 0x00A2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
            "DHE-DSS-AES128-GCM-SHA256" },
  { 0x00A3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
            "DHE-DSS-AES256-GCM-SHA384" },
  { 0x00A4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
            "DH-DSS-AES128-GCM-SHA256" },
  { 0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384",
            "DH-DSS-AES256-GCM-SHA384" },
  { 0x00A6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
            "ADH-AES128-GCM-SHA256" },
  { 0x00A7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
            "ADH-AES256-GCM-SHA384" },
  { 0xC002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
            "ECDH-ECDSA-RC4-SHA" },
  { 0xC007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
            "ECDHE-ECDSA-RC4-SHA" },
  { 0xC00C, "TLS_ECDH_RSA_WITH_RC4_128_SHA",
            "ECDH-RSA-RC4-SHA" },
  { 0xC011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
            "ECDHE-RSA-RC4-SHA" },
  { 0xC015, "TLS_ECDH_anon_WITH_NULL_SHA",
            "AECDH-NULL-SHA" },
  { 0xC016, "TLS_ECDH_anon_WITH_RC4_128_SHA",
            "AECDH-RC4-SHA" },
  { 0xC017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
            "AECDH-DES-CBC3-SHA" },
  { 0xC018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
            "AECDH-AES128-SHA" },
  { 0xC019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
            "AECDH-AES256-SHA" },
  /* Backward compatible aliases (EDH vs DHE) */
  { 0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
            "EXP-EDH-DSS-DES-CBC-SHA" },
  { 0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA",
            "EDH-DSS-DES-CBC-SHA" },
  { 0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
            "EDH-DSS-DES-CBC3-SHA" },
  { 0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
            "EXP-EDH-RSA-DES-CBC-SHA" },
  { 0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA",
            "EDH-RSA-DES-CBC-SHA" },
  { 0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
            "EDH-RSA-DES-CBC3-SHA" },
#endif
#if defined(USE_MBEDTLS)
  /* entries marked ns are non-"standard", they are not in OpenSSL */
  { 0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
            "CAMELLIA128-SHA" },
  { 0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
            "DHE-RSA-CAMELLIA128-SHA" },
  { 0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
            "CAMELLIA256-SHA" },
  { 0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485




486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
;

struct test_str_entry {
  uint16_t id;
  const char *str;
};
static const struct test_str_entry test_str_list[] = {
#if defined(USE_MBEDTLS)
  { 0x1301, "TLS_AES_128_GCM_SHA256"},
  { 0x1302, "TLS_AES_256_GCM_SHA384"},
  { 0x1303, "TLS_CHACHA20_POLY1305_SHA256"},
#else
  { 0x0000, "TLS_AES_128_GCM_SHA256"},
  { 0x0000, "TLS_AES_256_GCM_SHA384"},
  { 0x0000, "TLS_CHACHA20_POLY1305_SHA256"},
#endif
  { 0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"},
  { 0xC02F, "ECDHE-RSA-AES128-GCM-SHA256"},
  { 0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"},
  { 0xC030, "ECDHE-RSA-AES256-GCM-SHA384"},
  { 0xCCA9, "ECDHE-ECDSA-CHACHA20-POLY1305"},
  { 0xCCA8, "ECDHE-RSA-CHACHA20-POLY1305"},
#if defined(USE_MBEDTLS)
  { 0x009E, "DHE-RSA-AES128-GCM-SHA256"},
  { 0x009F, "DHE-RSA-AES256-GCM-SHA384"},
  { 0xCCAA, "DHE-RSA-CHACHA20-POLY1305"},
#else
  { 0x0000, "DHE-RSA-AES128-GCM-SHA256"},
  { 0x0000, "DHE-RSA-AES256-GCM-SHA384"},




  { 0x0000, "DHE-RSA-CHACHA20-POLY1305"},
#endif
  { 0xC023, "ECDHE-ECDSA-AES128-SHA256" },
  { 0xC027, "ECDHE-RSA-AES128-SHA256" },
  { 0xC009, "ECDHE-ECDSA-AES128-SHA" },
  { 0xC013, "ECDHE-RSA-AES128-SHA" },
  { 0xC024, "ECDHE-ECDSA-AES256-SHA384" },
  { 0xC028, "ECDHE-RSA-AES256-SHA384" },
  { 0xC00A, "ECDHE-ECDSA-AES256-SHA" },
  { 0xC014, "ECDHE-RSA-AES256-SHA" },
#if defined(USE_MBEDTLS)
  { 0x0067, "DHE-RSA-AES128-SHA256" },
  { 0x006B, "DHE-RSA-AES256-SHA256" },
#else
  { 0x0000, "DHE-RSA-AES128-SHA256" },
  { 0x0000, "DHE-RSA-AES256-SHA256" },
#endif
  { 0x009C, "AES128-GCM-SHA256" },
  { 0x009D, "AES256-GCM-SHA384" },
  { 0x003C, "AES128-SHA256" },
  { 0x003D, "AES256-SHA256" },
  { 0x002F, "AES128-SHA" },
  { 0x0035, "AES256-SHA" },
#if defined(USE_BEARSSL)
  { 0x000A, "DES-CBC3-SHA" },
#else
  { 0x0000, "DES-CBC3-SHA" },
#endif
  { 0x0000, "GIBBERISH" },
  { 0x0000, "" },
};
#define TEST_STR_LIST_LEN (sizeof(test_str_list) / sizeof(test_str_list[0]))

UNITTEST_START
{
  for(size_t i = 0; i < TEST_CS_LIST_LEN; i++) {
    const struct test_cs_entry *test = &test_cs_list[i];
    const char *expect;
    char buf[64] = "";

    uint16_t id;

    /* test Curl_cipher_suite_lookup_id() for rfc name */
    if(test->rfc) {
      id = Curl_cipher_suite_lookup_id(test->rfc, strlen(test->rfc));
      if(id != test->id) {
        fprintf(stderr, "Curl_cipher_suite_lookup_id FAILED for \"%s\", "
                        "result = 0x%04x, expected = 0x%04x\n",
                        test->rfc, id, test->id);
        unitfail++;
      }
    }

    /* test Curl_cipher_suite_lookup_id() for openssl name */
    if(test->openssl) {
      id = Curl_cipher_suite_lookup_id(test->openssl, strlen(test->openssl));
      if(id != test->id) {
        fprintf(stderr, "Curl_cipher_suite_lookup_id FAILED for \"%s\", "
                        "result = 0x%04x, expected = 0x%04x\n",
                        test->openssl, id, test->id);
        unitfail++;







|














|


<



>
>
>
>










|












|















>













|







600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624

625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
;

struct test_str_entry {
  uint16_t id;
  const char *str;
};
static const struct test_str_entry test_str_list[] = {
#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS)
  { 0x1301, "TLS_AES_128_GCM_SHA256"},
  { 0x1302, "TLS_AES_256_GCM_SHA384"},
  { 0x1303, "TLS_CHACHA20_POLY1305_SHA256"},
#else
  { 0x0000, "TLS_AES_128_GCM_SHA256"},
  { 0x0000, "TLS_AES_256_GCM_SHA384"},
  { 0x0000, "TLS_CHACHA20_POLY1305_SHA256"},
#endif
  { 0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"},
  { 0xC02F, "ECDHE-RSA-AES128-GCM-SHA256"},
  { 0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"},
  { 0xC030, "ECDHE-RSA-AES256-GCM-SHA384"},
  { 0xCCA9, "ECDHE-ECDSA-CHACHA20-POLY1305"},
  { 0xCCA8, "ECDHE-RSA-CHACHA20-POLY1305"},
#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS)
  { 0x009E, "DHE-RSA-AES128-GCM-SHA256"},
  { 0x009F, "DHE-RSA-AES256-GCM-SHA384"},

#else
  { 0x0000, "DHE-RSA-AES128-GCM-SHA256"},
  { 0x0000, "DHE-RSA-AES256-GCM-SHA384"},
#endif
#if defined(USE_MBEDTLS)
  { 0xCCAA, "DHE-RSA-CHACHA20-POLY1305"},
#else
  { 0x0000, "DHE-RSA-CHACHA20-POLY1305"},
#endif
  { 0xC023, "ECDHE-ECDSA-AES128-SHA256" },
  { 0xC027, "ECDHE-RSA-AES128-SHA256" },
  { 0xC009, "ECDHE-ECDSA-AES128-SHA" },
  { 0xC013, "ECDHE-RSA-AES128-SHA" },
  { 0xC024, "ECDHE-ECDSA-AES256-SHA384" },
  { 0xC028, "ECDHE-RSA-AES256-SHA384" },
  { 0xC00A, "ECDHE-ECDSA-AES256-SHA" },
  { 0xC014, "ECDHE-RSA-AES256-SHA" },
#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS)
  { 0x0067, "DHE-RSA-AES128-SHA256" },
  { 0x006B, "DHE-RSA-AES256-SHA256" },
#else
  { 0x0000, "DHE-RSA-AES128-SHA256" },
  { 0x0000, "DHE-RSA-AES256-SHA256" },
#endif
  { 0x009C, "AES128-GCM-SHA256" },
  { 0x009D, "AES256-GCM-SHA384" },
  { 0x003C, "AES128-SHA256" },
  { 0x003D, "AES256-SHA256" },
  { 0x002F, "AES128-SHA" },
  { 0x0035, "AES256-SHA" },
#if defined(USE_SECTRANSP) || defined(USE_BEARSSL)
  { 0x000A, "DES-CBC3-SHA" },
#else
  { 0x0000, "DES-CBC3-SHA" },
#endif
  { 0x0000, "GIBBERISH" },
  { 0x0000, "" },
};
#define TEST_STR_LIST_LEN (sizeof(test_str_list) / sizeof(test_str_list[0]))

UNITTEST_START
{
  for(size_t i = 0; i < TEST_CS_LIST_LEN; i++) {
    const struct test_cs_entry *test = &test_cs_list[i];
    const char *expect;
    char buf[64] = "";
    char alt[64] = "";
    uint16_t id;

    /* test Curl_cipher_suite_lookup_id() for rfc name */
    if(test->rfc) {
      id = Curl_cipher_suite_lookup_id(test->rfc, strlen(test->rfc));
      if(id != test->id) {
        fprintf(stderr, "Curl_cipher_suite_lookup_id FAILED for \"%s\", "
                        "result = 0x%04x, expected = 0x%04x\n",
                        test->rfc, id, test->id);
        unitfail++;
      }
    }

    /* test Curl_cipher_suite_lookup_id() for OpenSSL name */
    if(test->openssl) {
      id = Curl_cipher_suite_lookup_id(test->openssl, strlen(test->openssl));
      if(id != test->id) {
        fprintf(stderr, "Curl_cipher_suite_lookup_id FAILED for \"%s\", "
                        "result = 0x%04x, expected = 0x%04x\n",
                        test->openssl, id, test->id);
        unitfail++;
555
556
557
558
559
560
561
562
563
564
565
566








567
568
569
570
571
572
573
    if(strcmp(buf, expect) != 0) {
      fprintf(stderr, "Curl_cipher_suite_get_str FAILED for 0x%04x, "
                      "result = \"%s\", expected = \"%s\"\n",
                      test->id, buf, expect);
      unitfail++;
    }

    /* test Curl_cipher_suite_get_str() prefer openssl name */
    buf[0] = '\0';
    expect = test->openssl ? test->openssl : test->rfc;

    Curl_cipher_suite_get_str(test->id, buf, sizeof(buf), false);









    if(strcmp(buf, expect) != 0) {
      fprintf(stderr, "Curl_cipher_suite_get_str FAILED for 0x%04x, "
                      "result = \"%s\", expected = \"%s\"\n",
                      test->id, buf, expect);
      unitfail++;
    }







|




>
>
>
>
>
>
>
>







702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
    if(strcmp(buf, expect) != 0) {
      fprintf(stderr, "Curl_cipher_suite_get_str FAILED for 0x%04x, "
                      "result = \"%s\", expected = \"%s\"\n",
                      test->id, buf, expect);
      unitfail++;
    }

    /* test Curl_cipher_suite_get_str() prefer OpenSSL name */
    buf[0] = '\0';
    expect = test->openssl ? test->openssl : test->rfc;

    Curl_cipher_suite_get_str(test->id, buf, sizeof(buf), false);

    /* suites matched by EDH alias will return the DHE name */
    if(test->id >= 0x0011 && test->id < 0x0017) {
      if(memcmp(expect, "EDH-", 4) == 0)
        expect = (char *) memcpy(strcpy(alt, expect), "DHE-", 4);
      if(memcmp(expect + 4, "EDH-", 4) == 0)
        expect = (char *) memcpy(strcpy(alt, expect) + 4, "DHE-", 4) - 4;
    }

    if(strcmp(buf, expect) != 0) {
      fprintf(stderr, "Curl_cipher_suite_get_str FAILED for 0x%04x, "
                      "result = \"%s\", expected = \"%s\"\n",
                      test->id, buf, expect);
      unitfail++;
    }
603
604
605
606
607
608
609

610
611
612
613
614

615
      }
      i++;
    }
  }
}
UNITTEST_STOP


#else /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */

UNITTEST_START
UNITTEST_STOP


#endif /* defined(USE_MBEDTLS) || defined(USE_BEARSSL) */







>
|




>
|
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
      }
      i++;
    }
  }
}
UNITTEST_STOP

#else /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
          defined(USE_BEARSSL) */

UNITTEST_START
UNITTEST_STOP

#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
          defined(USE_BEARSSL) */
Changes to jni/curl/winbuild/MakefileBuild.vc.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
!If "$(CC)" == ""
CC = cl.exe
!Endif

!IF "$(VC)"=="6"
CC_NODEBUG  = $(CC) /O2 /DNDEBUG
CC_DEBUG    = $(CC) /Od /Gm /Zi /D_DEBUG /GZ
CFLAGS      = /I. /I../lib /I../include /nologo /W4 /GX /DWIN32 /YX /FD /c /DBUILDING_LIBCURL
!ELSE
CC_NODEBUG  = $(CC) /O2 /DNDEBUG
CC_DEBUG    = $(CC) /Od /D_DEBUG /RTC1 /Z7 /LDd
CFLAGS      = /I. /I ../lib /I../include /nologo /W4 /EHsc /DWIN32 /FD /c /DBUILDING_LIBCURL
!ENDIF

LFLAGS     = /nologo /machine:$(MACHINE)
LNKDLL     = link.exe /DLL
# Use lib.exe instead of link.exe as link.exe /lib has the following bad habits:
# - optimizing options like /opt:ref raises warnings (at least in Visual Studio 2015)
# - all (including Windows) dependencies are aggregated (as static parts)







|



|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
!If "$(CC)" == ""
CC = cl.exe
!Endif

!IF "$(VC)"=="6"
CC_NODEBUG  = $(CC) /O2 /DNDEBUG
CC_DEBUG    = $(CC) /Od /Gm /Zi /D_DEBUG /GZ
CFLAGS      = /I. /I../lib /I../include /nologo /W4 /GX /YX /FD /c /DBUILDING_LIBCURL
!ELSE
CC_NODEBUG  = $(CC) /O2 /DNDEBUG
CC_DEBUG    = $(CC) /Od /D_DEBUG /RTC1 /Z7 /LDd
CFLAGS      = /I. /I ../lib /I../include /nologo /W4 /EHsc /FD /c /DBUILDING_LIBCURL
!ENDIF

LFLAGS     = /nologo /machine:$(MACHINE)
LNKDLL     = link.exe /DLL
# Use lib.exe instead of link.exe as link.exe /lib has the following bad habits:
# - optimizing options like /opt:ref raises warnings (at least in Visual Studio 2015)
# - all (including Windows) dependencies are aggregated (as static parts)
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
PDB_NAME_STATIC        = $(BASE_NAME_STATIC).pdb
PDB_NAME_STATIC_DEBUG  = $(BASE_NAME_STATIC_DEBUG).pdb
PDB_NAME_DLL           = $(BASE_NAME).pdb
PDB_NAME_DLL_DEBUG     = $(BASE_NAME_DEBUG).pdb

# CURL Command section
PROGRAM_NAME  = curl.exe
CURL_CFLAGS   = /I../lib /I../include /nologo /W4 /EHsc /DWIN32 /FD /c
CURL_LFLAGS   = /out:$(DIRDIST)\bin\$(PROGRAM_NAME) /subsystem:console $(LFLAGS)
CURL_RESFLAGS = /i../include

#############################################################
## Nothing more to do below this line!
LIBCURL_SRC_DIR = ..\lib
CURL_SRC_DIR = ..\src







|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
PDB_NAME_STATIC        = $(BASE_NAME_STATIC).pdb
PDB_NAME_STATIC_DEBUG  = $(BASE_NAME_STATIC_DEBUG).pdb
PDB_NAME_DLL           = $(BASE_NAME).pdb
PDB_NAME_DLL_DEBUG     = $(BASE_NAME_DEBUG).pdb

# CURL Command section
PROGRAM_NAME  = curl.exe
CURL_CFLAGS   = /I../lib /I../include /nologo /W4 /EHsc /FD /c
CURL_LFLAGS   = /out:$(DIRDIST)\bin\$(PROGRAM_NAME) /subsystem:console $(LFLAGS)
CURL_RESFLAGS = /i../include

#############################################################
## Nothing more to do below this line!
LIBCURL_SRC_DIR = ..\lib
CURL_SRC_DIR = ..\src
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
!ENDIF



# CURL_XX macros are for the curl.exe command

!IF "$(DEBUG)"=="yes"
RC_FLAGS = /dDEBUGBUILD=1 /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc
CURL_CC       = $(CC_DEBUG) $(RTLIB_DEBUG)
CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /dDEBUGBUILD=1 /Fo $@ $(CURL_SRC_DIR)\curl.rc
!ELSE
RC_FLAGS = /dDEBUGBUILD=0 /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc
CURL_CC       = $(CC_NODEBUG) $(RTLIB)
CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /dDEBUGBUILD=0 /Fo $@ $(CURL_SRC_DIR)\curl.rc
!ENDIF

!IF "$(AS_DLL)" == "true"

LNK       = $(LNKDLL) $(LFLAGS) $(WIN_LIBS) /out:$(LIB_DIROBJ)\$(TARGET)
!IF "$(DEBUG)"=="yes"
TARGET    = $(LIB_NAME_DLL_DEBUG)







|

|

|

|







424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
!ENDIF



# CURL_XX macros are for the curl.exe command

!IF "$(DEBUG)"=="yes"
RC_FLAGS = /d_DEBUG /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc
CURL_CC       = $(CC_DEBUG) $(RTLIB_DEBUG)
CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /d_DEBUG /Fo $@ $(CURL_SRC_DIR)\curl.rc
!ELSE
RC_FLAGS = /Fo $@ $(LIBCURL_SRC_DIR)\libcurl.rc
CURL_CC       = $(CC_NODEBUG) $(RTLIB)
CURL_RC_FLAGS = $(CURL_RC_FLAGS) /i../include /Fo $@ $(CURL_SRC_DIR)\curl.rc
!ENDIF

!IF "$(AS_DLL)" == "true"

LNK       = $(LNKDLL) $(LFLAGS) $(WIN_LIBS) /out:$(LIB_DIROBJ)\$(TARGET)
!IF "$(DEBUG)"=="yes"
TARGET    = $(LIB_NAME_DLL_DEBUG)
Changes to jni/curl/winbuild/README.md.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
                                   Defaults to sibling directory: `../deps`
 - `WITH_SSL=<dll/static>`       - Enable OpenSSL support, DLL or static
 - `WITH_NGHTTP2=<dll/static>`   - Enable HTTP/2 support, DLL or static
 - `WITH_MSH3=<dll/static>`      - Enable (experimental) HTTP/3 support, DLL or static
 - `WITH_MBEDTLS=<dll/static>`   - Enable mbedTLS support, DLL or static
 - `WITH_CARES=<dll/static>`     - Enable c-ares support, DLL or static
 - `WITH_ZLIB=<dll/static>`      - Enable zlib support, DLL or static
 - `WITH_SSH=<dll/static>`       - Enable libSSH support, DLL or static
 - `WITH_SSH2=<dll/static>`      - Enable libSSH2 support, DLL or static
 - `WITH_PREFIX=<dir>`           - Where to install the build
 - `ENABLE_SSPI=<yes/no>`        - Enable SSPI support, defaults to yes
 - `ENABLE_IPV6=<yes/no>`        - Enable IPv6, defaults to yes
 - `ENABLE_IDN=<yes or no>`      - Enable use of Windows IDN APIs, defaults to yes
                                   Requires Windows Vista or later
 - `ENABLE_SCHANNEL=<yes/no>`    - Enable native Windows SSL support, defaults
                                   to yes if SSPI and no other SSL library
 - `ENABLE_OPENSSL_AUTO_LOAD_CONFIG=<yes/no>`
                                 - Enable loading OpenSSL configuration
                                   automatically, defaults to yes
 - `ENABLE_UNICODE=<yes/no>`     - Enable UNICODE support, defaults to no
 - `ENABLE_WEBSOCKETS=<yes/no>`  - Enable Web Socket support, defaults to no
 - `GEN_PDB=<yes/no>`            - Generate External Program Database
                                   (debug symbols for release build)
 - `DEBUG=<yes/no>`              - Debug builds
 - `MACHINE=<x86/x64/arm64>`     - Target architecture (default is x86)
 - `CARES_PATH=<path>`           - Custom path for c-ares
 - `MBEDTLS_PATH=<path>`         - Custom path for mbedTLS
 - `NGHTTP2_PATH=<path>`         - Custom path for nghttp2
 - `MSH3_PATH=<path>`            - Custom path for msh3
 - `SSH2_PATH=<path>`            - Custom path for libSSH2
 - `SSL_PATH=<path>`             - Custom path for OpenSSL
 - `ZLIB_PATH=<path>`            - Custom path for zlib

## Static linking of Microsoft's C runtime (CRT):

 If you are using mode=static nmake will create and link to the static build
 of libcurl but *not* the static CRT. If you must you can force nmake to link







|
|




















|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
                                   Defaults to sibling directory: `../deps`
 - `WITH_SSL=<dll/static>`       - Enable OpenSSL support, DLL or static
 - `WITH_NGHTTP2=<dll/static>`   - Enable HTTP/2 support, DLL or static
 - `WITH_MSH3=<dll/static>`      - Enable (experimental) HTTP/3 support, DLL or static
 - `WITH_MBEDTLS=<dll/static>`   - Enable mbedTLS support, DLL or static
 - `WITH_CARES=<dll/static>`     - Enable c-ares support, DLL or static
 - `WITH_ZLIB=<dll/static>`      - Enable zlib support, DLL or static
 - `WITH_SSH=<dll/static>`       - Enable libssh support, DLL or static
 - `WITH_SSH2=<dll/static>`      - Enable libssh2 support, DLL or static
 - `WITH_PREFIX=<dir>`           - Where to install the build
 - `ENABLE_SSPI=<yes/no>`        - Enable SSPI support, defaults to yes
 - `ENABLE_IPV6=<yes/no>`        - Enable IPv6, defaults to yes
 - `ENABLE_IDN=<yes or no>`      - Enable use of Windows IDN APIs, defaults to yes
                                   Requires Windows Vista or later
 - `ENABLE_SCHANNEL=<yes/no>`    - Enable native Windows SSL support, defaults
                                   to yes if SSPI and no other SSL library
 - `ENABLE_OPENSSL_AUTO_LOAD_CONFIG=<yes/no>`
                                 - Enable loading OpenSSL configuration
                                   automatically, defaults to yes
 - `ENABLE_UNICODE=<yes/no>`     - Enable UNICODE support, defaults to no
 - `ENABLE_WEBSOCKETS=<yes/no>`  - Enable Web Socket support, defaults to no
 - `GEN_PDB=<yes/no>`            - Generate External Program Database
                                   (debug symbols for release build)
 - `DEBUG=<yes/no>`              - Debug builds
 - `MACHINE=<x86/x64/arm64>`     - Target architecture (default is x86)
 - `CARES_PATH=<path>`           - Custom path for c-ares
 - `MBEDTLS_PATH=<path>`         - Custom path for mbedTLS
 - `NGHTTP2_PATH=<path>`         - Custom path for nghttp2
 - `MSH3_PATH=<path>`            - Custom path for msh3
 - `SSH2_PATH=<path>`            - Custom path for libssh2
 - `SSL_PATH=<path>`             - Custom path for OpenSSL
 - `ZLIB_PATH=<path>`            - Custom path for zlib

## Static linking of Microsoft's C runtime (CRT):

 If you are using mode=static nmake will create and link to the static build
 of libcurl but *not* the static CRT. If you must you can force nmake to link
Added jni/curl/winbuild/makedebug.bat.


































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@echo off
rem ***************************************************************************
rem *                                  _   _ ____  _
rem *  Project                     ___| | | |  _ \| |
rem *                             / __| | | | |_) | |
rem *                            | (__| |_| |  _ <| |___
rem *                             \___|\___/|_| \_\_____|
rem *
rem * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
rem *
rem * This software is licensed as described in the file COPYING, which
rem * you should have received as part of this distribution. The terms
rem * are also available at https://curl.se/docs/copyright.html.
rem *
rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell
rem * copies of the Software, and permit persons to whom the Software is
rem * furnished to do so, under the terms of the COPYING file.
rem *
rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
rem * KIND, either express or implied.
rem *
rem * SPDX-License-Identifier: curl
rem *
rem ***************************************************************************

where.exe nmake.exe >nul 2>&1

if %ERRORLEVEL% EQU 1 (
  echo Error: Cannot find nmake.exe - be sure to run this script from within a Developer Command-Prompt
) else (
  nmake.exe /f Makefile.vc mode=static DEBUG=yes GEN_PDB=yes
  if %ERRORLEVEL% NEQ 0 echo Error: Build Failed
)
Deleted jni/curl/winbuild/makedebug.cmd.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@echo off
rem ***************************************************************************
rem *                                  _   _ ____  _
rem *  Project                     ___| | | |  _ \| |
rem *                             / __| | | | |_) | |
rem *                            | (__| |_| |  _ <| |___
rem *                             \___|\___/|_| \_\_____|
rem *
rem * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
rem *
rem * This software is licensed as described in the file COPYING, which
rem * you should have received as part of this distribution. The terms
rem * are also available at https://curl.se/docs/copyright.html.
rem *
rem * You may opt to use, copy, modify, merge, publish, distribute and/or sell
rem * copies of the Software, and permit persons to whom the Software is
rem * furnished to do so, under the terms of the COPYING file.
rem *
rem * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
rem * KIND, either express or implied.
rem *
rem * SPDX-License-Identifier: curl
rem *
rem ***************************************************************************

where.exe nmake.exe >nul 2>&1

IF %ERRORLEVEL% == 1 (
  ECHO Error: Can't find `nmake.exe` - be sure to run this script from within a Developer Command-Prompt
  ECHO.
) ELSE (
  nmake /f Makefile.vc mode=static DEBUG=yes GEN_PDB=yes
  IF %ERRORLEVEL% NEQ 0 (
    ECHO "Error: Build Failed"
  )
)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































Changes to undroid/build-undroidwish-linux32.sh.
412
413
414
415
416
417
418



419
420
421
422
423
424
425

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0



  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  ./configure --prefix=${PFX} --build=i586-linux-gnu --with-pic \







>
>
>







412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0
  # cheat configure etc. for old sed w/o -E
  perl -pi -e 's@sed -E@sed -r@g' m4/curl-compilers.m4
  perl -pi -e 's@sed -E@sed -r@g' configure 
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  ./configure --prefix=${PFX} --build=i586-linux-gnu --with-pic \
Changes to undroid/build-undroidwish-linux64.sh.
412
413
414
415
416
417
418



419
420
421
422
423
424
425

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0



  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  ./configure --prefix=${PFX} --build=x86_64-linux-gnu --with-pic \







>
>
>







412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0
  # cheat configure etc. for old sed w/o -E
  perl -pi -e 's@sed -E@sed -r@g' m4/curl-compilers.m4
  perl -pi -e 's@sed -E@sed -r@g' configure 
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  ./configure --prefix=${PFX} --build=x86_64-linux-gnu --with-pic \
Changes to undroid/build-undroidwish-win32.sh.
453
454
455
456
457
458
459



460
461
462
463
464
465
466

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0



  CC=${CC_OLD}
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc







>
>
>







453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0
  # cheat configure etc. for old sed w/o -E
  perl -pi -e 's@sed -E@sed -r@g' m4/curl-compilers.m4
  perl -pi -e 's@sed -E@sed -r@g' configure 
  CC=${CC_OLD}
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
Changes to undroid/build-undroidwish-win64.sh.
433
434
435
436
437
438
439



440
441
442
443
444
445
446

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0



  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  perl -pi -e "s@'${PFX}@'${PFX_HERE}@g" ${PFX_HERE}/lib/libcrypto.la







>
>
>







433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0
  # cheat configure etc. for old sed w/o -E
  perl -pi -e 's@sed -E@sed -r@g' m4/curl-compilers.m4
  perl -pi -e 's@sed -E@sed -r@g' configure 
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  perl -pi -e "s@'${PFX}@'${PFX_HERE}@g" ${PFX_HERE}/lib/libcrypto.la
Changes to undroid/build-vanilla-linux32.sh.
406
407
408
409
410
411
412



413
414
415
416
417
418
419

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0



  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  ./configure --prefix=${PFX} --build=i586-linux-gnu --with-pic \







>
>
>







406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0
  # cheat configure etc. for old sed w/o -E
  perl -pi -e 's@sed -E@sed -r@g' m4/curl-compilers.m4
  perl -pi -e 's@sed -E@sed -r@g' configure 
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  ./configure --prefix=${PFX} --build=i586-linux-gnu --with-pic \
Changes to undroid/build-vanilla-linux64.sh.
406
407
408
409
410
411
412



413
414
415
416
417
418
419

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0



  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  ./configure --prefix=${PFX} --build=x86_64-linux-gnu --with-pic \







>
>
>







406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0
  # cheat configure etc. for old sed w/o -E
  perl -pi -e 's@sed -E@sed -r@g' m4/curl-compilers.m4
  perl -pi -e 's@sed -E@sed -r@g' configure 
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  ./configure --prefix=${PFX} --build=x86_64-linux-gnu --with-pic \
Changes to undroid/build-vanilla-win32.sh.
443
444
445
446
447
448
449



450
451
452
453
454
455
456

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0



  CC=${CC_OLD}
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc







>
>
>







443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0
  # cheat configure etc. for old sed w/o -E
  perl -pi -e 's@sed -E@sed -r@g' m4/curl-compilers.m4
  perl -pi -e 's@sed -E@sed -r@g' configure 
  CC=${CC_OLD}
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
Changes to undroid/build-vanilla-win64.sh.
422
423
424
425
426
427
428



429
430
431
432
433
434
435

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0



  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  perl -pi -e "s@'${PFX}@'${PFX_HERE}@g" ${PFX_HERE}/lib/libcrypto.la







>
>
>







422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438

echo -n "build curl (static, pic) ... "
(
  exec 3>&1
  exec >> build.log 2>&1
  cd curl
  test -e build-stamp && echo >&3 "already done" && exit 0
  # cheat configure etc. for old sed w/o -E
  perl -pi -e 's@sed -E@sed -r@g' m4/curl-compilers.m4
  perl -pi -e 's@sed -E@sed -r@g' configure 
  # cheat libressl for build
  mkdir -p ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/openssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libssl.pc ssl/lib/pkgconfig
  cp ${PFX_HERE}/lib/pkgconfig/libcrypto.pc ssl/lib/pkgconfig
  perl -pi -e "s@${PFX}@${PFX_HERE}@g" ssl/lib/pkgconfig/*.pc
  perl -pi -e "s@'${PFX}@'${PFX_HERE}@g" ${PFX_HERE}/lib/libcrypto.la