summaryrefslogtreecommitdiff
path: root/libs/libcurl/src
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src')
-rw-r--r--libs/libcurl/src/.checksrc3
-rw-r--r--libs/libcurl/src/CMakeLists.txt36
-rw-r--r--libs/libcurl/src/Makefile.am24
-rw-r--r--libs/libcurl/src/Makefile.in666
-rw-r--r--libs/libcurl/src/Makefile.inc15
-rw-r--r--libs/libcurl/src/altsvc.c306
-rw-r--r--libs/libcurl/src/amigaos.c2
-rw-r--r--libs/libcurl/src/asyn-ares.c341
-rw-r--r--libs/libcurl/src/asyn-thread.c196
-rw-r--r--libs/libcurl/src/asyn.h12
-rw-r--r--libs/libcurl/src/base64.c4
-rw-r--r--libs/libcurl/src/bufref.c4
-rw-r--r--libs/libcurl/src/cf-h1-proxy.c14
-rw-r--r--libs/libcurl/src/cf-h2-proxy.c6
-rw-r--r--libs/libcurl/src/cf-haproxy.c4
-rw-r--r--libs/libcurl/src/cf-https-connect.c144
-rw-r--r--libs/libcurl/src/cf-socket.c135
-rw-r--r--libs/libcurl/src/cfilters.c92
-rw-r--r--libs/libcurl/src/cfilters.h34
-rw-r--r--libs/libcurl/src/config-os400.h9
-rw-r--r--libs/libcurl/src/config-plan9.h2
-rw-r--r--libs/libcurl/src/config-riscos.h6
-rw-r--r--libs/libcurl/src/config-win32.h59
-rw-r--r--libs/libcurl/src/conncache.c1019
-rw-r--r--libs/libcurl/src/conncache.h77
-rw-r--r--libs/libcurl/src/connect.c45
-rw-r--r--libs/libcurl/src/connect.h4
-rw-r--r--libs/libcurl/src/content_encoding.c29
-rw-r--r--libs/libcurl/src/cookie.c278
-rw-r--r--libs/libcurl/src/cshutdn.c566
-rw-r--r--libs/libcurl/src/cshutdn.h104
-rw-r--r--libs/libcurl/src/curl_addrinfo.c12
-rw-r--r--libs/libcurl/src/curl_config.h.cmake12
-rw-r--r--libs/libcurl/src/curl_config.h.in15
-rw-r--r--libs/libcurl/src/curl_ctype.h1
-rw-r--r--libs/libcurl/src/curl_fnmatch.c23
-rw-r--r--libs/libcurl/src/curl_gssapi.c4
-rw-r--r--libs/libcurl/src/curl_krb5.h6
-rw-r--r--libs/libcurl/src/curl_memory.h14
-rw-r--r--libs/libcurl/src/curl_memrchr.c8
-rw-r--r--libs/libcurl/src/curl_memrchr.h6
-rw-r--r--libs/libcurl/src/curl_multibyte.c13
-rw-r--r--libs/libcurl/src/curl_multibyte.h4
-rw-r--r--libs/libcurl/src/curl_ntlm_core.c39
-rw-r--r--libs/libcurl/src/curl_range.c33
-rw-r--r--libs/libcurl/src/curl_rtmp.c2
-rw-r--r--libs/libcurl/src/curl_sasl.c1
-rw-r--r--libs/libcurl/src/curl_setup.h105
-rw-r--r--libs/libcurl/src/curl_setup_once.h136
-rw-r--r--libs/libcurl/src/curl_sha512_256.c4
-rw-r--r--libs/libcurl/src/curl_sspi.c6
-rw-r--r--libs/libcurl/src/curl_sspi.h245
-rw-r--r--libs/libcurl/src/curl_threads.c16
-rw-r--r--libs/libcurl/src/curl_threads.h2
-rw-r--r--libs/libcurl/src/curl_trc.c318
-rw-r--r--libs/libcurl/src/curl_trc.h28
-rw-r--r--libs/libcurl/src/curlx.h10
-rw-r--r--libs/libcurl/src/cw-out.c79
-rw-r--r--libs/libcurl/src/cw-pause.c242
-rw-r--r--libs/libcurl/src/cw-pause.h (renamed from libs/libcurl/src/strtok.h)24
-rw-r--r--libs/libcurl/src/dict.c23
-rw-r--r--libs/libcurl/src/doh.c95
-rw-r--r--libs/libcurl/src/doh.h2
-rw-r--r--libs/libcurl/src/dynbuf.c8
-rw-r--r--libs/libcurl/src/dynbuf.h4
-rw-r--r--libs/libcurl/src/easy.c78
-rw-r--r--libs/libcurl/src/easyoptions.c3
-rw-r--r--libs/libcurl/src/escape.c2
-rw-r--r--libs/libcurl/src/file.c5
-rw-r--r--libs/libcurl/src/fopen.c8
-rw-r--r--libs/libcurl/src/formdata.c6
-rw-r--r--libs/libcurl/src/ftp.c142
-rw-r--r--libs/libcurl/src/ftp.h9
-rw-r--r--libs/libcurl/src/ftplistparser.c37
-rw-r--r--libs/libcurl/src/getenv.c2
-rw-r--r--libs/libcurl/src/getinfo.c24
-rw-r--r--libs/libcurl/src/gopher.c4
-rw-r--r--libs/libcurl/src/hash.c279
-rw-r--r--libs/libcurl/src/hash.h38
-rw-r--r--libs/libcurl/src/hash_offt.c242
-rw-r--r--libs/libcurl/src/hash_offt.h67
-rw-r--r--libs/libcurl/src/headers.c9
-rw-r--r--libs/libcurl/src/hostasyn.c4
-rw-r--r--libs/libcurl/src/hostip.c204
-rw-r--r--libs/libcurl/src/hostip.h6
-rw-r--r--libs/libcurl/src/hostip4.c2
-rw-r--r--libs/libcurl/src/hostip6.c4
-rw-r--r--libs/libcurl/src/hsts.c68
-rw-r--r--libs/libcurl/src/http.c784
-rw-r--r--libs/libcurl/src/http.h25
-rw-r--r--libs/libcurl/src/http2.c210
-rw-r--r--libs/libcurl/src/http_aws_sigv4.c209
-rw-r--r--libs/libcurl/src/http_aws_sigv4.h2
-rw-r--r--libs/libcurl/src/http_chunks.c16
-rw-r--r--libs/libcurl/src/http_digest.c10
-rw-r--r--libs/libcurl/src/http_negotiate.c18
-rw-r--r--libs/libcurl/src/http_ntlm.c13
-rw-r--r--libs/libcurl/src/http_proxy.c13
-rw-r--r--libs/libcurl/src/httpsrr.c121
-rw-r--r--libs/libcurl/src/httpsrr.h19
-rw-r--r--libs/libcurl/src/idn.c4
-rw-r--r--libs/libcurl/src/if2ip.c7
-rw-r--r--libs/libcurl/src/imap.c120
-rw-r--r--libs/libcurl/src/imap.h1
-rw-r--r--libs/libcurl/src/inet_ntop.c19
-rw-r--r--libs/libcurl/src/inet_ntop.h16
-rw-r--r--libs/libcurl/src/inet_pton.c4
-rw-r--r--libs/libcurl/src/inet_pton.h8
-rw-r--r--libs/libcurl/src/krb5.c14
-rw-r--r--libs/libcurl/src/ldap.c83
-rw-r--r--libs/libcurl/src/llist.c5
-rw-r--r--libs/libcurl/src/md4.c17
-rw-r--r--libs/libcurl/src/md5.c8
-rw-r--r--libs/libcurl/src/memdebug.c52
-rw-r--r--libs/libcurl/src/memdebug.h82
-rw-r--r--libs/libcurl/src/mime.c2
-rw-r--r--libs/libcurl/src/mprintf.c118
-rw-r--r--libs/libcurl/src/mqtt.c85
-rw-r--r--libs/libcurl/src/mqtt.h8
-rw-r--r--libs/libcurl/src/multi.c761
-rw-r--r--libs/libcurl/src/multi_ev.c621
-rw-r--r--libs/libcurl/src/multi_ev.h82
-rw-r--r--libs/libcurl/src/multihandle.h22
-rw-r--r--libs/libcurl/src/multiif.h33
-rw-r--r--libs/libcurl/src/netrc.c17
-rw-r--r--libs/libcurl/src/noproxy.c17
-rw-r--r--libs/libcurl/src/openldap.c26
-rw-r--r--libs/libcurl/src/parsedate.c46
-rw-r--r--libs/libcurl/src/pingpong.c29
-rw-r--r--libs/libcurl/src/pingpong.h3
-rw-r--r--libs/libcurl/src/pop3.c20
-rw-r--r--libs/libcurl/src/psl.c2
-rw-r--r--libs/libcurl/src/rename.c6
-rw-r--r--libs/libcurl/src/request.c20
-rw-r--r--libs/libcurl/src/rtsp.c74
-rw-r--r--libs/libcurl/src/rtsp.h1
-rw-r--r--libs/libcurl/src/select.c15
-rw-r--r--libs/libcurl/src/select.h6
-rw-r--r--libs/libcurl/src/sendf.c63
-rw-r--r--libs/libcurl/src/sendf.h2
-rw-r--r--libs/libcurl/src/setopt.c105
-rw-r--r--libs/libcurl/src/setup-vms.h40
-rw-r--r--libs/libcurl/src/setup-win32.h6
-rw-r--r--libs/libcurl/src/sha256.c48
-rw-r--r--libs/libcurl/src/share.c16
-rw-r--r--libs/libcurl/src/share.h2
-rw-r--r--libs/libcurl/src/smb.c4
-rw-r--r--libs/libcurl/src/smtp.c19
-rw-r--r--libs/libcurl/src/socketpair.c12
-rw-r--r--libs/libcurl/src/socketpair.h23
-rw-r--r--libs/libcurl/src/socks.c13
-rw-r--r--libs/libcurl/src/socks_sspi.c16
-rw-r--r--libs/libcurl/src/strcase.c59
-rw-r--r--libs/libcurl/src/strdup.c5
-rw-r--r--libs/libcurl/src/strequal.c88
-rw-r--r--libs/libcurl/src/strerror.c42
-rw-r--r--libs/libcurl/src/strerror.h4
-rw-r--r--libs/libcurl/src/strparse.c214
-rw-r--r--libs/libcurl/src/strparse.h60
-rw-r--r--libs/libcurl/src/strtok.c68
-rw-r--r--libs/libcurl/src/strtoofft.c240
-rw-r--r--libs/libcurl/src/strtoofft.h54
-rw-r--r--libs/libcurl/src/system_win32.c14
-rw-r--r--libs/libcurl/src/system_win32.h2
-rw-r--r--libs/libcurl/src/telnet.c47
-rw-r--r--libs/libcurl/src/tftp.c50
-rw-r--r--libs/libcurl/src/timediff.c4
-rw-r--r--libs/libcurl/src/timeval.c46
-rw-r--r--libs/libcurl/src/timeval.h12
-rw-r--r--libs/libcurl/src/transfer.c15
-rw-r--r--libs/libcurl/src/transfer.h2
-rw-r--r--libs/libcurl/src/url.c436
-rw-r--r--libs/libcurl/src/url.h2
-rw-r--r--libs/libcurl/src/urlapi.c511
-rw-r--r--libs/libcurl/src/urldata.h38
-rw-r--r--libs/libcurl/src/vauth/cleartext.c1
-rw-r--r--libs/libcurl/src/vauth/digest.c72
-rw-r--r--libs/libcurl/src/vauth/digest_sspi.c49
-rw-r--r--libs/libcurl/src/vauth/krb5_gssapi.c4
-rw-r--r--libs/libcurl/src/vauth/krb5_sspi.c25
-rw-r--r--libs/libcurl/src/vauth/ntlm.c108
-rw-r--r--libs/libcurl/src/vauth/ntlm.h143
-rw-r--r--libs/libcurl/src/vauth/ntlm_sspi.c18
-rw-r--r--libs/libcurl/src/vauth/spnego_gssapi.c6
-rw-r--r--libs/libcurl/src/vauth/spnego_sspi.c20
-rw-r--r--libs/libcurl/src/version.c2
-rw-r--r--libs/libcurl/src/version_win32.c92
-rw-r--r--libs/libcurl/src/version_win32.h2
-rw-r--r--libs/libcurl/src/vquic/curl_msh3.c30
-rw-r--r--libs/libcurl/src/vquic/curl_ngtcp2.c156
-rw-r--r--libs/libcurl/src/vquic/curl_osslq.c220
-rw-r--r--libs/libcurl/src/vquic/curl_quiche.c221
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.c197
-rw-r--r--libs/libcurl/src/vquic/vquic-tls.h10
-rw-r--r--libs/libcurl/src/vquic/vquic.c44
-rw-r--r--libs/libcurl/src/vssh/libssh.c210
-rw-r--r--libs/libcurl/src/vssh/libssh2.c311
-rw-r--r--libs/libcurl/src/vssh/ssh.h1
-rw-r--r--libs/libcurl/src/vssh/wolfssh.c48
-rw-r--r--libs/libcurl/src/vtls/bearssl.c105
-rw-r--r--libs/libcurl/src/vtls/cipher_suite.c10
-rw-r--r--libs/libcurl/src/vtls/gtls.c518
-rw-r--r--libs/libcurl/src/vtls/gtls.h4
-rw-r--r--libs/libcurl/src/vtls/keylog.c15
-rw-r--r--libs/libcurl/src/vtls/keylog.h11
-rw-r--r--libs/libcurl/src/vtls/mbedtls.c118
-rw-r--r--libs/libcurl/src/vtls/openssl.c731
-rw-r--r--libs/libcurl/src/vtls/openssl.h23
-rw-r--r--libs/libcurl/src/vtls/rustls.c951
-rw-r--r--libs/libcurl/src/vtls/schannel.c239
-rw-r--r--libs/libcurl/src/vtls/schannel_verify.c120
-rw-r--r--libs/libcurl/src/vtls/sectransp.c199
-rw-r--r--libs/libcurl/src/vtls/vtls.c255
-rw-r--r--libs/libcurl/src/vtls/vtls_int.h14
-rw-r--r--libs/libcurl/src/vtls/vtls_scache.c113
-rw-r--r--libs/libcurl/src/vtls/vtls_scache.h17
-rw-r--r--libs/libcurl/src/vtls/vtls_spack.c3
-rw-r--r--libs/libcurl/src/vtls/vtls_spack.h2
-rw-r--r--libs/libcurl/src/vtls/wolfssl.c1399
-rw-r--r--libs/libcurl/src/vtls/wolfssl.h44
-rw-r--r--libs/libcurl/src/vtls/x509asn1.c43
-rw-r--r--libs/libcurl/src/vtls/x509asn1.h7
-rw-r--r--libs/libcurl/src/warnless.c27
-rw-r--r--libs/libcurl/src/warnless.h6
-rw-r--r--libs/libcurl/src/ws.c271
-rw-r--r--libs/libcurl/src/ws.h1
226 files changed, 11110 insertions, 9421 deletions
diff --git a/libs/libcurl/src/.checksrc b/libs/libcurl/src/.checksrc
index b3910efdcf..008da2160d 100644
--- a/libs/libcurl/src/.checksrc
+++ b/libs/libcurl/src/.checksrc
@@ -3,3 +3,6 @@ banfunc strncpy
banfunc sscanf
banfunc snprintf
banfunc vsnprint
+banfunc strtoul
+banfunc strtol
+banfunc strtok_r
diff --git a/libs/libcurl/src/CMakeLists.txt b/libs/libcurl/src/CMakeLists.txt
index 92e5ca0949..8dd4deadfa 100644
--- a/libs/libcurl/src/CMakeLists.txt
+++ b/libs/libcurl/src/CMakeLists.txt
@@ -23,7 +23,8 @@
###########################################################################
set(LIB_NAME "libcurl")
set(LIBCURL_OUTPUT_NAME "libcurl" CACHE STRING "Basename of the curl library")
-add_definitions("-DBUILDING_LIBCURL")
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "BUILDING_LIBCURL")
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "${CURL_DEBUG_MACROS}")
configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
@@ -31,9 +32,6 @@ configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h"
curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
-# DllMain is added later for DLL builds only.
-list(REMOVE_ITEM CSOURCES "dllmain.c")
-
list(APPEND HHEADERS "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
# The rest of the build
@@ -69,18 +67,27 @@ endif()
## Library definition
if(NOT DEFINED IMPORT_LIB_SUFFIX)
- set(IMPORT_LIB_SUFFIX "")
+ # Suffix implib name with "_imp" by default, to avoid conflicting with
+ # the generated static "libcurl.lib" (typically with MSVC).
+ if(WIN32 AND BUILD_SHARED_LIBS AND
+ CMAKE_IMPORT_LIBRARY_SUFFIX STREQUAL CMAKE_STATIC_LIBRARY_SUFFIX)
+ set(IMPORT_LIB_SUFFIX "_imp")
+ else()
+ set(IMPORT_LIB_SUFFIX "")
+ endif()
endif()
if(NOT DEFINED STATIC_LIB_SUFFIX)
set(STATIC_LIB_SUFFIX "")
endif()
-# 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)
- set(IMPORT_LIB_SUFFIX "_imp")
+# Detect implib static lib filename collision
+if(WIN32 AND BUILD_STATIC_LIBS AND BUILD_SHARED_LIBS AND
+ "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}" STREQUAL
+ "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}")
+ message(FATAL_ERROR "Library suffix is the same ('${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}') "
+ "for the import and static '${LIBCURL_OUTPUT_NAME}' library. "
+ "Set IMPORT_LIB_SUFFIX and/or STATIC_LIB_SUFFIX to different values, "
+ "or disable building either the shared or static library to avoid the filename collision.")
endif()
# Whether to do a single compilation pass for libcurl sources and reuse these
@@ -97,9 +104,9 @@ if(NOT DEFINED SHARE_LIB_OBJECT)
endif()
endif()
-if(SHARE_LIB_OBJECT)
+if(SHARE_LIB_OBJECT AND NOT CMAKE_VERSION VERSION_LESS 3.12)
set(LIB_OBJECT "libcurl_object")
- add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})
+ add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES}) # Requires CMake 3.12
if(WIN32)
# Define CURL_STATICLIB always, to disable __declspec(dllexport) for
# exported libcurl symbols. We handle exports via libcurl.def instead.
@@ -140,7 +147,8 @@ if(BUILD_STATIC_LIBS)
set_target_properties(${LIB_STATIC} PROPERTIES
PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}"
- INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
+ INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB"
+ INTERFACE_LINK_DIRECTORIES "${CURL_LIBDIRS}")
if(CURL_HIDES_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
diff --git a/libs/libcurl/src/Makefile.am b/libs/libcurl/src/Makefile.am
index 68b770cb68..275a467d13 100644
--- a/libs/libcurl/src/Makefile.am
+++ b/libs/libcurl/src/Makefile.am
@@ -64,19 +64,38 @@ include Makefile.soname
AM_CPPFLAGS += -DBUILDING_LIBCURL
AM_LDFLAGS =
AM_CFLAGS =
+if DEBUGBUILD
+AM_CPPFLAGS += -DDEBUGBUILD
+endif
+if CURLDEBUG
+AM_CPPFLAGS += -DCURLDEBUG
+endif
# Makefile.inc provides the CSOURCES and HHEADERS defines
include Makefile.inc
+if DOING_NATIVE_WINDOWS
+CSOURCES += dllmain.c
+else
+if DOING_CYGWIN
+CSOURCES += dllmain.c
+endif
+endif
+
if USE_UNITY
# Keep these separate to avoid duplicate definitions when linking libtests
# in static mode.
curl_EXCLUDE = curl_threads.c timediff.c warnless.c
-if DEBUGBUILD
+if CURLDEBUG
# We must compile these sources separately to avoid memdebug.h redefinitions
# applying to them.
curl_EXCLUDE += memdebug.c curl_multibyte.c
endif
+# For Cygwin always compile dllmain.c as a separate unit since it
+# includes windows.h, which should not be included in other units.
+if DOING_CYGWIN
+curl_EXCLUDE += dllmain.c
+endif
libcurl_unity.c: $(top_srcdir)/scripts/mk-unity.pl $(CSOURCES)
@PERL@ $(top_srcdir)/scripts/mk-unity.pl $(srcdir) $(CSOURCES) --exclude $(curl_EXCLUDE) > libcurl_unity.c
@@ -162,7 +181,8 @@ endif
TIDY := clang-tidy
tidy:
- $(TIDY) $(CSOURCES) $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H
+ (_csources=`echo ' $(CSOURCES)' | sed -E -e 's/ +$$//' -e 's/ +/ /g' -e 's| | $(srcdir)/|g'`; \
+ $(TIDY) $$_csources $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H)
optiontable:
perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c
diff --git a/libs/libcurl/src/Makefile.in b/libs/libcurl/src/Makefile.in
index 75602d81b8..f991461228 100644
--- a/libs/libcurl/src/Makefile.in
+++ b/libs/libcurl/src/Makefile.in
@@ -136,20 +136,29 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+@DEBUGBUILD_TRUE@am__append_1 = -DDEBUGBUILD
+@CURLDEBUG_TRUE@am__append_2 = -DCURLDEBUG
+
+# Makefile.inc provides the CSOURCES and HHEADERS defines
+@DOING_NATIVE_WINDOWS_TRUE@am__append_3 = dllmain.c
+@DOING_CYGWIN_TRUE@@DOING_NATIVE_WINDOWS_FALSE@am__append_4 = dllmain.c
# We must compile these sources separately to avoid memdebug.h redefinitions
# applying to them.
-@DEBUGBUILD_TRUE@@USE_UNITY_TRUE@am__append_1 = memdebug.c curl_multibyte.c
-@CURL_LT_SHLIB_USE_VERSION_INFO_TRUE@am__append_2 = $(VERSIONINFO)
-@CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_3 = -no-undefined
-@CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE@am__append_4 = -mimpure-text
-@CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE@am__append_5 = -Wl,--version-script=libcurl.vers
+@CURLDEBUG_TRUE@@USE_UNITY_TRUE@am__append_5 = memdebug.c curl_multibyte.c
+# For Cygwin always compile dllmain.c as a separate unit since it
+# includes windows.h, which should not be included in other units.
+@DOING_CYGWIN_TRUE@@USE_UNITY_TRUE@am__append_6 = dllmain.c
+@CURL_LT_SHLIB_USE_VERSION_INFO_TRUE@am__append_7 = $(VERSIONINFO)
+@CURL_LT_SHLIB_USE_NO_UNDEFINED_TRUE@am__append_8 = -no-undefined
+@CURL_LT_SHLIB_USE_MIMPURE_TEXT_TRUE@am__append_9 = -mimpure-text
+@CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_TRUE@am__append_10 = -Wl,--version-script=libcurl.vers
# if symbol-hiding is enabled, hide them!
-@CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE@@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_6 = -export-symbols-regex '^curl_.*'
-@USE_CPPFLAG_CURL_STATICLIB_TRUE@am__append_7 = -DCURL_STATICLIB
-@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@am__append_8 = $(LIB_RCFILES)
-@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_9 = -DCURL_HIDDEN_SYMBOLS
-@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_10 = $(CFLAG_CURL_SYMBOL_HIDING)
-@CURL_WERROR_TRUE@am__append_11 = --warnings-as-errors=*
+@CURL_LT_SHLIB_USE_VERSIONED_SYMBOLS_FALSE@@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_11 = -export-symbols-regex '^curl_.*'
+@USE_CPPFLAG_CURL_STATICLIB_TRUE@am__append_12 = -DCURL_STATICLIB
+@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@am__append_13 = $(LIB_RCFILES)
+@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_14 = -DCURL_HIDDEN_SYMBOLS
+@DOING_CURL_SYMBOL_HIDING_TRUE@am__append_15 = $(CFLAG_CURL_SYMBOL_HIDING)
+@CURL_WERROR_TRUE@am__append_16 = --warnings-as-errors=*
subdir = lib
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/curl-amissl.m4 \
@@ -217,28 +226,29 @@ libcurl_la_LIBADD =
am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \
asyn-thread.c base64.c bufq.c bufref.c cf-h1-proxy.c \
cf-h2-proxy.c cf-haproxy.c cf-https-connect.c cf-socket.c \
- cfilters.c conncache.c connect.c content_encoding.c cookie.c \
- curl_addrinfo.c curl_des.c curl_endian.c curl_fnmatch.c \
- curl_get_line.c curl_gethostname.c curl_gssapi.c \
- curl_memrchr.c curl_multibyte.c curl_ntlm_core.c curl_range.c \
- curl_rtmp.c curl_sasl.c curl_sha512_256.c curl_sspi.c \
- curl_threads.c curl_trc.c cw-out.c dict.c dllmain.c doh.c \
- dynbuf.c dynhds.c easy.c easygetopt.c easyoptions.c escape.c \
- file.c fileinfo.c fopen.c formdata.c ftp.c ftplistparser.c \
- getenv.c getinfo.c gopher.c hash.c headers.c hmac.c hostasyn.c \
- hostip.c hostip4.c hostip6.c hostsyn.c hsts.c http.c http1.c \
- http2.c http_aws_sigv4.c http_chunks.c http_digest.c \
- http_negotiate.c http_ntlm.c http_proxy.c httpsrr.c idn.c \
- if2ip.c imap.c inet_ntop.c inet_pton.c krb5.c ldap.c llist.c \
- macos.c md4.c md5.c memdebug.c mime.c mprintf.c mqtt.c multi.c \
+ cfilters.c conncache.c cshutdn.c connect.c content_encoding.c \
+ cookie.c curl_addrinfo.c curl_des.c curl_endian.c \
+ curl_fnmatch.c curl_get_line.c curl_gethostname.c \
+ curl_gssapi.c curl_memrchr.c curl_multibyte.c curl_ntlm_core.c \
+ curl_range.c curl_rtmp.c curl_sasl.c curl_sha512_256.c \
+ curl_sspi.c curl_threads.c curl_trc.c cw-out.c cw-pause.c \
+ dict.c doh.c dynbuf.c dynhds.c easy.c easygetopt.c \
+ easyoptions.c escape.c file.c fileinfo.c fopen.c formdata.c \
+ ftp.c ftplistparser.c getenv.c getinfo.c gopher.c hash.c \
+ hash_offt.c headers.c hmac.c hostasyn.c hostip.c hostip4.c \
+ hostip6.c hostsyn.c hsts.c http.c http1.c http2.c \
+ http_aws_sigv4.c http_chunks.c http_digest.c http_negotiate.c \
+ http_ntlm.c http_proxy.c httpsrr.c idn.c if2ip.c imap.c \
+ inet_ntop.c inet_pton.c krb5.c ldap.c llist.c macos.c md4.c \
+ md5.c memdebug.c mime.c mprintf.c mqtt.c multi.c multi_ev.c \
netrc.c nonblock.c noproxy.c openldap.c parsedate.c pingpong.c \
pop3.c progress.c psl.c rand.c rename.c request.c rtsp.c \
select.c sendf.c setopt.c sha256.c share.c slist.c smb.c \
smtp.c socketpair.c socks.c socks_gssapi.c socks_sspi.c \
- speedcheck.c splay.c strcase.c strdup.c strerror.c strparse.c \
- strtok.c strtoofft.c system_win32.c telnet.c tftp.c timediff.c \
- timeval.c transfer.c url.c urlapi.c version.c version_win32.c \
- warnless.c ws.c vauth/cleartext.c vauth/cram.c vauth/digest.c \
+ speedcheck.c splay.c strcase.c strdup.c strequal.c strerror.c \
+ strparse.c system_win32.c telnet.c tftp.c timediff.c timeval.c \
+ transfer.c url.c urlapi.c version.c version_win32.c warnless.c \
+ ws.c vauth/cleartext.c vauth/cram.c vauth/digest.c \
vauth/digest_sspi.c vauth/gsasl.c vauth/krb5_gssapi.c \
vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c \
vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \
@@ -250,68 +260,70 @@ am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \
vtls/wolfssl.c vtls/x509asn1.c vquic/curl_msh3.c \
vquic/curl_ngtcp2.c vquic/curl_osslq.c vquic/curl_quiche.c \
vquic/vquic.c vquic/vquic-tls.c vssh/libssh.c vssh/libssh2.c \
- vssh/curl_path.c vssh/wolfssh.c altsvc.h amigaos.h \
+ vssh/curl_path.c vssh/wolfssh.c dllmain.c altsvc.h amigaos.h \
arpa_telnet.h asyn.h bufq.h bufref.h cf-h1-proxy.h \
cf-h2-proxy.h cf-haproxy.h cf-https-connect.h cf-socket.h \
- cfilters.h conncache.h connect.h content_encoding.h cookie.h \
- curl_addrinfo.h curl_base64.h curl_ctype.h curl_des.h \
+ cfilters.h conncache.h cshutdn.h connect.h content_encoding.h \
+ cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h curl_des.h \
curl_endian.h curl_fnmatch.h curl_get_line.h \
curl_gethostname.h curl_gssapi.h curl_hmac.h curl_krb5.h \
curl_ldap.h curl_md4.h curl_md5.h curl_memory.h curl_memrchr.h \
curl_multibyte.h curl_ntlm_core.h curl_printf.h curl_range.h \
curl_rtmp.h curl_sasl.h curl_setup.h curl_setup_once.h \
curl_sha256.h curl_sha512_256.h curl_sspi.h curl_threads.h \
- curl_trc.h curlx.h cw-out.h dict.h doh.h dynbuf.h dynhds.h \
- easy_lock.h easyif.h easyoptions.h escape.h file.h fileinfo.h \
- fopen.h formdata.h ftp.h ftplistparser.h functypes.h getinfo.h \
- gopher.h hash.h headers.h hostip.h hsts.h http.h http1.h \
- http2.h http_aws_sigv4.h http_chunks.h http_digest.h \
- http_negotiate.h http_ntlm.h http_proxy.h httpsrr.h idn.h \
- if2ip.h imap.h inet_ntop.h inet_pton.h llist.h macos.h \
- memdebug.h mime.h mqtt.h multihandle.h multiif.h netrc.h \
- nonblock.h noproxy.h parsedate.h pingpong.h pop3.h progress.h \
- psl.h rand.h rename.h request.h rtsp.h select.h sendf.h \
- setopt.h setup-os400.h setup-vms.h setup-win32.h share.h \
- sigpipe.h slist.h smb.h smtp.h sockaddr.h socketpair.h socks.h \
+ curl_trc.h curlx.h cw-out.h cw-pause.h dict.h doh.h dynbuf.h \
+ dynhds.h easy_lock.h easyif.h easyoptions.h escape.h file.h \
+ fileinfo.h fopen.h formdata.h ftp.h ftplistparser.h \
+ functypes.h getinfo.h gopher.h hash.h hash_offt.h headers.h \
+ hostip.h hsts.h http.h http1.h http2.h http_aws_sigv4.h \
+ http_chunks.h http_digest.h http_negotiate.h http_ntlm.h \
+ http_proxy.h httpsrr.h idn.h if2ip.h imap.h inet_ntop.h \
+ inet_pton.h llist.h macos.h memdebug.h mime.h mqtt.h \
+ multihandle.h multi_ev.h multiif.h netrc.h nonblock.h \
+ noproxy.h parsedate.h pingpong.h pop3.h progress.h psl.h \
+ rand.h rename.h request.h rtsp.h select.h sendf.h setopt.h \
+ setup-os400.h setup-vms.h setup-win32.h share.h sigpipe.h \
+ slist.h smb.h smtp.h sockaddr.h socketpair.h socks.h \
speedcheck.h splay.h strcase.h strdup.h strerror.h strparse.h \
- strtok.h strtoofft.h system_win32.h telnet.h tftp.h timediff.h \
- timeval.h transfer.h url.h urlapi-int.h urldata.h \
- version_win32.h warnless.h ws.h vauth/digest.h vauth/ntlm.h \
- vauth/vauth.h vtls/bearssl.h vtls/cipher_suite.h vtls/gtls.h \
- vtls/hostcheck.h vtls/keylog.h vtls/mbedtls.h \
- vtls/mbedtls_threadlock.h vtls/openssl.h vtls/rustls.h \
- vtls/schannel.h vtls/schannel_int.h vtls/sectransp.h \
- vtls/vtls.h vtls/vtls_int.h vtls/vtls_scache.h \
- vtls/vtls_spack.h vtls/wolfssl.h vtls/x509asn1.h \
- vquic/curl_msh3.h vquic/curl_ngtcp2.h vquic/curl_osslq.h \
- vquic/curl_quiche.h vquic/vquic.h vquic/vquic_int.h \
- vquic/vquic-tls.h vssh/curl_path.h vssh/ssh.h libcurl.rc
+ system_win32.h telnet.h tftp.h timediff.h timeval.h transfer.h \
+ url.h urlapi-int.h urldata.h version_win32.h warnless.h ws.h \
+ vauth/digest.h vauth/vauth.h vtls/bearssl.h \
+ vtls/cipher_suite.h vtls/gtls.h vtls/hostcheck.h vtls/keylog.h \
+ vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/openssl.h \
+ vtls/rustls.h vtls/schannel.h vtls/schannel_int.h \
+ vtls/sectransp.h vtls/vtls.h vtls/vtls_int.h \
+ vtls/vtls_scache.h vtls/vtls_spack.h vtls/wolfssl.h \
+ vtls/x509asn1.h vquic/curl_msh3.h vquic/curl_ngtcp2.h \
+ vquic/curl_osslq.h vquic/curl_quiche.h vquic/vquic.h \
+ vquic/vquic_int.h vquic/vquic-tls.h vssh/curl_path.h \
+ vssh/ssh.h libcurl.rc
am__objects_1 = libcurl_la-altsvc.lo libcurl_la-amigaos.lo \
libcurl_la-asyn-ares.lo libcurl_la-asyn-thread.lo \
libcurl_la-base64.lo libcurl_la-bufq.lo libcurl_la-bufref.lo \
libcurl_la-cf-h1-proxy.lo libcurl_la-cf-h2-proxy.lo \
libcurl_la-cf-haproxy.lo libcurl_la-cf-https-connect.lo \
libcurl_la-cf-socket.lo libcurl_la-cfilters.lo \
- libcurl_la-conncache.lo libcurl_la-connect.lo \
- libcurl_la-content_encoding.lo libcurl_la-cookie.lo \
- libcurl_la-curl_addrinfo.lo libcurl_la-curl_des.lo \
- libcurl_la-curl_endian.lo libcurl_la-curl_fnmatch.lo \
- libcurl_la-curl_get_line.lo libcurl_la-curl_gethostname.lo \
- libcurl_la-curl_gssapi.lo libcurl_la-curl_memrchr.lo \
- libcurl_la-curl_multibyte.lo libcurl_la-curl_ntlm_core.lo \
- libcurl_la-curl_range.lo libcurl_la-curl_rtmp.lo \
- libcurl_la-curl_sasl.lo libcurl_la-curl_sha512_256.lo \
- libcurl_la-curl_sspi.lo libcurl_la-curl_threads.lo \
- libcurl_la-curl_trc.lo libcurl_la-cw-out.lo libcurl_la-dict.lo \
- libcurl_la-dllmain.lo libcurl_la-doh.lo libcurl_la-dynbuf.lo \
- libcurl_la-dynhds.lo libcurl_la-easy.lo \
- libcurl_la-easygetopt.lo libcurl_la-easyoptions.lo \
- libcurl_la-escape.lo libcurl_la-file.lo libcurl_la-fileinfo.lo \
- libcurl_la-fopen.lo libcurl_la-formdata.lo libcurl_la-ftp.lo \
+ libcurl_la-conncache.lo libcurl_la-cshutdn.lo \
+ libcurl_la-connect.lo libcurl_la-content_encoding.lo \
+ libcurl_la-cookie.lo libcurl_la-curl_addrinfo.lo \
+ libcurl_la-curl_des.lo libcurl_la-curl_endian.lo \
+ libcurl_la-curl_fnmatch.lo libcurl_la-curl_get_line.lo \
+ libcurl_la-curl_gethostname.lo libcurl_la-curl_gssapi.lo \
+ libcurl_la-curl_memrchr.lo libcurl_la-curl_multibyte.lo \
+ libcurl_la-curl_ntlm_core.lo libcurl_la-curl_range.lo \
+ libcurl_la-curl_rtmp.lo libcurl_la-curl_sasl.lo \
+ libcurl_la-curl_sha512_256.lo libcurl_la-curl_sspi.lo \
+ libcurl_la-curl_threads.lo libcurl_la-curl_trc.lo \
+ libcurl_la-cw-out.lo libcurl_la-cw-pause.lo libcurl_la-dict.lo \
+ libcurl_la-doh.lo libcurl_la-dynbuf.lo libcurl_la-dynhds.lo \
+ libcurl_la-easy.lo libcurl_la-easygetopt.lo \
+ libcurl_la-easyoptions.lo libcurl_la-escape.lo \
+ libcurl_la-file.lo libcurl_la-fileinfo.lo libcurl_la-fopen.lo \
+ libcurl_la-formdata.lo libcurl_la-ftp.lo \
libcurl_la-ftplistparser.lo libcurl_la-getenv.lo \
libcurl_la-getinfo.lo libcurl_la-gopher.lo libcurl_la-hash.lo \
- libcurl_la-headers.lo libcurl_la-hmac.lo \
- libcurl_la-hostasyn.lo libcurl_la-hostip.lo \
+ libcurl_la-hash_offt.lo libcurl_la-headers.lo \
+ libcurl_la-hmac.lo libcurl_la-hostasyn.lo libcurl_la-hostip.lo \
libcurl_la-hostip4.lo libcurl_la-hostip6.lo \
libcurl_la-hostsyn.lo libcurl_la-hsts.lo libcurl_la-http.lo \
libcurl_la-http1.lo libcurl_la-http2.lo \
@@ -324,22 +336,21 @@ am__objects_1 = libcurl_la-altsvc.lo libcurl_la-amigaos.lo \
libcurl_la-llist.lo libcurl_la-macos.lo libcurl_la-md4.lo \
libcurl_la-md5.lo libcurl_la-memdebug.lo libcurl_la-mime.lo \
libcurl_la-mprintf.lo libcurl_la-mqtt.lo libcurl_la-multi.lo \
- libcurl_la-netrc.lo libcurl_la-nonblock.lo \
- libcurl_la-noproxy.lo libcurl_la-openldap.lo \
- libcurl_la-parsedate.lo libcurl_la-pingpong.lo \
- libcurl_la-pop3.lo libcurl_la-progress.lo libcurl_la-psl.lo \
- libcurl_la-rand.lo libcurl_la-rename.lo libcurl_la-request.lo \
- libcurl_la-rtsp.lo libcurl_la-select.lo libcurl_la-sendf.lo \
- libcurl_la-setopt.lo libcurl_la-sha256.lo libcurl_la-share.lo \
- libcurl_la-slist.lo libcurl_la-smb.lo libcurl_la-smtp.lo \
- libcurl_la-socketpair.lo libcurl_la-socks.lo \
- libcurl_la-socks_gssapi.lo libcurl_la-socks_sspi.lo \
- libcurl_la-speedcheck.lo libcurl_la-splay.lo \
- libcurl_la-strcase.lo libcurl_la-strdup.lo \
- libcurl_la-strerror.lo libcurl_la-strparse.lo \
- libcurl_la-strtok.lo libcurl_la-strtoofft.lo \
- libcurl_la-system_win32.lo libcurl_la-telnet.lo \
- libcurl_la-tftp.lo libcurl_la-timediff.lo \
+ libcurl_la-multi_ev.lo libcurl_la-netrc.lo \
+ libcurl_la-nonblock.lo libcurl_la-noproxy.lo \
+ libcurl_la-openldap.lo libcurl_la-parsedate.lo \
+ libcurl_la-pingpong.lo libcurl_la-pop3.lo \
+ libcurl_la-progress.lo libcurl_la-psl.lo libcurl_la-rand.lo \
+ libcurl_la-rename.lo libcurl_la-request.lo libcurl_la-rtsp.lo \
+ libcurl_la-select.lo libcurl_la-sendf.lo libcurl_la-setopt.lo \
+ libcurl_la-sha256.lo libcurl_la-share.lo libcurl_la-slist.lo \
+ libcurl_la-smb.lo libcurl_la-smtp.lo libcurl_la-socketpair.lo \
+ libcurl_la-socks.lo libcurl_la-socks_gssapi.lo \
+ libcurl_la-socks_sspi.lo libcurl_la-speedcheck.lo \
+ libcurl_la-splay.lo libcurl_la-strcase.lo libcurl_la-strdup.lo \
+ libcurl_la-strequal.lo libcurl_la-strerror.lo \
+ libcurl_la-strparse.lo libcurl_la-system_win32.lo \
+ libcurl_la-telnet.lo libcurl_la-tftp.lo libcurl_la-timediff.lo \
libcurl_la-timeval.lo libcurl_la-transfer.lo libcurl_la-url.lo \
libcurl_la-urlapi.lo libcurl_la-version.lo \
libcurl_la-version_win32.lo libcurl_la-warnless.lo \
@@ -368,23 +379,28 @@ am__objects_4 = vquic/libcurl_la-curl_msh3.lo \
vquic/libcurl_la-vquic-tls.lo
am__objects_5 = vssh/libcurl_la-libssh.lo vssh/libcurl_la-libssh2.lo \
vssh/libcurl_la-curl_path.lo vssh/libcurl_la-wolfssh.lo
-am__objects_6 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \
- $(am__objects_4) $(am__objects_5)
-am__objects_7 =
-am__objects_8 = $(am__objects_7) $(am__objects_7) $(am__objects_7) \
- $(am__objects_7) $(am__objects_7)
-am__objects_9 = libcurl.lo
-@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@am__objects_10 = $(am__objects_9)
-@DEBUGBUILD_TRUE@@USE_UNITY_TRUE@am__objects_11 = \
-@DEBUGBUILD_TRUE@@USE_UNITY_TRUE@ libcurl_la-memdebug.lo \
-@DEBUGBUILD_TRUE@@USE_UNITY_TRUE@ libcurl_la-curl_multibyte.lo
-@USE_UNITY_TRUE@am__objects_12 = libcurl_la-curl_threads.lo \
+@DOING_NATIVE_WINDOWS_TRUE@am__objects_6 = libcurl_la-dllmain.lo
+@DOING_CYGWIN_TRUE@@DOING_NATIVE_WINDOWS_FALSE@am__objects_7 = libcurl_la-dllmain.lo
+am__objects_8 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \
+ $(am__objects_4) $(am__objects_5) $(am__objects_6) \
+ $(am__objects_7)
+am__objects_9 =
+am__objects_10 = $(am__objects_9) $(am__objects_9) $(am__objects_9) \
+ $(am__objects_9) $(am__objects_9)
+am__objects_11 = libcurl.lo
+@HAVE_WINDRES_TRUE@@USE_CPPFLAG_CURL_STATICLIB_FALSE@am__objects_12 = $(am__objects_11)
+@CURLDEBUG_TRUE@@USE_UNITY_TRUE@am__objects_13 = \
+@CURLDEBUG_TRUE@@USE_UNITY_TRUE@ libcurl_la-memdebug.lo \
+@CURLDEBUG_TRUE@@USE_UNITY_TRUE@ libcurl_la-curl_multibyte.lo
+@DOING_CYGWIN_TRUE@@USE_UNITY_TRUE@am__objects_14 = \
+@DOING_CYGWIN_TRUE@@USE_UNITY_TRUE@ libcurl_la-dllmain.lo
+@USE_UNITY_TRUE@am__objects_15 = libcurl_la-curl_threads.lo \
@USE_UNITY_TRUE@ libcurl_la-timediff.lo libcurl_la-warnless.lo \
-@USE_UNITY_TRUE@ $(am__objects_11)
-@USE_UNITY_FALSE@am_libcurl_la_OBJECTS = $(am__objects_6) \
-@USE_UNITY_FALSE@ $(am__objects_8) $(am__objects_10)
-@USE_UNITY_TRUE@am_libcurl_la_OBJECTS = $(am__objects_12) \
-@USE_UNITY_TRUE@ $(am__objects_10)
+@USE_UNITY_TRUE@ $(am__objects_13) $(am__objects_14)
+@USE_UNITY_FALSE@am_libcurl_la_OBJECTS = $(am__objects_8) \
+@USE_UNITY_FALSE@ $(am__objects_10) $(am__objects_12)
+@USE_UNITY_TRUE@am_libcurl_la_OBJECTS = $(am__objects_15) \
+@USE_UNITY_TRUE@ $(am__objects_12)
@USE_UNITY_TRUE@nodist_libcurl_la_OBJECTS = \
@USE_UNITY_TRUE@ libcurl_la-libcurl_unity.lo
libcurl_la_OBJECTS = $(am_libcurl_la_OBJECTS) \
@@ -400,28 +416,29 @@ libcurlu_la_LIBADD =
am__libcurlu_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \
asyn-thread.c base64.c bufq.c bufref.c cf-h1-proxy.c \
cf-h2-proxy.c cf-haproxy.c cf-https-connect.c cf-socket.c \
- cfilters.c conncache.c connect.c content_encoding.c cookie.c \
- curl_addrinfo.c curl_des.c curl_endian.c curl_fnmatch.c \
- curl_get_line.c curl_gethostname.c curl_gssapi.c \
- curl_memrchr.c curl_multibyte.c curl_ntlm_core.c curl_range.c \
- curl_rtmp.c curl_sasl.c curl_sha512_256.c curl_sspi.c \
- curl_threads.c curl_trc.c cw-out.c dict.c dllmain.c doh.c \
- dynbuf.c dynhds.c easy.c easygetopt.c easyoptions.c escape.c \
- file.c fileinfo.c fopen.c formdata.c ftp.c ftplistparser.c \
- getenv.c getinfo.c gopher.c hash.c headers.c hmac.c hostasyn.c \
- hostip.c hostip4.c hostip6.c hostsyn.c hsts.c http.c http1.c \
- http2.c http_aws_sigv4.c http_chunks.c http_digest.c \
- http_negotiate.c http_ntlm.c http_proxy.c httpsrr.c idn.c \
- if2ip.c imap.c inet_ntop.c inet_pton.c krb5.c ldap.c llist.c \
- macos.c md4.c md5.c memdebug.c mime.c mprintf.c mqtt.c multi.c \
+ cfilters.c conncache.c cshutdn.c connect.c content_encoding.c \
+ cookie.c curl_addrinfo.c curl_des.c curl_endian.c \
+ curl_fnmatch.c curl_get_line.c curl_gethostname.c \
+ curl_gssapi.c curl_memrchr.c curl_multibyte.c curl_ntlm_core.c \
+ curl_range.c curl_rtmp.c curl_sasl.c curl_sha512_256.c \
+ curl_sspi.c curl_threads.c curl_trc.c cw-out.c cw-pause.c \
+ dict.c doh.c dynbuf.c dynhds.c easy.c easygetopt.c \
+ easyoptions.c escape.c file.c fileinfo.c fopen.c formdata.c \
+ ftp.c ftplistparser.c getenv.c getinfo.c gopher.c hash.c \
+ hash_offt.c headers.c hmac.c hostasyn.c hostip.c hostip4.c \
+ hostip6.c hostsyn.c hsts.c http.c http1.c http2.c \
+ http_aws_sigv4.c http_chunks.c http_digest.c http_negotiate.c \
+ http_ntlm.c http_proxy.c httpsrr.c idn.c if2ip.c imap.c \
+ inet_ntop.c inet_pton.c krb5.c ldap.c llist.c macos.c md4.c \
+ md5.c memdebug.c mime.c mprintf.c mqtt.c multi.c multi_ev.c \
netrc.c nonblock.c noproxy.c openldap.c parsedate.c pingpong.c \
pop3.c progress.c psl.c rand.c rename.c request.c rtsp.c \
select.c sendf.c setopt.c sha256.c share.c slist.c smb.c \
smtp.c socketpair.c socks.c socks_gssapi.c socks_sspi.c \
- speedcheck.c splay.c strcase.c strdup.c strerror.c strparse.c \
- strtok.c strtoofft.c system_win32.c telnet.c tftp.c timediff.c \
- timeval.c transfer.c url.c urlapi.c version.c version_win32.c \
- warnless.c ws.c vauth/cleartext.c vauth/cram.c vauth/digest.c \
+ speedcheck.c splay.c strcase.c strdup.c strequal.c strerror.c \
+ strparse.c system_win32.c telnet.c tftp.c timediff.c timeval.c \
+ transfer.c url.c urlapi.c version.c version_win32.c warnless.c \
+ ws.c vauth/cleartext.c vauth/cram.c vauth/digest.c \
vauth/digest_sspi.c vauth/gsasl.c vauth/krb5_gssapi.c \
vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c \
vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \
@@ -433,61 +450,62 @@ am__libcurlu_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \
vtls/wolfssl.c vtls/x509asn1.c vquic/curl_msh3.c \
vquic/curl_ngtcp2.c vquic/curl_osslq.c vquic/curl_quiche.c \
vquic/vquic.c vquic/vquic-tls.c vssh/libssh.c vssh/libssh2.c \
- vssh/curl_path.c vssh/wolfssh.c altsvc.h amigaos.h \
+ vssh/curl_path.c vssh/wolfssh.c dllmain.c altsvc.h amigaos.h \
arpa_telnet.h asyn.h bufq.h bufref.h cf-h1-proxy.h \
cf-h2-proxy.h cf-haproxy.h cf-https-connect.h cf-socket.h \
- cfilters.h conncache.h connect.h content_encoding.h cookie.h \
- curl_addrinfo.h curl_base64.h curl_ctype.h curl_des.h \
+ cfilters.h conncache.h cshutdn.h connect.h content_encoding.h \
+ cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h curl_des.h \
curl_endian.h curl_fnmatch.h curl_get_line.h \
curl_gethostname.h curl_gssapi.h curl_hmac.h curl_krb5.h \
curl_ldap.h curl_md4.h curl_md5.h curl_memory.h curl_memrchr.h \
curl_multibyte.h curl_ntlm_core.h curl_printf.h curl_range.h \
curl_rtmp.h curl_sasl.h curl_setup.h curl_setup_once.h \
curl_sha256.h curl_sha512_256.h curl_sspi.h curl_threads.h \
- curl_trc.h curlx.h cw-out.h dict.h doh.h dynbuf.h dynhds.h \
- easy_lock.h easyif.h easyoptions.h escape.h file.h fileinfo.h \
- fopen.h formdata.h ftp.h ftplistparser.h functypes.h getinfo.h \
- gopher.h hash.h headers.h hostip.h hsts.h http.h http1.h \
- http2.h http_aws_sigv4.h http_chunks.h http_digest.h \
- http_negotiate.h http_ntlm.h http_proxy.h httpsrr.h idn.h \
- if2ip.h imap.h inet_ntop.h inet_pton.h llist.h macos.h \
- memdebug.h mime.h mqtt.h multihandle.h multiif.h netrc.h \
- nonblock.h noproxy.h parsedate.h pingpong.h pop3.h progress.h \
- psl.h rand.h rename.h request.h rtsp.h select.h sendf.h \
- setopt.h setup-os400.h setup-vms.h setup-win32.h share.h \
- sigpipe.h slist.h smb.h smtp.h sockaddr.h socketpair.h socks.h \
+ curl_trc.h curlx.h cw-out.h cw-pause.h dict.h doh.h dynbuf.h \
+ dynhds.h easy_lock.h easyif.h easyoptions.h escape.h file.h \
+ fileinfo.h fopen.h formdata.h ftp.h ftplistparser.h \
+ functypes.h getinfo.h gopher.h hash.h hash_offt.h headers.h \
+ hostip.h hsts.h http.h http1.h http2.h http_aws_sigv4.h \
+ http_chunks.h http_digest.h http_negotiate.h http_ntlm.h \
+ http_proxy.h httpsrr.h idn.h if2ip.h imap.h inet_ntop.h \
+ inet_pton.h llist.h macos.h memdebug.h mime.h mqtt.h \
+ multihandle.h multi_ev.h multiif.h netrc.h nonblock.h \
+ noproxy.h parsedate.h pingpong.h pop3.h progress.h psl.h \
+ rand.h rename.h request.h rtsp.h select.h sendf.h setopt.h \
+ setup-os400.h setup-vms.h setup-win32.h share.h sigpipe.h \
+ slist.h smb.h smtp.h sockaddr.h socketpair.h socks.h \
speedcheck.h splay.h strcase.h strdup.h strerror.h strparse.h \
- strtok.h strtoofft.h system_win32.h telnet.h tftp.h timediff.h \
- timeval.h transfer.h url.h urlapi-int.h urldata.h \
- version_win32.h warnless.h ws.h vauth/digest.h vauth/ntlm.h \
- vauth/vauth.h vtls/bearssl.h vtls/cipher_suite.h vtls/gtls.h \
- vtls/hostcheck.h vtls/keylog.h vtls/mbedtls.h \
- vtls/mbedtls_threadlock.h vtls/openssl.h vtls/rustls.h \
- vtls/schannel.h vtls/schannel_int.h vtls/sectransp.h \
- vtls/vtls.h vtls/vtls_int.h vtls/vtls_scache.h \
- vtls/vtls_spack.h vtls/wolfssl.h vtls/x509asn1.h \
- vquic/curl_msh3.h vquic/curl_ngtcp2.h vquic/curl_osslq.h \
- vquic/curl_quiche.h vquic/vquic.h vquic/vquic_int.h \
- vquic/vquic-tls.h vssh/curl_path.h vssh/ssh.h
-am__objects_13 = libcurlu_la-altsvc.lo libcurlu_la-amigaos.lo \
+ system_win32.h telnet.h tftp.h timediff.h timeval.h transfer.h \
+ url.h urlapi-int.h urldata.h version_win32.h warnless.h ws.h \
+ vauth/digest.h vauth/vauth.h vtls/bearssl.h \
+ vtls/cipher_suite.h vtls/gtls.h vtls/hostcheck.h vtls/keylog.h \
+ vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/openssl.h \
+ vtls/rustls.h vtls/schannel.h vtls/schannel_int.h \
+ vtls/sectransp.h vtls/vtls.h vtls/vtls_int.h \
+ vtls/vtls_scache.h vtls/vtls_spack.h vtls/wolfssl.h \
+ vtls/x509asn1.h vquic/curl_msh3.h vquic/curl_ngtcp2.h \
+ vquic/curl_osslq.h vquic/curl_quiche.h vquic/vquic.h \
+ vquic/vquic_int.h vquic/vquic-tls.h vssh/curl_path.h \
+ vssh/ssh.h
+am__objects_16 = libcurlu_la-altsvc.lo libcurlu_la-amigaos.lo \
libcurlu_la-asyn-ares.lo libcurlu_la-asyn-thread.lo \
libcurlu_la-base64.lo libcurlu_la-bufq.lo \
libcurlu_la-bufref.lo libcurlu_la-cf-h1-proxy.lo \
libcurlu_la-cf-h2-proxy.lo libcurlu_la-cf-haproxy.lo \
libcurlu_la-cf-https-connect.lo libcurlu_la-cf-socket.lo \
libcurlu_la-cfilters.lo libcurlu_la-conncache.lo \
- libcurlu_la-connect.lo libcurlu_la-content_encoding.lo \
- libcurlu_la-cookie.lo libcurlu_la-curl_addrinfo.lo \
- libcurlu_la-curl_des.lo libcurlu_la-curl_endian.lo \
- libcurlu_la-curl_fnmatch.lo libcurlu_la-curl_get_line.lo \
- libcurlu_la-curl_gethostname.lo libcurlu_la-curl_gssapi.lo \
- libcurlu_la-curl_memrchr.lo libcurlu_la-curl_multibyte.lo \
- libcurlu_la-curl_ntlm_core.lo libcurlu_la-curl_range.lo \
- libcurlu_la-curl_rtmp.lo libcurlu_la-curl_sasl.lo \
- libcurlu_la-curl_sha512_256.lo libcurlu_la-curl_sspi.lo \
- libcurlu_la-curl_threads.lo libcurlu_la-curl_trc.lo \
- libcurlu_la-cw-out.lo libcurlu_la-dict.lo \
- libcurlu_la-dllmain.lo libcurlu_la-doh.lo \
+ libcurlu_la-cshutdn.lo libcurlu_la-connect.lo \
+ libcurlu_la-content_encoding.lo libcurlu_la-cookie.lo \
+ libcurlu_la-curl_addrinfo.lo libcurlu_la-curl_des.lo \
+ libcurlu_la-curl_endian.lo libcurlu_la-curl_fnmatch.lo \
+ libcurlu_la-curl_get_line.lo libcurlu_la-curl_gethostname.lo \
+ libcurlu_la-curl_gssapi.lo libcurlu_la-curl_memrchr.lo \
+ libcurlu_la-curl_multibyte.lo libcurlu_la-curl_ntlm_core.lo \
+ libcurlu_la-curl_range.lo libcurlu_la-curl_rtmp.lo \
+ libcurlu_la-curl_sasl.lo libcurlu_la-curl_sha512_256.lo \
+ libcurlu_la-curl_sspi.lo libcurlu_la-curl_threads.lo \
+ libcurlu_la-curl_trc.lo libcurlu_la-cw-out.lo \
+ libcurlu_la-cw-pause.lo libcurlu_la-dict.lo libcurlu_la-doh.lo \
libcurlu_la-dynbuf.lo libcurlu_la-dynhds.lo \
libcurlu_la-easy.lo libcurlu_la-easygetopt.lo \
libcurlu_la-easyoptions.lo libcurlu_la-escape.lo \
@@ -496,43 +514,44 @@ am__objects_13 = libcurlu_la-altsvc.lo libcurlu_la-amigaos.lo \
libcurlu_la-ftp.lo libcurlu_la-ftplistparser.lo \
libcurlu_la-getenv.lo libcurlu_la-getinfo.lo \
libcurlu_la-gopher.lo libcurlu_la-hash.lo \
- libcurlu_la-headers.lo libcurlu_la-hmac.lo \
- libcurlu_la-hostasyn.lo libcurlu_la-hostip.lo \
- libcurlu_la-hostip4.lo libcurlu_la-hostip6.lo \
- libcurlu_la-hostsyn.lo libcurlu_la-hsts.lo libcurlu_la-http.lo \
- libcurlu_la-http1.lo libcurlu_la-http2.lo \
- libcurlu_la-http_aws_sigv4.lo libcurlu_la-http_chunks.lo \
- libcurlu_la-http_digest.lo libcurlu_la-http_negotiate.lo \
- libcurlu_la-http_ntlm.lo libcurlu_la-http_proxy.lo \
- libcurlu_la-httpsrr.lo libcurlu_la-idn.lo libcurlu_la-if2ip.lo \
- libcurlu_la-imap.lo libcurlu_la-inet_ntop.lo \
- libcurlu_la-inet_pton.lo libcurlu_la-krb5.lo \
- libcurlu_la-ldap.lo libcurlu_la-llist.lo libcurlu_la-macos.lo \
- libcurlu_la-md4.lo libcurlu_la-md5.lo libcurlu_la-memdebug.lo \
- libcurlu_la-mime.lo libcurlu_la-mprintf.lo libcurlu_la-mqtt.lo \
- libcurlu_la-multi.lo libcurlu_la-netrc.lo \
- libcurlu_la-nonblock.lo libcurlu_la-noproxy.lo \
- libcurlu_la-openldap.lo libcurlu_la-parsedate.lo \
- libcurlu_la-pingpong.lo libcurlu_la-pop3.lo \
- libcurlu_la-progress.lo libcurlu_la-psl.lo libcurlu_la-rand.lo \
- libcurlu_la-rename.lo libcurlu_la-request.lo \
- libcurlu_la-rtsp.lo libcurlu_la-select.lo libcurlu_la-sendf.lo \
+ libcurlu_la-hash_offt.lo libcurlu_la-headers.lo \
+ libcurlu_la-hmac.lo libcurlu_la-hostasyn.lo \
+ libcurlu_la-hostip.lo libcurlu_la-hostip4.lo \
+ libcurlu_la-hostip6.lo libcurlu_la-hostsyn.lo \
+ libcurlu_la-hsts.lo libcurlu_la-http.lo libcurlu_la-http1.lo \
+ libcurlu_la-http2.lo libcurlu_la-http_aws_sigv4.lo \
+ libcurlu_la-http_chunks.lo libcurlu_la-http_digest.lo \
+ libcurlu_la-http_negotiate.lo libcurlu_la-http_ntlm.lo \
+ libcurlu_la-http_proxy.lo libcurlu_la-httpsrr.lo \
+ libcurlu_la-idn.lo libcurlu_la-if2ip.lo libcurlu_la-imap.lo \
+ libcurlu_la-inet_ntop.lo libcurlu_la-inet_pton.lo \
+ libcurlu_la-krb5.lo libcurlu_la-ldap.lo libcurlu_la-llist.lo \
+ libcurlu_la-macos.lo libcurlu_la-md4.lo libcurlu_la-md5.lo \
+ libcurlu_la-memdebug.lo libcurlu_la-mime.lo \
+ libcurlu_la-mprintf.lo libcurlu_la-mqtt.lo \
+ libcurlu_la-multi.lo libcurlu_la-multi_ev.lo \
+ libcurlu_la-netrc.lo libcurlu_la-nonblock.lo \
+ libcurlu_la-noproxy.lo libcurlu_la-openldap.lo \
+ libcurlu_la-parsedate.lo libcurlu_la-pingpong.lo \
+ libcurlu_la-pop3.lo libcurlu_la-progress.lo libcurlu_la-psl.lo \
+ libcurlu_la-rand.lo libcurlu_la-rename.lo \
+ libcurlu_la-request.lo libcurlu_la-rtsp.lo \
+ libcurlu_la-select.lo libcurlu_la-sendf.lo \
libcurlu_la-setopt.lo libcurlu_la-sha256.lo \
libcurlu_la-share.lo libcurlu_la-slist.lo libcurlu_la-smb.lo \
libcurlu_la-smtp.lo libcurlu_la-socketpair.lo \
libcurlu_la-socks.lo libcurlu_la-socks_gssapi.lo \
libcurlu_la-socks_sspi.lo libcurlu_la-speedcheck.lo \
libcurlu_la-splay.lo libcurlu_la-strcase.lo \
- libcurlu_la-strdup.lo libcurlu_la-strerror.lo \
- libcurlu_la-strparse.lo libcurlu_la-strtok.lo \
- libcurlu_la-strtoofft.lo libcurlu_la-system_win32.lo \
- libcurlu_la-telnet.lo libcurlu_la-tftp.lo \
- libcurlu_la-timediff.lo libcurlu_la-timeval.lo \
- libcurlu_la-transfer.lo libcurlu_la-url.lo \
- libcurlu_la-urlapi.lo libcurlu_la-version.lo \
- libcurlu_la-version_win32.lo libcurlu_la-warnless.lo \
- libcurlu_la-ws.lo
-am__objects_14 = vauth/libcurlu_la-cleartext.lo \
+ libcurlu_la-strdup.lo libcurlu_la-strequal.lo \
+ libcurlu_la-strerror.lo libcurlu_la-strparse.lo \
+ libcurlu_la-system_win32.lo libcurlu_la-telnet.lo \
+ libcurlu_la-tftp.lo libcurlu_la-timediff.lo \
+ libcurlu_la-timeval.lo libcurlu_la-transfer.lo \
+ libcurlu_la-url.lo libcurlu_la-urlapi.lo \
+ libcurlu_la-version.lo libcurlu_la-version_win32.lo \
+ libcurlu_la-warnless.lo libcurlu_la-ws.lo
+am__objects_17 = vauth/libcurlu_la-cleartext.lo \
vauth/libcurlu_la-cram.lo vauth/libcurlu_la-digest.lo \
vauth/libcurlu_la-digest_sspi.lo vauth/libcurlu_la-gsasl.lo \
vauth/libcurlu_la-krb5_gssapi.lo \
@@ -540,7 +559,7 @@ am__objects_14 = vauth/libcurlu_la-cleartext.lo \
vauth/libcurlu_la-ntlm_sspi.lo vauth/libcurlu_la-oauth2.lo \
vauth/libcurlu_la-spnego_gssapi.lo \
vauth/libcurlu_la-spnego_sspi.lo vauth/libcurlu_la-vauth.lo
-am__objects_15 = vtls/libcurlu_la-bearssl.lo \
+am__objects_18 = vtls/libcurlu_la-bearssl.lo \
vtls/libcurlu_la-cipher_suite.lo vtls/libcurlu_la-gtls.lo \
vtls/libcurlu_la-hostcheck.lo vtls/libcurlu_la-keylog.lo \
vtls/libcurlu_la-mbedtls.lo \
@@ -551,25 +570,31 @@ am__objects_15 = vtls/libcurlu_la-bearssl.lo \
vtls/libcurlu_la-sectransp.lo vtls/libcurlu_la-vtls.lo \
vtls/libcurlu_la-vtls_scache.lo vtls/libcurlu_la-vtls_spack.lo \
vtls/libcurlu_la-wolfssl.lo vtls/libcurlu_la-x509asn1.lo
-am__objects_16 = vquic/libcurlu_la-curl_msh3.lo \
+am__objects_19 = vquic/libcurlu_la-curl_msh3.lo \
vquic/libcurlu_la-curl_ngtcp2.lo \
vquic/libcurlu_la-curl_osslq.lo \
vquic/libcurlu_la-curl_quiche.lo vquic/libcurlu_la-vquic.lo \
vquic/libcurlu_la-vquic-tls.lo
-am__objects_17 = vssh/libcurlu_la-libssh.lo \
+am__objects_20 = vssh/libcurlu_la-libssh.lo \
vssh/libcurlu_la-libssh2.lo vssh/libcurlu_la-curl_path.lo \
vssh/libcurlu_la-wolfssh.lo
-am__objects_18 = $(am__objects_13) $(am__objects_14) $(am__objects_15) \
- $(am__objects_16) $(am__objects_17)
-@DEBUGBUILD_TRUE@@USE_UNITY_TRUE@am__objects_19 = \
-@DEBUGBUILD_TRUE@@USE_UNITY_TRUE@ libcurlu_la-memdebug.lo \
-@DEBUGBUILD_TRUE@@USE_UNITY_TRUE@ libcurlu_la-curl_multibyte.lo
-@USE_UNITY_TRUE@am__objects_20 = libcurlu_la-curl_threads.lo \
+@DOING_NATIVE_WINDOWS_TRUE@am__objects_21 = libcurlu_la-dllmain.lo
+@DOING_CYGWIN_TRUE@@DOING_NATIVE_WINDOWS_FALSE@am__objects_22 = libcurlu_la-dllmain.lo
+am__objects_23 = $(am__objects_16) $(am__objects_17) $(am__objects_18) \
+ $(am__objects_19) $(am__objects_20) $(am__objects_21) \
+ $(am__objects_22)
+@CURLDEBUG_TRUE@@USE_UNITY_TRUE@am__objects_24 = \
+@CURLDEBUG_TRUE@@USE_UNITY_TRUE@ libcurlu_la-memdebug.lo \
+@CURLDEBUG_TRUE@@USE_UNITY_TRUE@ libcurlu_la-curl_multibyte.lo
+@DOING_CYGWIN_TRUE@@USE_UNITY_TRUE@am__objects_25 = \
+@DOING_CYGWIN_TRUE@@USE_UNITY_TRUE@ libcurlu_la-dllmain.lo
+@USE_UNITY_TRUE@am__objects_26 = libcurlu_la-curl_threads.lo \
@USE_UNITY_TRUE@ libcurlu_la-timediff.lo \
-@USE_UNITY_TRUE@ libcurlu_la-warnless.lo $(am__objects_19)
-@USE_UNITY_FALSE@am_libcurlu_la_OBJECTS = $(am__objects_18) \
-@USE_UNITY_FALSE@ $(am__objects_8)
-@USE_UNITY_TRUE@am_libcurlu_la_OBJECTS = $(am__objects_20)
+@USE_UNITY_TRUE@ libcurlu_la-warnless.lo $(am__objects_24) \
+@USE_UNITY_TRUE@ $(am__objects_25)
+@USE_UNITY_FALSE@am_libcurlu_la_OBJECTS = $(am__objects_23) \
+@USE_UNITY_FALSE@ $(am__objects_10)
+@USE_UNITY_TRUE@am_libcurlu_la_OBJECTS = $(am__objects_26)
@USE_UNITY_TRUE@nodist_libcurlu_la_OBJECTS = \
@USE_UNITY_TRUE@ libcurlu_la-libcurl_unity.lo
libcurlu_la_OBJECTS = $(am_libcurlu_la_OBJECTS) \
@@ -610,6 +635,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurl_la-connect.Plo \
./$(DEPDIR)/libcurl_la-content_encoding.Plo \
./$(DEPDIR)/libcurl_la-cookie.Plo \
+ ./$(DEPDIR)/libcurl_la-cshutdn.Plo \
./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo \
./$(DEPDIR)/libcurl_la-curl_des.Plo \
./$(DEPDIR)/libcurl_la-curl_endian.Plo \
@@ -628,6 +654,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurl_la-curl_threads.Plo \
./$(DEPDIR)/libcurl_la-curl_trc.Plo \
./$(DEPDIR)/libcurl_la-cw-out.Plo \
+ ./$(DEPDIR)/libcurl_la-cw-pause.Plo \
./$(DEPDIR)/libcurl_la-dict.Plo \
./$(DEPDIR)/libcurl_la-dllmain.Plo \
./$(DEPDIR)/libcurl_la-doh.Plo \
@@ -647,6 +674,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurl_la-getinfo.Plo \
./$(DEPDIR)/libcurl_la-gopher.Plo \
./$(DEPDIR)/libcurl_la-hash.Plo \
+ ./$(DEPDIR)/libcurl_la-hash_offt.Plo \
./$(DEPDIR)/libcurl_la-headers.Plo \
./$(DEPDIR)/libcurl_la-hmac.Plo \
./$(DEPDIR)/libcurl_la-hostasyn.Plo \
@@ -681,6 +709,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurl_la-mprintf.Plo \
./$(DEPDIR)/libcurl_la-mqtt.Plo \
./$(DEPDIR)/libcurl_la-multi.Plo \
+ ./$(DEPDIR)/libcurl_la-multi_ev.Plo \
./$(DEPDIR)/libcurl_la-netrc.Plo \
./$(DEPDIR)/libcurl_la-nonblock.Plo \
./$(DEPDIR)/libcurl_la-noproxy.Plo \
@@ -708,10 +737,9 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurl_la-splay.Plo \
./$(DEPDIR)/libcurl_la-strcase.Plo \
./$(DEPDIR)/libcurl_la-strdup.Plo \
+ ./$(DEPDIR)/libcurl_la-strequal.Plo \
./$(DEPDIR)/libcurl_la-strerror.Plo \
./$(DEPDIR)/libcurl_la-strparse.Plo \
- ./$(DEPDIR)/libcurl_la-strtok.Plo \
- ./$(DEPDIR)/libcurl_la-strtoofft.Plo \
./$(DEPDIR)/libcurl_la-system_win32.Plo \
./$(DEPDIR)/libcurl_la-telnet.Plo \
./$(DEPDIR)/libcurl_la-tftp.Plo \
@@ -741,6 +769,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurlu_la-connect.Plo \
./$(DEPDIR)/libcurlu_la-content_encoding.Plo \
./$(DEPDIR)/libcurlu_la-cookie.Plo \
+ ./$(DEPDIR)/libcurlu_la-cshutdn.Plo \
./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo \
./$(DEPDIR)/libcurlu_la-curl_des.Plo \
./$(DEPDIR)/libcurlu_la-curl_endian.Plo \
@@ -759,6 +788,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurlu_la-curl_threads.Plo \
./$(DEPDIR)/libcurlu_la-curl_trc.Plo \
./$(DEPDIR)/libcurlu_la-cw-out.Plo \
+ ./$(DEPDIR)/libcurlu_la-cw-pause.Plo \
./$(DEPDIR)/libcurlu_la-dict.Plo \
./$(DEPDIR)/libcurlu_la-dllmain.Plo \
./$(DEPDIR)/libcurlu_la-doh.Plo \
@@ -778,6 +808,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurlu_la-getinfo.Plo \
./$(DEPDIR)/libcurlu_la-gopher.Plo \
./$(DEPDIR)/libcurlu_la-hash.Plo \
+ ./$(DEPDIR)/libcurlu_la-hash_offt.Plo \
./$(DEPDIR)/libcurlu_la-headers.Plo \
./$(DEPDIR)/libcurlu_la-hmac.Plo \
./$(DEPDIR)/libcurlu_la-hostasyn.Plo \
@@ -813,6 +844,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurlu_la-mprintf.Plo \
./$(DEPDIR)/libcurlu_la-mqtt.Plo \
./$(DEPDIR)/libcurlu_la-multi.Plo \
+ ./$(DEPDIR)/libcurlu_la-multi_ev.Plo \
./$(DEPDIR)/libcurlu_la-netrc.Plo \
./$(DEPDIR)/libcurlu_la-nonblock.Plo \
./$(DEPDIR)/libcurlu_la-noproxy.Plo \
@@ -842,10 +874,9 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \
./$(DEPDIR)/libcurlu_la-splay.Plo \
./$(DEPDIR)/libcurlu_la-strcase.Plo \
./$(DEPDIR)/libcurlu_la-strdup.Plo \
+ ./$(DEPDIR)/libcurlu_la-strequal.Plo \
./$(DEPDIR)/libcurlu_la-strerror.Plo \
./$(DEPDIR)/libcurlu_la-strparse.Plo \
- ./$(DEPDIR)/libcurlu_la-strtok.Plo \
- ./$(DEPDIR)/libcurlu_la-strtoofft.Plo \
./$(DEPDIR)/libcurlu_la-system_win32.Plo \
./$(DEPDIR)/libcurlu_la-telnet.Plo \
./$(DEPDIR)/libcurlu_la-tftp.Plo \
@@ -1201,7 +1232,8 @@ lib_LTLIBRARIES = libcurl.la
# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "private" files
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/lib \
- -I$(top_srcdir)/lib -DBUILDING_LIBCURL
+ -I$(top_srcdir)/lib -DBUILDING_LIBCURL $(am__append_1) \
+ $(am__append_2)
# Keep in sync with CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME in configure.ac
VERSIONCHANGE = 12
@@ -1229,7 +1261,6 @@ LIB_VAUTH_CFILES = \
LIB_VAUTH_HFILES = \
vauth/digest.h \
- vauth/ntlm.h \
vauth/vauth.h
LIB_VTLS_CFILES = \
@@ -1313,6 +1344,7 @@ LIB_CFILES = \
cf-socket.c \
cfilters.c \
conncache.c \
+ cshutdn.c \
connect.c \
content_encoding.c \
cookie.c \
@@ -1334,8 +1366,8 @@ LIB_CFILES = \
curl_threads.c \
curl_trc.c \
cw-out.c \
+ cw-pause.c \
dict.c \
- dllmain.c \
doh.c \
dynbuf.c \
dynhds.c \
@@ -1353,6 +1385,7 @@ LIB_CFILES = \
getinfo.c \
gopher.c \
hash.c \
+ hash_offt.c \
headers.c \
hmac.c \
hostasyn.c \
@@ -1387,6 +1420,7 @@ LIB_CFILES = \
mprintf.c \
mqtt.c \
multi.c \
+ multi_ev.c \
netrc.c \
nonblock.c \
noproxy.c \
@@ -1416,10 +1450,9 @@ LIB_CFILES = \
splay.c \
strcase.c \
strdup.c \
+ strequal.c \
strerror.c \
strparse.c \
- strtok.c \
- strtoofft.c \
system_win32.c \
telnet.c \
tftp.c \
@@ -1447,6 +1480,7 @@ LIB_HFILES = \
cf-socket.h \
cfilters.h \
conncache.h \
+ cshutdn.h \
connect.h \
content_encoding.h \
cookie.h \
@@ -1481,6 +1515,7 @@ LIB_HFILES = \
curl_trc.h \
curlx.h \
cw-out.h \
+ cw-pause.h \
dict.h \
doh.h \
dynbuf.h \
@@ -1499,6 +1534,7 @@ LIB_HFILES = \
getinfo.h \
gopher.h \
hash.h \
+ hash_offt.h \
headers.h \
hostip.h \
hsts.h \
@@ -1523,6 +1559,7 @@ LIB_HFILES = \
mime.h \
mqtt.h \
multihandle.h \
+ multi_ev.h \
multiif.h \
netrc.h \
nonblock.h \
@@ -1556,8 +1593,6 @@ LIB_HFILES = \
strdup.h \
strerror.h \
strparse.h \
- strtok.h \
- strtoofft.h \
system_win32.h \
telnet.h \
tftp.h \
@@ -1573,30 +1608,28 @@ LIB_HFILES = \
LIB_RCFILES = libcurl.rc
CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \
- $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES)
-
+ $(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES) $(am__append_3) \
+ $(am__append_4)
HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \
$(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES)
-# Makefile.inc provides the CSOURCES and HHEADERS defines
-
# Keep these separate to avoid duplicate definitions when linking libtests
# in static mode.
@USE_UNITY_TRUE@curl_EXCLUDE = curl_threads.c timediff.c warnless.c \
-@USE_UNITY_TRUE@ $(am__append_1)
+@USE_UNITY_TRUE@ $(am__append_5) $(am__append_6)
@USE_UNITY_TRUE@nodist_libcurl_la_SOURCES = libcurl_unity.c
@USE_UNITY_FALSE@libcurl_la_SOURCES = $(CSOURCES) $(HHEADERS) \
-@USE_UNITY_FALSE@ $(am__append_8)
-@USE_UNITY_TRUE@libcurl_la_SOURCES = $(curl_EXCLUDE) $(am__append_8)
+@USE_UNITY_FALSE@ $(am__append_13)
+@USE_UNITY_TRUE@libcurl_la_SOURCES = $(curl_EXCLUDE) $(am__append_13)
@USE_UNITY_TRUE@nodist_libcurlu_la_SOURCES = libcurl_unity.c
@USE_UNITY_FALSE@libcurlu_la_SOURCES = $(CSOURCES) $(HHEADERS)
@USE_UNITY_TRUE@libcurlu_la_SOURCES = $(curl_EXCLUDE)
@USE_UNITY_TRUE@CLEANFILES = libcurl_unity.c
-libcurl_la_CPPFLAGS_EXTRA = $(am__append_7) $(am__append_9)
-libcurl_la_LDFLAGS_EXTRA = $(am__append_2) $(am__append_3) \
- $(am__append_4) $(am__append_5) $(am__append_6)
-libcurl_la_CFLAGS_EXTRA = $(am__append_10)
+libcurl_la_CPPFLAGS_EXTRA = $(am__append_12) $(am__append_14)
+libcurl_la_LDFLAGS_EXTRA = $(am__append_7) $(am__append_8) \
+ $(am__append_9) $(am__append_10) $(am__append_11)
+libcurl_la_CFLAGS_EXTRA = $(am__append_15)
libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA)
libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(CURL_LDFLAGS_LIB) $(LIBCURL_PC_LIBS_PRIVATE)
libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA)
@@ -1610,7 +1643,7 @@ 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-security.insecureAPI.DeprecatedOrUnsafeBufferHandling \
- -quiet $(am__append_11)
+ -quiet $(am__append_16)
TIDY := clang-tidy
all: curl_config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -1932,6 +1965,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-connect.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-content_encoding.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cookie.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cshutdn.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_des.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_endian.Plo@am__quote@ # am--include-marker
@@ -1950,6 +1984,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_threads.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-curl_trc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cw-out.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cw-pause.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dict.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-dllmain.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-doh.Plo@am__quote@ # am--include-marker
@@ -1969,6 +2004,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-getinfo.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-gopher.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hash.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hash_offt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-headers.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hmac.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-hostasyn.Plo@am__quote@ # am--include-marker
@@ -2004,6 +2040,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-mprintf.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-mqtt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-multi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-multi_ev.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-netrc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-nonblock.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-noproxy.Plo@am__quote@ # am--include-marker
@@ -2033,10 +2070,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-splay.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strcase.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strdup.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strequal.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strerror.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strparse.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strtok.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-strtoofft.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-system_win32.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-telnet.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-tftp.Plo@am__quote@ # am--include-marker
@@ -2066,6 +2102,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-connect.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-content_encoding.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cookie.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cshutdn.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_des.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_endian.Plo@am__quote@ # am--include-marker
@@ -2084,6 +2121,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_threads.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-curl_trc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cw-out.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cw-pause.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dict.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-dllmain.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-doh.Plo@am__quote@ # am--include-marker
@@ -2103,6 +2141,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-getinfo.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-gopher.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hash.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hash_offt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-headers.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hmac.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-hostasyn.Plo@am__quote@ # am--include-marker
@@ -2138,6 +2177,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-mprintf.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-mqtt.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-multi.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-multi_ev.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-netrc.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-nonblock.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-noproxy.Plo@am__quote@ # am--include-marker
@@ -2167,10 +2207,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-splay.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strcase.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strdup.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strequal.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strerror.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strparse.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strtok.Plo@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-strtoofft.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-system_win32.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-telnet.Plo@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-tftp.Plo@am__quote@ # am--include-marker
@@ -2392,6 +2431,13 @@ libcurl_la-conncache.lo: conncache.c
@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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c
+libcurl_la-cshutdn.lo: cshutdn.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cshutdn.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cshutdn.Tpo -c -o libcurl_la-cshutdn.lo `test -f 'cshutdn.c' || echo '$(srcdir)/'`cshutdn.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cshutdn.Tpo $(DEPDIR)/libcurl_la-cshutdn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cshutdn.c' object='libcurl_la-cshutdn.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cshutdn.lo `test -f 'cshutdn.c' || echo '$(srcdir)/'`cshutdn.c
+
libcurl_la-connect.lo: connect.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-connect.lo -MD -MP -MF $(DEPDIR)/libcurl_la-connect.Tpo -c -o libcurl_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-connect.Tpo $(DEPDIR)/libcurl_la-connect.Plo
@@ -2539,6 +2585,13 @@ libcurl_la-cw-out.lo: cw-out.c
@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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cw-out.lo `test -f 'cw-out.c' || echo '$(srcdir)/'`cw-out.c
+libcurl_la-cw-pause.lo: cw-pause.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cw-pause.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cw-pause.Tpo -c -o libcurl_la-cw-pause.lo `test -f 'cw-pause.c' || echo '$(srcdir)/'`cw-pause.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cw-pause.Tpo $(DEPDIR)/libcurl_la-cw-pause.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cw-pause.c' object='libcurl_la-cw-pause.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cw-pause.lo `test -f 'cw-pause.c' || echo '$(srcdir)/'`cw-pause.c
+
libcurl_la-dict.lo: dict.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dict.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dict.Tpo -c -o libcurl_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dict.Tpo $(DEPDIR)/libcurl_la-dict.Plo
@@ -2546,13 +2599,6 @@ libcurl_la-dict.lo: dict.c
@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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
-libcurl_la-dllmain.lo: dllmain.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dllmain.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dllmain.Tpo -c -o libcurl_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dllmain.Tpo $(DEPDIR)/libcurl_la-dllmain.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dllmain.c' object='libcurl_la-dllmain.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
-
libcurl_la-doh.lo: doh.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-doh.lo -MD -MP -MF $(DEPDIR)/libcurl_la-doh.Tpo -c -o libcurl_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-doh.Tpo $(DEPDIR)/libcurl_la-doh.Plo
@@ -2672,6 +2718,13 @@ libcurl_la-hash.lo: hash.c
@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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c
+libcurl_la-hash_offt.lo: hash_offt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-hash_offt.lo -MD -MP -MF $(DEPDIR)/libcurl_la-hash_offt.Tpo -c -o libcurl_la-hash_offt.lo `test -f 'hash_offt.c' || echo '$(srcdir)/'`hash_offt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-hash_offt.Tpo $(DEPDIR)/libcurl_la-hash_offt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hash_offt.c' object='libcurl_la-hash_offt.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-hash_offt.lo `test -f 'hash_offt.c' || echo '$(srcdir)/'`hash_offt.c
+
libcurl_la-headers.lo: headers.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-headers.lo -MD -MP -MF $(DEPDIR)/libcurl_la-headers.Tpo -c -o libcurl_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-headers.Tpo $(DEPDIR)/libcurl_la-headers.Plo
@@ -2910,6 +2963,13 @@ libcurl_la-multi.lo: multi.c
@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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c
+libcurl_la-multi_ev.lo: multi_ev.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-multi_ev.lo -MD -MP -MF $(DEPDIR)/libcurl_la-multi_ev.Tpo -c -o libcurl_la-multi_ev.lo `test -f 'multi_ev.c' || echo '$(srcdir)/'`multi_ev.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-multi_ev.Tpo $(DEPDIR)/libcurl_la-multi_ev.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='multi_ev.c' object='libcurl_la-multi_ev.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-multi_ev.lo `test -f 'multi_ev.c' || echo '$(srcdir)/'`multi_ev.c
+
libcurl_la-netrc.lo: netrc.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-netrc.lo -MD -MP -MF $(DEPDIR)/libcurl_la-netrc.Tpo -c -o libcurl_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-netrc.Tpo $(DEPDIR)/libcurl_la-netrc.Plo
@@ -3113,6 +3173,13 @@ libcurl_la-strdup.lo: strdup.c
@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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c
+libcurl_la-strequal.lo: strequal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strequal.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strequal.Tpo -c -o libcurl_la-strequal.lo `test -f 'strequal.c' || echo '$(srcdir)/'`strequal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strequal.Tpo $(DEPDIR)/libcurl_la-strequal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strequal.c' object='libcurl_la-strequal.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strequal.lo `test -f 'strequal.c' || echo '$(srcdir)/'`strequal.c
+
libcurl_la-strerror.lo: strerror.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strerror.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strerror.Tpo -c -o libcurl_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strerror.Tpo $(DEPDIR)/libcurl_la-strerror.Plo
@@ -3127,20 +3194,6 @@ libcurl_la-strparse.lo: strparse.c
@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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strparse.lo `test -f 'strparse.c' || echo '$(srcdir)/'`strparse.c
-libcurl_la-strtok.lo: strtok.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strtok.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strtok.Tpo -c -o libcurl_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strtok.Tpo $(DEPDIR)/libcurl_la-strtok.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strtok.c' object='libcurl_la-strtok.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c
-
-libcurl_la-strtoofft.lo: strtoofft.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-strtoofft.lo -MD -MP -MF $(DEPDIR)/libcurl_la-strtoofft.Tpo -c -o libcurl_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-strtoofft.Tpo $(DEPDIR)/libcurl_la-strtoofft.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strtoofft.c' object='libcurl_la-strtoofft.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c
-
libcurl_la-system_win32.lo: system_win32.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-system_win32.lo -MD -MP -MF $(DEPDIR)/libcurl_la-system_win32.Tpo -c -o libcurl_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-system_win32.Tpo $(DEPDIR)/libcurl_la-system_win32.Plo
@@ -3505,6 +3558,13 @@ vssh/libcurl_la-wolfssh.lo: vssh/wolfssh.c
@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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurl_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c
+libcurl_la-dllmain.lo: dllmain.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-dllmain.lo -MD -MP -MF $(DEPDIR)/libcurl_la-dllmain.Tpo -c -o libcurl_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-dllmain.Tpo $(DEPDIR)/libcurl_la-dllmain.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dllmain.c' object='libcurl_la-dllmain.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) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
+
libcurl_la-libcurl_unity.lo: libcurl_unity.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-libcurl_unity.lo -MD -MP -MF $(DEPDIR)/libcurl_la-libcurl_unity.Tpo -c -o libcurl_la-libcurl_unity.lo `test -f 'libcurl_unity.c' || echo '$(srcdir)/'`libcurl_unity.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-libcurl_unity.Tpo $(DEPDIR)/libcurl_la-libcurl_unity.Plo
@@ -3610,6 +3670,13 @@ libcurlu_la-conncache.lo: conncache.c
@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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-conncache.lo `test -f 'conncache.c' || echo '$(srcdir)/'`conncache.c
+libcurlu_la-cshutdn.lo: cshutdn.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cshutdn.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cshutdn.Tpo -c -o libcurlu_la-cshutdn.lo `test -f 'cshutdn.c' || echo '$(srcdir)/'`cshutdn.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cshutdn.Tpo $(DEPDIR)/libcurlu_la-cshutdn.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cshutdn.c' object='libcurlu_la-cshutdn.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cshutdn.lo `test -f 'cshutdn.c' || echo '$(srcdir)/'`cshutdn.c
+
libcurlu_la-connect.lo: connect.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-connect.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-connect.Tpo -c -o libcurlu_la-connect.lo `test -f 'connect.c' || echo '$(srcdir)/'`connect.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-connect.Tpo $(DEPDIR)/libcurlu_la-connect.Plo
@@ -3757,6 +3824,13 @@ libcurlu_la-cw-out.lo: cw-out.c
@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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cw-out.lo `test -f 'cw-out.c' || echo '$(srcdir)/'`cw-out.c
+libcurlu_la-cw-pause.lo: cw-pause.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cw-pause.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cw-pause.Tpo -c -o libcurlu_la-cw-pause.lo `test -f 'cw-pause.c' || echo '$(srcdir)/'`cw-pause.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cw-pause.Tpo $(DEPDIR)/libcurlu_la-cw-pause.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cw-pause.c' object='libcurlu_la-cw-pause.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cw-pause.lo `test -f 'cw-pause.c' || echo '$(srcdir)/'`cw-pause.c
+
libcurlu_la-dict.lo: dict.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dict.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dict.Tpo -c -o libcurlu_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dict.Tpo $(DEPDIR)/libcurlu_la-dict.Plo
@@ -3764,13 +3838,6 @@ libcurlu_la-dict.lo: dict.c
@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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dict.lo `test -f 'dict.c' || echo '$(srcdir)/'`dict.c
-libcurlu_la-dllmain.lo: dllmain.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dllmain.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dllmain.Tpo -c -o libcurlu_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dllmain.Tpo $(DEPDIR)/libcurlu_la-dllmain.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dllmain.c' object='libcurlu_la-dllmain.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
-
libcurlu_la-doh.lo: doh.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-doh.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-doh.Tpo -c -o libcurlu_la-doh.lo `test -f 'doh.c' || echo '$(srcdir)/'`doh.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-doh.Tpo $(DEPDIR)/libcurlu_la-doh.Plo
@@ -3890,6 +3957,13 @@ libcurlu_la-hash.lo: hash.c
@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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hash.lo `test -f 'hash.c' || echo '$(srcdir)/'`hash.c
+libcurlu_la-hash_offt.lo: hash_offt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-hash_offt.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-hash_offt.Tpo -c -o libcurlu_la-hash_offt.lo `test -f 'hash_offt.c' || echo '$(srcdir)/'`hash_offt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-hash_offt.Tpo $(DEPDIR)/libcurlu_la-hash_offt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hash_offt.c' object='libcurlu_la-hash_offt.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-hash_offt.lo `test -f 'hash_offt.c' || echo '$(srcdir)/'`hash_offt.c
+
libcurlu_la-headers.lo: headers.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-headers.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-headers.Tpo -c -o libcurlu_la-headers.lo `test -f 'headers.c' || echo '$(srcdir)/'`headers.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-headers.Tpo $(DEPDIR)/libcurlu_la-headers.Plo
@@ -4128,6 +4202,13 @@ libcurlu_la-multi.lo: multi.c
@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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-multi.lo `test -f 'multi.c' || echo '$(srcdir)/'`multi.c
+libcurlu_la-multi_ev.lo: multi_ev.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-multi_ev.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-multi_ev.Tpo -c -o libcurlu_la-multi_ev.lo `test -f 'multi_ev.c' || echo '$(srcdir)/'`multi_ev.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-multi_ev.Tpo $(DEPDIR)/libcurlu_la-multi_ev.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='multi_ev.c' object='libcurlu_la-multi_ev.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-multi_ev.lo `test -f 'multi_ev.c' || echo '$(srcdir)/'`multi_ev.c
+
libcurlu_la-netrc.lo: netrc.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-netrc.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-netrc.Tpo -c -o libcurlu_la-netrc.lo `test -f 'netrc.c' || echo '$(srcdir)/'`netrc.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-netrc.Tpo $(DEPDIR)/libcurlu_la-netrc.Plo
@@ -4331,6 +4412,13 @@ libcurlu_la-strdup.lo: strdup.c
@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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strdup.lo `test -f 'strdup.c' || echo '$(srcdir)/'`strdup.c
+libcurlu_la-strequal.lo: strequal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strequal.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strequal.Tpo -c -o libcurlu_la-strequal.lo `test -f 'strequal.c' || echo '$(srcdir)/'`strequal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strequal.Tpo $(DEPDIR)/libcurlu_la-strequal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strequal.c' object='libcurlu_la-strequal.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strequal.lo `test -f 'strequal.c' || echo '$(srcdir)/'`strequal.c
+
libcurlu_la-strerror.lo: strerror.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strerror.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strerror.Tpo -c -o libcurlu_la-strerror.lo `test -f 'strerror.c' || echo '$(srcdir)/'`strerror.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strerror.Tpo $(DEPDIR)/libcurlu_la-strerror.Plo
@@ -4345,20 +4433,6 @@ libcurlu_la-strparse.lo: strparse.c
@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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strparse.lo `test -f 'strparse.c' || echo '$(srcdir)/'`strparse.c
-libcurlu_la-strtok.lo: strtok.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strtok.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strtok.Tpo -c -o libcurlu_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strtok.Tpo $(DEPDIR)/libcurlu_la-strtok.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strtok.c' object='libcurlu_la-strtok.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strtok.lo `test -f 'strtok.c' || echo '$(srcdir)/'`strtok.c
-
-libcurlu_la-strtoofft.lo: strtoofft.c
-@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-strtoofft.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-strtoofft.Tpo -c -o libcurlu_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c
-@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-strtoofft.Tpo $(DEPDIR)/libcurlu_la-strtoofft.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strtoofft.c' object='libcurlu_la-strtoofft.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-strtoofft.lo `test -f 'strtoofft.c' || echo '$(srcdir)/'`strtoofft.c
-
libcurlu_la-system_win32.lo: system_win32.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-system_win32.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-system_win32.Tpo -c -o libcurlu_la-system_win32.lo `test -f 'system_win32.c' || echo '$(srcdir)/'`system_win32.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-system_win32.Tpo $(DEPDIR)/libcurlu_la-system_win32.Plo
@@ -4723,6 +4797,13 @@ vssh/libcurlu_la-wolfssh.lo: vssh/wolfssh.c
@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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vssh/libcurlu_la-wolfssh.lo `test -f 'vssh/wolfssh.c' || echo '$(srcdir)/'`vssh/wolfssh.c
+libcurlu_la-dllmain.lo: dllmain.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-dllmain.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-dllmain.Tpo -c -o libcurlu_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-dllmain.Tpo $(DEPDIR)/libcurlu_la-dllmain.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dllmain.c' object='libcurlu_la-dllmain.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) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-dllmain.lo `test -f 'dllmain.c' || echo '$(srcdir)/'`dllmain.c
+
libcurlu_la-libcurl_unity.lo: libcurl_unity.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-libcurl_unity.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-libcurl_unity.Tpo -c -o libcurlu_la-libcurl_unity.lo `test -f 'libcurl_unity.c' || echo '$(srcdir)/'`libcurl_unity.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-libcurl_unity.Tpo $(DEPDIR)/libcurlu_la-libcurl_unity.Plo
@@ -4894,6 +4975,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurl_la-connect.Plo
-rm -f ./$(DEPDIR)/libcurl_la-content_encoding.Plo
-rm -f ./$(DEPDIR)/libcurl_la-cookie.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-cshutdn.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_des.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_endian.Plo
@@ -4912,6 +4994,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurl_la-curl_threads.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_trc.Plo
-rm -f ./$(DEPDIR)/libcurl_la-cw-out.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-cw-pause.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dict.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dllmain.Plo
-rm -f ./$(DEPDIR)/libcurl_la-doh.Plo
@@ -4931,6 +5014,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurl_la-getinfo.Plo
-rm -f ./$(DEPDIR)/libcurl_la-gopher.Plo
-rm -f ./$(DEPDIR)/libcurl_la-hash.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-hash_offt.Plo
-rm -f ./$(DEPDIR)/libcurl_la-headers.Plo
-rm -f ./$(DEPDIR)/libcurl_la-hmac.Plo
-rm -f ./$(DEPDIR)/libcurl_la-hostasyn.Plo
@@ -4966,6 +5050,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurl_la-mprintf.Plo
-rm -f ./$(DEPDIR)/libcurl_la-mqtt.Plo
-rm -f ./$(DEPDIR)/libcurl_la-multi.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-multi_ev.Plo
-rm -f ./$(DEPDIR)/libcurl_la-netrc.Plo
-rm -f ./$(DEPDIR)/libcurl_la-nonblock.Plo
-rm -f ./$(DEPDIR)/libcurl_la-noproxy.Plo
@@ -4995,10 +5080,9 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurl_la-splay.Plo
-rm -f ./$(DEPDIR)/libcurl_la-strcase.Plo
-rm -f ./$(DEPDIR)/libcurl_la-strdup.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-strequal.Plo
-rm -f ./$(DEPDIR)/libcurl_la-strerror.Plo
-rm -f ./$(DEPDIR)/libcurl_la-strparse.Plo
- -rm -f ./$(DEPDIR)/libcurl_la-strtok.Plo
- -rm -f ./$(DEPDIR)/libcurl_la-strtoofft.Plo
-rm -f ./$(DEPDIR)/libcurl_la-system_win32.Plo
-rm -f ./$(DEPDIR)/libcurl_la-telnet.Plo
-rm -f ./$(DEPDIR)/libcurl_la-tftp.Plo
@@ -5028,6 +5112,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurlu_la-connect.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-content_encoding.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-cookie.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-cshutdn.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_des.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_endian.Plo
@@ -5046,6 +5131,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurlu_la-curl_threads.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_trc.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-cw-out.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-cw-pause.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dict.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dllmain.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-doh.Plo
@@ -5065,6 +5151,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurlu_la-getinfo.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-gopher.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-hash.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-hash_offt.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-headers.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-hmac.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-hostasyn.Plo
@@ -5100,6 +5187,7 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurlu_la-mprintf.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-mqtt.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-multi.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-multi_ev.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-netrc.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-nonblock.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-noproxy.Plo
@@ -5129,10 +5217,9 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/libcurlu_la-splay.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-strcase.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-strdup.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-strequal.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-strerror.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-strparse.Plo
- -rm -f ./$(DEPDIR)/libcurlu_la-strtok.Plo
- -rm -f ./$(DEPDIR)/libcurlu_la-strtoofft.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-system_win32.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-telnet.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-tftp.Plo
@@ -5287,6 +5374,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurl_la-connect.Plo
-rm -f ./$(DEPDIR)/libcurl_la-content_encoding.Plo
-rm -f ./$(DEPDIR)/libcurl_la-cookie.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-cshutdn.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_addrinfo.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_des.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_endian.Plo
@@ -5305,6 +5393,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurl_la-curl_threads.Plo
-rm -f ./$(DEPDIR)/libcurl_la-curl_trc.Plo
-rm -f ./$(DEPDIR)/libcurl_la-cw-out.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-cw-pause.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dict.Plo
-rm -f ./$(DEPDIR)/libcurl_la-dllmain.Plo
-rm -f ./$(DEPDIR)/libcurl_la-doh.Plo
@@ -5324,6 +5413,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurl_la-getinfo.Plo
-rm -f ./$(DEPDIR)/libcurl_la-gopher.Plo
-rm -f ./$(DEPDIR)/libcurl_la-hash.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-hash_offt.Plo
-rm -f ./$(DEPDIR)/libcurl_la-headers.Plo
-rm -f ./$(DEPDIR)/libcurl_la-hmac.Plo
-rm -f ./$(DEPDIR)/libcurl_la-hostasyn.Plo
@@ -5359,6 +5449,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurl_la-mprintf.Plo
-rm -f ./$(DEPDIR)/libcurl_la-mqtt.Plo
-rm -f ./$(DEPDIR)/libcurl_la-multi.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-multi_ev.Plo
-rm -f ./$(DEPDIR)/libcurl_la-netrc.Plo
-rm -f ./$(DEPDIR)/libcurl_la-nonblock.Plo
-rm -f ./$(DEPDIR)/libcurl_la-noproxy.Plo
@@ -5388,10 +5479,9 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurl_la-splay.Plo
-rm -f ./$(DEPDIR)/libcurl_la-strcase.Plo
-rm -f ./$(DEPDIR)/libcurl_la-strdup.Plo
+ -rm -f ./$(DEPDIR)/libcurl_la-strequal.Plo
-rm -f ./$(DEPDIR)/libcurl_la-strerror.Plo
-rm -f ./$(DEPDIR)/libcurl_la-strparse.Plo
- -rm -f ./$(DEPDIR)/libcurl_la-strtok.Plo
- -rm -f ./$(DEPDIR)/libcurl_la-strtoofft.Plo
-rm -f ./$(DEPDIR)/libcurl_la-system_win32.Plo
-rm -f ./$(DEPDIR)/libcurl_la-telnet.Plo
-rm -f ./$(DEPDIR)/libcurl_la-tftp.Plo
@@ -5421,6 +5511,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurlu_la-connect.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-content_encoding.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-cookie.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-cshutdn.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_addrinfo.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_des.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_endian.Plo
@@ -5439,6 +5530,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurlu_la-curl_threads.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-curl_trc.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-cw-out.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-cw-pause.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dict.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-dllmain.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-doh.Plo
@@ -5458,6 +5550,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurlu_la-getinfo.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-gopher.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-hash.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-hash_offt.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-headers.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-hmac.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-hostasyn.Plo
@@ -5493,6 +5586,7 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurlu_la-mprintf.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-mqtt.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-multi.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-multi_ev.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-netrc.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-nonblock.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-noproxy.Plo
@@ -5522,10 +5616,9 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/libcurlu_la-splay.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-strcase.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-strdup.Plo
+ -rm -f ./$(DEPDIR)/libcurlu_la-strequal.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-strerror.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-strparse.Plo
- -rm -f ./$(DEPDIR)/libcurlu_la-strtok.Plo
- -rm -f ./$(DEPDIR)/libcurlu_la-strtoofft.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-system_win32.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-telnet.Plo
-rm -f ./$(DEPDIR)/libcurlu_la-tftp.Plo
@@ -5682,7 +5775,8 @@ checksrc:
@DEBUGBUILD_TRUE@all-local: checksrc
tidy:
- $(TIDY) $(CSOURCES) $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H
+ (_csources=`echo ' $(CSOURCES)' | sed -E -e 's/ +$$//' -e 's/ +/ /g' -e 's| | $(srcdir)/|g'`; \
+ $(TIDY) $$_csources $(TIDYFLAGS) $(CURL_CLANG_TIDYFLAGS) -- $(AM_CPPFLAGS) $(CPPFLAGS) -DHAVE_CONFIG_H)
optiontable:
perl optiontable.pl < $(top_srcdir)/include/curl/curl.h > easyoptions.c
diff --git a/libs/libcurl/src/Makefile.inc b/libs/libcurl/src/Makefile.inc
index 229f60a94e..d1a54a1d3c 100644
--- a/libs/libcurl/src/Makefile.inc
+++ b/libs/libcurl/src/Makefile.inc
@@ -39,7 +39,6 @@ LIB_VAUTH_CFILES = \
LIB_VAUTH_HFILES = \
vauth/digest.h \
- vauth/ntlm.h \
vauth/vauth.h
LIB_VTLS_CFILES = \
@@ -123,6 +122,7 @@ LIB_CFILES = \
cf-socket.c \
cfilters.c \
conncache.c \
+ cshutdn.c \
connect.c \
content_encoding.c \
cookie.c \
@@ -144,8 +144,8 @@ LIB_CFILES = \
curl_threads.c \
curl_trc.c \
cw-out.c \
+ cw-pause.c \
dict.c \
- dllmain.c \
doh.c \
dynbuf.c \
dynhds.c \
@@ -163,6 +163,7 @@ LIB_CFILES = \
getinfo.c \
gopher.c \
hash.c \
+ hash_offt.c \
headers.c \
hmac.c \
hostasyn.c \
@@ -197,6 +198,7 @@ LIB_CFILES = \
mprintf.c \
mqtt.c \
multi.c \
+ multi_ev.c \
netrc.c \
nonblock.c \
noproxy.c \
@@ -226,10 +228,9 @@ LIB_CFILES = \
splay.c \
strcase.c \
strdup.c \
+ strequal.c \
strerror.c \
strparse.c \
- strtok.c \
- strtoofft.c \
system_win32.c \
telnet.c \
tftp.c \
@@ -257,6 +258,7 @@ LIB_HFILES = \
cf-socket.h \
cfilters.h \
conncache.h \
+ cshutdn.h \
connect.h \
content_encoding.h \
cookie.h \
@@ -291,6 +293,7 @@ LIB_HFILES = \
curl_trc.h \
curlx.h \
cw-out.h \
+ cw-pause.h \
dict.h \
doh.h \
dynbuf.h \
@@ -309,6 +312,7 @@ LIB_HFILES = \
getinfo.h \
gopher.h \
hash.h \
+ hash_offt.h \
headers.h \
hostip.h \
hsts.h \
@@ -333,6 +337,7 @@ LIB_HFILES = \
mime.h \
mqtt.h \
multihandle.h \
+ multi_ev.h \
multiif.h \
netrc.h \
nonblock.h \
@@ -366,8 +371,6 @@ LIB_HFILES = \
strdup.h \
strerror.h \
strparse.h \
- strtok.h \
- strtoofft.h \
system_win32.h \
telnet.h \
tftp.h \
diff --git a/libs/libcurl/src/altsvc.c b/libs/libcurl/src/altsvc.c
index ff03020153..89f2a100f9 100644
--- a/libs/libcurl/src/altsvc.c
+++ b/libs/libcurl/src/altsvc.c
@@ -138,18 +138,20 @@ static struct altsvc *altsvc_create(struct Curl_str *srchost,
size_t srcport,
size_t dstport)
{
- enum alpnid dstalpnid = Curl_alpn2alpnid(dstalpn->str, dstalpn->len);
- enum alpnid srcalpnid = Curl_alpn2alpnid(srcalpn->str, srcalpn->len);
+ enum alpnid dstalpnid =
+ Curl_alpn2alpnid(Curl_str(dstalpn), Curl_strlen(dstalpn));
+ enum alpnid srcalpnid =
+ Curl_alpn2alpnid(Curl_str(srcalpn), Curl_strlen(srcalpn));
if(!srcalpnid || !dstalpnid)
return NULL;
- return altsvc_createid(srchost->str, srchost->len,
- dsthost->str, dsthost->len,
+ return altsvc_createid(Curl_str(srchost), Curl_strlen(srchost),
+ Curl_str(dsthost), Curl_strlen(dsthost),
srcalpnid, dstalpnid,
srcport, dstport);
}
/* only returns SERIOUS errors */
-static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
+static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line)
{
/* Example line:
h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
@@ -159,10 +161,10 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
struct Curl_str srcalpn;
struct Curl_str dstalpn;
struct Curl_str date;
- size_t srcport;
- size_t dstport;
- size_t persist;
- size_t prio;
+ curl_off_t srcport;
+ curl_off_t dstport;
+ curl_off_t persist;
+ curl_off_t prio;
if(Curl_str_word(&line, &srcalpn, MAX_ALTSVC_ALPNLEN) ||
Curl_str_singlespace(&line) ||
@@ -190,11 +192,11 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
/* The date parser works on a null terminated string. The maximum length
is upheld by Curl_str_quotedword(). */
- memcpy(dbuf, date.str, date.len);
- dbuf[date.len] = 0;
+ memcpy(dbuf, Curl_str(&date), Curl_strlen(&date));
+ dbuf[Curl_strlen(&date)] = 0;
expires = Curl_getdate_capped(dbuf);
- as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, srcport,
- dstport);
+ as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn,
+ (size_t)srcport, (size_t)dstport);
if(as) {
as->expires = expires;
as->prio = 0; /* not supported to just set zero */
@@ -231,14 +233,10 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
struct dynbuf buf;
Curl_dyn_init(&buf, MAX_ALTSVC_LINE);
while(Curl_get_line(&buf, fp)) {
- char *lineptr = Curl_dyn_ptr(&buf);
- while(*lineptr && ISBLANK(*lineptr))
- lineptr++;
- if(*lineptr == '#')
- /* skip commented lines */
- continue;
-
- altsvc_add(asi, lineptr);
+ const char *lineptr = Curl_dyn_ptr(&buf);
+ Curl_str_passblanks(&lineptr);
+ if(Curl_str_single(&lineptr, '#'))
+ altsvc_add(asi, lineptr);
}
Curl_dyn_free(&buf); /* free the line buffer */
fclose(fp);
@@ -263,11 +261,11 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
#ifdef USE_IPV6
else {
char ipv6_unused[16];
- if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
+ if(1 == curlx_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
dst6_pre = "[";
dst6_post = "]";
}
- if(1 == Curl_inet_pton(AF_INET6, as->src.host, ipv6_unused)) {
+ if(1 == curlx_inet_pton(AF_INET6, as->src.host, ipv6_unused)) {
src6_pre = "[";
src6_post = "]";
}
@@ -405,26 +403,6 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
return result;
}
-static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
-{
- size_t len;
- const char *protop;
- const char *p = *ptr;
- while(*p && ISBLANK(*p))
- p++;
- protop = p;
- while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '='))
- p++;
- len = p - protop;
- *ptr = p;
-
- if(!len || (len >= buflen))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- memcpy(alpnbuf, protop, len);
- alpnbuf[len] = 0;
- return CURLE_OK;
-}
-
/* hostcompare() returns true if 'host' matches 'check'. The first host
* argument may have a trailing dot present that will be ignored.
*/
@@ -460,15 +438,16 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
}
}
-#ifdef DEBUGBUILD
+#if defined(DEBUGBUILD) || defined(UNITTESTS)
/* 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");
+ const char *timestr = getenv("CURL_TIME");
(void)unused;
if(timestr) {
- long val = strtol(timestr, NULL, 10);
+ curl_off_t val;
+ Curl_str_number(&timestr, &val, TIME_T_MAX);
return (time_t)val;
}
return time(NULL);
@@ -494,153 +473,124 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
unsigned short srcport)
{
const char *p = value;
- char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
struct altsvc *as;
unsigned short dstport = srcport; /* the same by default */
- CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
size_t entries = 0;
- size_t alpnlen = strlen(alpnbuf);
- size_t srchostlen = strlen(srchost);
+ struct Curl_str alpn;
+ const char *sp;
+ time_t maxage = 24 * 3600; /* default is 24 hours */
+ bool persist = FALSE;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)data;
#endif
- if(result) {
- infof(data, "Excessive alt-svc header, ignoring.");
- return CURLE_OK;
- }
DEBUGASSERT(asi);
- /* "clear" is a magic keyword */
- if(strcasecompare(alpnbuf, "clear")) {
- /* Flush cached alternatives for this source origin */
- altsvc_flush(asi, srcalpnid, srchost, srcport);
- return CURLE_OK;
+ /* initial check for "clear" */
+ if(!Curl_str_until(&p, &alpn, MAX_ALTSVC_LINE, ';') &&
+ !Curl_str_single(&p, ';')) {
+ Curl_str_trimblanks(&alpn);
+ /* "clear" is a magic keyword */
+ if(Curl_str_casecompare(&alpn, "clear")) {
+ /* Flush cached alternatives for this source origin */
+ altsvc_flush(asi, srcalpnid, srchost, srcport);
+ return CURLE_OK;
+ }
+ }
+
+ p = value;
+
+ if(Curl_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
+ return CURLE_OK; /* strange line */
+
+ Curl_str_trimblanks(&alpn);
+
+ /* Handle the optional 'ma' and 'persist' flags once first, as they need to
+ be known for each alternative service. Unknown flags are skipped. */
+ sp = strchr(p, ';');
+ if(sp) {
+ sp++; /* pass the semicolon */
+ for(;;) {
+ struct Curl_str name;
+ struct Curl_str val;
+ const char *vp;
+ curl_off_t num;
+ bool quoted;
+ /* allow some extra whitespaces around name and value */
+ if(Curl_str_until(&sp, &name, 20, '=') ||
+ Curl_str_single(&sp, '=') ||
+ Curl_str_until(&sp, &val, 80, ';'))
+ break;
+ Curl_str_trimblanks(&name);
+ Curl_str_trimblanks(&val);
+ /* the value might be quoted */
+ vp = Curl_str(&val);
+ quoted = (*vp == '\"');
+ if(quoted)
+ vp++;
+ if(!Curl_str_number(&vp, &num, TIME_T_MAX)) {
+ if(Curl_str_casecompare(&name, "ma"))
+ maxage = (time_t)num;
+ else if(Curl_str_casecompare(&name, "persist") && (num == 1))
+ persist = TRUE;
+ }
+ if(quoted && Curl_str_single(&sp, '\"'))
+ break;
+ if(Curl_str_single(&sp, ';'))
+ break;
+ }
}
do {
- if(*p == '=') {
- /* [protocol]="[host][:port]" */
- enum alpnid dstalpnid = Curl_alpn2alpnid(alpnbuf, alpnlen);
- p++;
- if(*p == '\"') {
- const char *dsthost = "";
- size_t dstlen = 0; /* destination hostname length */
- const char *value_ptr;
- char option[32];
- unsigned long num;
- char *end_ptr;
- bool quoted = FALSE;
- time_t maxage = 24 * 3600; /* default is 24 hours */
- bool persist = FALSE;
- bool valid = TRUE;
- p++;
- if(*p != ':') {
+ if(!Curl_str_single(&p, '=')) {
+ /* [protocol]="[host][:port], [protocol]="[host][:port]" */
+ enum alpnid dstalpnid =
+ Curl_alpn2alpnid(Curl_str(&alpn), Curl_strlen(&alpn));
+ if(!Curl_str_single(&p, '\"')) {
+ struct Curl_str dsthost;
+ curl_off_t port = 0;
+ if(Curl_str_single(&p, ':')) {
/* hostname starts here */
- const char *hostp = p;
- if(*p == '[') {
- /* pass all valid IPv6 letters - does not handle zone id */
- dstlen = strspn(++p, "0123456789abcdefABCDEF:.");
- if(p[dstlen] != ']')
- /* invalid host syntax, bail out */
+ if(Curl_str_single(&p, '[')) {
+ if(Curl_str_until(&p, &dsthost, MAX_ALTSVC_HOSTLEN, ':')) {
+ infof(data, "Bad alt-svc hostname, ignoring.");
break;
- /* we store the IPv6 numerical address *with* brackets */
- dstlen += 2;
- p = &p[dstlen-1];
+ }
}
else {
- while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
- p++;
- dstlen = p - hostp;
- }
- if(!dstlen || (dstlen >= MAX_ALTSVC_HOSTLEN)) {
- infof(data, "Excessive alt-svc hostname, ignoring.");
- valid = FALSE;
- }
- else {
- dsthost = hostp;
+ /* IPv6 host name */
+ if(Curl_str_until(&p, &dsthost, MAX_IPADR_LEN, ']') ||
+ Curl_str_single(&p, ']')) {
+ infof(data, "Bad alt-svc IPv6 hostname, ignoring.");
+ break;
+ }
}
+ if(Curl_str_single(&p, ':'))
+ break;
}
- else {
+ else
/* no destination name, use source host */
- dsthost = srchost;
- dstlen = strlen(srchost);
- }
- if(*p == ':') {
- unsigned long port = 0;
- p++;
- if(ISDIGIT(*p))
- /* a port number */
- port = strtoul(p, &end_ptr, 10);
- else
- end_ptr = (char *)p; /* not left uninitialized */
- if(!port || port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
- infof(data, "Unknown alt-svc port number, ignoring.");
- valid = FALSE;
- }
- else {
- dstport = curlx_ultous(port);
- p = end_ptr;
- }
- }
- if(*p++ != '\"')
+ Curl_str_assign(&dsthost, srchost, strlen(srchost));
+
+ if(Curl_str_number(&p, &port, 0xffff)) {
+ infof(data, "Unknown alt-svc port number, ignoring.");
break;
- /* Handle the optional 'ma' and 'persist' flags. Unknown flags
- are skipped. */
- for(;;) {
- while(ISBLANK(*p))
- p++;
- if(*p != ';')
- break;
- p++; /* pass the semicolon */
- if(!*p || ISNEWLINE(*p))
- break;
- result = getalnum(&p, option, sizeof(option));
- if(result) {
- /* skip option if name is too long */
- option[0] = '\0';
- }
- while(*p && ISBLANK(*p))
- p++;
- if(*p != '=')
- return CURLE_OK;
- p++;
- while(*p && ISBLANK(*p))
- p++;
- if(!*p)
- return CURLE_OK;
- if(*p == '\"') {
- /* quoted value */
- p++;
- quoted = TRUE;
- }
- value_ptr = p;
- if(quoted) {
- while(*p && *p != '\"')
- p++;
- if(!*p++)
- return CURLE_OK;
- }
- 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) {
+
+ dstport = (unsigned short)port;
+
+ if(Curl_str_single(&p, '\"'))
+ break;
+
+ if(dstalpnid) {
if(!entries++)
/* Flush cached alternatives for this source origin, if any - when
this is the first entry of the line. */
altsvc_flush(asi, srcalpnid, srchost, srcport);
- as = altsvc_createid(srchost, srchostlen,
- dsthost, dstlen,
+ as = altsvc_createid(srchost, strlen(srchost),
+ Curl_str(&dsthost),
+ Curl_strlen(&dsthost),
srcalpnid, dstalpnid,
srcport, dstport);
if(as) {
@@ -653,26 +603,28 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
as->expires = maxage + secs;
as->persist = persist;
Curl_llist_append(&asi->list, as, &as->node);
- infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
- Curl_alpnid2str(dstalpnid));
+ infof(data, "Added alt-svc: %.*s:%d over %s",
+ (int)Curl_strlen(&dsthost), Curl_str(&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;
- }
+ if(Curl_str_single(&p, ','))
+ break;
+
+ /* comma means another alternative is present */
+ if(Curl_str_until(&p, &alpn, MAX_ALTSVC_LINE, '='))
+ break;
+ Curl_str_trimblanks(&alpn);
}
else
break;
- } while(*p && (*p != ';') && (*p != '\n') && (*p != '\r'));
+ } while(1);
return CURLE_OK;
}
diff --git a/libs/libcurl/src/amigaos.c b/libs/libcurl/src/amigaos.c
index 50aa41db39..fe61764a6e 100644
--- a/libs/libcurl/src/amigaos.c
+++ b/libs/libcurl/src/amigaos.c
@@ -184,7 +184,7 @@ int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds,
{
int r = WaitSelect(nfds, readfds, writefds, errorfds, timeout, 0);
/* Ensure Ctrl-C signal is actioned */
- if((r == -1) && (SOCKERRNO == EINTR))
+ if((r == -1) && (SOCKERRNO == SOCKEINTR))
raise(SIGINT);
return r;
}
diff --git a/libs/libcurl/src/asyn-ares.c b/libs/libcurl/src/asyn-ares.c
index 900c028dca..389a6cc1ad 100644
--- a/libs/libcurl/src/asyn-ares.c
+++ b/libs/libcurl/src/asyn-ares.c
@@ -66,6 +66,18 @@
#include <ares_version.h> /* really old c-ares did not include this by
itself */
+#ifdef USE_HTTPSRR
+/* 1.28.0 and later have ares_query_dnsrec */
+#if ARES_VERSION < 0x011c00
+#error "requires c-ares 1.28.0 or newer for HTTPSRR"
+#endif
+#define HTTPSRR_WORKS
+#else
+#if ARES_VERSION < 0x010600
+#error "requires c-ares 1.6.0 or newer"
+#endif
+#endif
+
/*
* Curl_ares_getsock() is called when the outside world (using
* curl_multi_fdset()) wants to get our fd_set setup and we are talking with
@@ -157,11 +169,6 @@ int Curl_ares_perform(ares_channel channel,
#ifdef CURLRES_ARES
-#if ARES_VERSION >= 0x010500
-/* c-ares 1.5.0 or later, the callback proto is modified */
-#define HAVE_CARES_CALLBACK_TIMEOUTS 1
-#endif
-
#if ARES_VERSION >= 0x010601
/* IPv6 supported since 1.6.1 */
#define HAVE_CARES_IPV6 1
@@ -182,14 +189,6 @@ int Curl_ares_perform(ares_channel channel,
#define HAVE_CARES_GETADDRINFO 1
#endif
-#if ARES_VERSION >= 0x011c00
-/* 1.28.0 and later have ares_query_dnsrec */
-#define HAVE_ARES_QUERY_DNSREC 1
-#ifdef USE_HTTPSRR
-#define USE_HTTPSRR_ARES 1
-#endif
-#endif
-
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -246,7 +245,7 @@ static void sock_state_cb(void *data, ares_socket_t socket_fd,
struct Curl_easy *easy = data;
if(!readable && !writable) {
DEBUGASSERT(easy);
- Curl_multi_closed(easy, socket_fd);
+ Curl_multi_will_close(easy, socket_fd);
}
}
@@ -351,17 +350,12 @@ void Curl_resolver_kill(struct Curl_easy *data)
*/
static void destroy_async_data(struct Curl_async *async)
{
- if(async->tdata) {
- struct thread_data *res = async->tdata;
- if(res) {
- if(res->temp_ai) {
- Curl_freeaddrinfo(res->temp_ai);
- res->temp_ai = NULL;
- }
- free(res);
- }
- async->tdata = NULL;
+ struct thread_data *res = &async->thdata;
+ if(res->temp_ai) {
+ Curl_freeaddrinfo(res->temp_ai);
+ res->temp_ai = NULL;
}
+ Curl_safefree(res->hostname);
}
/*
@@ -385,7 +379,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns)
{
- struct thread_data *res = data->state.async.tdata;
+ struct thread_data *res = &data->state.async.thdata;
CURLcode result = CURLE_OK;
DEBUGASSERT(dns);
@@ -398,8 +392,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
/* 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
+ if(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)
@@ -419,20 +412,20 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
}
#endif
- if(res && !res->num_pending) {
+ if(!res->num_pending) {
(void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
/* temp_ai ownership is moved to the connection, so we need not free-up
them */
res->temp_ai = NULL;
+ result = res->result;
if(!data->state.async.dns)
result = Curl_resolver_error(data);
- else {
+ if(!result) {
*dns = data->state.async.dns;
-#ifdef USE_HTTPSRR_ARES
+#ifdef HTTPSRR_WORKS
{
- struct Curl_https_rrinfo *lhrr =
- Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo));
+ struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&res->hinfo);
if(!lhrr)
result = CURLE_OUT_OF_MEMORY;
else
@@ -583,97 +576,90 @@ static void compound_results(struct thread_data *res,
*/
static void query_completed_cb(void *arg, /* (struct connectdata *) */
int status,
-#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
int timeouts,
-#endif
struct hostent *hostent)
{
struct Curl_easy *data = (struct Curl_easy *)arg;
- struct thread_data *res;
+ struct thread_data *res = &data->state.async.thdata;
-#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
(void)timeouts; /* ignored */
-#endif
if(ARES_EDESTRUCTION == status)
/* when this ares handle is getting destroyed, the 'arg' pointer may not
be valid so only defer it when we know the 'status' says its fine! */
return;
- res = data->state.async.tdata;
- if(res) {
- res->num_pending--;
+ res->num_pending--;
- if(CURL_ASYNC_SUCCESS == status) {
- struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
- if(ai) {
- compound_results(res, ai);
- }
- }
- /* 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);
+ if(CURL_ASYNC_SUCCESS == status) {
+ struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
+ if(ai) {
+ compound_results(res, ai);
}
}
+ /* 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);
+ }
}
#else
/* c-ares 1.16.0 or later */
@@ -756,7 +742,7 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
struct ares_addrinfo *result)
{
struct Curl_easy *data = (struct Curl_easy *)arg;
- struct thread_data *res = data->state.async.tdata;
+ struct thread_data *res = &data->state.async.thdata;
(void)timeouts;
if(ARES_SUCCESS == status) {
res->temp_ai = ares2addr(result->nodes);
@@ -781,87 +767,86 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int port,
int *waitp)
{
- struct thread_data *res = NULL;
- size_t namelen = strlen(hostname);
+ struct thread_data *res = &data->state.async.thdata;
*waitp = 0; /* default to synchronous response */
- res = calloc(1, sizeof(struct thread_data) + namelen);
- if(res) {
- strcpy(res->hostname, hostname);
- data->state.async.hostname = res->hostname;
- data->state.async.port = port;
- data->state.async.done = FALSE; /* not done */
- data->state.async.status = 0; /* clear */
- data->state.async.dns = NULL; /* clear */
- data->state.async.tdata = res;
+ res->hostname = strdup(hostname);
+ if(!res->hostname)
+ return NULL;
- /* initial status - failed */
- res->last_status = ARES_ENOTFOUND;
+ data->state.async.port = port;
+ data->state.async.done = FALSE; /* not done */
+ data->state.async.dns = NULL; /* clear */
+
+ /* initial status - failed */
+ res->last_status = ARES_ENOTFOUND;
#ifdef HAVE_CARES_GETADDRINFO
- {
- struct ares_addrinfo_hints hints;
- char service[12];
- int pf = PF_INET;
- memset(&hints, 0, sizeof(hints));
+ {
+ struct ares_addrinfo_hints hints;
+ char service[12];
+ int pf = PF_INET;
+ memset(&hints, 0, sizeof(hints));
#ifdef CURLRES_IPV6
- if((data->conn->ip_version != CURL_IPRESOLVE_V4) &&
- Curl_ipv6works(data)) {
- /* The stack seems to be IPv6-enabled */
- if(data->conn->ip_version == CURL_IPRESOLVE_V6)
- pf = PF_INET6;
- else
- pf = PF_UNSPEC;
- }
-#endif /* CURLRES_IPV6 */
- hints.ai_family = pf;
- hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
- SOCK_STREAM : SOCK_DGRAM;
- /* Since the service is a numerical one, set the hint flags
- * accordingly to save a call to getservbyname in inside C-Ares
- */
- hints.ai_flags = ARES_AI_NUMERICSERV;
- msnprintf(service, sizeof(service), "%d", port);
- res->num_pending = 1;
- ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
- service, &hints, addrinfo_cb, data);
+ if((data->conn->ip_version != CURL_IPRESOLVE_V4) &&
+ Curl_ipv6works(data)) {
+ /* The stack seems to be IPv6-enabled */
+ if(data->conn->ip_version == CURL_IPRESOLVE_V6)
+ pf = PF_INET6;
+ else
+ pf = PF_UNSPEC;
}
+#endif /* CURLRES_IPV6 */
+ hints.ai_family = pf;
+ hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
+ SOCK_STREAM : SOCK_DGRAM;
+ /* Since the service is a numerical one, set the hint flags
+ * accordingly to save a call to getservbyname in inside C-Ares
+ */
+ hints.ai_flags = ARES_AI_NUMERICSERV;
+ msnprintf(service, sizeof(service), "%d", port);
+ res->num_pending = 1;
+ ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
+ service, &hints, addrinfo_cb, data);
+ }
#else
#ifdef HAVE_CARES_IPV6
- if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
- /* The stack seems to be IPv6-enabled */
- res->num_pending = 2;
-
- /* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET, query_completed_cb, data);
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET6, query_completed_cb, data);
- }
- else
+ if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
+ /* The stack seems to be IPv6-enabled */
+ res->num_pending = 2;
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+ PF_INET, query_completed_cb, data);
+ ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+ PF_INET6, query_completed_cb, data);
+ }
+ else
#endif
- {
- res->num_pending = 1;
+ {
+ res->num_pending = 1;
- /* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->state.async.resolver,
- hostname, PF_INET,
- query_completed_cb, data);
- }
-#endif
-#ifdef USE_HTTPSRR_ARES
- {
- res->num_pending++; /* one more */
- memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
- ares_query_dnsrec((ares_channel)data->state.async.resolver,
- hostname, ARES_CLASS_IN,
- ARES_REC_TYPE_HTTPS,
- Curl_dnsrec_done_cb, data, NULL);
- }
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.async.resolver,
+ hostname, PF_INET,
+ query_completed_cb, data);
+ }
#endif
- *waitp = 1; /* expect asynchronous response */
+#ifdef USE_HTTPSRR
+ {
+ CURL_TRC_DNS(data, "asyn-ares: fire off query for HTTPSRR");
+ res->num_pending++; /* one more */
+ memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
+ res->hinfo.port = -1;
+ ares_query_dnsrec((ares_channel)data->state.async.resolver,
+ hostname, ARES_CLASS_IN,
+ ARES_REC_TYPE_HTTPS,
+ Curl_dnsrec_done_cb, data, NULL);
}
+#endif
+ *waitp = 1; /* expect asynchronous response */
+
return NULL; /* no struct yet */
}
@@ -948,7 +933,7 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
a4.s_addr = 0; /* disabled: do not bind to a specific address */
}
else {
- if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
+ if(curlx_inet_pton(AF_INET, local_ip4, &a4) != 1) {
DEBUGF(infof(data, "bad DNS IPv4 address"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
@@ -976,7 +961,7 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
memset(a6, 0, sizeof(a6));
}
else {
- if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
+ if(curlx_inet_pton(AF_INET6, local_ip6, a6) != 1) {
DEBUGF(infof(data, "bad DNS IPv6 address"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
diff --git a/libs/libcurl/src/asyn-thread.c b/libs/libcurl/src/asyn-thread.c
index 1044166e1e..c7db2e1b60 100644
--- a/libs/libcurl/src/asyn-thread.c
+++ b/libs/libcurl/src/asyn-thread.c
@@ -49,9 +49,9 @@
#endif
#ifdef HAVE_GETADDRINFO
-# define RESOLVER_ENOMEM EAI_MEMORY
+# define RESOLVER_ENOMEM EAI_MEMORY /* = WSA_NOT_ENOUGH_MEMORY on Windows */
#else
-# define RESOLVER_ENOMEM ENOMEM
+# define RESOLVER_ENOMEM SOCKENOMEM
#endif
#include "urldata.h"
@@ -69,7 +69,7 @@
#ifdef USE_ARES
#include <ares.h>
#ifdef USE_HTTPSRR
-#define USE_HTTPSRR_ARES 1 /* the combo */
+#define USE_HTTPSRR_ARES /* the combo */
#endif
#endif
@@ -78,9 +78,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-struct resdata {
- struct curltime start;
-};
/*
* Curl_resolver_global_init()
@@ -110,9 +107,7 @@ void Curl_resolver_global_cleanup(void)
CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
{
(void)easy;
- *resolver = calloc(1, sizeof(struct resdata));
- if(!*resolver)
- return CURLE_OUT_OF_MEMORY;
+ (void)resolver;
return CURLE_OK;
}
@@ -124,7 +119,7 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
*/
void Curl_resolver_cleanup(void *resolver)
{
- free(resolver);
+ (void)resolver;
}
/*
@@ -156,17 +151,14 @@ static bool init_resolve_thread(struct Curl_easy *data,
static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{
- return &(data->state.async.tdata->tsd);
+ return &(data->state.async.thdata.tsd);
}
/* Destroy resolver thread synchronization data */
static
void destroy_thread_sync_data(struct thread_sync_data *tsd)
{
- if(tsd->mtx) {
- Curl_mutex_destroy(tsd->mtx);
- free(tsd->mtx);
- }
+ Curl_mutex_destroy(&tsd->mutx);
free(tsd->hostname);
@@ -178,7 +170,7 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd)
* close one end of the socket pair (may be done in resolver thread);
* the other end (for reading) is always closed in the parent thread.
*/
-#ifndef USE_EVENTFD
+#ifndef HAVE_EVENTFD
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
wakeup_close(tsd->sock_pair[1]);
}
@@ -190,15 +182,15 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd)
/* Initialize resolver thread synchronization data */
static
int init_thread_sync_data(struct thread_data *td,
- const char *hostname,
- int port,
- const struct addrinfo *hints)
+ const char *hostname,
+ int port,
+ const struct addrinfo *hints)
{
struct thread_sync_data *tsd = &td->tsd;
memset(tsd, 0, sizeof(*tsd));
- tsd->td = td;
+ td->init = TRUE;
tsd->port = port;
/* Treat the request as done until the thread actually starts so any early
* cleanup gets done properly.
@@ -211,11 +203,7 @@ int init_thread_sync_data(struct thread_data *td,
(void) hints;
#endif
- tsd->mtx = malloc(sizeof(curl_mutex_t));
- if(!tsd->mtx)
- goto err_exit;
-
- Curl_mutex_init(tsd->mtx);
+ Curl_mutex_init(&tsd->mutx);
#ifndef CURL_DISABLE_SOCKETPAIR
/* create socket pair or pipe */
@@ -271,15 +259,15 @@ static CURLcode getaddrinfo_complete(struct Curl_easy *data)
* and wait on it.
*/
static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
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;
+ struct thread_data *td = arg;
+ struct thread_sync_data *tsd = &td->tsd;
char service[12];
int rc;
@@ -296,17 +284,16 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
Curl_addrinfo_set_port(tsd->res, tsd->port);
}
- Curl_mutex_acquire(tsd->mtx);
+ Curl_mutex_acquire(&tsd->mutx);
if(tsd->done) {
/* too late, gotta clean up the mess */
- Curl_mutex_release(tsd->mtx);
+ Curl_mutex_release(&tsd->mutx);
destroy_thread_sync_data(tsd);
- free(td);
}
else {
#ifndef CURL_DISABLE_SOCKETPAIR
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
-#ifdef USE_EVENTFD
+#ifdef HAVE_EVENTFD
const uint64_t buf[1] = { 1 };
#else
const char buf[1] = { 1 };
@@ -319,7 +306,7 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
}
#endif
tsd->done = TRUE;
- Curl_mutex_release(tsd->mtx);
+ Curl_mutex_release(&tsd->mutx);
}
return 0;
@@ -331,15 +318,15 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
* gethostbyname_thread() resolves a name and then exits.
*/
static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
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;
+ struct thread_data *td = arg;
+ struct thread_sync_data *tsd = &td->tsd;
tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
@@ -349,16 +336,15 @@ CURL_STDCALL gethostbyname_thread(void *arg)
tsd->sock_error = RESOLVER_ENOMEM;
}
- Curl_mutex_acquire(tsd->mtx);
+ Curl_mutex_acquire(&tsd->mutx);
if(tsd->done) {
/* too late, gotta clean up the mess */
- Curl_mutex_release(tsd->mtx);
+ Curl_mutex_release(&tsd->mutx);
destroy_thread_sync_data(tsd);
- free(td);
}
else {
tsd->done = TRUE;
- Curl_mutex_release(tsd->mtx);
+ Curl_mutex_release(&tsd->mutx);
}
return 0;
@@ -371,29 +357,28 @@ CURL_STDCALL gethostbyname_thread(void *arg)
*/
static void destroy_async_data(struct Curl_easy *data)
{
- struct Curl_async *async;
- DEBUGASSERT(data);
- async = &data->state.async;
- DEBUGASSERT(async);
- if(async->tdata) {
- struct thread_data *td = async->tdata;
+ struct Curl_async *async = &data->state.async;
+ struct thread_data *td = &async->thdata;
+ if(td->init) {
bool done;
#ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0];
#endif
#ifdef USE_HTTPSRR_ARES
- if(data->state.async.tdata->channel)
- ares_destroy(data->state.async.tdata->channel);
+ if(td->channel) {
+ ares_destroy(td->channel);
+ td->channel = NULL;
+ }
#endif
/*
* if the thread is still blocking in the resolve syscall, detach it and
* let the thread do the cleanup...
*/
- Curl_mutex_acquire(td->tsd.mtx);
+ Curl_mutex_acquire(&td->tsd.mutx);
done = td->tsd.done;
td->tsd.done = TRUE;
- Curl_mutex_release(td->tsd.mtx);
+ Curl_mutex_release(&td->tsd.mutx);
if(!done) {
Curl_thread_destroy(td->thread_hnd);
@@ -403,35 +388,33 @@ static void destroy_async_data(struct Curl_easy *data)
Curl_thread_join(&td->thread_hnd);
destroy_thread_sync_data(&td->tsd);
-
- free(async->tdata);
}
#ifndef CURL_DISABLE_SOCKETPAIR
/*
* ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
* before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
*/
- Curl_multi_closed(data, sock_rd);
+ Curl_multi_will_close(data, sock_rd);
wakeup_close(sock_rd);
#endif
+
+ td->init = FALSE;
}
- async->tdata = NULL;
- free(async->hostname);
- async->hostname = NULL;
}
#ifdef USE_HTTPSRR_ARES
static CURLcode resolve_httpsrr(struct Curl_easy *data,
- struct Curl_async *asp)
+ struct Curl_async *async)
{
- int status = ares_init_options(&asp->tdata->channel, NULL, 0);
+ int status = ares_init_options(&async->thdata.channel, NULL, 0);
if(status != ARES_SUCCESS)
return CURLE_FAILED_INIT;
- memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo));
- ares_query_dnsrec(asp->tdata->channel,
- asp->hostname, ARES_CLASS_IN,
+ memset(&async->thdata.hinfo, 0, sizeof(struct Curl_https_rrinfo));
+ async->thdata.hinfo.port = -1;
+ ares_query_dnsrec(async->thdata.channel,
+ data->conn->host.name, ARES_CLASS_IN,
ARES_REC_TYPE_HTTPS,
Curl_dnsrec_done_cb, data, NULL);
@@ -449,38 +432,28 @@ static bool init_resolve_thread(struct Curl_easy *data,
const char *hostname, int port,
const struct addrinfo *hints)
{
- struct thread_data *td = calloc(1, sizeof(struct thread_data));
+ struct thread_data *td = &data->state.async.thdata;
+ /* !checksrc! disable ERRNOVAR 1 */
int err = ENOMEM;
- struct Curl_async *asp = &data->state.async;
-
- data->state.async.tdata = td;
- if(!td)
- goto errno_exit;
+ struct Curl_async *async = &data->state.async;
- asp->port = port;
- asp->done = FALSE;
- asp->status = 0;
- asp->dns = NULL;
+ async->port = port;
+ async->done = FALSE;
+ async->dns = NULL;
td->thread_hnd = curl_thread_t_null;
+ td->start = Curl_now();
if(!init_thread_sync_data(td, hostname, port, hints)) {
- asp->tdata = NULL;
- free(td);
goto errno_exit;
}
- free(asp->hostname);
- asp->hostname = strdup(hostname);
- if(!asp->hostname)
- goto err_exit;
-
/* The thread will set this TRUE when complete. */
td->tsd.done = FALSE;
#ifdef HAVE_GETADDRINFO
- td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
+ td->thread_hnd = Curl_thread_create(getaddrinfo_thread, td);
#else
- td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
+ td->thread_hnd = Curl_thread_create(gethostbyname_thread, td);
#endif
if(td->thread_hnd == curl_thread_t_null) {
@@ -490,7 +463,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
goto err_exit;
}
#ifdef USE_HTTPSRR_ARES
- if(resolve_httpsrr(data, asp))
+ if(resolve_httpsrr(data, async))
infof(data, "Failed HTTPS RR operation");
#endif
return TRUE;
@@ -499,7 +472,7 @@ err_exit:
destroy_async_data(data);
errno_exit:
- errno = err;
+ CURL_SETERRNO(err);
return FALSE;
}
@@ -514,7 +487,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- td = data->state.async.tdata;
+ td = &data->state.async.thdata;
DEBUGASSERT(td);
DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
@@ -550,13 +523,12 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
*/
void Curl_resolver_kill(struct Curl_easy *data)
{
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = &data->state.async.thdata;
/* 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. */
- if(td && td->thread_hnd != curl_thread_t_null
- && (data->set.quick_exit != 1L))
+ if((td->thread_hnd != curl_thread_t_null) && !data->set.quick_exit)
(void)thread_wait_resolv(data, NULL, FALSE);
else
Curl_resolver_cancel(data);
@@ -589,37 +561,34 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry)
{
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = &data->state.async.thdata;
bool done = FALSE;
DEBUGASSERT(entry);
*entry = NULL;
- if(!td) {
- DEBUGASSERT(td);
- return CURLE_COULDNT_RESOLVE_HOST;
- }
#ifdef USE_HTTPSRR_ARES
- if(Curl_ares_perform(data->state.async.tdata->channel, 0) < 0)
- return CURLE_UNRECOVERABLE_POLL;
+ (void)Curl_ares_perform(td->channel, 0); /* ignore errors */
#endif
- Curl_mutex_acquire(td->tsd.mtx);
+ Curl_mutex_acquire(&td->tsd.mutx);
done = td->tsd.done;
- Curl_mutex_release(td->tsd.mtx);
+ Curl_mutex_release(&td->tsd.mutx);
if(done) {
+ CURLcode result = td->result;
getaddrinfo_complete(data);
- if(!data->state.async.dns) {
- CURLcode result = Curl_resolver_error(data);
+ if(!result && !data->state.async.dns)
+ result = Curl_resolver_error(data);
+
+ if(result) {
destroy_async_data(data);
return result;
}
#ifdef USE_HTTPSRR_ARES
{
- struct Curl_https_rrinfo *lhrr =
- Curl_memdup(&td->hinfo, sizeof(struct Curl_https_rrinfo));
+ struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&td->hinfo);
if(!lhrr) {
destroy_async_data(data);
return CURLE_OUT_OF_MEMORY;
@@ -658,12 +627,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
int ret_val = 0;
- timediff_t milli;
- timediff_t ms;
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-#ifndef CURL_DISABLE_SOCKETPAIR
- struct thread_data *td = data->state.async.tdata;
-#endif
+ struct thread_data *td = &data->state.async.thdata;
#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
int socketi = 0;
#else
@@ -671,8 +635,8 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
#endif
#ifdef USE_HTTPSRR_ARES
- if(data->state.async.tdata && data->state.async.tdata->channel) {
- ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks);
+ if(td->init && td->channel) {
+ ret_val = Curl_ares_getsock(data, td->channel, socks);
for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
!ARES_GETSOCK_WRITABLE(ret_val, socketi))
@@ -680,14 +644,16 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
}
#endif
#ifndef CURL_DISABLE_SOCKETPAIR
- if(td) {
+ if(td->init) {
/* return read fd to client for polling the DNS resolution status */
socks[socketi] = td->tsd.sock_pair[0];
ret_val |= GETSOCK_READSOCK(socketi);
}
- else {
+ else
#endif
- ms = Curl_timediff(Curl_now(), reslv->start);
+ {
+ timediff_t milli;
+ timediff_t ms = Curl_timediff(Curl_now(), td->start);
if(ms < 3)
milli = 0;
else if(ms <= 50)
@@ -697,10 +663,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
else
milli = 200;
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
-#ifndef CURL_DISABLE_SOCKETPAIR
}
-#endif
-
return ret_val;
}
@@ -714,12 +677,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int port,
int *waitp)
{
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-
*waitp = 0; /* default to synchronous response */
- reslv->start = Curl_now();
-
/* fire up a new resolver thread! */
if(init_resolve_thread(data, hostname, port, NULL)) {
*waitp = 1; /* expect asynchronous response */
@@ -743,8 +702,6 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
{
struct addrinfo hints;
int pf = PF_INET;
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-
*waitp = 0; /* default to synchronous response */
#ifdef CURLRES_IPV6
@@ -762,7 +719,6 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
SOCK_STREAM : SOCK_DGRAM;
- reslv->start = Curl_now();
/* fire up a new resolver thread! */
if(init_resolve_thread(data, hostname, port, &hints)) {
*waitp = 1; /* expect asynchronous response */
diff --git a/libs/libcurl/src/asyn.h b/libs/libcurl/src/asyn.h
index 194cab2c93..50cd7e858b 100644
--- a/libs/libcurl/src/asyn.h
+++ b/libs/libcurl/src/asyn.h
@@ -39,9 +39,9 @@ struct Curl_dns_entry;
/* Data for synchronization between resolver thread and its parent */
struct thread_sync_data {
- curl_mutex_t *mtx;
char *hostname; /* hostname to resolve, Curl_async.hostname
duplicate */
+ curl_mutex_t mutx;
#ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
#endif
@@ -49,7 +49,6 @@ struct thread_sync_data {
#ifdef HAVE_GETADDRINFO
struct addrinfo hints;
#endif
- struct thread_data *td; /* for thread-self cleanup */
int port;
int sock_error;
bool done;
@@ -59,11 +58,15 @@ struct thread_data {
curl_thread_t thread_hnd;
unsigned int poll_interval;
timediff_t interval_end;
+ struct curltime start;
struct thread_sync_data tsd;
+ CURLcode result; /* CURLE_OK or error handling response */
#if defined(USE_HTTPSRR) && defined(USE_ARES)
struct Curl_https_rrinfo hinfo;
ares_channel channel;
+ int num_pending; /* number of outstanding c-ares requests */
#endif
+ bool init;
};
#elif defined(CURLRES_ARES) /* CURLRES_THREADED */
@@ -73,13 +76,14 @@ struct thread_data {
struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
parts */
int last_status;
+ CURLcode result; /* CURLE_OK or error handling response */
#ifndef HAVE_CARES_GETADDRINFO
struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
#endif
#ifdef USE_HTTPSRR
struct Curl_https_rrinfo hinfo;
#endif
- char hostname[1];
+ char *hostname;
};
#endif /* CURLRES_ARES */
@@ -173,7 +177,7 @@ void Curl_resolver_kill(struct Curl_easy *data);
/* Curl_resolver_getsock()
*
- * This function is called from the multi_getsock() function. 'sock' is a
+ * This function is called from the Curl_multi_getsock() function. 'sock' is a
* pointer to an array to hold the file descriptors, with 'numsock' being the
* size of that array (in number of entries). This function is supposed to
* return bitmask indicating what file descriptors (referring to array indexes
diff --git a/libs/libcurl/src/base64.c b/libs/libcurl/src/base64.c
index a60d4542b7..24a8fc1f0f 100644
--- a/libs/libcurl/src/base64.c
+++ b/libs/libcurl/src/base64.c
@@ -32,7 +32,7 @@
!defined(CURL_DISABLE_POP3) || \
!defined(CURL_DISABLE_IMAP) || \
!defined(CURL_DISABLE_DIGEST_AUTH) || \
- !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || defined(BUILDING_CURL)
+ !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || !defined(BUILDING_LIBCURL)
#include "curl/curl.h"
#include "warnless.h"
#include "curl_base64.h"
@@ -191,7 +191,7 @@ static CURLcode base64_encode(const char *table64,
{
char *output;
char *base64data;
- const unsigned char *in = (unsigned char *)inputbuff;
+ const unsigned char *in = (const unsigned char *)inputbuff;
const char *padstr = &table64[64]; /* Point to padding string. */
*outptr = NULL;
diff --git a/libs/libcurl/src/bufref.c b/libs/libcurl/src/bufref.c
index e94dc910b2..45409d02e2 100644
--- a/libs/libcurl/src/bufref.c
+++ b/libs/libcurl/src/bufref.c
@@ -30,7 +30,9 @@
#include "curl_memory.h"
#include "memdebug.h"
+#ifdef DEBUGBUILD
#define SIGNATURE 0x5c48e9b2 /* Random pattern. */
+#endif
/*
* Init a bufref struct.
@@ -59,7 +61,7 @@ void Curl_bufref_free(struct bufref *br)
DEBUGASSERT(br->ptr || !br->len);
if(br->ptr && br->dtor)
- br->dtor((void *) br->ptr);
+ br->dtor(CURL_UNCONST(br->ptr));
br->dtor = NULL;
br->ptr = NULL;
diff --git a/libs/libcurl/src/cf-h1-proxy.c b/libs/libcurl/src/cf-h1-proxy.c
index 8f71ea4c72..0e9db654fa 100644
--- a/libs/libcurl/src/cf-h1-proxy.c
+++ b/libs/libcurl/src/cf-h1-proxy.c
@@ -44,6 +44,7 @@
#include "vtls/vtls.h"
#include "transfer.h"
#include "multiif.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -314,8 +315,11 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
k->httpcode);
}
else {
- (void)curlx_strtoofft(header + strlen("Content-Length:"),
- NULL, 10, &ts->cl);
+ const char *p = header + strlen("Content-Length:");
+ if(Curl_str_numblanks(&p, &ts->cl)) {
+ failf(data, "Unsupported Content-Length value");
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
}
}
else if(Curl_compareheader(header,
@@ -597,7 +601,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
infof(data, "Connect me again please");
Curl_conn_cf_close(cf, data);
connkeep(conn, "HTTP proxy CONNECT");
- result = Curl_conn_cf_connect(cf->next, data, FALSE, &done);
+ result = Curl_conn_cf_connect(cf->next, data, &done);
goto out;
}
else {
@@ -637,7 +641,7 @@ out:
static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
CURLcode result;
struct h1_tunnel_state *ts = cf->ctx;
@@ -648,7 +652,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
}
CURL_TRC_CF(data, cf, "connect");
- result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+ result = cf->next->cft->do_connect(cf->next, data, done);
if(result || !*done)
return result;
diff --git a/libs/libcurl/src/cf-h2-proxy.c b/libs/libcurl/src/cf-h2-proxy.c
index 34fde28ca6..1175399696 100644
--- a/libs/libcurl/src/cf-h2-proxy.c
+++ b/libs/libcurl/src/cf-h2-proxy.c
@@ -619,7 +619,7 @@ static int proxy_h2_fr_print(const nghttp2_frame *frame,
frame->hd.flags & NGHTTP2_FLAG_ACK);
case NGHTTP2_GOAWAY: {
char scratch[128];
- size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
+ size_t s_len = CURL_ARRAYSIZE(scratch);
size_t len = (frame->goaway.opaque_data_len < s_len) ?
frame->goaway.opaque_data_len : s_len-1;
if(len)
@@ -1090,7 +1090,7 @@ out:
static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
@@ -1105,7 +1105,7 @@ static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
/* Connect the lower filters first */
if(!cf->next->connected) {
- result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+ result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
return result;
}
diff --git a/libs/libcurl/src/cf-haproxy.c b/libs/libcurl/src/cf-haproxy.c
index 375105e297..a0dadce173 100644
--- a/libs/libcurl/src/cf-haproxy.c
+++ b/libs/libcurl/src/cf-haproxy.c
@@ -105,7 +105,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_haproxy_ctx *ctx = cf->ctx;
CURLcode result;
@@ -117,7 +117,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
- result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+ result = cf->next->cft->do_connect(cf->next, data, done);
if(result || !*done)
return result;
diff --git a/libs/libcurl/src/cf-https-connect.c b/libs/libcurl/src/cf-https-connect.c
index ad1090f4a0..1cc4a03e49 100644
--- a/libs/libcurl/src/cf-https-connect.c
+++ b/libs/libcurl/src/cf-https-connect.c
@@ -175,7 +175,7 @@ static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b,
struct Curl_cfilter *save = cf->next;
cf->next = b->cf;
- b->result = Curl_conn_cf_connect(cf->next, data, FALSE, done);
+ b->result = Curl_conn_cf_connect(cf->next, data, done);
b->cf = cf->next; /* it might mutate */
cf->next = save;
return b->result;
@@ -192,7 +192,7 @@ static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data)
ctx->state = CF_HC_INIT;
ctx->result = CURLE_OK;
ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
- ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 2;
+ ctx->soft_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout / 4;
}
}
@@ -263,8 +263,8 @@ static bool time_to_start_next(struct Curl_cfilter *cf,
break;
}
if(i == idx) {
- CURL_TRC_CF(data, cf, "all previous ballers have failed, time to start "
- "baller %zu [%s]", idx, ctx->ballers[idx].name);
+ CURL_TRC_CF(data, cf, "all previous attempts failed, starting %s",
+ ctx->ballers[idx].name);
return TRUE;
}
elapsed_ms = Curl_timediff(now, ctx->started);
@@ -291,14 +291,13 @@ static bool time_to_start_next(struct Curl_cfilter *cf,
static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_hc_ctx *ctx = cf->ctx;
struct curltime now;
CURLcode result = CURLE_OK;
size_t i, failed_ballers;
- (void)blocking;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
@@ -316,7 +315,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
cf_hc_baller_init(&ctx->ballers[0], cf, data, cf->conn->transport);
if(ctx->baller_count > 1) {
Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
- CURL_TRC_CF(data, cf, "set expire for starting next baller in %ums",
+ CURL_TRC_CF(data, cf, "set next attempt to start in %ums",
ctx->soft_eyeballs_timeout_ms);
}
ctx->state = CF_HC_CONNECT;
@@ -352,7 +351,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
if(failed_ballers == ctx->baller_count) {
/* all have failed. we give up */
- CURL_TRC_CF(data, cf, "connect, all failed");
+ CURL_TRC_CF(data, cf, "connect, all attempts failed");
for(i = 0; i < ctx->baller_count; i++) {
if(ctx->ballers[i].result) {
result = ctx->ballers[i].result;
@@ -451,7 +450,6 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
if(cf->connected)
return cf->next->cft->has_data_pending(cf->next, data);
- CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
for(i = 0; i < ctx->baller_count; i++)
if(cf_hc_baller_data_pending(&ctx->ballers[i], data))
return TRUE;
@@ -607,8 +605,6 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
ctx->baller_count = alpn_count;
result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx);
- CURL_TRC_CF(data, cf, "created with %zu ALPNs -> %d",
- ctx->baller_count, result);
if(result)
goto out;
ctx = NULL;
@@ -638,6 +634,17 @@ out:
return result;
}
+static bool cf_https_alpns_contain(enum alpnid id,
+ enum alpnid *list, size_t len)
+{
+ size_t i;
+ for(i = 0; i < len; ++i) {
+ if(id == list[i])
+ return TRUE;
+ }
+ return FALSE;
+}
+
CURLcode Curl_cf_https_setup(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
@@ -646,72 +653,85 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
enum alpnid alpn_ids[2];
size_t alpn_count = 0;
CURLcode result = CURLE_OK;
+ struct Curl_cfilter cf_fake, *cf = NULL;
(void)sockindex;
(void)remotehost;
+ /* we want to log for the filter before we create it, fake it. */
+ memset(&cf_fake, 0, sizeof(cf_fake));
+ cf_fake.cft = &Curl_cft_http_connect;
+ cf = &cf_fake;
if(conn->bits.tls_enable_alpn) {
- switch(data->state.httpwant) {
- case CURL_HTTP_VERSION_NONE:
- /* No preferences by transfer setup. Choose best defaults */
#ifdef USE_HTTPSRR
- if(conn->dns_entry && conn->dns_entry->hinfo &&
- !conn->dns_entry->hinfo->no_def_alpn) {
- size_t i, j;
- for(i = 0; i < CURL_ARRAYSIZE(conn->dns_entry->hinfo->alpns) &&
- alpn_count < CURL_ARRAYSIZE(alpn_ids); ++i) {
- bool present = FALSE;
- enum alpnid alpn = conn->dns_entry->hinfo->alpns[i];
- for(j = 0; j < alpn_count; ++j) {
- if(alpn == alpn_ids[j]) {
- present = TRUE;
- break;
- }
+ /* Is there a HTTPSRR and if so, do its ALPNs it apply here?
+ * We are here after having selected a connection to a host+port and
+ * can no longer change that. Any HTTPSRR advice for other hosts and ports
+ * we need to ignore. */
+ if(conn->dns_entry && conn->dns_entry->hinfo &&
+ !conn->dns_entry->hinfo->no_def_alpn && /* ALPNs are defaults */
+ (!conn->dns_entry->hinfo->target || /* for same host */
+ !conn->dns_entry->hinfo->target[0] ||
+ (conn->dns_entry->hinfo->target[0] == '.' &&
+ !conn->dns_entry->hinfo->target[0])) &&
+ (conn->dns_entry->hinfo->port < 0 || /* for same port */
+ conn->dns_entry->hinfo->port == conn->remote_port)) {
+ size_t i;
+ for(i = 0; i < CURL_ARRAYSIZE(conn->dns_entry->hinfo->alpns) &&
+ alpn_count < CURL_ARRAYSIZE(alpn_ids); ++i) {
+ enum alpnid alpn = conn->dns_entry->hinfo->alpns[i];
+ if(cf_https_alpns_contain(alpn, alpn_ids, alpn_count))
+ continue;
+ switch(alpn) {
+ case ALPN_h3:
+ if(Curl_conn_may_http3(data, conn))
+ break; /* not possible */
+ if(data->state.http_neg.allowed & CURL_HTTP_V3x) {
+ CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR");
+ alpn_ids[alpn_count++] = alpn;
}
- if(!present) {
- switch(alpn) {
- case ALPN_h3:
- if(Curl_conn_may_http3(data, conn))
- break; /* not possible */
- FALLTHROUGH();
- case ALPN_h2:
- case ALPN_h1:
- alpn_ids[alpn_count++] = alpn;
- break;
- default: /* ignore */
- break;
- }
+ break;
+ case ALPN_h2:
+ if(data->state.http_neg.allowed & CURL_HTTP_V2x) {
+ CURL_TRC_CF(data, cf, "adding h2 via HTTPS-RR");
+ alpn_ids[alpn_count++] = alpn;
+ }
+ break;
+ case ALPN_h1:
+ if(data->state.http_neg.allowed & CURL_HTTP_V1x) {
+ CURL_TRC_CF(data, cf, "adding h1 via HTTPS-RR");
+ alpn_ids[alpn_count++] = alpn;
}
+ break;
+ default: /* ignore */
+ break;
}
}
+ }
#endif
- if(!alpn_count)
- alpn_ids[alpn_count++] = ALPN_h2;
- break;
- case CURL_HTTP_VERSION_3ONLY:
+
+ if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+ (data->state.http_neg.wanted & CURL_HTTP_V3x) &&
+ !cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) {
result = Curl_conn_may_http3(data, conn);
- if(result) /* cannot do it */
- goto out;
- alpn_ids[alpn_count++] = ALPN_h3;
- break;
- case CURL_HTTP_VERSION_3:
- /* We assume that silently not even trying H3 is ok here */
- if(Curl_conn_may_http3(data, conn) == CURLE_OK)
+ if(!result) {
+ CURL_TRC_CF(data, cf, "adding wanted h3");
alpn_ids[alpn_count++] = ALPN_h3;
+ }
+ else if(data->state.http_neg.wanted == CURL_HTTP_V3x)
+ goto out; /* only h3 allowed, not possible, error out */
+ }
+ if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+ (data->state.http_neg.wanted & CURL_HTTP_V2x) &&
+ !cf_https_alpns_contain(ALPN_h2, alpn_ids, alpn_count)) {
+ CURL_TRC_CF(data, cf, "adding wanted h2");
alpn_ids[alpn_count++] = ALPN_h2;
- break;
- case CURL_HTTP_VERSION_2_0:
- case CURL_HTTP_VERSION_2TLS:
- case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
- alpn_ids[alpn_count++] = ALPN_h2;
- break;
- case CURL_HTTP_VERSION_1_0:
- case CURL_HTTP_VERSION_1_1:
+ }
+ else if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) &&
+ (data->state.http_neg.wanted & CURL_HTTP_V1x) &&
+ !cf_https_alpns_contain(ALPN_h1, alpn_ids, alpn_count)) {
+ CURL_TRC_CF(data, cf, "adding wanted h1");
alpn_ids[alpn_count++] = ALPN_h1;
- break;
- default:
- alpn_ids[alpn_count++] = ALPN_h2;
- break;
}
}
diff --git a/libs/libcurl/src/cf-socket.c b/libs/libcurl/src/cf-socket.c
index e552120b31..b40bd05801 100644
--- a/libs/libcurl/src/cf-socket.c
+++ b/libs/libcurl/src/cf-socket.c
@@ -82,7 +82,9 @@
#include "rand.h"
#include "share.h"
#include "strdup.h"
+#include "system_win32.h"
#include "version_win32.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -113,8 +115,8 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
int level = IPPROTO_TCP;
char buffer[STRERROR_LEN];
- if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
- sizeof(onoff)) < 0)
+ if(setsockopt(sockfd, level, TCP_NODELAY,
+ (void *)&onoff, sizeof(onoff)) < 0)
infof(data, "Could not set TCP_NODELAY: %s",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
#else
@@ -133,8 +135,8 @@ static void nosigpipe(struct Curl_easy *data,
{
int onoff = 1;
(void)data;
- if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
- sizeof(onoff)) < 0) {
+ if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE,
+ (void *)&onoff, sizeof(onoff)) < 0) {
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
char buffer[STRERROR_LEN];
infof(data, "Could not set SO_NOSIGPIPE: %s",
@@ -181,7 +183,7 @@ tcpkeepalive(struct Curl_easy *data,
/* only set IDLE and INTVL if setting KEEPALIVE is successful */
if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
- (void *)&optval, sizeof(optval)) < 0) {
+ (void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set SO_KEEPALIVE on fd "
"%" FMT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
@@ -234,7 +236,7 @@ tcpkeepalive(struct Curl_easy *data,
optval = curlx_sltosi(data->set.tcp_keepidle);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
- (void *)&optval, sizeof(optval)) < 0) {
+ (void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPIDLE on fd "
"%" FMT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
@@ -244,7 +246,7 @@ tcpkeepalive(struct Curl_easy *data,
optval = curlx_sltosi(data->set.tcp_keepidle);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
- (void *)&optval, sizeof(optval)) < 0) {
+ (void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPALIVE on fd "
"%" FMT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
@@ -254,7 +256,7 @@ tcpkeepalive(struct Curl_easy *data,
optval = curlx_sltosi(data->set.tcp_keepidle);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
- (void *)&optval, sizeof(optval)) < 0) {
+ (void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
"%" FMT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
@@ -264,7 +266,7 @@ tcpkeepalive(struct Curl_easy *data,
optval = curlx_sltosi(data->set.tcp_keepintvl);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
- (void *)&optval, sizeof(optval)) < 0) {
+ (void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPINTVL on fd "
"%" FMT_SOCKET_T ": errno %d",
sockfd, SOCKERRNO);
@@ -285,7 +287,7 @@ tcpkeepalive(struct Curl_easy *data,
curlx_sltosi(data->set.tcp_keepintvl);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
- (void *)&optval, sizeof(optval)) < 0) {
+ (void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
"%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
}
@@ -293,7 +295,7 @@ tcpkeepalive(struct Curl_easy *data,
#ifdef TCP_KEEPCNT
optval = curlx_sltosi(data->set.tcp_keepcnt);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
- (void *)&optval, sizeof(optval)) < 0) {
+ (void *)&optval, sizeof(optval)) < 0) {
infof(data, "Failed to set TCP_KEEPCNT on fd "
"%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
}
@@ -420,7 +422,7 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
if(use_callback && conn && conn->fclosesocket) {
int rc;
- Curl_multi_closed(data, sock);
+ Curl_multi_will_close(data, sock);
Curl_set_in_callback(data, TRUE);
rc = conn->fclosesocket(conn->closesocket_client, sock);
Curl_set_in_callback(data, FALSE);
@@ -429,7 +431,7 @@ static int socket_close(struct Curl_easy *data, struct connectdata *conn,
if(conn)
/* tell the multi-socket code about this */
- Curl_multi_closed(data, sock);
+ Curl_multi_will_close(data, sock);
sclose(sock);
@@ -460,9 +462,6 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
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)
{
@@ -470,17 +469,7 @@ void Curl_sndbuf_init(curl_socket_t sockfd)
int curval = 0;
int curlen = sizeof(curval);
- static int detectOsState = DETECT_OS_NONE;
-
- if(detectOsState == DETECT_OS_NONE) {
- if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
- VERSION_GREATER_THAN_EQUAL))
- detectOsState = DETECT_OS_VISTA_OR_LATER;
- else
- detectOsState = DETECT_OS_PREVISTA;
- }
-
- if(detectOsState == DETECT_OS_VISTA_OR_LATER)
+ if(Curl_isVistaOrGreater)
return;
if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
@@ -732,7 +721,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
if(scope_ptr)
*(scope_ptr++) = '\0';
#endif
- if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
+ if(curlx_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
@@ -741,10 +730,10 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
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)
+ curl_off_t scope_id;
+ if(Curl_str_number((const char **)CURL_UNCONST(&scope_ptr),
+ &scope_id, UINT_MAX))
return CURLE_UNSUPPORTED_PROTOCOL;
-
si6->sin6_scope_id = (unsigned int)scope_id;
}
#endif
@@ -755,7 +744,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
#endif
/* IPv4 address */
if((af == AF_INET) &&
- (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
+ (curlx_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
si4->sin_family = AF_INET;
si4->sin_port = htons(port);
sizeof_sa = sizeof(struct sockaddr_in);
@@ -855,7 +844,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
* Someone got to verify this on Win-NT 4.0, 2000."
*/
-#ifdef _WIN32_WCE
+#ifdef UNDER_CE
Sleep(0);
#else
SleepEx(0, FALSE);
@@ -865,7 +854,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
err = SOCKERRNO;
-#ifdef _WIN32_WCE
+#ifdef UNDER_CE
/* Old Windows CE versions do not support SO_ERROR */
if(WSAENOPROTOOPT == err) {
SET_SOCKERRNO(0);
@@ -879,7 +868,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
err = 0;
}
#endif
- if((0 == err) || (EISCONN == err))
+ if((0 == err) || (SOCKEISCONN == err))
/* we are connected, awesome! */
rc = TRUE;
else
@@ -902,10 +891,10 @@ static CURLcode socket_connect_result(struct Curl_easy *data,
const char *ipaddress, int error)
{
switch(error) {
- case EINPROGRESS:
- case EWOULDBLOCK:
+ case SOCKEINPROGRESS:
+ case SOCKEWOULDBLOCK:
#if defined(EAGAIN)
-#if (EAGAIN) != (EWOULDBLOCK)
+#if (EAGAIN) != (SOCKEWOULDBLOCK)
/* On some platforms EAGAIN and EWOULDBLOCK are the
* same value, and on others they are different, hence
* the odd #if
@@ -932,15 +921,6 @@ static CURLcode socket_connect_result(struct Curl_easy *data,
}
}
-/* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
- * This happens often on TLS connections where the TLS implementation
- * tries to read the head of a TLS record, determine the length of the
- * full record and then make a subsequent read for that.
- * On large reads, we will not fill the buffer to avoid the double copy. */
-#define NW_RECV_CHUNK_SIZE (64 * 1024)
-#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 */
@@ -983,28 +963,28 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
#ifdef DEBUGBUILD
{
- char *p = getenv("CURL_DBG_SOCK_WBLOCK");
+ const char *p = getenv("CURL_DBG_SOCK_WBLOCK");
if(p) {
- long l = strtol(p, NULL, 10);
- if(l >= 0 && l <= 100)
+ curl_off_t l;
+ if(!Curl_str_number(&p, &l, 100))
ctx->wblock_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_WPARTIAL");
if(p) {
- long l = strtol(p, NULL, 10);
- if(l >= 0 && l <= 100)
+ curl_off_t l;
+ if(!Curl_str_number(&p, &l, 100))
ctx->wpartial_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_RBLOCK");
if(p) {
- long l = strtol(p, NULL, 10);
- if(l >= 0 && l <= 100)
+ curl_off_t l;
+ if(!Curl_str_number(&p, &l, 100))
ctx->rblock_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_RMAX");
if(p) {
- long l = strtol(p, NULL, 10);
- if(l >= 0)
+ curl_off_t l;
+ if(!Curl_str_number(&p, &l, CURL_OFF_T_MAX))
ctx->recv_max = (size_t)l;
}
}
@@ -1018,7 +998,7 @@ 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(%" FMT_SOCKET_T ")", ctx->sock);
+ CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_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);
@@ -1040,7 +1020,7 @@ static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
if(cf->connected) {
struct cf_socket_ctx *ctx = cf->ctx;
- CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" FMT_SOCKET_T ")", ctx->sock);
+ CURL_TRC_CF(data, cf, "cf_socket_shutdown, fd=%" FMT_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. */
@@ -1313,7 +1293,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_socket_ctx *ctx = cf->ctx;
CURLcode result = CURLE_COULDNT_CONNECT;
@@ -1325,9 +1305,6 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
- if(blocking)
- return CURLE_UNSUPPORTED_PROTOCOL;
-
*done = FALSE; /* a negative world view is best */
if(ctx->sock == CURL_SOCKET_BAD) {
int error;
@@ -1538,15 +1515,16 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
int sockerr = SOCKERRNO;
if(
-#ifdef WSAEWOULDBLOCK
+#ifdef USE_WINSOCK
/* This is how Windows does it */
- (WSAEWOULDBLOCK == sockerr)
+ (SOCKEWOULDBLOCK == 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) ||
- (EINPROGRESS == sockerr)
+ (SOCKEWOULDBLOCK == sockerr) ||
+ (EAGAIN == sockerr) || (SOCKEINTR == sockerr) ||
+ (SOCKEINPROGRESS == sockerr)
#endif
) {
/* this is just a case of EWOULDBLOCK */
@@ -1606,14 +1584,15 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
int sockerr = SOCKERRNO;
if(
-#ifdef WSAEWOULDBLOCK
+#ifdef USE_WINSOCK
/* This is how Windows does it */
- (WSAEWOULDBLOCK == sockerr)
+ (SOCKEWOULDBLOCK == 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)
+ (SOCKEWOULDBLOCK == sockerr) ||
+ (EAGAIN == sockerr) || (SOCKEINTR == sockerr)
#endif
) {
/* this is just a case of EWOULDBLOCK */
@@ -1849,7 +1828,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
/* QUIC needs a connected socket, nonblocking */
DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
- rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, /* NOLINT */
+ /* error: The 1st argument to 'connect' is -1 but should be >= 0
+ NOLINTNEXTLINE(clang-analyzer-unix.StdCLibraryFunctions) */
+ rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
(curl_socklen_t)ctx->addr.addrlen);
if(-1 == rc) {
return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
@@ -1867,8 +1848,9 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
* 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.
*/
+#ifdef __linux__
switch(ctx->addr.family) {
-#if defined(__linux__) && defined(IP_MTU_DISCOVER)
+#ifdef IP_MTU_DISCOVER
case AF_INET: {
int val = IP_PMTUDISC_DO;
(void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
@@ -1876,7 +1858,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
break;
}
#endif
-#if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
+#ifdef IPV6_MTU_DISCOVER
case AF_INET6: {
int val = IPV6_PMTUDISC_DO;
(void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
@@ -1886,24 +1868,24 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
#endif
}
-#if defined(__linux__) && defined(UDP_GRO) && \
+#if 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
+#endif
return CURLE_OK;
}
static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_socket_ctx *ctx = cf->ctx;
CURLcode result = CURLE_COULDNT_CONNECT;
- (void)blocking;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
@@ -2108,7 +2090,7 @@ static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_socket_ctx *ctx = cf->ctx;
#ifdef USE_IPV6
@@ -2124,7 +2106,6 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
/* we start accepted, if we ever close, we cannot go on */
(void)data;
- (void)blocking;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
diff --git a/libs/libcurl/src/cfilters.c b/libs/libcurl/src/cfilters.c
index c7f3c2d88c..c2036f7092 100644
--- a/libs/libcurl/src/cfilters.c
+++ b/libs/libcurl/src/cfilters.c
@@ -28,13 +28,14 @@
#include "strerror.h"
#include "cfilters.h"
#include "connect.h"
-#include "url.h" /* for Curl_safefree() */
+#include "url.h"
#include "sendf.h"
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "multiif.h"
#include "progress.h"
#include "select.h"
#include "warnless.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -199,9 +200,9 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
*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);
+ CURL_TRC_M(data, "shutdown start on%s connection",
+ sockindex ? " secondary" : "");
+ Curl_shutdown_start(data, sockindex, 0, &now);
}
else {
timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
@@ -367,10 +368,10 @@ bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf,
CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
if(cf)
- return cf->cft->do_connect(cf, data, blocking, done);
+ return cf->cft->do_connect(cf, data, done);
return CURLE_FAILED_INIT;
}
@@ -404,6 +405,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
bool blocking,
bool *done)
{
+#define CF_CONN_NUM_POLLS_ON_STACK 5
+ struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
+ struct curl_pollfds cpfds;
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
@@ -418,7 +422,11 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
}
*done = cf->connected;
- if(!*done) {
+ if(*done)
+ return CURLE_OK;
+
+ Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
+ while(!*done) {
if(Curl_conn_needs_flush(data, sockindex)) {
DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
result = Curl_conn_flush(data, sockindex);
@@ -426,7 +434,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
return result;
}
- result = cf->cft->do_connect(cf, data, blocking, done);
+ result = cf->cft->do_connect(cf, data, done);
+ CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d",
+ blocking, result, *done);
if(!result && *done) {
/* Now that the complete filter chain is connected, let all filters
* persist information at the connection. E.g. cf-socket sets the
@@ -435,12 +445,56 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
conn_report_connect_stats(data, data->conn);
data->conn->keepalive = Curl_now();
Curl_verboseconnect(data, data->conn, sockindex);
+ goto out;
}
else if(result) {
+ CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d",
+ result);
conn_report_connect_stats(data, data->conn);
+ goto out;
+ }
+
+ if(!blocking)
+ goto out;
+ else {
+ /* check allowed time left */
+ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+ struct easy_pollset ps;
+ int rc;
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "connect timeout");
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
+ }
+
+ CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
+ Curl_pollfds_reset(&cpfds);
+ memset(&ps, 0, sizeof(ps));
+ /* In general, we want to send after connect, wait on that. */
+ if(sockfd != CURL_SOCKET_BAD)
+ Curl_pollset_set_out_only(data, &ps, sockfd);
+ Curl_conn_adjust_pollset(data, data->conn, &ps);
+ result = Curl_pollfds_add_ps(&cpfds, &ps);
+ if(result)
+ goto out;
+
+ rc = Curl_poll(cpfds.pfds, cpfds.n,
+ CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10)));
+ CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d",
+ rc);
+ if(rc < 0) {
+ result = CURLE_COULDNT_CONNECT;
+ goto out;
+ }
+ /* continue iterating */
}
}
+out:
+ Curl_pollfds_cleanup(&cpfds);
return result;
}
@@ -496,13 +550,14 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
return FALSE;
}
-unsigned char Curl_conn_http_version(struct Curl_easy *data)
+unsigned char Curl_conn_http_version(struct Curl_easy *data,
+ struct connectdata *conn)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_UNKNOWN_OPTION;
unsigned char v = 0;
- cf = data->conn ? data->conn->cfilter[FIRSTSOCKET] : NULL;
+ cf = conn->cfilter[FIRSTSOCKET];
for(; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_HTTP) {
int value = 0;
@@ -571,14 +626,15 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
}
void Curl_conn_adjust_pollset(struct Curl_easy *data,
- struct easy_pollset *ps)
+ struct connectdata *conn,
+ struct easy_pollset *ps)
{
int i;
DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
+ DEBUGASSERT(conn);
for(i = 0; i < 2; ++i) {
- Curl_conn_cf_adjust_pollset(data->conn->cfilter[i], data, ps);
+ Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
}
}
@@ -880,14 +936,14 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
DEBUGASSERT(data->conn);
conn = data->conn;
#ifdef DEBUGBUILD
- {
+ if(write_len) {
/* Allow debug builds to override this logic to force short sends
*/
- char *p = getenv("CURL_SMALLSENDS");
+ const char *p = getenv("CURL_SMALLSENDS");
if(p) {
- size_t altsize = (size_t)strtoul(p, NULL, 10);
- if(altsize)
- write_len = CURLMIN(write_len, altsize);
+ curl_off_t altsize;
+ if(!Curl_str_number(&p, &altsize, write_len))
+ write_len = (size_t)altsize;
}
}
#endif
diff --git a/libs/libcurl/src/cfilters.h b/libs/libcurl/src/cfilters.h
index f5d5dde19c..7155695418 100644
--- a/libs/libcurl/src/cfilters.h
+++ b/libs/libcurl/src/cfilters.h
@@ -51,7 +51,7 @@ typedef CURLcode Curl_cft_shutdown(struct Curl_cfilter *cf,
typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done);
+ bool *done);
/* Return the hostname and port the connection goes to.
* This may change with the connection state of filters when tunneling
@@ -65,10 +65,10 @@ typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
* @param pport on return, contains the port number
*/
typedef void Curl_cft_get_host(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const char **phost,
- const char **pdisplay_host,
- int *pport);
+ struct Curl_easy *data,
+ const char **phost,
+ const char **pdisplay_host,
+ int *pport);
struct easy_pollset;
@@ -96,8 +96,8 @@ struct easy_pollset;
* @param ps the pollset (inout) for the easy handle
*/
typedef void Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct easy_pollset *ps);
+ struct Curl_easy *data,
+ struct easy_pollset *ps);
typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
@@ -245,8 +245,8 @@ void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
const char **phost, const char **pdisplay_host,
int *pport);
void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct easy_pollset *ps);
+ struct Curl_easy *data,
+ struct easy_pollset *ps);
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -255,8 +255,8 @@ ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err);
CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int event, int arg1, void *arg2);
+ struct Curl_easy *data,
+ int event, int arg1, void *arg2);
bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *input_pending);
@@ -324,7 +324,7 @@ void Curl_conn_cf_discard_all(struct Curl_easy *data,
CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done);
+ bool *done);
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, bool eos,
@@ -399,7 +399,8 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
* Return the HTTP version used on the FIRSTSOCKET connection filters
* or 0 if unknown. Value otherwise is 09, 10, 11, etc.
*/
-unsigned char Curl_conn_http_version(struct Curl_easy *data);
+unsigned char Curl_conn_http_version(struct Curl_easy *data,
+ struct connectdata *conn);
/**
* Close the filter chain at `sockindex` for connection `data->conn`.
@@ -454,7 +455,8 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
* Adjust pollset from filters installed at transfer's connection.
*/
void Curl_conn_adjust_pollset(struct Curl_easy *data,
- struct easy_pollset *ps);
+ struct connectdata *conn,
+ struct easy_pollset *ps);
/**
* Curl_poll() the filter chain at `cf` with timeout `timeout_ms`.
@@ -654,7 +656,7 @@ struct cf_call_data {
(save) = CF_CTX_CALL_DATA(cf); \
DEBUGASSERT((save).data == NULL || (save).depth > 0); \
CF_CTX_CALL_DATA(cf).depth++; \
- CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \
+ CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)CURL_UNCONST(data); \
} while(0)
#define CF_DATA_RESTORE(cf, save) \
@@ -669,7 +671,7 @@ struct cf_call_data {
#define CF_DATA_SAVE(save, cf, data) \
do { \
(save) = CF_CTX_CALL_DATA(cf); \
- CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)data; \
+ CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)CURL_UNCONST(data); \
} while(0)
#define CF_DATA_RESTORE(cf, save) \
diff --git a/libs/libcurl/src/config-os400.h b/libs/libcurl/src/config-os400.h
index ee43e8cd8a..ca60ad334c 100644
--- a/libs/libcurl/src/config-os400.h
+++ b/libs/libcurl/src/config-os400.h
@@ -152,12 +152,6 @@
/* Define if you have the <stropts.h> header file. */
#undef HAVE_STROPTS_H
-/* Define if you have the `strtok_r' function. */
-#define HAVE_STRTOK_R
-
-/* Define if you have the `strtoll' function. */
-#undef HAVE_STRTOLL /* Allows ASCII compile on V5R1. */
-
/* Define if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H
@@ -234,9 +228,6 @@
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
-/* type to use in place of in_addr_t if not defined */
-#define in_addr_t unsigned long
-
/* Define to `unsigned' if <sys/types.h> does not define. */
#undef size_t
diff --git a/libs/libcurl/src/config-plan9.h b/libs/libcurl/src/config-plan9.h
index d93c8a03e5..191c7ce6e0 100644
--- a/libs/libcurl/src/config-plan9.h
+++ b/libs/libcurl/src/config-plan9.h
@@ -109,8 +109,6 @@
#define HAVE_STDBOOL_H 1
#define HAVE_STRCASECMP 1
#define HAVE_STRDUP 1
-#define HAVE_STRTOK_R 1
-#define HAVE_STRTOLL 1
#define HAVE_STRUCT_TIMEVAL 1
#define HAVE_SYS_IOCTL_H 1
#define HAVE_SYS_PARAM_H 1
diff --git a/libs/libcurl/src/config-riscos.h b/libs/libcurl/src/config-riscos.h
index 67ed83cf33..cb24c34f6d 100644
--- a/libs/libcurl/src/config-riscos.h
+++ b/libs/libcurl/src/config-riscos.h
@@ -138,12 +138,6 @@
/* Define if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
-/* Define if you have the `strtok_r' function. */
-#undef HAVE_STRTOK_R
-
-/* Define if you have the `strtoll' function. */
-#undef HAVE_STRTOLL
-
/* Define if you have the <sys/param.h> header file. */
#undef HAVE_SYS_PARAM_H
diff --git a/libs/libcurl/src/config-win32.h b/libs/libcurl/src/config-win32.h
index 7543604b37..3544a29557 100644
--- a/libs/libcurl/src/config-win32.h
+++ b/libs/libcurl/src/config-win32.h
@@ -35,15 +35,17 @@
/* Define if you have the <arpa/inet.h> header file. */
/* #define HAVE_ARPA_INET_H 1 */
+#ifndef UNDER_CE
+
/* Define if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
+#define HAVE_FCNTL_H 1 /* exists on __MINGW32CE__ */
/* Define if you have the <io.h> header file. */
-#define HAVE_IO_H 1
+#define HAVE_IO_H 1 /* exists on __MINGW32CE__ */
/* Define if you have the <locale.h> header file. */
-#ifndef UNDER_CE
#define HAVE_LOCALE_H 1
+
#endif
/* Define if you have the <netdb.h> header file. */
@@ -53,8 +55,15 @@
/* #define HAVE_NETINET_IN_H 1 */
/* Define to 1 if you have the <stdbool.h> header file. */
+#ifndef UNDER_CE
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__)
-#define HAVE_STDBOOL_H 1
+#define HAVE_STDBOOL_H 1 /* exists on __MINGW32CE__ */
+#endif
+#endif
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#if (defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(__MINGW32__)
+#define HAVE_STDINT_H 1
#endif
/* Define if you have the <sys/param.h> header file. */
@@ -109,8 +118,10 @@
#define STDC_HEADERS 1
/* Define to 1 if bool is an available type. */
+#ifndef UNDER_CE
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__)
-#define HAVE_BOOL_T 1
+#define HAVE_BOOL_T 1 /* exists on __MINGW32CE__ */
+#endif
#endif
/* ---------------------------------------------------------------- */
@@ -148,10 +159,6 @@
/* Define if you have the select function. */
#define HAVE_SELECT 1
-/* Define if libSSH2 is in use */
-#define USE_LIBSSH2 1
-#define HAVE_LIBSSH2_H 1
-
#ifndef UNDER_CE
/* Define if you have the setlocale function. */
#define HAVE_SETLOCALE 1
@@ -169,11 +176,6 @@
/* Define if you have the strdup function. */
#define HAVE_STRDUP 1
-/* Define if you have the strtoll function. */
-#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || defined(__MINGW32__)
-#define HAVE_STRTOLL 1
-#endif
-
/* Define if you have the utime function. */
#define HAVE_UTIME 1
@@ -234,11 +236,6 @@
#define HAVE_BASENAME 1
#endif
-/* Define to 1 if you have the strtok_r function. */
-#if defined(__MINGW32__) && !defined(__MINGW32CE__)
-#define HAVE_STRTOK_R 1
-#endif
-
/* Define to 1 if you have the signal function. */
#ifndef UNDER_CE
#define HAVE_SIGNAL 1
@@ -248,9 +245,6 @@
/* TYPEDEF REPLACEMENTS */
/* ---------------------------------------------------------------- */
-/* Define if in_addr_t is not an available 'typedefed' type. */
-#define in_addr_t unsigned long
-
/* Define if ssize_t is not an available 'typedefed' type. */
#ifndef _SSIZE_T_DEFINED
# ifdef __MINGW32__
@@ -300,13 +294,12 @@
/* #undef HAVE_GMTIME_R */
/* Define if the compiler supports the 'long long' data type. */
-#if (defined(_MSC_VER) && (_MSC_VER >= 1310)) || defined(__MINGW32__)
+#if defined(_MSC_VER) || defined(__MINGW32__)
#define HAVE_LONGLONG 1
#endif
-/* mingw-w64 and visual studio >= 2005 (MSVCR80)
- all default to 64-bit time_t unless _USE_32BIT_TIME_T is defined */
-#if (defined(_MSC_VER) && (_MSC_VER >= 1400)) || defined(__MINGW32__)
+/* Default to 64-bit time_t unless _USE_32BIT_TIME_T is defined */
+#if defined(_MSC_VER) || defined(__MINGW32__)
# ifndef _USE_32BIT_TIME_T
# define SIZEOF_TIME_T 8
# else
@@ -348,7 +341,7 @@
#endif
/* VS2008 default target settings and minimum build target check. */
-#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (_MSC_VER <= 1600)
+#if defined(_MSC_VER) && (_MSC_VER <= 1600)
# ifndef _WIN32_WINNT
# define _WIN32_WINNT VS2008_DEF_TARGET
# endif
@@ -406,8 +399,7 @@ Vista
#ifndef UNDER_CE
-/* _fseeki64() requires VS2005 */
-#if (defined(_MSC_VER) && (_MSC_VER >= 1400)) || defined(__MINGW32__)
+#if defined(_MSC_VER) || defined(__MINGW32__)
# define USE_WIN32_LARGE_FILES
/* Number of bits in a file offset, on hosts where this is settable. */
# ifdef __MINGW32__
@@ -461,9 +453,6 @@ Vista
#define USE_WIN32_LDAP 1
#endif
-/* if SSL is enabled */
-#define USE_OPENSSL 1
-
/* Define to use the Windows crypto library. */
#ifndef CURL_WINDOWS_UWP
#define USE_WIN32_CRYPTO
@@ -521,11 +510,9 @@ Vista
#define CURL_DISABLE_TELNET 1
#define CURL_DISABLE_LDAP 1
-#define ENOSPC 1
-#define ENOMEM 2
-#define EAGAIN 3
-
+#ifndef _MSC_VER
extern int stat(const char *path, struct stat *buffer);
+#endif
#endif /* UNDER_CE */
diff --git a/libs/libcurl/src/conncache.c b/libs/libcurl/src/conncache.c
index 15c932f7a5..5cc9fc88d2 100644
--- a/libs/libcurl/src/conncache.c
+++ b/libs/libcurl/src/conncache.c
@@ -32,7 +32,9 @@
#include "cfilters.h"
#include "progress.h"
#include "multiif.h"
+#include "multi_ev.h"
#include "sendf.h"
+#include "cshutdn.h"
#include "conncache.h"
#include "http_negotiate.h"
#include "http_ntlm.h"
@@ -41,6 +43,7 @@
#include "connect.h"
#include "select.h"
#include "strcase.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -50,24 +53,24 @@
#define CPOOL_IS_LOCKED(c) ((c) && (c)->locked)
-#define CPOOL_LOCK(c) \
+#define CPOOL_LOCK(c,d) \
do { \
if((c)) { \
if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
- Curl_share_lock(((c)->idata), CURL_LOCK_DATA_CONNECT, \
+ Curl_share_lock((d), CURL_LOCK_DATA_CONNECT, \
CURL_LOCK_ACCESS_SINGLE); \
DEBUGASSERT(!(c)->locked); \
(c)->locked = TRUE; \
} \
} while(0)
-#define CPOOL_UNLOCK(c) \
+#define CPOOL_UNLOCK(c,d) \
do { \
if((c)) { \
DEBUGASSERT((c)->locked); \
(c)->locked = FALSE; \
if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
- Curl_share_unlock((c)->idata, CURL_LOCK_DATA_CONNECT); \
+ Curl_share_unlock((d), CURL_LOCK_DATA_CONNECT); \
} \
} while(0)
@@ -84,35 +87,18 @@ static void cpool_discard_conn(struct cpool *cpool,
struct Curl_easy *data,
struct connectdata *conn,
bool aborted);
-static void cpool_close_and_destroy(struct cpool *cpool,
- struct connectdata *conn,
- struct Curl_easy *data,
- bool do_shutdown);
-static void cpool_run_conn_shutdown(struct Curl_easy *data,
- struct connectdata *conn,
- bool *done);
-static void cpool_run_conn_shutdown_handler(struct Curl_easy *data,
- struct connectdata *conn);
-static CURLMcode cpool_update_shutdown_ev(struct Curl_multi *multi,
- struct Curl_easy *data,
- struct connectdata *conn);
-static void cpool_shutdown_all(struct cpool *cpool,
- struct Curl_easy *data, int timeout_ms);
-static void cpool_close_and_destroy_all(struct cpool *cpool);
-static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool);
-static size_t cpool_shutdown_dest_count(struct cpool *cpool,
- const char *destination);
-
-static struct cpool_bundle *cpool_bundle_create(const char *dest,
- size_t dest_len)
+
+static struct cpool_bundle *cpool_bundle_create(const char *dest)
{
struct cpool_bundle *bundle;
+ size_t dest_len = strlen(dest);
+
bundle = calloc(1, sizeof(*bundle) + dest_len);
if(!bundle)
return NULL;
Curl_llist_init(&bundle->conns, NULL);
- bundle->dest_len = dest_len;
- memcpy(bundle->dest, dest, dest_len);
+ bundle->dest_len = dest_len + 1;
+ memcpy(bundle->dest, dest, bundle->dest_len);
return bundle;
}
@@ -147,56 +133,102 @@ static void cpool_bundle_free_entry(void *freethis)
}
int Curl_cpool_init(struct cpool *cpool,
- Curl_cpool_disconnect_cb *disconnect_cb,
- struct Curl_multi *multi,
- struct Curl_share *share,
- size_t size)
+ struct Curl_easy *idata,
+ struct Curl_share *share,
+ size_t size)
{
- DEBUGASSERT(!!multi != !!share); /* either one */
Curl_hash_init(&cpool->dest2bundle, size, Curl_hash_str,
Curl_str_key_compare, cpool_bundle_free_entry);
- Curl_llist_init(&cpool->shutdowns, NULL);
- DEBUGASSERT(disconnect_cb);
- if(!disconnect_cb)
- return 1;
+ DEBUGASSERT(idata);
- /* allocate a new easy handle to use when closing cached connections */
- cpool->idata = curl_easy_init();
- if(!cpool->idata)
- return 1; /* bad */
- cpool->idata->state.internal = TRUE;
- /* This is quirky. We need an internal handle for certain operations, but we
- * do not add it to the multi (if there is one). We give it the multi so
- * that socket event operations can work. Probably better to have an
- * internal handle owned by the multi that can be used for cpool
- * operations. */
- cpool->idata->multi = multi;
-#ifdef DEBUGBUILD
- if(getenv("CURL_DEBUG"))
- cpool->idata->set.verbose = TRUE;
-#endif
+ cpool->idata = idata;
+ cpool->share = share;
+ cpool->initialised = TRUE;
+ return 0; /* good */
+}
- cpool->disconnect_cb = disconnect_cb;
- cpool->idata->multi = cpool->multi = multi;
- cpool->idata->share = cpool->share = share;
+/* Return the "first" connection in the pool or NULL. */
+static struct connectdata *cpool_get_first(struct cpool *cpool)
+{
+ struct Curl_hash_iterator iter;
+ struct Curl_hash_element *he;
+ struct cpool_bundle *bundle;
+ struct Curl_llist_node *conn_node;
- return 0; /* good */
+ Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
+ for(he = Curl_hash_next_element(&iter); he;
+ he = Curl_hash_next_element(&iter)) {
+ bundle = he->ptr;
+ conn_node = Curl_llist_head(&bundle->conns);
+ if(conn_node)
+ return Curl_node_elem(conn_node);
+ }
+ return NULL;
+}
+
+
+static struct cpool_bundle *cpool_find_bundle(struct cpool *cpool,
+ struct connectdata *conn)
+{
+ return Curl_hash_pick(&cpool->dest2bundle,
+ conn->destination, strlen(conn->destination) + 1);
+}
+
+
+static void cpool_remove_bundle(struct cpool *cpool,
+ struct cpool_bundle *bundle)
+{
+ if(!cpool)
+ return;
+ Curl_hash_delete(&cpool->dest2bundle, bundle->dest, bundle->dest_len);
+}
+
+
+static void cpool_remove_conn(struct cpool *cpool,
+ struct connectdata *conn)
+{
+ struct Curl_llist *list = Curl_node_llist(&conn->cpool_node);
+ DEBUGASSERT(cpool);
+ if(list) {
+ /* The connection is certainly in the pool, but where? */
+ struct cpool_bundle *bundle = cpool_find_bundle(cpool, conn);
+ if(bundle && (list == &bundle->conns)) {
+ cpool_bundle_remove(bundle, conn);
+ if(!Curl_llist_count(&bundle->conns))
+ cpool_remove_bundle(cpool, bundle);
+ conn->bits.in_cpool = FALSE;
+ cpool->num_conn--;
+ }
+ else {
+ /* Should have been in the bundle list */
+ DEBUGASSERT(NULL);
+ }
+ }
}
void Curl_cpool_destroy(struct cpool *cpool)
{
- if(cpool) {
- if(cpool->idata) {
- cpool_close_and_destroy_all(cpool);
- /* The internal closure handle is special and we need to
- * disconnect it from multi/share before closing it down. */
- cpool->idata->multi = NULL;
- cpool->idata->share = NULL;
- Curl_close(&cpool->idata);
+ if(cpool && cpool->initialised && cpool->idata) {
+ struct connectdata *conn;
+ SIGPIPE_VARIABLE(pipe_st);
+
+ CURL_TRC_M(cpool->idata, "%s[CPOOL] destroy, %zu connections",
+ cpool->share ? "[SHARE] " : "", cpool->num_conn);
+ /* Move all connections to the shutdown list */
+ sigpipe_init(&pipe_st);
+ CPOOL_LOCK(cpool, cpool->idata);
+ conn = cpool_get_first(cpool);
+ while(conn) {
+ cpool_remove_conn(cpool, conn);
+ sigpipe_apply(cpool->idata, &pipe_st);
+ connclose(conn, "kill all");
+ cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
+ conn = cpool_get_first(cpool);
}
+ CPOOL_UNLOCK(cpool, cpool->idata);
+ sigpipe_restore(&pipe_st);
Curl_hash_destroy(&cpool->dest2bundle);
- cpool->multi = NULL;
}
}
@@ -219,23 +251,14 @@ void Curl_cpool_xfer_init(struct Curl_easy *data)
DEBUGASSERT(cpool);
if(cpool) {
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, data);
/* the identifier inside the connection cache */
data->id = cpool->next_easy_id++;
if(cpool->next_easy_id <= 0)
cpool->next_easy_id = 0;
data->state.lastconnect_id = -1;
- /* The closure handle only ever has default timeouts set. To improve the
- state somewhat we clone the timeouts from each added handle so that the
- closure handle always has the same timeouts as the most recently added
- easy handle. */
- cpool->idata->set.timeout = data->set.timeout;
- cpool->idata->set.server_response_timeout =
- data->set.server_response_timeout;
- cpool->idata->set.no_signal = data->set.no_signal;
-
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, data);
}
else {
/* We should not get here, but in a non-debug build, do something */
@@ -244,19 +267,12 @@ void Curl_cpool_xfer_init(struct Curl_easy *data)
}
}
-static struct cpool_bundle *cpool_find_bundle(struct cpool *cpool,
- struct connectdata *conn)
-{
- return Curl_hash_pick(&cpool->dest2bundle,
- conn->destination, conn->destination_len);
-}
-
static struct cpool_bundle *
cpool_add_bundle(struct cpool *cpool, struct connectdata *conn)
{
struct cpool_bundle *bundle;
- bundle = cpool_bundle_create(conn->destination, conn->destination_len);
+ bundle = cpool_bundle_create(conn->destination);
if(!bundle)
return NULL;
@@ -268,17 +284,70 @@ cpool_add_bundle(struct cpool *cpool, struct connectdata *conn)
return bundle;
}
-static void cpool_remove_bundle(struct cpool *cpool,
- struct cpool_bundle *bundle)
+static struct connectdata *
+cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle)
{
- if(!cpool)
- return;
+ struct Curl_llist_node *curr;
+ timediff_t highscore = -1;
+ timediff_t score;
+ struct curltime now;
+ struct connectdata *oldest_idle = NULL;
+ struct connectdata *conn;
- Curl_hash_delete(&cpool->dest2bundle, bundle->dest, bundle->dest_len);
+ now = Curl_now();
+ curr = Curl_llist_head(&bundle->conns);
+ while(curr) {
+ conn = Curl_node_elem(curr);
+
+ if(!CONN_INUSE(conn)) {
+ /* Set higher score for the age passed since the connection was used */
+ score = Curl_timediff(now, conn->lastused);
+
+ if(score > highscore) {
+ highscore = score;
+ oldest_idle = conn;
+ }
+ }
+ curr = Curl_node_next(curr);
+ }
+ return oldest_idle;
+}
+
+static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool)
+{
+ struct Curl_hash_iterator iter;
+ struct Curl_llist_node *curr;
+ struct Curl_hash_element *he;
+ struct connectdata *oldest_idle = NULL;
+ struct cpool_bundle *bundle;
+ struct curltime now;
+ timediff_t highscore =- 1;
+ timediff_t score;
+
+ now = Curl_now();
+ Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
+
+ for(he = Curl_hash_next_element(&iter); he;
+ he = Curl_hash_next_element(&iter)) {
+ struct connectdata *conn;
+ bundle = he->ptr;
+
+ for(curr = Curl_llist_head(&bundle->conns); curr;
+ curr = Curl_node_next(curr)) {
+ conn = Curl_node_elem(curr);
+ if(CONN_INUSE(conn) || conn->bits.close || conn->connect_only)
+ continue;
+ /* Set higher score for the age passed since the connection was used */
+ score = Curl_timediff(now, conn->lastused);
+ if(score > highscore) {
+ highscore = score;
+ oldest_idle = conn;
+ }
+ }
+ }
+ return oldest_idle;
}
-static struct connectdata *
-cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle);
int Curl_cpool_check_limits(struct Curl_easy *data,
struct connectdata *conn)
@@ -293,21 +362,21 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!cpool)
return CPOOL_LIMIT_OK;
- if(data && data->multi) {
- dest_limit = data->multi->max_host_connections;
- total_limit = data->multi->max_total_connections;
+ if(cpool->idata->multi) {
+ dest_limit = cpool->idata->multi->max_host_connections;
+ total_limit = cpool->idata->multi->max_total_connections;
}
if(!dest_limit && !total_limit)
return CPOOL_LIMIT_OK;
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, cpool->idata);
if(dest_limit) {
size_t live;
bundle = cpool_find_bundle(cpool, conn);
live = bundle ? Curl_llist_count(&bundle->conns) : 0;
- shutdowns = cpool_shutdown_dest_count(cpool, conn->destination);
+ shutdowns = Curl_cshutdn_dest_count(data, conn->destination);
while(!shutdowns && bundle && live >= dest_limit) {
struct connectdata *oldest_idle = NULL;
/* The bundle is full. Extract the oldest connection that may
@@ -316,16 +385,16 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
- DEBUGF(infof(data, "Discarding connection #%"
+ CURL_TRC_M(data, "Discarding connection #%"
FMT_OFF_T " from %zu to reach destination "
"limit of %zu", oldest_idle->connection_id,
- Curl_llist_count(&bundle->conns), dest_limit));
- Curl_cpool_disconnect(data, oldest_idle, FALSE);
+ Curl_llist_count(&bundle->conns), dest_limit);
+ Curl_conn_terminate(cpool->idata, oldest_idle, FALSE);
/* in case the bundle was destroyed in disconnect, look it up again */
bundle = cpool_find_bundle(cpool, conn);
live = bundle ? Curl_llist_count(&bundle->conns) : 0;
- shutdowns = cpool_shutdown_dest_count(cpool, conn->destination);
+ shutdowns = Curl_cshutdn_dest_count(cpool->idata, conn->destination);
}
if((live + shutdowns) >= dest_limit) {
result = CPOOL_LIMIT_DEST;
@@ -334,18 +403,18 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
}
if(total_limit) {
- shutdowns = Curl_llist_count(&cpool->shutdowns);
+ shutdowns = Curl_cshutdn_count(cpool->idata);
while((cpool->num_conn + shutdowns) >= total_limit) {
struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool);
if(!oldest_idle)
break;
/* disconnect the old conn and continue */
- DEBUGF(infof(data, "Discarding connection #%"
- FMT_OFF_T " from %zu to reach total "
- "limit of %zu",
- oldest_idle->connection_id, cpool->num_conn, total_limit));
- Curl_cpool_disconnect(data, oldest_idle, FALSE);
- shutdowns = Curl_llist_count(&cpool->shutdowns);
+ CURL_TRC_M(data, "Discarding connection #%"
+ FMT_OFF_T " from %zu to reach total "
+ "limit of %zu",
+ oldest_idle->connection_id, cpool->num_conn, total_limit);
+ Curl_conn_terminate(cpool->idata, oldest_idle, FALSE);
+ shutdowns = Curl_cshutdn_count(cpool->idata);
}
if((cpool->num_conn + shutdowns) >= total_limit) {
result = CPOOL_LIMIT_TOTAL;
@@ -354,12 +423,12 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
}
out:
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, cpool->idata);
return result;
}
-CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
- struct connectdata *conn)
+CURLcode Curl_cpool_add(struct Curl_easy *data,
+ struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct cpool_bundle *bundle = NULL;
@@ -370,7 +439,7 @@ CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
if(!cpool)
return CURLE_FAILED_INIT;
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, data);
bundle = cpool_find_bundle(cpool, conn);
if(!bundle) {
bundle = cpool_add_bundle(cpool, conn);
@@ -383,38 +452,15 @@ CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
cpool_bundle_add(bundle, conn);
conn->connection_id = cpool->next_connection_id++;
cpool->num_conn++;
- DEBUGF(infof(data, "Added connection %" FMT_OFF_T ". "
- "The cache now contains %zu members",
- conn->connection_id,
- cpool->num_conn + Curl_llist_count(&cpool->shutdowns)));
+ CURL_TRC_M(data, "[CPOOL] added connection %" FMT_OFF_T ". "
+ "The cache now contains %zu members",
+ conn->connection_id, cpool->num_conn);
out:
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, data);
return result;
}
-static void cpool_remove_conn(struct cpool *cpool,
- struct connectdata *conn)
-{
- struct Curl_llist *list = Curl_node_llist(&conn->cpool_node);
- DEBUGASSERT(cpool);
- if(list) {
- /* The connection is certainly in the pool, but where? */
- struct cpool_bundle *bundle = cpool_find_bundle(cpool, conn);
- if(bundle && (list == &bundle->conns)) {
- cpool_bundle_remove(bundle, conn);
- if(!Curl_llist_count(&bundle->conns))
- cpool_remove_bundle(cpool, bundle);
- conn->bits.in_cpool = FALSE;
- cpool->num_conn--;
- }
- else {
- /* Not in a bundle, already in the shutdown list? */
- DEBUGASSERT(list == &cpool->shutdowns);
- }
- }
-}
-
/* This function iterates the entire connection pool and calls the function
func() with the connection pointer as the first argument and the supplied
'param' argument as the other.
@@ -462,25 +508,6 @@ static bool cpool_foreach(struct Curl_easy *data,
return FALSE;
}
-/* Return a live connection in the pool or NULL. */
-static struct connectdata *cpool_get_live_conn(struct cpool *cpool)
-{
- struct Curl_hash_iterator iter;
- struct Curl_hash_element *he;
- struct cpool_bundle *bundle;
- struct Curl_llist_node *conn_node;
-
- Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
- for(he = Curl_hash_next_element(&iter); he;
- he = Curl_hash_next_element(&iter)) {
- bundle = he->ptr;
- conn_node = Curl_llist_head(&bundle->conns);
- if(conn_node)
- return Curl_node_elem(conn_node);
- }
- return NULL;
-}
-
/*
* A connection (already in the pool) has become idle. Do any
* cleanups in regard to the pool's limits.
@@ -501,93 +528,26 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
/* may be called form a callback already under lock */
bool do_lock = !CPOOL_IS_LOCKED(cpool);
if(do_lock)
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, data);
if(cpool->num_conn > maxconnects) {
- infof(data, "Connection pool is full, closing the oldest one");
+ infof(data, "Connection pool is full, closing the oldest of %zu/%u",
+ cpool->num_conn, maxconnects);
oldest_idle = cpool_get_oldest_idle(cpool);
kept = (oldest_idle != conn);
if(oldest_idle) {
- Curl_cpool_disconnect(cpool->idata, oldest_idle, FALSE);
+ Curl_conn_terminate(data, oldest_idle, FALSE);
}
}
if(do_lock)
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, data);
}
return kept;
}
-/*
- * This function finds the connection in the connection bundle that has been
- * unused for the longest time.
- */
-static struct connectdata *
-cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle)
-{
- struct Curl_llist_node *curr;
- timediff_t highscore = -1;
- timediff_t score;
- struct curltime now;
- struct connectdata *oldest_idle = NULL;
- struct connectdata *conn;
-
- now = Curl_now();
- curr = Curl_llist_head(&bundle->conns);
- while(curr) {
- conn = Curl_node_elem(curr);
-
- if(!CONN_INUSE(conn)) {
- /* Set higher score for the age passed since the connection was used */
- score = Curl_timediff(now, conn->lastused);
-
- if(score > highscore) {
- highscore = score;
- oldest_idle = conn;
- }
- }
- curr = Curl_node_next(curr);
- }
- return oldest_idle;
-}
-
-static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool)
-{
- struct Curl_hash_iterator iter;
- struct Curl_llist_node *curr;
- struct Curl_hash_element *he;
- struct connectdata *oldest_idle = NULL;
- struct cpool_bundle *bundle;
- struct curltime now;
- timediff_t highscore =- 1;
- timediff_t score;
-
- now = Curl_now();
- Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
-
- for(he = Curl_hash_next_element(&iter); he;
- he = Curl_hash_next_element(&iter)) {
- struct connectdata *conn;
- bundle = he->ptr;
-
- for(curr = Curl_llist_head(&bundle->conns); curr;
- curr = Curl_node_next(curr)) {
- conn = Curl_node_elem(curr);
- if(CONN_INUSE(conn) || conn->bits.close || conn->connect_only)
- continue;
- /* Set higher score for the age passed since the connection was used */
- score = Curl_timediff(now, conn->lastused);
- if(score > highscore) {
- highscore = score;
- oldest_idle = conn;
- }
- }
- }
- return oldest_idle;
-}
-
bool Curl_cpool_find(struct Curl_easy *data,
- const char *destination, size_t dest_len,
+ const char *destination,
Curl_cpool_conn_match_cb *conn_cb,
Curl_cpool_done_match_cb *done_cb,
void *userdata)
@@ -601,8 +561,10 @@ bool Curl_cpool_find(struct Curl_easy *data,
if(!cpool)
return FALSE;
- CPOOL_LOCK(cpool);
- bundle = Curl_hash_pick(&cpool->dest2bundle, (void *)destination, dest_len);
+ CPOOL_LOCK(cpool, data);
+ bundle = Curl_hash_pick(&cpool->dest2bundle,
+ CURL_UNCONST(destination),
+ strlen(destination) + 1);
if(bundle) {
struct Curl_llist_node *curr = Curl_llist_head(&bundle->conns);
while(curr) {
@@ -620,104 +582,10 @@ bool Curl_cpool_find(struct Curl_easy *data,
if(done_cb) {
result = done_cb(result, userdata);
}
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, data);
return result;
}
-/* How many connections to the given destination are in shutdown? */
-static size_t cpool_shutdown_dest_count(struct cpool *cpool,
- const char *destination)
-{
- size_t n = 0;
- struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
- while(e) {
- struct connectdata *conn = Curl_node_elem(e);
- if(!strcmp(destination, conn->destination))
- ++n;
- e = Curl_node_next(e);
- }
- return n;
-}
-
-static void cpool_shutdown_discard_all(struct cpool *cpool)
-{
- struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
- struct connectdata *conn;
-
- if(!e)
- return;
-
- DEBUGF(infof(cpool->idata, "cpool_shutdown_discard_all"));
- while(e) {
- conn = Curl_node_elem(e);
- Curl_node_remove(e);
- DEBUGF(infof(cpool->idata, "discard connection #%" FMT_OFF_T,
- conn->connection_id));
- cpool_close_and_destroy(cpool, conn, NULL, FALSE);
- e = Curl_llist_head(&cpool->shutdowns);
- }
-}
-
-static void cpool_close_and_destroy_all(struct cpool *cpool)
-{
- struct connectdata *conn;
- int timeout_ms = 0;
- SIGPIPE_VARIABLE(pipe_st);
-
- DEBUGASSERT(cpool);
- /* Move all connections to the shutdown list */
- sigpipe_init(&pipe_st);
- CPOOL_LOCK(cpool);
- conn = cpool_get_live_conn(cpool);
- while(conn) {
- cpool_remove_conn(cpool, conn);
- sigpipe_apply(cpool->idata, &pipe_st);
- connclose(conn, "kill all");
- cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
-
- conn = cpool_get_live_conn(cpool);
- }
- CPOOL_UNLOCK(cpool);
-
- /* 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
- sigpipe_apply(cpool->idata, &pipe_st);
- cpool_shutdown_all(cpool, cpool->idata, timeout_ms);
-
- /* discard all connections in the shutdown list */
- cpool_shutdown_discard_all(cpool);
-
- Curl_hostcache_clean(cpool->idata, cpool->idata->dns.hostcache);
- sigpipe_restore(&pipe_st);
-}
-
-
-static void cpool_shutdown_destroy_oldest(struct cpool *cpool)
-{
- struct Curl_llist_node *e;
- struct connectdata *conn;
-
- e = Curl_llist_head(&cpool->shutdowns);
- if(e) {
- SIGPIPE_VARIABLE(pipe_st);
- conn = Curl_node_elem(e);
- Curl_node_remove(e);
- sigpipe_init(&pipe_st);
- sigpipe_apply(cpool->idata, &pipe_st);
- cpool_close_and_destroy(cpool, conn, NULL, FALSE);
- sigpipe_restore(&pipe_st);
- }
-}
-
static void cpool_discard_conn(struct cpool *cpool,
struct Curl_easy *data,
struct connectdata *conn,
@@ -726,6 +594,7 @@ static void cpool_discard_conn(struct cpool *cpool,
bool done = FALSE;
DEBUGASSERT(data);
+ DEBUGASSERT(!data->conn);
DEBUGASSERT(cpool);
DEBUGASSERT(!conn->bits.in_cpool);
@@ -734,9 +603,9 @@ static void cpool_discard_conn(struct cpool *cpool,
* are other users of it
*/
if(CONN_INUSE(conn) && !aborted) {
- DEBUGF(infof(data, "[CCACHE] not discarding #%" FMT_OFF_T
- " still in use by %zu transfers", conn->connection_id,
- CONN_INUSE(conn)));
+ CURL_TRC_M(data, "[CPOOL] not discarding #%" FMT_OFF_T
+ " still in use by %zu transfers", conn->connection_id,
+ CONN_INUSE(conn));
return;
}
@@ -755,52 +624,18 @@ static void cpool_discard_conn(struct cpool *cpool,
done = TRUE;
if(!done) {
/* Attempt to shutdown the connection right away. */
- Curl_attach_connection(data, conn);
- cpool_run_conn_shutdown(data, conn, &done);
- DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
- conn->connection_id, done));
- Curl_detach_connection(data);
- }
-
- if(done) {
- cpool_close_and_destroy(cpool, conn, data, FALSE);
- return;
+ Curl_cshutdn_run_once(cpool->idata, conn, &done);
}
- /* Add the connection to our shutdown list for non-blocking shutdown
- * during multi processing. */
- if(data->multi && data->multi->max_total_connections > 0 &&
- (data->multi->max_total_connections <=
- (long)(cpool->num_conn + Curl_llist_count(&cpool->shutdowns)))) {
- DEBUGF(infof(data, "[CCACHE] discarding oldest shutdown connection "
- "due to connection limit of %ld",
- data->multi->max_total_connections));
- cpool_shutdown_destroy_oldest(cpool);
- }
-
- if(data->multi && data->multi->socket_cb) {
- DEBUGASSERT(cpool == &data->multi->cpool);
- /* 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(cpool_update_shutdown_ev(data->multi, cpool->idata, conn)) {
- DEBUGF(infof(data, "[CCACHE] update events for shutdown failed, "
- "discarding #%" FMT_OFF_T,
- conn->connection_id));
- cpool_close_and_destroy(cpool, conn, data, FALSE);
- return;
- }
- }
-
- Curl_llist_append(&cpool->shutdowns, conn, &conn->cpool_node);
- DEBUGF(infof(data, "[CCACHE] added #%" FMT_OFF_T
- " to shutdowns, now %zu conns in shutdown",
- conn->connection_id, Curl_llist_count(&cpool->shutdowns)));
+ if(done || !data->multi)
+ Curl_cshutdn_terminate(cpool->idata, conn, FALSE);
+ else
+ Curl_cshutdn_add(&data->multi->cshutdn, conn, cpool->num_conn);
}
-void Curl_cpool_disconnect(struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted)
+void Curl_conn_terminate(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool aborted)
{
struct cpool *cpool = cpool_get_instance(data);
bool do_lock;
@@ -822,15 +657,17 @@ void Curl_cpool_disconnect(struct Curl_easy *data,
* user callback in find. */
do_lock = !CPOOL_IS_LOCKED(cpool);
if(do_lock)
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, data);
if(conn->bits.in_cpool) {
cpool_remove_conn(cpool, conn);
DEBUGASSERT(!conn->bits.in_cpool);
}
- /* Run the callback to let it clean up anything it wants to. */
- aborted = cpool->disconnect_cb(data, conn, aborted);
+ /* treat the connection as aborted in CONNECT_ONLY situations,
+ * so no graceful shutdown is attempted. */
+ if(conn->connect_only)
+ aborted = TRUE;
if(data->multi) {
/* Add it to the multi's cpool for shutdown handling */
@@ -839,419 +676,15 @@ void Curl_cpool_disconnect(struct Curl_easy *data,
cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
}
else {
- /* No multi available. Make a best-effort shutdown + close */
+ /* No multi available, terminate */
infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id);
- cpool_close_and_destroy(NULL, conn, data, !aborted);
+ Curl_cshutdn_terminate(cpool->idata, conn, !aborted);
}
if(do_lock)
- CPOOL_UNLOCK(cpool);
-}
-
-static void cpool_run_conn_shutdown_handler(struct Curl_easy *data,
- struct connectdata *conn)
-{
- if(!conn->bits.shutdown_handler) {
- if(conn->dns_entry)
- Curl_resolv_unlink(data, &conn->dns_entry);
-
- /* 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 #%" FMT_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;
- }
+ CPOOL_UNLOCK(cpool, data);
}
-static void cpool_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);
-
- cpool_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;
-}
-
-static CURLcode cpool_add_pollfds(struct cpool *cpool,
- struct curl_pollfds *cpfds)
-{
- CURLcode result = CURLE_OK;
-
- if(Curl_llist_head(&cpool->shutdowns)) {
- struct Curl_llist_node *e;
- struct easy_pollset ps;
- struct connectdata *conn;
-
- for(e = Curl_llist_head(&cpool->shutdowns); e;
- e = Curl_node_next(e)) {
- conn = Curl_node_elem(e);
- memset(&ps, 0, sizeof(ps));
- Curl_attach_connection(cpool->idata, conn);
- Curl_conn_adjust_pollset(cpool->idata, &ps);
- Curl_detach_connection(cpool->idata);
-
- result = Curl_pollfds_add_ps(cpfds, &ps);
- if(result) {
- Curl_pollfds_cleanup(cpfds);
- goto out;
- }
- }
- }
-out:
- return result;
-}
-
-CURLcode Curl_cpool_add_pollfds(struct cpool *cpool,
- struct curl_pollfds *cpfds)
-{
- CURLcode result;
- CPOOL_LOCK(cpool);
- result = cpool_add_pollfds(cpool, cpfds);
- CPOOL_UNLOCK(cpool);
- return result;
-}
-
-/* return information about the shutdown connections */
-unsigned int Curl_cpool_add_waitfds(struct cpool *cpool,
- struct Curl_waitfds *cwfds)
-{
- unsigned int need = 0;
-
- CPOOL_LOCK(cpool);
- if(Curl_llist_head(&cpool->shutdowns)) {
- struct Curl_llist_node *e;
- struct easy_pollset ps;
- struct connectdata *conn;
-
- for(e = Curl_llist_head(&cpool->shutdowns); e;
- e = Curl_node_next(e)) {
- conn = Curl_node_elem(e);
- memset(&ps, 0, sizeof(ps));
- Curl_attach_connection(cpool->idata, conn);
- Curl_conn_adjust_pollset(cpool->idata, &ps);
- Curl_detach_connection(cpool->idata);
-
- need += Curl_waitfds_add_ps(cwfds, &ps);
- }
- }
- CPOOL_UNLOCK(cpool);
- return need;
-}
-
-/* return fd_set info about the shutdown connections */
-void Curl_cpool_setfds(struct cpool *cpool,
- fd_set *read_fd_set, fd_set *write_fd_set,
- int *maxfd)
-{
- CPOOL_LOCK(cpool);
- if(Curl_llist_head(&cpool->shutdowns)) {
- struct Curl_llist_node *e;
-
- for(e = Curl_llist_head(&cpool->shutdowns); e;
- e = Curl_node_next(e)) {
- struct easy_pollset ps;
- unsigned int i;
- struct connectdata *conn = Curl_node_elem(e);
- memset(&ps, 0, sizeof(ps));
- Curl_attach_connection(cpool->idata, conn);
- Curl_conn_adjust_pollset(cpool->idata, &ps);
- Curl_detach_connection(cpool->idata);
-
- for(i = 0; i < ps.num; i++) {
-#if defined(__DJGPP__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warith-conversion"
-#endif
- 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 defined(__DJGPP__)
-#pragma GCC diagnostic pop
-#endif
- if((ps.actions[i] & (CURL_POLL_OUT | CURL_POLL_IN)) &&
- ((int)ps.sockets[i] > *maxfd))
- *maxfd = (int)ps.sockets[i];
- }
- }
- }
- CPOOL_UNLOCK(cpool);
-}
-
-static void cpool_perform(struct cpool *cpool)
-{
- struct Curl_easy *data = cpool->idata;
- struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
- struct Curl_llist_node *enext;
- struct connectdata *conn;
- struct curltime *nowp = NULL;
- struct curltime now;
- timediff_t next_from_now_ms = 0, ms;
- bool done;
-
- if(!e)
- return;
-
- DEBUGASSERT(data);
- DEBUGF(infof(data, "[CCACHE] perform, %zu connections being shutdown",
- Curl_llist_count(&cpool->shutdowns)));
- while(e) {
- enext = Curl_node_next(e);
- conn = Curl_node_elem(e);
- Curl_attach_connection(data, conn);
- cpool_run_conn_shutdown(data, conn, &done);
- DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
- conn->connection_id, done));
- Curl_detach_connection(data);
- if(done) {
- Curl_node_remove(e);
- cpool_close_and_destroy(cpool, conn, NULL, FALSE);
- }
- else {
- /* Not done, when does this connection time out? */
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
- }
- ms = Curl_conn_shutdown_timeleft(conn, nowp);
- if(ms && ms < next_from_now_ms)
- next_from_now_ms = ms;
- }
- e = enext;
- }
-
- if(next_from_now_ms)
- Curl_expire(data, next_from_now_ms, EXPIRE_RUN_NOW);
-}
-
-void Curl_cpool_multi_perform(struct Curl_multi *multi)
-{
- CPOOL_LOCK(&multi->cpool);
- cpool_perform(&multi->cpool);
- CPOOL_UNLOCK(&multi->cpool);
-}
-
-
-/*
- * Close and destroy the connection. Run the shutdown sequence once,
- * of so requested.
- */
-static void cpool_close_and_destroy(struct cpool *cpool,
- struct connectdata *conn,
- struct Curl_easy *data,
- bool do_shutdown)
-{
- bool done;
-
- /* there must be a connection to close */
- DEBUGASSERT(conn);
- /* it must be removed from the connection pool */
- DEBUGASSERT(!conn->bits.in_cpool);
- /* there must be an associated transfer */
- DEBUGASSERT(data || cpool);
- if(!data)
- data = cpool->idata;
-
- /* the transfer must be detached from the connection */
- DEBUGASSERT(data && !data->conn);
-
- Curl_attach_connection(data, conn);
-
- cpool_run_conn_shutdown_handler(data, conn);
- if(do_shutdown) {
- /* Make a last attempt to shutdown handlers and filters, if
- * not done so already. */
- cpool_run_conn_shutdown(data, conn, &done);
- }
-
- if(cpool)
- DEBUGF(infof(data, "[CCACHE] closing #%" FMT_OFF_T,
- conn->connection_id));
- else
- DEBUGF(infof(data, "closing connection #%" FMT_OFF_T,
- conn->connection_id));
- Curl_conn_close(data, SECONDARYSOCKET);
- Curl_conn_close(data, FIRSTSOCKET);
- Curl_detach_connection(data);
-
- Curl_conn_free(data, conn);
-
- if(cpool && cpool->multi) {
- DEBUGF(infof(data, "[CCACHE] trigger multi connchanged"));
- Curl_multi_connchanged(cpool->multi);
- }
-}
-
-
-static CURLMcode cpool_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_cpool_multi_socket(struct Curl_multi *multi,
- curl_socket_t s, int ev_bitmask)
-{
- struct cpool *cpool = &multi->cpool;
- struct Curl_easy *data = cpool->idata;
- struct Curl_llist_node *e;
- struct connectdata *conn;
- bool done;
-
- (void)ev_bitmask;
- DEBUGASSERT(multi->socket_cb);
- CPOOL_LOCK(cpool);
- e = Curl_llist_head(&cpool->shutdowns);
- while(e) {
- conn = Curl_node_elem(e);
- if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
- Curl_attach_connection(data, conn);
- cpool_run_conn_shutdown(data, conn, &done);
- DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
- conn->connection_id, done));
- Curl_detach_connection(data);
- if(done || cpool_update_shutdown_ev(multi, data, conn)) {
- Curl_node_remove(e);
- cpool_close_and_destroy(cpool, conn, NULL, FALSE);
- }
- break;
- }
- e = Curl_node_next(e);
- }
- CPOOL_UNLOCK(cpool);
-}
-
-#define NUM_POLLS_ON_STACK 10
-
-static CURLcode cpool_shutdown_wait(struct cpool *cpool, 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 = cpool_add_pollfds(cpool, &cpfds);
- if(result)
- goto out;
-
- Curl_poll(cpfds.pfds, cpfds.n, CURLMIN(timeout_ms, 1000));
-
-out:
- Curl_pollfds_cleanup(&cpfds);
- return result;
-}
-
-static void cpool_shutdown_all(struct cpool *cpool,
- struct Curl_easy *data, int timeout_ms)
-{
- struct connectdata *conn;
- struct curltime started = Curl_now();
-
- if(!data)
- return;
- (void)data;
-
- DEBUGF(infof(data, "cpool shutdown all"));
-
- /* Move all connections into the shutdown queue */
- for(conn = cpool_get_live_conn(cpool); conn;
- conn = cpool_get_live_conn(cpool)) {
- /* Move conn from live set to shutdown or destroy right away */
- DEBUGF(infof(data, "moving connection #%" FMT_OFF_T
- " to shutdown queue", conn->connection_id));
- cpool_remove_conn(cpool, conn);
- cpool_discard_conn(cpool, data, conn, FALSE);
- }
-
- while(Curl_llist_head(&cpool->shutdowns)) {
- timediff_t timespent;
- int remain_ms;
-
- cpool_perform(cpool);
-
- if(!Curl_llist_head(&cpool->shutdowns)) {
- DEBUGF(infof(data, "cpool shutdown ok"));
- break;
- }
-
- /* wait for activity, timeout or "nothing" */
- timespent = Curl_timediff(Curl_now(), started);
- if(timespent >= (timediff_t)timeout_ms) {
- DEBUGF(infof(data, "cpool shutdown %s",
- (timeout_ms > 0) ? "timeout" : "best effort done"));
- break;
- }
-
- remain_ms = timeout_ms - (int)timespent;
- if(cpool_shutdown_wait(cpool, remain_ms)) {
- DEBUGF(infof(data, "cpool shutdown all, abort"));
- break;
- }
- }
-
- /* Due to errors/timeout, we might come here without being done. */
- cpool_shutdown_discard_all(cpool);
-}
struct cpool_reaper_ctx {
struct curltime now;
@@ -1263,7 +696,7 @@ static int cpool_reap_dead_cb(struct Curl_easy *data,
struct cpool_reaper_ctx *rctx = param;
if(Curl_conn_seems_dead(conn, data, &rctx->now)) {
/* stop the iteration here, pass back the connection that was pruned */
- Curl_cpool_disconnect(data, conn, FALSE);
+ Curl_conn_terminate(data, conn, FALSE);
return 1;
}
return 0; /* continue iteration */
@@ -1286,7 +719,7 @@ void Curl_cpool_prune_dead(struct Curl_easy *data)
return;
rctx.now = Curl_now();
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, data);
elapsed = Curl_timediff(rctx.now, cpool->last_cleanup);
if(elapsed >= 1000L) {
@@ -1294,7 +727,7 @@ void Curl_cpool_prune_dead(struct Curl_easy *data)
;
cpool->last_cleanup = rctx.now;
}
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, data);
}
static int conn_upkeep(struct Curl_easy *data,
@@ -1314,9 +747,9 @@ CURLcode Curl_cpool_upkeep(void *data)
if(!cpool)
return CURLE_OK;
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, data);
cpool_foreach(data, cpool, &now, conn_upkeep);
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, data);
return CURLE_OK;
}
@@ -1347,9 +780,9 @@ struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
return NULL;
fctx.id = conn_id;
fctx.conn = NULL;
- CPOOL_LOCK(cpool);
- cpool_foreach(cpool->idata, cpool, &fctx, cpool_find_conn);
- CPOOL_UNLOCK(cpool);
+ CPOOL_LOCK(cpool, data);
+ cpool_foreach(data, cpool, &fctx, cpool_find_conn);
+ CPOOL_UNLOCK(cpool, data);
return fctx.conn;
}
@@ -1382,9 +815,9 @@ void Curl_cpool_do_by_id(struct Curl_easy *data, curl_off_t conn_id,
dctx.id = conn_id;
dctx.cb = cb;
dctx.cbdata = cbdata;
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, data);
cpool_foreach(data, cpool, &dctx, cpool_do_conn);
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, data);
}
void Curl_cpool_do_locked(struct Curl_easy *data,
@@ -1393,9 +826,9 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
{
struct cpool *cpool = cpool_get_instance(data);
if(cpool) {
- CPOOL_LOCK(cpool);
+ CPOOL_LOCK(cpool, data);
cb(conn, data, cbdata);
- CPOOL_UNLOCK(cpool);
+ CPOOL_UNLOCK(cpool, data);
}
else
cb(conn, data, cbdata);
diff --git a/libs/libcurl/src/conncache.h b/libs/libcurl/src/conncache.h
index ab3a1828ba..e900e786fa 100644
--- a/libs/libcurl/src/conncache.h
+++ b/libs/libcurl/src/conncache.h
@@ -36,16 +36,17 @@ struct Curl_multi;
struct Curl_share;
/**
- * Callback invoked when disconnecting connections.
- * @param data transfer last handling the connection, not attached
- * @param conn the connection to discard
- * @param aborted if the connection is being aborted
- * @return if the connection is being aborted, e.g. should NOT perform
- * a shutdown and just close.
- **/
-typedef bool Curl_cpool_disconnect_cb(struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted);
+ * Terminate the connection, e.g. close and destroy.
+ * If the connection is in a cpool, remove it.
+ * If a `cshutdn` is available (e.g. data has a multi handle),
+ * pass the connection to that for controlled shutdown.
+ * Otherwise terminate it right away.
+ * Takes ownership of `conn`.
+ * `data` should not be attached to a connection.
+ */
+void Curl_conn_terminate(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool aborted);
struct cpool {
/* the pooled connections, bundled per destination */
@@ -54,20 +55,17 @@ struct cpool {
curl_off_t next_connection_id;
curl_off_t next_easy_id;
struct curltime last_cleanup;
- struct Curl_llist shutdowns; /* The connections being shut down */
- struct Curl_easy *idata; /* internal handle used for discard */
- struct Curl_multi *multi; /* != NULL iff pool belongs to multi */
- struct Curl_share *share; /* != NULL iff pool belongs to share */
- Curl_cpool_disconnect_cb *disconnect_cb;
+ struct Curl_easy *idata; /* internal handle for maintenance */
+ struct Curl_share *share; /* != NULL if pool belongs to share */
BIT(locked);
+ BIT(initialised);
};
/* Init the pool, pass multi only if pool is owned by it.
* returns 1 on error, 0 is fine.
*/
int Curl_cpool_init(struct cpool *cpool,
- Curl_cpool_disconnect_cb *disconnect_cb,
- struct Curl_multi *multi,
+ struct Curl_easy *idata,
struct Curl_share *share,
size_t size);
@@ -78,14 +76,13 @@ void Curl_cpool_destroy(struct cpool *connc);
* Assigns `data->id`. */
void Curl_cpool_xfer_init(struct Curl_easy *data);
-/**
- * Get the connection with the given id from the transfer's pool.
- */
+/* Get the connection with the given id from `data`'s conn pool. */
struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
curl_off_t conn_id);
-CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
- struct connectdata *conn) WARN_UNUSED_RESULT;
+/* Add the connection to the pool. */
+CURLcode Curl_cpool_add(struct Curl_easy *data,
+ struct connectdata *conn) WARN_UNUSED_RESULT;
/**
* Return if the pool has reached its configured limits for adding
@@ -110,14 +107,13 @@ typedef bool Curl_cpool_done_match_cb(bool result, void *userdata);
* All callbacks are invoked while the pool's lock is held.
* @param data current transfer
* @param destination match agaonst `conn->destination` in pool
- * @param dest_len destination length, including terminating NUL
* @param conn_cb must be present, called for each connection in the
* bundle until it returns TRUE
* @return combined result of last conn_db and result_cb or FALSE if no
connections were present.
*/
bool Curl_cpool_find(struct Curl_easy *data,
- const char *destination, size_t dest_len,
+ const char *destination,
Curl_cpool_conn_match_cb *conn_cb,
Curl_cpool_done_match_cb *done_cb,
void *userdata);
@@ -132,17 +128,6 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
struct connectdata *conn);
/**
- * Remove the connection from the pool and tear it down.
- * If `aborted` is FALSE, the connection will be shut down first
- * before closing and destroying it.
- * If the shutdown is not immediately complete, the connection
- * will be placed into the pool's shutdown queue.
- */
-void Curl_cpool_disconnect(struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted);
-
-/**
* This function scans the data's connection pool for half-open/dead
* connections, closes and removes them.
* The cleanup is done at most once per second.
@@ -178,26 +163,4 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
struct connectdata *conn,
Curl_cpool_conn_do_cb *cb, void *cbdata);
-/**
- * Add sockets and POLLIN/OUT flags for connections handled by the pool.
- */
-CURLcode Curl_cpool_add_pollfds(struct cpool *connc,
- struct curl_pollfds *cpfds);
-unsigned int Curl_cpool_add_waitfds(struct cpool *connc,
- struct Curl_waitfds *cwfds);
-
-void Curl_cpool_setfds(struct cpool *cpool,
- fd_set *read_fd_set, fd_set *write_fd_set,
- int *maxfd);
-
-/**
- * Perform maintenance on connections in the pool. Specifically,
- * progress the shutdown of connections in the queue.
- */
-void Curl_cpool_multi_perform(struct Curl_multi *multi);
-
-void Curl_cpool_multi_socket(struct Curl_multi *multi,
- curl_socket_t s, int ev_bitmask);
-
-
#endif /* HEADER_CURL_CONNCACHE_H */
diff --git a/libs/libcurl/src/connect.c b/libs/libcurl/src/connect.c
index 4c29377783..c909d6b544 100644
--- a/libs/libcurl/src/connect.c
+++ b/libs/libcurl/src/connect.c
@@ -87,7 +87,7 @@
#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
-enum alpnid Curl_alpn2alpnid(char *name, size_t len)
+enum alpnid Curl_alpn2alpnid(const char *name, size_t len)
{
if(len == 2) {
if(strncasecompare(name, "h1", 2))
@@ -161,7 +161,7 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
}
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
- struct curltime *nowp)
+ int timeout_ms, struct curltime *nowp)
{
struct curltime now;
@@ -171,8 +171,13 @@ void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
nowp = &now;
}
data->conn->shutdown.start[sockindex] = *nowp;
- data->conn->shutdown.timeout_ms = (data->set.shutdowntimeout > 0) ?
- data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS;
+ data->conn->shutdown.timeout_ms = (timeout_ms >= 0) ?
+ (unsigned int)timeout_ms :
+ ((data->set.shutdowntimeout > 0) ?
+ data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS);
+ if(data->conn->shutdown.timeout_ms)
+ Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms,
+ EXPIRE_SHUTDOWN);
}
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
@@ -249,7 +254,7 @@ addr_next_match(const struct Curl_addrinfo *addr, int family)
}
/* retrieves ip address and port from a sockaddr structure.
- note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
+ note it calls curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, int *port)
{
@@ -266,8 +271,8 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
switch(sa->sa_family) {
case AF_INET:
si = (struct sockaddr_in *)(void *) sa;
- if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
- addr, MAX_IPADR_LEN)) {
+ if(curlx_inet_ntop(sa->sa_family, &si->sin_addr,
+ addr, MAX_IPADR_LEN)) {
unsigned short us_port = ntohs(si->sin_port);
*port = us_port;
return TRUE;
@@ -276,8 +281,8 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
#ifdef USE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *) sa;
- if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
- addr, MAX_IPADR_LEN)) {
+ if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr,
+ addr, MAX_IPADR_LEN)) {
unsigned short us_port = ntohs(si6->sin6_port);
*port = us_port;
return TRUE;
@@ -301,7 +306,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
addr[0] = '\0';
*port = 0;
- errno = EAFNOSUPPORT;
+ CURL_SETERRNO(SOCKEAFNOSUPPORT);
return FALSE;
}
@@ -593,7 +598,7 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
*connected = baller->connected;
if(!baller->result && !*connected) {
/* evaluate again */
- baller->result = Curl_conn_cf_connect(baller->cf, data, 0, connected);
+ baller->result = Curl_conn_cf_connect(baller->cf, data, connected);
if(!baller->result) {
if(*connected) {
@@ -603,8 +608,8 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
else if(Curl_timediff(*now, baller->started) >= baller->timeoutms) {
infof(data, "%s connect timeout after %" FMT_TIMEDIFF_T
"ms, move on!", baller->name, baller->timeoutms);
-#if defined(ETIMEDOUT)
- baller->error = ETIMEDOUT;
+#ifdef SOCKETIMEDOUT
+ baller->error = SOCKETIMEDOUT;
#endif
baller->result = CURLE_OPERATION_TIMEDOUT;
}
@@ -765,11 +770,8 @@ evaluate:
Curl_timediff(now, data->progress.t_startsingle),
curl_easy_strerror(result));
-#ifdef WSAETIMEDOUT
- if(WSAETIMEDOUT == data->state.os_errno)
- result = CURLE_OPERATION_TIMEDOUT;
-#elif defined(ETIMEDOUT)
- if(ETIMEDOUT == data->state.os_errno)
+#ifdef SOCKETIMEDOUT
+ if(SOCKETIMEDOUT == data->state.os_errno)
result = CURLE_OPERATION_TIMEDOUT;
#endif
@@ -948,7 +950,7 @@ static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
static CURLcode cf_he_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_he_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
@@ -958,7 +960,6 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
- (void)blocking;
DEBUGASSERT(ctx);
*done = FALSE;
@@ -1263,7 +1264,7 @@ struct cf_setup_ctx {
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
@@ -1276,7 +1277,7 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
/* connect current sub-chain */
connect_sub_chain:
if(cf->next && !cf->next->connected) {
- result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+ result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
return result;
}
diff --git a/libs/libcurl/src/connect.h b/libs/libcurl/src/connect.h
index 60cec0a9b3..3077178d8c 100644
--- a/libs/libcurl/src/connect.h
+++ b/libs/libcurl/src/connect.h
@@ -32,7 +32,7 @@
struct Curl_dns_entry;
struct ip_quadruple;
-enum alpnid Curl_alpn2alpnid(char *name, size_t len);
+enum alpnid Curl_alpn2alpnid(const char *name, size_t len);
/* generic function that returns how much time there is left to run, according
to the timeouts set */
@@ -45,7 +45,7 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
#define DEFAULT_SHUTDOWN_TIMEOUT_MS (2 * 1000)
void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
- struct curltime *nowp);
+ int timeout_ms, struct curltime *nowp);
/* return how much time there is left to shutdown the connection at
* sockindex. Returns 0 if there is no limit or shutdown has not started. */
diff --git a/libs/libcurl/src/content_encoding.c b/libs/libcurl/src/content_encoding.c
index 5f1a8089e9..b185890df9 100644
--- a/libs/libcurl/src/content_encoding.c
+++ b/libs/libcurl/src/content_encoding.c
@@ -65,12 +65,15 @@
/* allow no more than 5 "chained" compression steps */
#define MAX_ENCODE_STACK 5
+
+#if defined(HAVE_LIBZ) || defined(HAVE_BROTLI) || defined(HAVE_ZSTD)
#define DECOMPRESS_BUFFER_SIZE 16384 /* buffer size for decompressed data */
+#endif
#ifdef HAVE_LIBZ
-#if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1204)
-#error "requires zlib 1.2.0.4 or newer"
+#if !defined(ZLIB_VERNUM) || (ZLIB_VERNUM < 0x1252)
+#error "requires zlib 1.2.5.2 or newer"
#endif
typedef enum {
@@ -163,7 +166,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
uInt nread = z->avail_in;
- Bytef *orig_in = z->next_in;
+ z_const Bytef *orig_in = z->next_in;
bool done = FALSE;
CURLcode result = CURLE_OK; /* Curl_client_write status */
@@ -183,13 +186,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
z->next_out = (Bytef *) zp->buffer;
z->avail_out = DECOMPRESS_BUFFER_SIZE;
-#ifdef Z_BLOCK
- /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */
status = inflate(z, Z_BLOCK);
-#else
- /* fallback for zlib ver. < 1.2.0.5 */
- status = inflate(z, Z_SYNC_FLUSH);
-#endif
/* Flush output data if some. */
if(z->avail_out != DECOMPRESS_BUFFER_SIZE) {
@@ -220,9 +217,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
/* 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) {
+ if(inflateReset2(z, -MAX_WBITS) == Z_OK) {
z->next_in = orig_in;
z->avail_in = nread;
zp->zlib_init = ZLIB_INFLATING;
@@ -278,8 +273,8 @@ static CURLcode deflate_do_write(struct Curl_easy *data,
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
/* Set the compressed input when this function is called */
- z->next_in = (Bytef *) buf;
- z->avail_in = (uInt) nbytes;
+ z->next_in = (z_const Bytef *)buf;
+ z->avail_in = (uInt)nbytes;
if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
return process_trailer(data, zp);
@@ -337,8 +332,8 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
if(zp->zlib_init == ZLIB_INIT_GZIP) {
/* Let zlib handle the gzip decompression entirely */
- z->next_in = (Bytef *) buf;
- z->avail_in = (uInt) nbytes;
+ z->next_in = (z_const Bytef *)buf;
+ z->avail_in = (uInt)nbytes;
/* Now uncompress the data */
return inflate_stream(data, writer, type, ZLIB_INIT_GZIP);
}
@@ -755,7 +750,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
name = enclist;
for(namelen = 0; *enclist && *enclist != ','; enclist++)
- if(!ISSPACE(*enclist))
+ if(*enclist > ' ')
namelen = enclist - name + 1;
if(namelen) {
diff --git a/libs/libcurl/src/cookie.c b/libs/libcurl/src/cookie.c
index 147378d812..455d3962b1 100644
--- a/libs/libcurl/src/cookie.c
+++ b/libs/libcurl/src/cookie.c
@@ -76,11 +76,9 @@ Example set of cookies:
#include "urldata.h"
#include "cookie.h"
#include "psl.h"
-#include "strtok.h"
#include "sendf.h"
#include "slist.h"
#include "share.h"
-#include "strtoofft.h"
#include "strcase.h"
#include "curl_get_line.h"
#include "curl_memrchr.h"
@@ -89,6 +87,7 @@ Example set of cookies:
#include "fopen.h"
#include "strdup.h"
#include "llist.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -160,12 +159,10 @@ static bool cookie_tailmatch(const char *cookie_domain,
* 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)
+static bool pathmatch(const char *cookie_path, const char *uri_path)
{
size_t cookie_path_len;
size_t uri_path_len;
- char *uri_path = NULL;
- char *pos;
bool ret = FALSE;
/* cookie_path must not have last '/' separator. ex: /sample */
@@ -175,19 +172,9 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
return TRUE;
}
- uri_path = strdup(request_uri);
- if(!uri_path)
- return FALSE;
- pos = strchr(uri_path, '?');
- if(pos)
- *pos = 0x0;
-
/* #-fragments are already cut off! */
- if(0 == strlen(uri_path) || uri_path[0] != '/') {
- strstore(&uri_path, "/", 1);
- if(!uri_path)
- return FALSE;
- }
+ if(0 == strlen(uri_path) || uri_path[0] != '/')
+ uri_path = "/";
/*
* here, RFC6265 5.1.4 says
@@ -201,16 +188,12 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
uri_path_len = strlen(uri_path);
- if(uri_path_len < cookie_path_len) {
- ret = FALSE;
+ if(uri_path_len < cookie_path_len)
goto pathmatched;
- }
/* not using checkprefix() because matching should be case-sensitive */
- if(strncmp(cookie_path, uri_path, cookie_path_len)) {
- ret = FALSE;
+ if(strncmp(cookie_path, uri_path, cookie_path_len))
goto pathmatched;
- }
/* The cookie-path and the uri-path are identical. */
if(cookie_path_len == uri_path_len) {
@@ -224,10 +207,7 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
goto pathmatched;
}
- ret = FALSE;
-
pathmatched:
- free(uri_path);
return ret;
}
@@ -301,34 +281,27 @@ static size_t cookiehash(const char * const domain)
*/
static char *sanitize_cookie_path(const char *cookie_path)
{
- size_t len;
- char *new_path = strdup(cookie_path);
- if(!new_path)
- return NULL;
+ size_t len = strlen(cookie_path);
- /* some stupid site sends path attribute with '"'. */
- len = strlen(new_path);
- if(new_path[0] == '\"') {
- memmove(new_path, new_path + 1, len);
+ /* some sites send path attribute within '"'. */
+ if(cookie_path[0] == '\"') {
+ cookie_path++;
len--;
}
- if(len && (new_path[len - 1] == '\"')) {
- new_path[--len] = 0x0;
- }
+ if(len && (cookie_path[len - 1] == '\"'))
+ len--;
/* RFC6265 5.2.4 The Path Attribute */
- if(new_path[0] != '/') {
+ if(cookie_path[0] != '/')
/* Let cookie-path be the default-path. */
- strstore(&new_path, "/", 1);
- return new_path;
- }
+ return strdup("/");
+ /* remove trailing slash */
/* convert /hoge/ to /hoge */
- if(len && new_path[len - 1] == '/') {
- new_path[len - 1] = 0x0;
- }
+ if(len && cookie_path[len - 1] == '/')
+ len--;
- return new_path;
+ return Curl_memdup0(cookie_path, len);
}
/*
@@ -370,9 +343,12 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
*/
static void strstore(char **str, const char *newstr, size_t len)
{
- DEBUGASSERT(newstr);
DEBUGASSERT(str);
free(*str);
+ if(!len) {
+ len++;
+ newstr = "";
+ }
*str = Curl_memdup0(newstr, len);
}
@@ -458,18 +434,16 @@ static bool bad_domain(const char *domain, size_t len)
fine. The prime reason for filtering out control bytes is that some HTTP
servers return 400 for requests that contain such.
*/
-static bool invalid_octets(const char *p)
+static bool invalid_octets(const char *ptr)
{
+ const unsigned char *p = (const unsigned char *)ptr;
/* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */
- static const char badoctets[] = {
- "\x01\x02\x03\x04\x05\x06\x07\x08\x0a"
- "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14"
- "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f"
- };
- size_t len;
- /* scan for all the octets that are *not* in cookie-octet */
- len = strcspn(p, badoctets);
- return p[len] != '\0';
+ while(*p) {
+ if(((*p != 9) && (*p < 0x20)) || (*p == 0x7f))
+ return TRUE;
+ p++;
+ }
+ return FALSE;
}
#define CERR_OK 0
@@ -486,7 +460,9 @@ static bool invalid_octets(const char *p)
#define CERR_COMMENT 11 /* a commented line */
#define CERR_RANGE 12 /* expire range problem */
#define CERR_FIELDS 13 /* incomplete netscape line */
+#ifdef USE_LIBPSL
#define CERR_PSL 14 /* a public suffix */
+#endif
#define CERR_LIVE_WINS 15
/* The maximum length we accept a date string for the 'expire' keyword. The
@@ -517,51 +493,29 @@ parse_cookie_header(struct Curl_easy *data,
now = time(NULL);
do {
- size_t vlen;
- size_t nlen;
-
- while(*ptr && ISBLANK(*ptr))
- ptr++;
+ struct Curl_str name;
+ struct Curl_str val;
/* we have a <name>=<value> pair or a stand-alone word here */
- nlen = strcspn(ptr, ";\t\r\n=");
- if(nlen) {
+ if(!Curl_str_cspn(&ptr, &name, ";\t\r\n=")) {
bool done = FALSE;
bool sep = FALSE;
- const char *namep = ptr;
- const char *valuep;
-
- ptr += nlen;
-
- /* trim trailing spaces and tabs after name */
- while(nlen && ISBLANK(namep[nlen - 1]))
- nlen--;
-
- if(*ptr == '=') {
- vlen = strcspn(++ptr, ";\r\n");
- valuep = ptr;
- sep = TRUE;
- ptr = &valuep[vlen];
-
- /* Strip off trailing whitespace from the value */
- while(vlen && ISBLANK(valuep[vlen-1]))
- vlen--;
+ Curl_str_trimblanks(&name);
- /* Skip leading whitespace from the value */
- while(vlen && ISBLANK(*valuep)) {
- valuep++;
- vlen--;
- }
+ if(!Curl_str_single(&ptr, '=')) {
+ sep = TRUE; /* a '=' was used */
+ if(!Curl_str_cspn(&ptr, &val, ";\r\n")) {
+ Curl_str_trimblanks(&val);
- /* Reject cookies with a TAB inside the value */
- if(memchr(valuep, '\t', vlen)) {
- infof(data, "cookie contains TAB, dropping");
- return CERR_TAB;
+ /* Reject cookies with a TAB inside the value */
+ if(memchr(Curl_str(&val), '\t', Curl_strlen(&val))) {
+ infof(data, "cookie contains TAB, dropping");
+ return CERR_TAB;
+ }
}
}
else {
- valuep = NULL;
- vlen = 0;
+ Curl_str_init(&val);
}
/*
@@ -569,10 +523,11 @@ parse_cookie_header(struct Curl_easy *data,
* combination of name + contents. Chrome and Firefox support 4095 or
* 4096 bytes combo
*/
- if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) ||
- ((nlen + vlen) > MAX_NAME)) {
+ if(Curl_strlen(&name) >= (MAX_NAME-1) ||
+ Curl_strlen(&val) >= (MAX_NAME-1) ||
+ ((Curl_strlen(&name) + Curl_strlen(&val)) > MAX_NAME)) {
infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
- nlen, vlen);
+ Curl_strlen(&name), Curl_strlen(&val));
return CERR_TOO_BIG;
}
@@ -582,12 +537,10 @@ parse_cookie_header(struct Curl_easy *data,
* "the rest". Prefixes must start with '__' and end with a '-', so
* only test for names where that can possibly be true.
*/
- if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
- if(strncasecompare("__Secure-", namep, 9))
- co->prefix_secure = TRUE;
- else if(strncasecompare("__Host-", namep, 7))
- co->prefix_host = TRUE;
- }
+ if(!strncmp("__Secure-", Curl_str(&name), 9))
+ co->prefix_secure = TRUE;
+ else if(!strncmp("__Host-", Curl_str(&name), 7))
+ co->prefix_host = TRUE;
/*
* Use strstore() below to properly deal with received cookie
@@ -601,8 +554,8 @@ parse_cookie_header(struct Curl_easy *data,
/* Bad name/value pair. */
return CERR_NO_SEP;
- strstore(&co->name, namep, nlen);
- strstore(&co->value, valuep, vlen);
+ strstore(&co->name, Curl_str(&name), Curl_strlen(&name));
+ strstore(&co->value, Curl_str(&val), Curl_strlen(&val));
done = TRUE;
if(!co->name || !co->value)
return CERR_NO_NAME_VALUE;
@@ -612,7 +565,7 @@ parse_cookie_header(struct Curl_easy *data,
return CERR_INVALID_OCTET;
}
}
- else if(!vlen) {
+ else if(!Curl_strlen(&val)) {
/*
* this was a "<name>=" with no content, and we must allow
* 'secure' and 'httponly' specified this weirdly
@@ -623,7 +576,7 @@ parse_cookie_header(struct Curl_easy *data,
* using a secure protocol, or when the cookie is being set by
* reading from file
*/
- if((nlen == 6) && strncasecompare("secure", namep, 6)) {
+ if(Curl_str_casecompare(&name, "secure")) {
if(secure || !ci->running) {
co->secure = TRUE;
}
@@ -631,7 +584,7 @@ parse_cookie_header(struct Curl_easy *data,
return CERR_BAD_SECURE;
}
}
- else if((nlen == 8) && strncasecompare("httponly", namep, 8))
+ else if(Curl_str_casecompare(&name, "httponly"))
co->httponly = TRUE;
else if(sep)
/* there was a '=' so we are not done parsing this field */
@@ -639,8 +592,8 @@ parse_cookie_header(struct Curl_easy *data,
}
if(done)
;
- else if((nlen == 4) && strncasecompare("path", namep, 4)) {
- strstore(&co->path, valuep, vlen);
+ else if(Curl_str_casecompare(&name, "path")) {
+ strstore(&co->path, Curl_str(&val), Curl_strlen(&val));
if(!co->path)
return CERR_OUT_OF_MEMORY;
free(co->spath); /* if this is set again */
@@ -648,19 +601,16 @@ parse_cookie_header(struct Curl_easy *data,
if(!co->spath)
return CERR_OUT_OF_MEMORY;
}
- else if((nlen == 6) &&
- strncasecompare("domain", namep, 6) && vlen) {
+ else if(Curl_str_casecompare(&name, "domain") && Curl_strlen(&val)) {
bool is_ip;
-
+ const char *v = Curl_str(&val);
/*
* Now, we make sure that our host is within the given domain, or
* the given domain is not valid and thus cannot be set.
*/
- if('.' == valuep[0]) {
- valuep++; /* ignore preceding dot */
- vlen--;
- }
+ if('.' == *v)
+ Curl_str_nudge(&val, 1);
#ifndef USE_LIBPSL
/*
@@ -668,17 +618,18 @@ parse_cookie_header(struct Curl_easy *data,
* TLD or otherwise "protected" suffix. To reduce risk, we require a
* dot OR the exact hostname being "localhost".
*/
- if(bad_domain(valuep, vlen))
+ if(bad_domain(Curl_str(&val), Curl_strlen(&val)))
domain = ":";
#endif
- is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
+ is_ip = Curl_host_is_ipnum(domain ? domain : Curl_str(&val));
if(!domain
- || (is_ip && !strncmp(valuep, domain, vlen) &&
- (vlen == strlen(domain)))
- || (!is_ip && cookie_tailmatch(valuep, vlen, domain))) {
- strstore(&co->domain, valuep, vlen);
+ || (is_ip && !strncmp(Curl_str(&val), domain, Curl_strlen(&val)) &&
+ (Curl_strlen(&val) == strlen(domain)))
+ || (!is_ip && cookie_tailmatch(Curl_str(&val),
+ Curl_strlen(&val), domain))) {
+ strstore(&co->domain, Curl_str(&val), Curl_strlen(&val));
if(!co->domain)
return CERR_OUT_OF_MEMORY;
@@ -692,14 +643,14 @@ parse_cookie_header(struct Curl_easy *data,
* not a domain to which the current host belongs. Mark as bad.
*/
infof(data, "skipped cookie with bad tailmatch domain: %s",
- valuep);
+ Curl_str(&val));
return CERR_NO_TAILMATCH;
}
}
- else if((nlen == 7) && strncasecompare("version", namep, 7)) {
+ else if(Curl_str_casecompare(&name, "version")) {
/* just ignore */
}
- else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
+ else if(Curl_str_casecompare(&name, "max-age") && Curl_strlen(&val)) {
/*
* Defined in RFC2109:
*
@@ -709,21 +660,22 @@ parse_cookie_header(struct Curl_easy *data,
* 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);
- switch(offt) {
- case CURL_OFFT_FLOW:
+ int rc;
+ const char *maxage = Curl_str(&val);
+ if(*maxage == '\"')
+ maxage++;
+ rc = Curl_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
+
+ switch(rc) {
+ case STRE_OVERFLOW:
/* overflow, used max value */
co->expires = CURL_OFF_T_MAX;
break;
- case CURL_OFFT_INVAL:
+ default:
/* negative or otherwise bad, expire */
co->expires = 1;
break;
- case CURL_OFFT_OK:
+ case STRE_OK:
if(!co->expires)
/* already expired */
co->expires = 1;
@@ -736,8 +688,8 @@ parse_cookie_header(struct Curl_easy *data,
}
cap_expires(now, co);
}
- else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
- if(!co->expires && (vlen < MAX_DATE_LENGTH)) {
+ else if(Curl_str_casecompare(&name, "expires") && Curl_strlen(&val)) {
+ if(!co->expires && (Curl_strlen(&val) < MAX_DATE_LENGTH)) {
/*
* Let max-age have priority.
*
@@ -745,8 +697,8 @@ parse_cookie_header(struct Curl_easy *data,
* will be treated as a session cookie
*/
char dbuf[MAX_DATE_LENGTH + 1];
- memcpy(dbuf, valuep, vlen);
- dbuf[vlen] = 0;
+ memcpy(dbuf, Curl_str(&val), Curl_strlen(&val));
+ dbuf[Curl_strlen(&val)] = 0;
co->expires = Curl_getdate_capped(dbuf);
/*
@@ -766,15 +718,8 @@ parse_cookie_header(struct Curl_easy *data,
* 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))
- ptr++;
- if(*ptr == ';')
- ptr++;
- else
+ if(Curl_str_single(&ptr, ';'))
break;
} while(1);
@@ -787,23 +732,11 @@ parse_cookie_header(struct Curl_easy *data,
if(!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.
+ * No path was given in the header line, set the default.
*/
- char *queryp = strchr(path, '?');
-
- /*
- * queryp is where the interesting part of the path ends, so now we
- * want to the find the last
- */
- char *endslash;
- if(!queryp)
- endslash = strrchr(path, '/');
- else
- endslash = memrchr(path, '/', (queryp - path));
+ const char *endslash = strrchr(path, '/');
if(endslash) {
- size_t pathlen = (endslash-path + 1); /* include end slash */
+ size_t pathlen = (endslash - path + 1); /* include end slash */
co->path = Curl_memdup0(path, pathlen);
if(co->path) {
co->spath = sanitize_cookie_path(co->path);
@@ -916,16 +849,8 @@ parse_netscape(struct Cookie *co,
}
break;
case 4:
- {
- char *endp;
- const char *p;
- /* make sure curlx_strtoofft won't read past the current field */
- for(p = ptr; p < &ptr[len] && ISDIGIT(*p); ++p)
- ;
- if(p == ptr || p != &ptr[len] ||
- curlx_strtoofft(ptr, &endp, 10, &co->expires) || endp != &ptr[len])
- return CERR_RANGE;
- }
+ if(Curl_str_number(&ptr, &co->expires, CURL_OFF_T_MAX))
+ return CERR_RANGE;
break;
case 5:
co->name = Curl_memdup0(ptr, len);
@@ -1286,14 +1211,13 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
struct dynbuf buf;
Curl_dyn_init(&buf, MAX_COOKIE_LINE);
while(Curl_get_line(&buf, fp)) {
- char *lineptr = Curl_dyn_ptr(&buf);
+ const char *lineptr = Curl_dyn_ptr(&buf);
bool headerline = FALSE;
if(checkprefix("Set-Cookie:", lineptr)) {
/* This is a cookie line, get it! */
lineptr += 11;
headerline = TRUE;
- while(*lineptr && ISBLANK(*lineptr))
- lineptr++;
+ Curl_str_passblanks(&lineptr);
}
Curl_cookie_add(data, ci, headerline, TRUE, lineptr, NULL, NULL, TRUE);
@@ -1326,8 +1250,8 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
*/
static int cookie_sort(const void *p1, const void *p2)
{
- struct Cookie *c1 = *(struct Cookie **)p1;
- struct Cookie *c2 = *(struct Cookie **)p2;
+ const struct Cookie *c1 = *(const struct Cookie * const *)p1;
+ const struct Cookie *c2 = *(const struct Cookie * const *)p2;
size_t l1, l2;
/* 1 - compare cookie path lengths */
@@ -1362,8 +1286,8 @@ static int cookie_sort(const void *p1, const void *p2)
*/
static int cookie_sort_ct(const void *p1, const void *p2)
{
- struct Cookie *c1 = *(struct Cookie **)p1;
- struct Cookie *c2 = *(struct Cookie **)p2;
+ const struct Cookie *c1 = *(const struct Cookie * const *)p1;
+ const struct Cookie *c2 = *(const struct Cookie * const *)p2;
return (c2->creationtime > c1->creationtime) ? 1 : -1;
}
diff --git a/libs/libcurl/src/cshutdn.c b/libs/libcurl/src/cshutdn.c
new file mode 100644
index 0000000000..fb6e34410b
--- /dev/null
+++ b/libs/libcurl/src/cshutdn.c
@@ -0,0 +1,566 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Linus Nielsen Feltzing, <linus@haxx.se>
+ * 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 "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "url.h"
+#include "cfilters.h"
+#include "progress.h"
+#include "multiif.h"
+#include "multi_ev.h"
+#include "sendf.h"
+#include "cshutdn.h"
+#include "http_negotiate.h"
+#include "http_ntlm.h"
+#include "sigpipe.h"
+#include "connect.h"
+#include "select.h"
+#include "strcase.h"
+#include "strparse.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+static void cshutdn_run_conn_handler(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ if(!conn->bits.shutdown_handler) {
+ if(conn->dns_entry)
+ Curl_resolv_unlink(data, &conn->dns_entry);
+
+ /* 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) {
+ /* Some disconnect handlers do a blocking wait on server responses.
+ * FTP/IMAP/SMTP and SFTP are among them. When using the internal
+ * handle, set an overall short timeout so we do not hang for the
+ * default 120 seconds. */
+ if(data->state.internal) {
+ data->set.timeout = DEFAULT_SHUTDOWN_TIMEOUT_MS;
+ (void)Curl_pgrsTime(data, TIMER_STARTOP);
+ }
+
+ /* This is set if protocol-specific cleanups should be made */
+ DEBUGF(infof(data, "connection #%" FMT_OFF_T
+ ", shutdown protocol handler (aborted=%d)",
+ conn->connection_id, conn->bits.aborted));
+ /* There are protocol handlers that block on retrieving
+ * server responses here (FTP). Set a short timeout. */
+ 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 cshutdn_run_once(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);
+
+ cshutdn_run_conn_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;
+}
+
+void Curl_cshutdn_run_once(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *done)
+{
+ DEBUGASSERT(!data->conn);
+ Curl_attach_connection(data, conn);
+ cshutdn_run_once(data, conn, done);
+ CURL_TRC_M(data, "[SHUTDOWN] shutdown, done=%d", *done);
+ Curl_detach_connection(data);
+}
+
+
+void Curl_cshutdn_terminate(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool do_shutdown)
+{
+ struct Curl_easy *admin = data;
+ bool done;
+
+ /* there must be a connection to close */
+ DEBUGASSERT(conn);
+ /* it must be removed from the connection pool */
+ DEBUGASSERT(!conn->bits.in_cpool);
+ /* the transfer must be detached from the connection */
+ DEBUGASSERT(data && !data->conn);
+
+ /* If we can obtain an internal admin handle, use that to attach
+ * and terminate the connection. Some protocol will try to mess with
+ * `data` during shutdown and we do not want that with a `data` from
+ * the application. */
+ if(data->multi && data->multi->admin)
+ admin = data->multi->admin;
+
+ Curl_attach_connection(admin, conn);
+
+ cshutdn_run_conn_handler(admin, conn);
+ if(do_shutdown) {
+ /* Make a last attempt to shutdown handlers and filters, if
+ * not done so already. */
+ cshutdn_run_once(admin, conn, &done);
+ }
+ CURL_TRC_M(admin, "[SHUTDOWN] closing connection");
+ Curl_conn_close(admin, SECONDARYSOCKET);
+ Curl_conn_close(admin, FIRSTSOCKET);
+ Curl_detach_connection(admin);
+
+ if(data->multi)
+ Curl_multi_ev_conn_done(data->multi, data, conn);
+ Curl_conn_free(admin, conn);
+
+ if(data->multi) {
+ CURL_TRC_M(data, "[SHUTDOWN] trigger multi connchanged");
+ Curl_multi_connchanged(data->multi);
+ }
+}
+
+static void cshutdn_destroy_oldest(struct cshutdn *cshutdn,
+ struct Curl_easy *data)
+{
+ struct Curl_llist_node *e;
+ struct connectdata *conn;
+
+ e = Curl_llist_head(&cshutdn->list);
+ if(e) {
+ SIGPIPE_VARIABLE(pipe_st);
+ conn = Curl_node_elem(e);
+ Curl_node_remove(e);
+ sigpipe_init(&pipe_st);
+ sigpipe_apply(data, &pipe_st);
+ Curl_cshutdn_terminate(data, conn, FALSE);
+ sigpipe_restore(&pipe_st);
+ }
+}
+
+#define NUM_POLLS_ON_STACK 10
+
+static CURLcode cshutdn_wait(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ 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_cshutdn_add_pollfds(cshutdn, data, &cpfds);
+ if(result)
+ goto out;
+
+ Curl_poll(cpfds.pfds, cpfds.n, CURLMIN(timeout_ms, 1000));
+
+out:
+ Curl_pollfds_cleanup(&cpfds);
+ return result;
+}
+
+
+static void cshutdn_perform(struct cshutdn *cshutdn,
+ struct Curl_easy *data)
+{
+ struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
+ struct Curl_llist_node *enext;
+ struct connectdata *conn;
+ struct curltime *nowp = NULL;
+ struct curltime now;
+ timediff_t next_expire_ms = 0, ms;
+ bool done;
+
+ if(!e)
+ return;
+
+ CURL_TRC_M(data, "[SHUTDOWN] perform on %zu connections",
+ Curl_llist_count(&cshutdn->list));
+ while(e) {
+ enext = Curl_node_next(e);
+ conn = Curl_node_elem(e);
+ Curl_cshutdn_run_once(data, conn, &done);
+ if(done) {
+ Curl_node_remove(e);
+ Curl_cshutdn_terminate(data, conn, FALSE);
+ }
+ else {
+ /* idata has one timer list, but maybe more than one connection.
+ * Set EXPIRE_SHUTDOWN to the smallest time left for all. */
+ if(!nowp) {
+ now = Curl_now();
+ nowp = &now;
+ }
+ ms = Curl_conn_shutdown_timeleft(conn, nowp);
+ if(ms && ms < next_expire_ms)
+ next_expire_ms = ms;
+ }
+ e = enext;
+ }
+
+ if(next_expire_ms)
+ Curl_expire_ex(data, nowp, next_expire_ms, EXPIRE_SHUTDOWN);
+}
+
+
+static void cshutdn_terminate_all(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ int timeout_ms)
+{
+ struct curltime started = Curl_now();
+ struct Curl_llist_node *e;
+ SIGPIPE_VARIABLE(pipe_st);
+
+ DEBUGASSERT(cshutdn);
+ DEBUGASSERT(data);
+
+ CURL_TRC_M(data, "[SHUTDOWN] shutdown all");
+ sigpipe_init(&pipe_st);
+ sigpipe_apply(data, &pipe_st);
+
+ while(Curl_llist_head(&cshutdn->list)) {
+ timediff_t timespent;
+ int remain_ms;
+
+ cshutdn_perform(cshutdn, data);
+
+ if(!Curl_llist_head(&cshutdn->list)) {
+ CURL_TRC_M(data, "[SHUTDOWN] shutdown finished cleanly");
+ break;
+ }
+
+ /* wait for activity, timeout or "nothing" */
+ timespent = Curl_timediff(Curl_now(), started);
+ if(timespent >= (timediff_t)timeout_ms) {
+ CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, %s",
+ (timeout_ms > 0) ? "timeout" : "best effort done");
+ break;
+ }
+
+ remain_ms = timeout_ms - (int)timespent;
+ if(cshutdn_wait(cshutdn, data, remain_ms)) {
+ CURL_TRC_M(data, "[SHUTDOWN] shutdown finished, aborted");
+ break;
+ }
+ }
+
+ /* Terminate any remaining. */
+ e = Curl_llist_head(&cshutdn->list);
+ while(e) {
+ struct connectdata *conn = Curl_node_elem(e);
+ Curl_node_remove(e);
+ Curl_cshutdn_terminate(data, conn, FALSE);
+ e = Curl_llist_head(&cshutdn->list);
+ }
+ DEBUGASSERT(!Curl_llist_count(&cshutdn->list));
+
+ Curl_hostcache_clean(data, data->dns.hostcache);
+
+ sigpipe_restore(&pipe_st);
+}
+
+
+int Curl_cshutdn_init(struct cshutdn *cshutdn,
+ struct Curl_multi *multi)
+{
+ DEBUGASSERT(multi);
+ cshutdn->multi = multi;
+ Curl_llist_init(&cshutdn->list, NULL);
+ cshutdn->initialised = TRUE;
+ return 0; /* good */
+}
+
+
+void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
+ struct Curl_easy *data)
+{
+ if(cshutdn->initialised && data) {
+ int timeout_ms = 0;
+ /* Just for testing, run graceful shutdown */
+#ifdef DEBUGBUILD
+ {
+ const char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
+ if(p) {
+ curl_off_t l;
+ if(!Curl_str_number(&p, &l, INT_MAX))
+ timeout_ms = (int)l;
+ }
+ }
+#endif
+
+ CURL_TRC_M(data, "[SHUTDOWN] destroy, %zu connections, timeout=%dms",
+ Curl_llist_count(&cshutdn->list), timeout_ms);
+ cshutdn_terminate_all(cshutdn, data, timeout_ms);
+ }
+ cshutdn->multi = NULL;
+}
+
+size_t Curl_cshutdn_count(struct Curl_easy *data)
+{
+ if(data && data->multi) {
+ struct cshutdn *csd = &data->multi->cshutdn;
+ return Curl_llist_count(&csd->list);
+ }
+ return 0;
+}
+
+size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
+ const char *destination)
+{
+ if(data && data->multi) {
+ struct cshutdn *csd = &data->multi->cshutdn;
+ size_t n = 0;
+ struct Curl_llist_node *e = Curl_llist_head(&csd->list);
+ while(e) {
+ struct connectdata *conn = Curl_node_elem(e);
+ if(!strcmp(destination, conn->destination))
+ ++n;
+ e = Curl_node_next(e);
+ }
+ return n;
+ }
+ return 0;
+}
+
+
+static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ CURLMcode mresult;
+
+ DEBUGASSERT(cshutdn);
+ DEBUGASSERT(cshutdn->multi->socket_cb);
+
+ Curl_attach_connection(data, conn);
+ mresult = Curl_multi_ev_assess_conn(cshutdn->multi, data, conn);
+ Curl_detach_connection(data);
+ return mresult;
+}
+
+
+void Curl_cshutdn_add(struct cshutdn *cshutdn,
+ struct connectdata *conn,
+ size_t conns_in_pool)
+{
+ struct Curl_easy *data = cshutdn->multi->admin;
+ size_t max_total = (cshutdn->multi->max_total_connections > 0) ?
+ (size_t)cshutdn->multi->max_total_connections : 0;
+
+ /* Add the connection to our shutdown list for non-blocking shutdown
+ * during multi processing. */
+ if(max_total > 0 && (max_total <=
+ (conns_in_pool + Curl_llist_count(&cshutdn->list)))) {
+ CURL_TRC_M(data, "[SHUTDOWN] discarding oldest shutdown connection "
+ "due to connection limit of %zu", max_total);
+ cshutdn_destroy_oldest(cshutdn, data);
+ }
+
+ if(cshutdn->multi->socket_cb) {
+ if(cshutdn_update_ev(cshutdn, data, conn)) {
+ CURL_TRC_M(data, "[SHUTDOWN] update events failed, discarding #%"
+ FMT_OFF_T, conn->connection_id);
+ Curl_cshutdn_terminate(data, conn, FALSE);
+ return;
+ }
+ }
+
+ Curl_llist_append(&cshutdn->list, conn, &conn->cshutdn_node);
+ CURL_TRC_M(data, "[SHUTDOWN] added #%" FMT_OFF_T
+ " to shutdowns, now %zu conns in shutdown",
+ conn->connection_id, Curl_llist_count(&cshutdn->list));
+}
+
+
+static void cshutdn_multi_socket(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ curl_socket_t s)
+{
+ struct Curl_llist_node *e;
+ struct connectdata *conn;
+ bool done;
+
+ DEBUGASSERT(cshutdn->multi->socket_cb);
+ e = Curl_llist_head(&cshutdn->list);
+ while(e) {
+ conn = Curl_node_elem(e);
+ if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
+ Curl_cshutdn_run_once(data, conn, &done);
+ if(done || cshutdn_update_ev(cshutdn, data, conn)) {
+ Curl_node_remove(e);
+ Curl_cshutdn_terminate(data, conn, FALSE);
+ }
+ break;
+ }
+ e = Curl_node_next(e);
+ }
+}
+
+
+void Curl_cshutdn_perform(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ curl_socket_t s)
+{
+ if((s == CURL_SOCKET_TIMEOUT) || (!cshutdn->multi->socket_cb))
+ cshutdn_perform(cshutdn, data);
+ else
+ cshutdn_multi_socket(cshutdn, data, s);
+}
+
+/* return fd_set info about the shutdown connections */
+void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ fd_set *read_fd_set, fd_set *write_fd_set,
+ int *maxfd)
+{
+ if(Curl_llist_head(&cshutdn->list)) {
+ struct Curl_llist_node *e;
+
+ for(e = Curl_llist_head(&cshutdn->list); e;
+ e = Curl_node_next(e)) {
+ struct easy_pollset ps;
+ unsigned int i;
+ struct connectdata *conn = Curl_node_elem(e);
+ memset(&ps, 0, sizeof(ps));
+ Curl_attach_connection(data, conn);
+ Curl_conn_adjust_pollset(data, conn, &ps);
+ Curl_detach_connection(data);
+
+ for(i = 0; i < ps.num; i++) {
+#if defined(__DJGPP__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warith-conversion"
+#endif
+ 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 defined(__DJGPP__)
+#pragma GCC diagnostic pop
+#endif
+ if((ps.actions[i] & (CURL_POLL_OUT | CURL_POLL_IN)) &&
+ ((int)ps.sockets[i] > *maxfd))
+ *maxfd = (int)ps.sockets[i];
+ }
+ }
+ }
+}
+
+/* return information about the shutdown connections */
+unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ struct Curl_waitfds *cwfds)
+{
+ unsigned int need = 0;
+
+ if(Curl_llist_head(&cshutdn->list)) {
+ struct Curl_llist_node *e;
+ struct easy_pollset ps;
+ struct connectdata *conn;
+
+ for(e = Curl_llist_head(&cshutdn->list); e;
+ e = Curl_node_next(e)) {
+ conn = Curl_node_elem(e);
+ memset(&ps, 0, sizeof(ps));
+ Curl_attach_connection(data, conn);
+ Curl_conn_adjust_pollset(data, conn, &ps);
+ Curl_detach_connection(data);
+
+ need += Curl_waitfds_add_ps(cwfds, &ps);
+ }
+ }
+ return need;
+}
+
+CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ struct curl_pollfds *cpfds)
+{
+ CURLcode result = CURLE_OK;
+
+ if(Curl_llist_head(&cshutdn->list)) {
+ struct Curl_llist_node *e;
+ struct easy_pollset ps;
+ struct connectdata *conn;
+
+ for(e = Curl_llist_head(&cshutdn->list); e;
+ e = Curl_node_next(e)) {
+ conn = Curl_node_elem(e);
+ memset(&ps, 0, sizeof(ps));
+ Curl_attach_connection(data, conn);
+ Curl_conn_adjust_pollset(data, conn, &ps);
+ Curl_detach_connection(data);
+
+ result = Curl_pollfds_add_ps(cpfds, &ps);
+ if(result) {
+ Curl_pollfds_cleanup(cpfds);
+ goto out;
+ }
+ }
+ }
+out:
+ return result;
+}
diff --git a/libs/libcurl/src/cshutdn.h b/libs/libcurl/src/cshutdn.h
new file mode 100644
index 0000000000..070fb53b67
--- /dev/null
+++ b/libs/libcurl/src/cshutdn.h
@@ -0,0 +1,104 @@
+#ifndef HEADER_CURL_CSHUTDN_H
+#define HEADER_CURL_CSHUTDN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Linus Nielsen Feltzing, <linus@haxx.se>
+ *
+ * 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 <curl/curl.h>
+#include "timeval.h"
+
+struct connectdata;
+struct Curl_easy;
+struct curl_pollfds;
+struct Curl_waitfds;
+struct Curl_multi;
+struct Curl_share;
+
+/* Run the shutdown of the connection once.
+ * Will shortly attach/detach `data` to `conn` while doing so.
+ * `done` will be set TRUE if any error was encountered or if
+ * the connection was shut down completely. */
+void Curl_cshutdn_run_once(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *done);
+
+/* Terminates the connection, e.g. closes and destroys it.
+ * If `run_shutdown` is TRUE, the shutdown will be run once before
+ * terminating it.
+ * Takes ownership of `conn`. */
+void Curl_cshutdn_terminate(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool run_shutdown);
+
+/* A `cshutdown` is always owned by a multi handle to maintain
+ * the connections to be shut down. It registers timers and
+ * sockets to monitor via the multi handle. */
+struct cshutdn {
+ struct Curl_llist list; /* connections being shut down */
+ struct Curl_multi *multi; /* the multi owning this */
+ BIT(initialised);
+};
+
+/* Init as part of the given multi handle. */
+int Curl_cshutdn_init(struct cshutdn *cshutdn,
+ struct Curl_multi *multi);
+
+/* Terminate all remaining connections and free resources. */
+void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
+ struct Curl_easy *data);
+
+/* Number of connections being shut down. */
+size_t Curl_cshutdn_count(struct Curl_easy *data);
+
+/* Number of connections to the destination being shut down. */
+size_t Curl_cshutdn_dest_count(struct Curl_easy *data,
+ const char *destination);
+
+/* Add a connection to have it shut down. Will terminate the oldest
+ * connection when total connection limit of multi is being reached. */
+void Curl_cshutdn_add(struct cshutdn *cshutdn,
+ struct connectdata *conn,
+ size_t conns_in_pool);
+
+/* Add sockets and POLLIN/OUT flags for connections being shut down. */
+CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ struct curl_pollfds *cpfds);
+
+unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ struct Curl_waitfds *cwfds);
+
+void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ fd_set *read_fd_set, fd_set *write_fd_set,
+ int *maxfd);
+
+/* Run shut down connections using socket. If socket is CURL_SOCKET_TIMEOUT,
+ * run maintenance on all connections. */
+void Curl_cshutdn_perform(struct cshutdn *cshutdn,
+ struct Curl_easy *data,
+ curl_socket_t s);
+
+#endif /* HEADER_CURL_CSHUTDN_H */
diff --git a/libs/libcurl/src/curl_addrinfo.c b/libs/libcurl/src/curl_addrinfo.c
index 446c566be9..7f60477ed6 100644
--- a/libs/libcurl/src/curl_addrinfo.c
+++ b/libs/libcurl/src/curl_addrinfo.c
@@ -118,7 +118,7 @@ Curl_getaddrinfo_ex(const char *nodename,
*result = NULL; /* assume failure */
- error = getaddrinfo(nodename, servname, hints, &aihead);
+ error = CURL_GETADDRINFO(nodename, servname, hints, &aihead);
if(error)
return error;
@@ -184,7 +184,7 @@ Curl_getaddrinfo_ex(const char *nodename,
/* destroy the addrinfo list */
if(aihead)
- freeaddrinfo(aihead);
+ CURL_FREEADDRINFO(aihead);
/* if we failed, also destroy the Curl_addrinfo list */
if(error) {
@@ -430,13 +430,13 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
struct Curl_addrinfo *Curl_str2addr(char *address, int port)
{
struct in_addr in;
- if(Curl_inet_pton(AF_INET, address, &in) > 0)
+ if(curlx_inet_pton(AF_INET, address, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
return Curl_ip2addr(AF_INET, &in, address, port);
#ifdef USE_IPV6
{
struct in6_addr in6;
- if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
+ if(curlx_inet_pton(AF_INET6, address, &in6) > 0)
/* This is a dotted IPv6 address ::1-style */
return Curl_ip2addr(AF_INET6, &in6, address, port);
}
@@ -509,7 +509,7 @@ curl_dbg_freeaddrinfo(struct addrinfo *freethis,
#ifdef USE_LWIPSOCK
lwip_freeaddrinfo(freethis);
#else
- (freeaddrinfo)(freethis);
+ freeaddrinfo(freethis);
#endif
}
#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
@@ -534,7 +534,7 @@ curl_dbg_getaddrinfo(const char *hostname,
#ifdef USE_LWIPSOCK
int res = lwip_getaddrinfo(hostname, service, hints, result);
#else
- int res = (getaddrinfo)(hostname, service, hints, result);
+ int res = getaddrinfo(hostname, service, hints, result);
#endif
if(0 == res)
/* success */
diff --git a/libs/libcurl/src/curl_config.h.cmake b/libs/libcurl/src/curl_config.h.cmake
index c6ecb255ba..6f7b9a736b 100644
--- a/libs/libcurl/src/curl_config.h.cmake
+++ b/libs/libcurl/src/curl_config.h.cmake
@@ -469,6 +469,9 @@
/* Define to 1 if you have the sendmmsg function. */
#cmakedefine HAVE_SENDMMSG 1
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H 1
+
/* Define to 1 if you have the 'fsetxattr' function. */
#cmakedefine HAVE_FSETXATTR 1
@@ -547,12 +550,6 @@
/* Define to 1 if you have the <stropts.h> header file. */
#cmakedefine HAVE_STROPTS_H 1
-/* Define to 1 if you have the strtok_r function. */
-#cmakedefine HAVE_STRTOK_R 1
-
-/* Define to 1 if you have the strtoll function. */
-#cmakedefine HAVE_STRTOLL 1
-
/* Define to 1 if you have the memrchr function. */
#cmakedefine HAVE_MEMRCHR 1
@@ -797,9 +794,6 @@ ${SIZEOF_TIME_T_CODE}
/* Define to empty if `const' does not conform to ANSI C. */
#cmakedefine const ${const}
-/* Type to use in place of in_addr_t when system does not provide it. */
-#cmakedefine in_addr_t ${in_addr_t}
-
/* Define to `unsigned int' if <sys/types.h> does not define. */
#cmakedefine size_t ${size_t}
diff --git a/libs/libcurl/src/curl_config.h.in b/libs/libcurl/src/curl_config.h.in
index c139f814cb..7f3dea8c08 100644
--- a/libs/libcurl/src/curl_config.h.in
+++ b/libs/libcurl/src/curl_config.h.in
@@ -1,8 +1,5 @@
/* lib/curl_config.h.in. Generated from configure.ac by autoheader. */
-/* to enable curl debug memory tracking */
-#undef CURLDEBUG
-
/* Location of default ca bundle */
#undef CURL_CA_BUNDLE
@@ -162,9 +159,6 @@
/* built with multiple SSL backends */
#undef CURL_WITH_MULTI_SSL
-/* enable debug build options */
-#undef DEBUGBUILD
-
/* Define to the type of arg 2 for gethostname. */
#undef GETHOSTNAME_TYPE_ARG2
@@ -632,12 +626,6 @@
/* Define to 1 if you have the <stropts.h> header file. */
#undef HAVE_STROPTS_H
-/* Define to 1 if you have the strtok_r function. */
-#undef HAVE_STRTOK_R
-
-/* Define to 1 if you have the strtoll function. */
-#undef HAVE_STRTOLL
-
/* if struct sockaddr_storage is defined */
#undef HAVE_STRUCT_SOCKADDR_STORAGE
@@ -950,9 +938,6 @@
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
-/* Type to use in place of in_addr_t when system does not provide it. */
-#undef in_addr_t
-
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
diff --git a/libs/libcurl/src/curl_ctype.h b/libs/libcurl/src/curl_ctype.h
index 02fa4e685e..ba870a15ee 100644
--- a/libs/libcurl/src/curl_ctype.h
+++ b/libs/libcurl/src/curl_ctype.h
@@ -37,6 +37,7 @@
#define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x))
#define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
#define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x))
+#define ISODIGIT(x) (((x) >= '0') && ((x) <= '7'))
#define ISALNUM(x) (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x))
#define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z'))
#define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z'))
diff --git a/libs/libcurl/src/curl_fnmatch.c b/libs/libcurl/src/curl_fnmatch.c
index f2188f8322..473f6ef40a 100644
--- a/libs/libcurl/src/curl_fnmatch.c
+++ b/libs/libcurl/src/curl_fnmatch.c
@@ -71,13 +71,13 @@ typedef enum {
#define SETCHARSET_OK 1
#define SETCHARSET_FAIL 0
-static int parsekeyword(unsigned char **pattern, unsigned char *charset)
+static int parsekeyword(const unsigned char **pattern, unsigned char *charset)
{
parsekey_state state = CURLFNM_PKW_INIT;
#define KEYLEN 10
char keyword[KEYLEN] = { 0 };
int i;
- unsigned char *p = *pattern;
+ const unsigned char *p = *pattern;
bool found = FALSE;
for(i = 0; !found; i++) {
char c = (char)*p++;
@@ -140,9 +140,9 @@ static char_class charclass(unsigned char c)
}
/* Include a character or a range in set. */
-static void setcharorrange(unsigned char **pp, unsigned char *charset)
+static void setcharorrange(const unsigned char **pp, unsigned char *charset)
{
- unsigned char *p = (*pp)++;
+ const unsigned char *p = (*pp)++;
unsigned char c = *p++;
charset[c] = 1;
@@ -162,7 +162,7 @@ static void setcharorrange(unsigned char **pp, unsigned char *charset)
}
/* returns 1 (TRUE) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
-static int setcharset(unsigned char **p, unsigned char *charset)
+static int setcharset(const unsigned char **p, unsigned char *charset)
{
setcharset_state state = CURLFNM_SCHS_DEFAULT;
bool something_found = FALSE;
@@ -185,7 +185,7 @@ static int setcharset(unsigned char **p, unsigned char *charset)
(*p)++;
}
else if(c == '[') {
- unsigned char *pp = *p + 1;
+ const unsigned char *pp = *p + 1;
if(*pp++ == ':' && parsekeyword(&pp, charset))
*p = pp;
@@ -257,12 +257,12 @@ fail:
static int loop(const unsigned char *pattern, const unsigned char *string,
int maxstars)
{
- unsigned char *p = (unsigned char *)pattern;
- unsigned char *s = (unsigned char *)string;
+ const unsigned char *p = (const unsigned char *)pattern;
+ const unsigned char *s = (const unsigned char *)string;
unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
for(;;) {
- unsigned char *pp;
+ const unsigned char *pp;
switch(*p) {
case '*':
@@ -319,7 +319,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string,
else if(charset[CURLFNM_PRINT])
found = ISPRINT(*s);
else if(charset[CURLFNM_SPACE])
- found = ISSPACE(*s);
+ found = ISBLANK(*s);
else if(charset[CURLFNM_UPPER])
found = ISUPPER(*s);
else if(charset[CURLFNM_LOWER])
@@ -359,7 +359,8 @@ int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
if(!pattern || !string) {
return CURL_FNMATCH_FAIL;
}
- return loop((unsigned char *)pattern, (unsigned char *)string, 2);
+ return loop((const unsigned char *)pattern,
+ (const unsigned char *)string, 2);
}
#else
#include <fnmatch.h>
diff --git a/libs/libcurl/src/curl_gssapi.c b/libs/libcurl/src/curl_gssapi.c
index e963bc487a..24f35b66bb 100644
--- a/libs/libcurl/src/curl_gssapi.c
+++ b/libs/libcurl/src/curl_gssapi.c
@@ -46,10 +46,10 @@
#endif
gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = {
- 6, (char *)"\x2b\x06\x01\x05\x05\x02"
+ 6, CURL_UNCONST("\x2b\x06\x01\x05\x05\x02")
};
gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = {
- 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
+ 9, CURL_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")
};
OM_uint32 Curl_gss_init_sec_context(
diff --git a/libs/libcurl/src/curl_krb5.h b/libs/libcurl/src/curl_krb5.h
index 7e8e61ac23..b9742fd14f 100644
--- a/libs/libcurl/src/curl_krb5.h
+++ b/libs/libcurl/src/curl_krb5.h
@@ -40,13 +40,15 @@ struct Curl_sec_client_mech {
#define AUTH_ERROR 2
#ifdef HAVE_GSSAPI
+void Curl_sec_conn_init(struct connectdata *);
+void Curl_sec_conn_destroy(struct connectdata *);
int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *,
enum protection_level);
-void Curl_sec_end(struct connectdata *);
CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *);
int Curl_sec_request_prot(struct connectdata *conn, const char *level);
#else
-#define Curl_sec_end(x)
+#define Curl_sec_conn_init(x) Curl_nop_stmt
+#define Curl_sec_conn_destroy(x) Curl_nop_stmt
#endif
#endif /* HEADER_CURL_KRB5_H */
diff --git a/libs/libcurl/src/curl_memory.h b/libs/libcurl/src/curl_memory.h
index f34afa5c75..18b810b0e8 100644
--- a/libs/libcurl/src/curl_memory.h
+++ b/libs/libcurl/src/curl_memory.h
@@ -84,20 +84,6 @@
#undef socketpair
#endif
-#ifndef CURL_NO_GETADDRINFO_OVERRIDE
-#ifdef HAVE_GETADDRINFO
-#if defined(getaddrinfo) && defined(__osf__)
-#undef ogetaddrinfo
-#else
-#undef getaddrinfo
-#endif
-#endif /* HAVE_GETADDRINFO */
-
-#ifdef HAVE_FREEADDRINFO
-#undef freeaddrinfo
-#endif /* HAVE_FREEADDRINFO */
-#endif /* !CURL_NO_GETADDRINFO_OVERRIDE */
-
/* sclose is probably already defined, redefine it! */
#undef sclose
#undef fopen
diff --git a/libs/libcurl/src/curl_memrchr.c b/libs/libcurl/src/curl_memrchr.c
index 9b7ab8258b..f1d3f35c4d 100644
--- a/libs/libcurl/src/curl_memrchr.c
+++ b/libs/libcurl/src/curl_memrchr.c
@@ -33,10 +33,6 @@
#include "memdebug.h"
#ifndef HAVE_MEMRCHR
-#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \
- defined(USE_OPENSSL) || \
- defined(USE_SCHANNEL)
-
/*
* Curl_memrchr()
*
@@ -57,12 +53,10 @@ Curl_memrchr(const void *s, int c, size_t n)
while(p >= q) {
if(*p == (unsigned char)c)
- return (void *)p;
+ return CURL_UNCONST(p);
p--;
}
}
return NULL;
}
-
-#endif
#endif /* HAVE_MEMRCHR */
diff --git a/libs/libcurl/src/curl_memrchr.h b/libs/libcurl/src/curl_memrchr.h
index dbced53b38..ea15561d31 100644
--- a/libs/libcurl/src/curl_memrchr.h
+++ b/libs/libcurl/src/curl_memrchr.h
@@ -34,15 +34,9 @@
#endif
#else /* HAVE_MEMRCHR */
-#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \
- defined(USE_OPENSSL) || \
- defined(USE_SCHANNEL)
-
void *Curl_memrchr(const void *s, int c, size_t n);
-
#define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
-#endif
#endif /* HAVE_MEMRCHR */
#endif /* HEADER_CURL_MEMRCHR_H */
diff --git a/libs/libcurl/src/curl_multibyte.c b/libs/libcurl/src/curl_multibyte.c
index 5da11e1c38..2e96362b8c 100644
--- a/libs/libcurl/src/curl_multibyte.c
+++ b/libs/libcurl/src/curl_multibyte.c
@@ -84,6 +84,8 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
return str_utf8;
}
+#ifndef UNDER_CE
+
/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */
#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
(_WIN32_WINNT < _WIN32_WINNT_WIN10)
@@ -267,7 +269,8 @@ int curlx_win32_open(const char *filename, int oflag, ...)
curlx_unicodefree(filename_w);
}
else
- errno = EINVAL;
+ /* !checksrc! disable ERRNOVAR 1 */
+ CURL_SETERRNO(EINVAL);
#else
if(fix_excessive_path(filename, &fixed))
target = fixed;
@@ -297,7 +300,8 @@ FILE *curlx_win32_fopen(const char *filename, const char *mode)
result = _wfopen(target, mode_w);
}
else
- errno = EINVAL;
+ /* !checksrc! disable ERRNOVAR 1 */
+ CURL_SETERRNO(EINVAL);
curlx_unicodefree(filename_w);
curlx_unicodefree(mode_w);
#else
@@ -333,7 +337,8 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
curlx_unicodefree(path_w);
}
else
- errno = EINVAL;
+ /* !checksrc! disable ERRNOVAR 1 */
+ CURL_SETERRNO(EINVAL);
#else
if(fix_excessive_path(path, &fixed))
target = fixed;
@@ -350,4 +355,6 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
return result;
}
+#endif /* UNDER_CE */
+
#endif /* _WIN32 */
diff --git a/libs/libcurl/src/curl_multibyte.h b/libs/libcurl/src/curl_multibyte.h
index 449d0ac97f..7c56631a07 100644
--- a/libs/libcurl/src/curl_multibyte.h
+++ b/libs/libcurl/src/curl_multibyte.h
@@ -25,7 +25,7 @@
***************************************************************************/
#include "curl_setup.h"
-#if defined(_WIN32)
+#ifdef _WIN32
/*
* MultiByte conversions using Windows kernel32 library.
@@ -84,7 +84,7 @@ typedef union {
#define curlx_unicodefree(ptr) \
do { \
if(ptr) { \
- (free)(ptr); \
+ (free)(CURL_UNCONST(ptr)); \
(ptr) = NULL; \
} \
} while(0)
diff --git a/libs/libcurl/src/curl_ntlm_core.c b/libs/libcurl/src/curl_ntlm_core.c
index 944bfa2c09..b574a1b612 100644
--- a/libs/libcurl/src/curl_ntlm_core.c
+++ b/libs/libcurl/src/curl_ntlm_core.c
@@ -71,16 +71,7 @@
# include <openssl/md5.h>
# include <openssl/ssl.h>
# include <openssl/rand.h>
-# if (defined(OPENSSL_VERSION_NUMBER) && \
- (OPENSSL_VERSION_NUMBER < 0x00907001L)) && !defined(USE_WOLFSSL)
-# define DES_key_schedule des_key_schedule
-# define DES_cblock des_cblock
-# define DES_set_odd_parity des_set_odd_parity
-# define DES_set_key des_set_key
-# define DES_ecb_encrypt des_ecb_encrypt
-# define DESKEY(x) x
-# define DESKEYARG(x) x
-# elif defined(OPENSSL_IS_AWSLC)
+# if defined(OPENSSL_IS_AWSLC)
# define DES_set_key_unchecked (void)DES_set_key
# define DESKEYARG(x) *x
# define DESKEY(x) &x
@@ -144,9 +135,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00"
-#define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4)
-
#if !defined(CURL_NTLM_NOT_SUPPORTED)
/*
* Turns a 56-bit key into being 64-bit wide.
@@ -333,16 +321,16 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
DES_key_schedule ks;
setup_des_key(keys, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
- DESKEY(ks), DES_ENCRYPT);
+ DES_ecb_encrypt((DES_cblock*)CURL_UNCONST(plaintext),
+ (DES_cblock*)results, DESKEY(ks), DES_ENCRYPT);
setup_des_key(keys + 7, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8),
- DESKEY(ks), DES_ENCRYPT);
+ DES_ecb_encrypt((DES_cblock*)CURL_UNCONST(plaintext),
+ (DES_cblock*)(results + 8), DESKEY(ks), DES_ENCRYPT);
setup_des_key(keys + 14, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
- DESKEY(ks), DES_ENCRYPT);
+ DES_ecb_encrypt((DES_cblock*)CURL_UNCONST(plaintext),
+ (DES_cblock*)(results + 16), DESKEY(ks), DES_ENCRYPT);
#elif defined(USE_GNUTLS)
struct des_ctx des;
setup_des_key(keys, &des);
@@ -387,12 +375,12 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
DES_key_schedule ks;
setup_des_key(pw, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
- DESKEY(ks), DES_ENCRYPT);
+ DES_ecb_encrypt((DES_cblock *)CURL_UNCONST(magic),
+ (DES_cblock *)lmbuffer, DESKEY(ks), DES_ENCRYPT);
setup_des_key(pw + 7, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
- DESKEY(ks), DES_ENCRYPT);
+ DES_ecb_encrypt((DES_cblock *)CURL_UNCONST(magic),
+ (DES_cblock *)(lmbuffer + 8), DESKEY(ks), DES_ENCRYPT);
#elif defined(USE_GNUTLS)
struct des_ctx des;
setup_des_key(pw, &des);
@@ -465,6 +453,9 @@ CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
#if !defined(USE_WINDOWS_SSPI)
+#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00"
+#define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4)
+
/* Timestamp in tenths of a microsecond since January 1, 1601 00:00:00 UTC. */
struct ms_filetime {
unsigned int dwLowDateTime;
@@ -626,7 +617,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
/* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */
memcpy(ptr + 8, &ntlm->nonce[0], 8);
result = Curl_hmacit(&Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8,
- NTLMv2_BLOB_LEN + 8, hmac_output);
+ NTLMv2_BLOB_LEN + 8, hmac_output);
if(result) {
free(ptr);
return result;
diff --git a/libs/libcurl/src/curl_range.c b/libs/libcurl/src/curl_range.c
index 3ab7f98b3c..795ff097df 100644
--- a/libs/libcurl/src/curl_range.c
+++ b/libs/libcurl/src/curl_range.c
@@ -26,7 +26,7 @@
#include <curl/curl.h>
#include "curl_range.h"
#include "sendf.h"
-#include "strtoofft.h"
+#include "strparse.h"
/* Only include this function if one or more of FTP, FILE are enabled. */
#if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE)
@@ -37,28 +37,29 @@
*/
CURLcode Curl_range(struct Curl_easy *data)
{
- curl_off_t from, to;
- char *ptr;
- char *ptr2;
-
if(data->state.use_range && data->state.range) {
- CURLofft from_t;
- CURLofft to_t;
- from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
- if(from_t == CURL_OFFT_FLOW)
- return CURLE_RANGE_ERROR;
- while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
- ptr++;
- to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
- if(to_t == CURL_OFFT_FLOW)
+ curl_off_t from, to;
+ bool first_num = TRUE;
+ const char *p = data->state.range;
+ if(Curl_str_number(&p, &from, CURL_OFF_T_MAX))
+ first_num = FALSE;
+
+ if(Curl_str_single(&p, '-'))
+ /* no leading dash or after the first number is an error */
return CURLE_RANGE_ERROR;
- if((to_t == CURL_OFFT_INVAL) && !from_t) {
+
+ if(Curl_str_number(&p, &to, CURL_OFF_T_MAX)) {
+ /* no second number */
/* X - */
data->state.resume_from = from;
DEBUGF(infof(data, "RANGE %" FMT_OFF_T " to end of file", from));
}
- else if((from_t == CURL_OFFT_INVAL) && !to_t) {
+ else if(!first_num) {
/* -Y */
+ if(!to)
+ /* "-0" is just wrong */
+ return CURLE_RANGE_ERROR;
+
data->req.maxdownload = to;
data->state.resume_from = -to;
DEBUGF(infof(data, "RANGE the last %" FMT_OFF_T " bytes", to));
diff --git a/libs/libcurl/src/curl_rtmp.c b/libs/libcurl/src/curl_rtmp.c
index d00c1f4e22..e3a075dc5e 100644
--- a/libs/libcurl/src/curl_rtmp.c
+++ b/libs/libcurl/src/curl_rtmp.c
@@ -344,7 +344,7 @@ static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
(void)sockindex; /* unused */
(void)eos; /* unused */
- num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
+ num = RTMP_Write(r, (const char *)buf, curlx_uztosi(len));
if(num < 0)
*err = CURLE_SEND_ERROR;
diff --git a/libs/libcurl/src/curl_sasl.c b/libs/libcurl/src/curl_sasl.c
index 729e192f41..09a2b85719 100644
--- a/libs/libcurl/src/curl_sasl.c
+++ b/libs/libcurl/src/curl_sasl.c
@@ -50,7 +50,6 @@
#include "curl_hmac.h"
#include "curl_sasl.h"
#include "warnless.h"
-#include "strtok.h"
#include "sendf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
diff --git a/libs/libcurl/src/curl_setup.h b/libs/libcurl/src/curl_setup.h
index 1fd2b16c4e..88c3e12dcc 100644
--- a/libs/libcurl/src/curl_setup.h
+++ b/libs/libcurl/src/curl_setup.h
@@ -56,7 +56,7 @@
# endif
#endif
-#if defined(__APPLE__)
+#ifdef __APPLE__
#include <sys/types.h>
#include <TargetConditionals.h>
/* Fixup faulty target macro initialization in macOS SDK since v14.4 (as of
@@ -78,6 +78,12 @@
#endif
#endif
+/* Visual Studio 2008 is the minimum Visual Studio version we support.
+ Workarounds for older versions of Visual Studio have been removed. */
+#if defined(_MSC_VER) && (_MSC_VER < 1500)
+#error "Ancient versions of Visual Studio are no longer supported due to bugs."
+#endif
+
#ifdef _MSC_VER
/* Disable Visual Studio warnings: 4127 "conditional expression is constant" */
#pragma warning(disable:4127)
@@ -102,6 +108,24 @@
# ifndef NOGDI
# define NOGDI
# endif
+/* Detect Windows App environment which has a restricted access
+ * to the Win32 APIs. */
+# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
+ defined(WINAPI_FAMILY)
+# include <winapifamily.h>
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define CURL_WINDOWS_UWP
+# endif
+# endif
+#endif
+
+/* Avoid bogus format check warnings with mingw32ce gcc 4.4.0 in
+ C99 (-std=gnu99) mode */
+#if defined(__MINGW32CE__) && !defined(CURL_NO_FMT_CHECKS) && \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) && \
+ (defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 4))
+#define CURL_NO_FMT_CHECKS
#endif
/* Compatibility */
@@ -151,6 +175,12 @@
/* system header files in our config files, avoid this at any cost. */
/* ================================================================ */
+#ifdef HAVE_LIBZ
+# ifndef ZLIB_CONST
+# define ZLIB_CONST /* Use z_const. Supported by v1.2.5.2 and upper. */
+# endif
+#endif
+
/*
* AIX 4.3 and newer needs _THREAD_SAFE defined to build
* proper reentrant code. Others may also need it.
@@ -252,7 +282,7 @@
* When HTTP is disabled, disable HTTP-only features
*/
-#if defined(CURL_DISABLE_HTTP)
+#ifdef CURL_DISABLE_HTTP
# define CURL_DISABLE_ALTSVC 1
# define CURL_DISABLE_COOKIES 1
# define CURL_DISABLE_BASIC_AUTH 1
@@ -439,9 +469,9 @@
#endif
#ifdef _WIN32
-#define Curl_getpid() GetCurrentProcessId()
+#define curlx_getpid() GetCurrentProcessId()
#else
-#define Curl_getpid() getpid()
+#define curlx_getpid() getpid()
#endif
/*
@@ -449,7 +479,9 @@
*/
#ifdef USE_WIN32_LARGE_FILES
+# ifdef HAVE_IO_H
# include <io.h>
+# endif
# include <sys/types.h>
# include <sys/stat.h>
# undef lseek
@@ -480,10 +512,12 @@
*/
#if defined(_WIN32) && !defined(USE_WIN32_LARGE_FILES)
+# ifdef HAVE_IO_H
# include <io.h>
+# endif
# include <sys/types.h>
# include <sys/stat.h>
-# ifndef _WIN32_WCE
+# ifndef UNDER_CE
# undef lseek
# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
# define fstat(fdes,stp) _fstat(fdes, stp)
@@ -658,7 +692,6 @@
# ifdef __minix
/* Minix 3 versions up to at least 3.1.3 are missing these prototypes */
- extern char *strtok_r(char *s, const char *delim, char **last);
extern struct tm *gmtime_r(const time_t * const timep, struct tm *tmp);
# endif
@@ -672,16 +705,6 @@
/* ---------------------------------------------------------------- */
/*
- * MSVC threads support requires a multi-threaded runtime library.
- * _beginthreadex() is not available in single-threaded ones.
- * Single-threaded option was last available in VS2005: _MSC_VER <= 1400
- */
-#if defined(_MSC_VER) && !defined(_MT) /* available in _MSC_VER <= 1400 */
-# undef USE_THREADS_POSIX
-# undef USE_THREADS_WIN32
-#endif
-
-/*
* Mutually exclusive CURLRES_* definitions.
*/
@@ -754,7 +777,7 @@
#endif
/* Single point where USE_NTLM definition might be defined */
-#if !defined(CURL_DISABLE_NTLM)
+#ifndef CURL_DISABLE_NTLM
# if defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
defined(USE_GNUTLS) || defined(USE_SECTRANSP) || \
defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \
@@ -794,7 +817,7 @@
/* noreturn attribute */
-#if !defined(CURL_NORETURN)
+#ifndef CURL_NORETURN
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) || \
defined(__IAR_SYSTEMS_ICC__)
# define CURL_NORETURN __attribute__((__noreturn__))
@@ -807,7 +830,7 @@
/* fallthrough attribute */
-#if !defined(FALLTHROUGH)
+#ifndef FALLTHROUGH
#if (defined(__GNUC__) && __GNUC__ >= 7) || \
(defined(__clang__) && __clang_major__ >= 10)
# define FALLTHROUGH() __attribute__((fallthrough))
@@ -824,6 +847,27 @@
#include "curl_setup_once.h"
#endif
+#ifdef UNDER_CE
+#define getenv curl_getenv /* Windows CE does not support getenv() */
+#define raise(s) ((void)(s))
+/* Terrible workarounds to make Windows CE compile */
+#define errno 0
+#define CURL_SETERRNO(x) ((void)(x))
+#define EINTR 4
+#define EAGAIN 11
+#define ENOMEM 12
+#define EACCES 13
+#define EEXIST 17
+#define EISDIR 21
+#define EINVAL 22
+#define ENOSPC 28
+#define strerror(x) "?"
+#undef STDIN_FILENO
+#define STDIN_FILENO 0
+#else
+#define CURL_SETERRNO(x) (errno = (x))
+#endif
+
/*
* Definition of our NOP statement Object-like macro
*/
@@ -868,6 +912,17 @@
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
+/* For MSVC (all versions as of VS2022) */
+#ifndef STDIN_FILENO
+#define STDIN_FILENO fileno(stdin)
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO fileno(stdout)
+#endif
+#ifndef STDERR_FILENO
+#define STDERR_FILENO fileno(stderr)
+#endif
+
/* Since O_BINARY is used in bitmasks, setting it to zero makes it usable in
source code but yet it does not ruin anything */
#ifdef O_BINARY
@@ -925,6 +980,16 @@ endings either CRLF or LF so 't' is appropriate.
#define CURL_ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#ifdef CURLDEBUG
+#define CURL_GETADDRINFO(host,serv,hint,res) \
+ curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
+#define CURL_FREEADDRINFO(data) \
+ curl_dbg_freeaddrinfo(data, __LINE__, __FILE__)
+#else
+#define CURL_GETADDRINFO getaddrinfo
+#define CURL_FREEADDRINFO freeaddrinfo
+#endif
+
/* Some versions of the Android NDK is missing the declaration */
#if defined(HAVE_GETPWUID_R) && \
defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
@@ -987,7 +1052,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
# endif
#endif
-#if defined(CURL_INLINE)
+#ifdef CURL_INLINE
/* 'CURL_INLINE' defined, use as-is */
#elif defined(inline)
# define CURL_INLINE inline /* 'inline' defined, assumed correct */
diff --git a/libs/libcurl/src/curl_setup_once.h b/libs/libcurl/src/curl_setup_once.h
index efd025730a..89ee951f9d 100644
--- a/libs/libcurl/src/curl_setup_once.h
+++ b/libs/libcurl/src/curl_setup_once.h
@@ -33,7 +33,9 @@
#include <string.h>
#include <stdarg.h>
#include <time.h>
+#ifndef UNDER_CE
#include <errno.h>
+#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
@@ -63,10 +65,20 @@
#include <unistd.h>
#endif
-#ifdef USE_WOLFSSL
+#if defined(HAVE_STDINT_H) || defined(USE_WOLFSSL)
#include <stdint.h>
#endif
+/* Macro to strip 'const' without triggering a compiler warning.
+ Use it for APIs that do not or cannot support the const qualifier. */
+#ifdef HAVE_STDINT_H
+# define CURL_UNCONST(p) ((void *)(uintptr_t)(const void *)(p))
+#elif defined(_WIN32) /* for VS2008 */
+# define CURL_UNCONST(p) ((void *)(ULONG_PTR)(const void *)(p))
+#else
+# define CURL_UNCONST(p) ((void *)(p)) /* Fall back to simple cast */
+#endif
+
#ifdef USE_SCHANNEL
/* Must set this before <schannel.h> is included directly or indirectly by
another Windows header. */
@@ -123,7 +135,7 @@ struct timeval {
#endif
-#if defined(__minix)
+#ifdef __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), \
@@ -163,15 +175,14 @@ struct timeval {
#endif /* HAVE_RECV */
-#if defined(__minix)
+#ifdef __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))
-
+ (SEND_TYPE_ARG2)CURL_UNCONST(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), \
+ (SEND_QUAL_ARG2 SEND_TYPE_ARG2)CURL_UNCONST(y), \
(SEND_TYPE_ARG3)(z), \
(SEND_TYPE_ARG4)(SEND_4TH_ARG))
#else /* HAVE_SEND */
@@ -185,7 +196,7 @@ struct timeval {
* Function-like macro definition used to close a socket.
*/
-#if defined(HAVE_CLOSESOCKET)
+#ifdef HAVE_CLOSESOCKET
# define sclose(x) closesocket((x))
#elif defined(HAVE_CLOSESOCKET_CAMEL)
# define sclose(x) CloseSocket((x))
@@ -200,7 +211,7 @@ struct timeval {
/*
* Stack-independent version of fcntl() on sockets:
*/
-#if defined(USE_LWIPSOCK)
+#ifdef USE_LWIPSOCK
# define sfcntl lwip_fcntl
#else
# define sfcntl fcntl
@@ -284,7 +295,7 @@ typedef unsigned int bit;
*/
#undef DEBUGASSERT
-#if defined(DEBUGBUILD)
+#ifdef DEBUGBUILD
#define DEBUGASSERT(x) assert(x)
#else
#define DEBUGASSERT(x) do { } while(0)
@@ -310,78 +321,39 @@ typedef unsigned int bit;
*/
#ifdef USE_WINSOCK
-#undef EBADF /* override definition in errno.h */
-#define EBADF WSAEBADF
-#undef EINTR /* override definition in errno.h */
-#define EINTR WSAEINTR
-#undef EINVAL /* override definition in errno.h */
-#define EINVAL WSAEINVAL
-#undef EWOULDBLOCK /* override definition in errno.h */
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#undef EINPROGRESS /* override definition in errno.h */
-#define EINPROGRESS WSAEINPROGRESS
-#undef EALREADY /* override definition in errno.h */
-#define EALREADY WSAEALREADY
-#undef ENOTSOCK /* override definition in errno.h */
-#define ENOTSOCK WSAENOTSOCK
-#undef EDESTADDRREQ /* override definition in errno.h */
-#define EDESTADDRREQ WSAEDESTADDRREQ
-#undef EMSGSIZE /* override definition in errno.h */
-#define EMSGSIZE WSAEMSGSIZE
-#undef EPROTOTYPE /* override definition in errno.h */
-#define EPROTOTYPE WSAEPROTOTYPE
-#undef ENOPROTOOPT /* override definition in errno.h */
-#define ENOPROTOOPT WSAENOPROTOOPT
-#undef EPROTONOSUPPORT /* override definition in errno.h */
-#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
-#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
-#undef EOPNOTSUPP /* override definition in errno.h */
-#define EOPNOTSUPP WSAEOPNOTSUPP
-#define EPFNOSUPPORT WSAEPFNOSUPPORT
-#undef EAFNOSUPPORT /* override definition in errno.h */
-#define EAFNOSUPPORT WSAEAFNOSUPPORT
-#undef EADDRINUSE /* override definition in errno.h */
-#define EADDRINUSE WSAEADDRINUSE
-#undef EADDRNOTAVAIL /* override definition in errno.h */
-#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
-#undef ENETDOWN /* override definition in errno.h */
-#define ENETDOWN WSAENETDOWN
-#undef ENETUNREACH /* override definition in errno.h */
-#define ENETUNREACH WSAENETUNREACH
-#undef ENETRESET /* override definition in errno.h */
-#define ENETRESET WSAENETRESET
-#undef ECONNABORTED /* override definition in errno.h */
-#define ECONNABORTED WSAECONNABORTED
-#undef ECONNRESET /* override definition in errno.h */
-#define ECONNRESET WSAECONNRESET
-#undef ENOBUFS /* override definition in errno.h */
-#define ENOBUFS WSAENOBUFS
-#undef EISCONN /* override definition in errno.h */
-#define EISCONN WSAEISCONN
-#undef ENOTCONN /* override definition in errno.h */
-#define ENOTCONN WSAENOTCONN
-#define ESHUTDOWN WSAESHUTDOWN
-#define ETOOMANYREFS WSAETOOMANYREFS
-#undef ETIMEDOUT /* override definition in errno.h */
-#define ETIMEDOUT WSAETIMEDOUT
-#undef ECONNREFUSED /* override definition in errno.h */
-#define ECONNREFUSED WSAECONNREFUSED
-#undef ELOOP /* override definition in errno.h */
-#define ELOOP WSAELOOP
-#ifndef ENAMETOOLONG /* possible previous definition in errno.h */
-#define ENAMETOOLONG WSAENAMETOOLONG
-#endif
-#define EHOSTDOWN WSAEHOSTDOWN
-#undef EHOSTUNREACH /* override definition in errno.h */
-#define EHOSTUNREACH WSAEHOSTUNREACH
-#ifndef ENOTEMPTY /* possible previous definition in errno.h */
-#define ENOTEMPTY WSAENOTEMPTY
+#define SOCKEACCES WSAEACCES
+#define SOCKEADDRINUSE WSAEADDRINUSE
+#define SOCKEADDRNOTAVAIL WSAEADDRNOTAVAIL
+#define SOCKEAFNOSUPPORT WSAEAFNOSUPPORT
+#define SOCKEBADF WSAEBADF
+#define SOCKECONNREFUSED WSAECONNREFUSED
+#define SOCKECONNRESET WSAECONNRESET
+#define SOCKEINPROGRESS WSAEINPROGRESS
+#define SOCKEINTR WSAEINTR
+#define SOCKEINVAL WSAEINVAL
+#define SOCKEISCONN WSAEISCONN
+#define SOCKEMSGSIZE WSAEMSGSIZE
+#define SOCKENOMEM WSA_NOT_ENOUGH_MEMORY
+#define SOCKETIMEDOUT WSAETIMEDOUT
+#define SOCKEWOULDBLOCK WSAEWOULDBLOCK
+#else
+#define SOCKEACCES EACCES
+#define SOCKEADDRINUSE EADDRINUSE
+#define SOCKEADDRNOTAVAIL EADDRNOTAVAIL
+#define SOCKEAFNOSUPPORT EAFNOSUPPORT
+#define SOCKEBADF EBADF
+#define SOCKECONNREFUSED ECONNREFUSED
+#define SOCKECONNRESET ECONNRESET
+#define SOCKEINPROGRESS EINPROGRESS
+#define SOCKEINTR EINTR
+#define SOCKEINVAL EINVAL
+#define SOCKEISCONN EISCONN
+#define SOCKEMSGSIZE EMSGSIZE
+#define SOCKENOMEM ENOMEM
+#ifdef ETIMEDOUT
+#define SOCKETIMEDOUT ETIMEDOUT
#endif
-#define EPROCLIM WSAEPROCLIM
-#define EUSERS WSAEUSERS
-#define EDQUOT WSAEDQUOT
-#define ESTALE WSAESTALE
-#define EREMOTE WSAEREMOTE
+#define SOCKEWOULDBLOCK EWOULDBLOCK
#endif
/*
@@ -390,7 +362,7 @@ typedef unsigned int bit;
#ifdef __VMS
#define argv_item_t __char_ptr32
-#elif defined(_UNICODE)
+#elif defined(_UNICODE) && !defined(UNDER_CE)
#define argv_item_t wchar_t *
#else
#define argv_item_t char *
diff --git a/libs/libcurl/src/curl_sha512_256.c b/libs/libcurl/src/curl_sha512_256.c
index 75708ba914..d43b2e420c 100644
--- a/libs/libcurl/src/curl_sha512_256.c
+++ b/libs/libcurl/src/curl_sha512_256.c
@@ -82,7 +82,6 @@
# include <nettle/sha.h>
# if defined(SHA512_256_DIGEST_SIZE)
# define USE_GNUTLS_SHA512_256 1
-# define HAS_SHA512_256_IMPLEMENTATION 1
# endif
#endif /* ! HAS_SHA512_256_IMPLEMENTATION && USE_GNUTLS */
@@ -269,9 +268,6 @@ Curl_sha512_256_finish(unsigned char *digest,
#else /* No system or TLS backend SHA-512/256 implementation available */
-/* 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 ** *
diff --git a/libs/libcurl/src/curl_sspi.c b/libs/libcurl/src/curl_sspi.c
index a08957c7cc..cdec76c263 100644
--- a/libs/libcurl/src/curl_sspi.c
+++ b/libs/libcurl/src/curl_sspi.c
@@ -42,7 +42,7 @@ typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
/* See definition of SECURITY_ENTRYPOINT in sspi.h */
#ifdef UNICODE
-# ifdef _WIN32_WCE
+# ifdef UNDER_CE
# define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
# else
# define SECURITYENTRYPOINT "InitSecurityInterfaceW"
@@ -154,7 +154,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
/* Initialize the identity */
memset(identity, 0, sizeof(*identity));
- useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)userp);
+ useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar(userp);
if(!useranddomain.tchar_ptr)
return CURLE_OUT_OF_MEMORY;
@@ -198,7 +198,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
curlx_unicodefree(useranddomain.tchar_ptr);
/* Setup the identity's password and length */
- passwd.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)passwdp);
+ passwd.tchar_ptr = curlx_convert_UTF8_to_tchar(passwdp);
if(!passwd.tchar_ptr)
return CURLE_OUT_OF_MEMORY;
dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
diff --git a/libs/libcurl/src/curl_sspi.h b/libs/libcurl/src/curl_sspi.h
index e5a843fbd2..6d72774862 100644
--- a/libs/libcurl/src/curl_sspi.h
+++ b/libs/libcurl/src/curl_sspi.h
@@ -70,6 +70,225 @@ extern PSecurityFunctionTable Curl_pSecFn;
#define ISC_REQ_USE_HTTP_STYLE 0x01000000
#endif
+#ifdef __MINGW32CE__
+#ifndef ISC_RET_REPLAY_DETECT
+#define ISC_RET_REPLAY_DETECT 0x00000004
+#endif
+#ifndef ISC_RET_SEQUENCE_DETECT
+#define ISC_RET_SEQUENCE_DETECT 0x00000008
+#endif
+#ifndef ISC_RET_CONFIDENTIALITY
+#define ISC_RET_CONFIDENTIALITY 0x00000010
+#endif
+#ifndef ISC_RET_ALLOCATED_MEMORY
+#define ISC_RET_ALLOCATED_MEMORY 0x00000100
+#endif
+#ifndef ISC_RET_STREAM
+#define ISC_RET_STREAM 0x00008000
+#endif
+
+#ifndef SEC_E_INSUFFICIENT_MEMORY
+#define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L)
+#endif
+#ifndef SEC_E_INVALID_HANDLE
+#define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L)
+#endif
+#ifndef SEC_E_UNSUPPORTED_FUNCTION
+#define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L)
+#endif
+#ifndef SEC_E_TARGET_UNKNOWN
+#define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L)
+#endif
+#ifndef SEC_E_INTERNAL_ERROR
+#define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L)
+#endif
+#ifndef SEC_E_SECPKG_NOT_FOUND
+#define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L)
+#endif
+#ifndef SEC_E_NOT_OWNER
+#define SEC_E_NOT_OWNER ((HRESULT)0x80090306L)
+#endif
+#ifndef SEC_E_CANNOT_INSTALL
+#define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L)
+#endif
+#ifndef SEC_E_INVALID_TOKEN
+#define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L)
+#endif
+#ifndef SEC_E_CANNOT_PACK
+#define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L)
+#endif
+#ifndef SEC_E_QOP_NOT_SUPPORTED
+#define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL)
+#endif
+#ifndef SEC_E_NO_IMPERSONATION
+#define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL)
+#endif
+#ifndef SEC_E_LOGON_DENIED
+#define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL)
+#endif
+#ifndef SEC_E_UNKNOWN_CREDENTIALS
+#define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL)
+#endif
+#ifndef SEC_E_NO_CREDENTIALS
+#define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL)
+#endif
+#ifndef SEC_E_MESSAGE_ALTERED
+#define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL)
+#endif
+#ifndef SEC_E_OUT_OF_SEQUENCE
+#define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L)
+#endif
+#ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY
+#define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L)
+#endif
+#ifndef SEC_E_BAD_PKGID
+#define SEC_E_BAD_PKGID ((HRESULT)0x80090316L)
+#endif
+#ifndef SEC_E_CONTEXT_EXPIRED
+#define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L)
+#endif
+#ifndef SEC_E_INCOMPLETE_MESSAGE
+#define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L)
+#endif
+#ifndef SEC_E_INCOMPLETE_CREDENTIALS
+#define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L)
+#endif
+#ifndef SEC_E_BUFFER_TOO_SMALL
+#define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L)
+#endif
+#ifndef SEC_E_WRONG_PRINCIPAL
+#define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L)
+#endif
+#ifndef SEC_E_TIME_SKEW
+#define SEC_E_TIME_SKEW ((HRESULT)0x80090324L)
+#endif
+#ifndef SEC_E_UNTRUSTED_ROOT
+#define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L)
+#endif
+#ifndef SEC_E_ILLEGAL_MESSAGE
+#define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L)
+#endif
+#ifndef SEC_E_CERT_UNKNOWN
+#define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L)
+#endif
+#ifndef SEC_E_CERT_EXPIRED
+#define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L)
+#endif
+#ifndef SEC_E_ENCRYPT_FAILURE
+#define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L)
+#endif
+#ifndef SEC_E_DECRYPT_FAILURE
+#define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L)
+#endif
+#ifndef SEC_E_ALGORITHM_MISMATCH
+#define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L)
+#endif
+#ifndef SEC_E_SECURITY_QOS_FAILED
+#define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L)
+#endif
+#ifndef SEC_E_UNFINISHED_CONTEXT_DELETED
+#define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L)
+#endif
+#ifndef SEC_E_NO_TGT_REPLY
+#define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L)
+#endif
+#ifndef SEC_E_NO_IP_ADDRESSES
+#define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L)
+#endif
+#ifndef SEC_E_WRONG_CREDENTIAL_HANDLE
+#define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L)
+#endif
+#ifndef SEC_E_CRYPTO_SYSTEM_INVALID
+#define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L)
+#endif
+#ifndef SEC_E_MAX_REFERRALS_EXCEEDED
+#define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L)
+#endif
+#ifndef SEC_E_MUST_BE_KDC
+#define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L)
+#endif
+#ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED
+#define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL)
+#endif
+#ifndef SEC_E_TOO_MANY_PRINCIPALS
+#define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL)
+#endif
+#ifndef SEC_E_NO_PA_DATA
+#define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL)
+#endif
+#ifndef SEC_E_PKINIT_NAME_MISMATCH
+#define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL)
+#endif
+#ifndef SEC_E_SMARTCARD_LOGON_REQUIRED
+#define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL)
+#endif
+#ifndef SEC_E_SHUTDOWN_IN_PROGRESS
+#define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL)
+#endif
+#ifndef SEC_E_KDC_INVALID_REQUEST
+#define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L)
+#endif
+#ifndef SEC_E_KDC_UNABLE_TO_REFER
+#define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L)
+#endif
+#ifndef SEC_E_KDC_UNKNOWN_ETYPE
+#define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L)
+#endif
+#ifndef SEC_E_UNSUPPORTED_PREAUTH
+#define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L)
+#endif
+#ifndef SEC_E_DELEGATION_REQUIRED
+#define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L)
+#endif
+#ifndef SEC_E_BAD_BINDINGS
+#define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L)
+#endif
+#ifndef SEC_E_MULTIPLE_ACCOUNTS
+#define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L)
+#endif
+#ifndef SEC_E_NO_KERB_KEY
+#define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L)
+#endif
+#ifndef SEC_E_CERT_WRONG_USAGE
+#define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L)
+#endif
+#ifndef SEC_E_DOWNGRADE_DETECTED
+#define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L)
+#endif
+#ifndef SEC_E_SMARTCARD_CERT_REVOKED
+#define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L)
+#endif
+#ifndef SEC_E_ISSUING_CA_UNTRUSTED
+#define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L)
+#endif
+#ifndef SEC_E_REVOCATION_OFFLINE_C
+#define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L)
+#endif
+#ifndef SEC_E_PKINIT_CLIENT_FAILURE
+#define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L)
+#endif
+#ifndef SEC_E_SMARTCARD_CERT_EXPIRED
+#define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L)
+#endif
+#ifndef SEC_E_NO_S4U_PROT_SUPPORT
+#define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L)
+#endif
+#ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE
+#define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L)
+#endif
+#ifndef SEC_E_REVOCATION_OFFLINE_KDC
+#define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L)
+#endif
+#ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC
+#define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L)
+#endif
+#ifndef SEC_E_KDC_CERT_EXPIRED
+#define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL)
+#endif
+#ifndef SEC_E_KDC_CERT_REVOKED
+#define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL)
+#endif
+#endif /* __MINGW32CE__ */
#ifndef SEC_E_INVALID_PARAMETER
# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL)
#endif
@@ -80,6 +299,32 @@ extern PSecurityFunctionTable Curl_pSecFn;
# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL)
#endif
+#ifdef __MINGW32CE__
+#ifndef SEC_I_CONTINUE_NEEDED
+#define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L)
+#endif
+#ifndef SEC_I_COMPLETE_NEEDED
+#define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L)
+#endif
+#ifndef SEC_I_COMPLETE_AND_CONTINUE
+#define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L)
+#endif
+#ifndef SEC_I_LOCAL_LOGON
+#define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L)
+#endif
+#ifndef SEC_I_CONTEXT_EXPIRED
+#define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L)
+#endif
+#ifndef SEC_I_INCOMPLETE_CREDENTIALS
+#define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L)
+#endif
+#ifndef SEC_I_RENEGOTIATE
+#define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L)
+#endif
+#ifndef SEC_I_NO_LSA_CONTEXT
+#define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L)
+#endif
+#endif /* __MINGW32CE__ */
#ifndef SEC_I_SIGNATURE_NEEDED
#define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL)
#endif
diff --git a/libs/libcurl/src/curl_threads.c b/libs/libcurl/src/curl_threads.c
index 3879fb4355..caee0a6df9 100644
--- a/libs/libcurl/src/curl_threads.c
+++ b/libs/libcurl/src/curl_threads.c
@@ -103,7 +103,7 @@ int Curl_thread_join(curl_thread_t *hnd)
#elif defined(USE_THREADS_WIN32)
curl_thread_t Curl_thread_create(
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
DWORD
#else
unsigned int
@@ -111,25 +111,27 @@ curl_thread_t Curl_thread_create(
(CURL_STDCALL *func) (void *),
void *arg)
{
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
typedef HANDLE 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_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
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
+#ifdef UNDER_CE
DWORD gle = GetLastError();
- errno = ((gle == ERROR_ACCESS_DENIED ||
- gle == ERROR_NOT_ENOUGH_MEMORY) ?
- EACCES : EINVAL);
+ /* !checksrc! disable ERRNOVAR 1 */
+ int err = (gle == ERROR_ACCESS_DENIED ||
+ gle == ERROR_NOT_ENOUGH_MEMORY) ?
+ EACCES : EINVAL;
+ CURL_SETERRNO(err);
#endif
return curl_thread_t_null;
}
diff --git a/libs/libcurl/src/curl_threads.h b/libs/libcurl/src/curl_threads.h
index 3b29556ffd..b8e4b316fa 100644
--- a/libs/libcurl/src/curl_threads.h
+++ b/libs/libcurl/src/curl_threads.h
@@ -53,7 +53,7 @@
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
curl_thread_t Curl_thread_create(
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
DWORD
#else
unsigned int
diff --git a/libs/libcurl/src/curl_trc.c b/libs/libcurl/src/curl_trc.c
index 2e3c42ed87..4ac583b140 100644
--- a/libs/libcurl/src/curl_trc.c
+++ b/libs/libcurl/src/curl_trc.c
@@ -30,7 +30,6 @@
#include "urldata.h"
#include "easyif.h"
#include "cfilters.h"
-#include "timeval.h"
#include "multiif.h"
#include "strcase.h"
@@ -44,7 +43,7 @@
#include "cf-haproxy.h"
#include "cf-https-connect.h"
#include "socks.h"
-#include "strtok.h"
+#include "strparse.h"
#include "vtls/vtls.h"
#include "vquic/vquic.h"
@@ -53,19 +52,20 @@
#include "curl_memory.h"
#include "memdebug.h"
-void Curl_debug(struct Curl_easy *data, curl_infotype type,
- char *ptr, size_t size)
+static void trc_write(struct Curl_easy *data, curl_infotype type,
+ const char *ptr, size_t size)
{
if(data->set.verbose) {
- static const char s_infotype[CURLINFO_END][3] = {
- "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
if(data->set.fdebug) {
bool inCallback = Curl_is_in_callback(data);
Curl_set_in_callback(data, TRUE);
- (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
+ (void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr), size,
+ data->set.debugdata);
Curl_set_in_callback(data, inCallback);
}
else {
+ static const char s_infotype[CURLINFO_END][3] = {
+ "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
switch(type) {
case CURLINFO_TEXT:
case CURLINFO_HEADER_OUT:
@@ -80,6 +80,101 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
}
}
+/* max length we trace before ending in '...' */
+#define TRC_LINE_MAX 2048
+
+#define CURL_TRC_FMT_IDSC "[x-%" CURL_FORMAT_CURL_OFF_T "] "
+#define CURL_TRC_FMT_IDSD "[%" CURL_FORMAT_CURL_OFF_T "-x] "
+#define CURL_TRC_FMT_IDSDC "[%" CURL_FORMAT_CURL_OFF_T "-%" \
+ CURL_FORMAT_CURL_OFF_T "] "
+
+static struct curl_trc_feat Curl_trc_feat_ids = {
+ "LIB-IDS",
+ CURL_LOG_LVL_NONE,
+};
+#define CURL_TRC_IDS(data) \
+ (Curl_trc_is_verbose(data) && \
+ Curl_trc_feat_ids.log_level >= CURL_LOG_LVL_INFO)
+
+static size_t trc_print_ids(struct Curl_easy *data, char *buf, size_t maxlen)
+{
+ curl_off_t cid = data->conn ?
+ data->conn->connection_id : data->state.recent_conn_id;
+ if(data->id >= 0) {
+ if(cid >= 0)
+ return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSDC, data->id, cid);
+ else
+ return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSD, data->id);
+ }
+ else if(cid >= 0)
+ return msnprintf(buf, maxlen, CURL_TRC_FMT_IDSC, cid);
+ else {
+ return msnprintf(buf, maxlen, "[x-x] ");
+ }
+}
+
+static size_t trc_end_buf(char *buf, size_t len, size_t maxlen, bool addnl)
+{
+ /* make sure we end the trace line in `buf` properly. It needs
+ * to end with a terminating '\0' or '\n\0' */
+ if(len >= (maxlen - (addnl ? 2 : 1))) {
+ len = maxlen - 5;
+ buf[len++] = '.';
+ buf[len++] = '.';
+ buf[len++] = '.';
+ buf[len++] = '\n';
+ }
+ else if(addnl)
+ buf[len++] = '\n';
+ buf[len] = '\0';
+ return len;
+}
+
+void Curl_debug(struct Curl_easy *data, curl_infotype type,
+ const char *ptr, size_t size)
+{
+ if(data->set.verbose) {
+ static const char s_infotype[CURLINFO_END][3] = {
+ "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
+ char buf[TRC_LINE_MAX];
+ size_t len;
+ if(data->set.fdebug) {
+ bool inCallback = Curl_is_in_callback(data);
+
+ if(CURL_TRC_IDS(data) && (size < TRC_LINE_MAX)) {
+ len = trc_print_ids(data, buf, TRC_LINE_MAX);
+ len += msnprintf(buf + len, TRC_LINE_MAX - len, "%.*s",
+ (int)size, ptr);
+ len = trc_end_buf(buf, len, TRC_LINE_MAX, FALSE);
+ Curl_set_in_callback(data, TRUE);
+ (void)(*data->set.fdebug)(data, type, buf, len, data->set.debugdata);
+ Curl_set_in_callback(data, inCallback);
+ }
+ else {
+ Curl_set_in_callback(data, TRUE);
+ (void)(*data->set.fdebug)(data, type, CURL_UNCONST(ptr),
+ size, data->set.debugdata);
+ Curl_set_in_callback(data, inCallback);
+ }
+ }
+ else {
+ switch(type) {
+ case CURLINFO_TEXT:
+ case CURLINFO_HEADER_OUT:
+ case CURLINFO_HEADER_IN:
+ if(CURL_TRC_IDS(data)) {
+ len = trc_print_ids(data, buf, TRC_LINE_MAX);
+ fwrite(buf, len, 1, data->set.err);
+ }
+ fwrite(s_infotype[type], 2, 1, data->set.err);
+ fwrite(ptr, size, 1, data->set.err);
+ break;
+ default: /* nada */
+ break;
+ }
+ }
+ }
+}
/* Curl_failf() is for messages stating why we failed.
* The message SHALL NOT include any LF or CR.
@@ -89,7 +184,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
DEBUGASSERT(!strchr(fmt, '\n'));
if(data->set.verbose || data->set.errorbuffer) {
va_list ap;
- int len;
+ size_t len;
char error[CURL_ERROR_SIZE + 2];
va_start(ap, fmt);
len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
@@ -100,36 +195,41 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
}
error[len++] = '\n';
error[len] = '\0';
- Curl_debug(data, CURLINFO_TEXT, error, len);
+ trc_write(data, CURLINFO_TEXT, error, len);
va_end(ap);
}
}
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-/* Curl_infof() is for info message along the way */
-#define MAXINFO 2048
-static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
- const char * const fmt, va_list ap) CURL_PRINTF(3, 0);
+static void trc_infof(struct Curl_easy *data,
+ struct curl_trc_feat *feat,
+ const char *opt_id, int opt_id_idx,
+ const char * const fmt, va_list ap) CURL_PRINTF(5, 0);
-static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
+static void trc_infof(struct Curl_easy *data,
+ struct curl_trc_feat *feat,
+ const char *opt_id, int opt_id_idx,
const char * const fmt, va_list ap)
{
- int len = 0;
- char buffer[MAXINFO + 5];
+ size_t len = 0;
+ char buf[TRC_LINE_MAX];
+
+ if(CURL_TRC_IDS(data))
+ len += trc_print_ids(data, buf + len, TRC_LINE_MAX - len);
if(feat)
- len = msnprintf(buffer, (MAXINFO + 1), "[%s] ", feat->name);
- len += mvsnprintf(buffer + len, (MAXINFO + 1) - len, fmt, ap);
- if(len >= MAXINFO) { /* too long, shorten with '...' */
- --len;
- buffer[len++] = '.';
- buffer[len++] = '.';
- buffer[len++] = '.';
+ len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", feat->name);
+ if(opt_id) {
+ if(opt_id_idx > 0)
+ len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s-%d] ",
+ opt_id, opt_id_idx);
+ else
+ len += msnprintf(buf + len, TRC_LINE_MAX - len, "[%s] ", opt_id);
}
- buffer[len++] = '\n';
- buffer[len] = '\0';
- Curl_debug(data, CURLINFO_TEXT, buffer, len);
+ len += mvsnprintf(buf + len, TRC_LINE_MAX - len, fmt, ap);
+ len = trc_end_buf(buf, len, TRC_LINE_MAX, TRUE);
+ trc_write(data, CURLINFO_TEXT, buf, len);
}
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
@@ -138,36 +238,27 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_is_verbose(data)) {
va_list ap;
va_start(ap, fmt);
- trc_infof(data, data->state.feat, fmt, ap);
+ trc_infof(data, data->state.feat, NULL, 0, fmt, ap);
va_end(ap);
}
}
-void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
+void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
const char *fmt, ...)
{
DEBUGASSERT(cf);
if(Curl_trc_cf_is_verbose(cf, data)) {
va_list ap;
- int len = 0;
- char buffer[MAXINFO + 2];
- if(data->state.feat)
- len += msnprintf(buffer + len, MAXINFO - len, "[%s] ",
- data->state.feat->name);
- if(cf->sockindex)
- len += msnprintf(buffer + len, MAXINFO - len, "[%s-%d] ",
- cf->cft->name, cf->sockindex);
- else
- len += msnprintf(buffer + len, MAXINFO - len, "[%s] ", cf->cft->name);
va_start(ap, fmt);
- len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
+ trc_infof(data, data->state.feat, cf->cft->name, cf->sockindex, fmt, ap);
va_end(ap);
- buffer[len++] = '\n';
- buffer[len] = '\0';
- Curl_debug(data, CURLINFO_TEXT, buffer, len);
}
}
+struct curl_trc_feat Curl_trc_feat_multi = {
+ "MULTI",
+ CURL_LOG_LVL_NONE,
+};
struct curl_trc_feat Curl_trc_feat_read = {
"READ",
CURL_LOG_LVL_NONE,
@@ -176,6 +267,52 @@ struct curl_trc_feat Curl_trc_feat_write = {
"WRITE",
CURL_LOG_LVL_NONE,
};
+struct curl_trc_feat Curl_trc_feat_dns = {
+ "DNS",
+ CURL_LOG_LVL_NONE,
+};
+
+
+static const char * const Curl_trc_mstate_names[]={
+ "INIT",
+ "PENDING",
+ "SETUP",
+ "CONNECT",
+ "RESOLVING",
+ "CONNECTING",
+ "TUNNELING",
+ "PROTOCONNECT",
+ "PROTOCONNECTING",
+ "DO",
+ "DOING",
+ "DOING_MORE",
+ "DID",
+ "PERFORMING",
+ "RATELIMITING",
+ "DONE",
+ "COMPLETED",
+ "MSGSENT",
+};
+
+const char *Curl_trc_mstate_name(int state)
+{
+ if((state >= 0) && ((size_t)state < CURL_ARRAYSIZE(Curl_trc_mstate_names)))
+ return Curl_trc_mstate_names[(size_t)state];
+ return "?";
+}
+
+void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
+{
+ DEBUGASSERT(!strchr(fmt, '\n'));
+ if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) {
+ const char *sname = (data->id >= 0) ?
+ Curl_trc_mstate_name(data->mstate) : NULL;
+ va_list ap;
+ va_start(ap, fmt);
+ trc_infof(data, &Curl_trc_feat_multi, sname, 0, fmt, ap);
+ va_end(ap);
+ }
+}
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
{
@@ -183,7 +320,7 @@ void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
va_list ap;
va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_read, fmt, ap);
+ trc_infof(data, &Curl_trc_feat_read, NULL, 0, fmt, ap);
va_end(ap);
}
}
@@ -194,7 +331,18 @@ void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
va_list ap;
va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_write, fmt, ap);
+ trc_infof(data, &Curl_trc_feat_write, NULL, 0, fmt, ap);
+ va_end(ap);
+ }
+}
+
+void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
+{
+ DEBUGASSERT(!strchr(fmt, '\n'));
+ if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
+ va_list ap;
+ va_start(ap, fmt);
+ trc_infof(data, &Curl_trc_feat_dns, NULL, 0, fmt, ap);
va_end(ap);
}
}
@@ -211,7 +359,7 @@ void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
va_list ap;
va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_ftp, fmt, ap);
+ trc_infof(data, &Curl_trc_feat_ftp, NULL, 0, fmt, ap);
va_end(ap);
}
}
@@ -229,7 +377,7 @@ void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
va_list ap;
va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_smtp, fmt, ap);
+ trc_infof(data, &Curl_trc_feat_smtp, NULL, 0, fmt, ap);
va_end(ap);
}
}
@@ -247,7 +395,7 @@ void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
va_list ap;
va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_ssls, fmt, ap);
+ trc_infof(data, &Curl_trc_feat_ssls, NULL, 0, fmt, ap);
va_end(ap);
}
}
@@ -265,7 +413,7 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
va_list ap;
va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_ws, fmt, ap);
+ trc_infof(data, &Curl_trc_feat_ws, NULL, 0, fmt, ap);
va_end(ap);
}
}
@@ -275,6 +423,7 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
#define TRC_CT_PROTOCOL (1<<(0))
#define TRC_CT_NETWORK (1<<(1))
#define TRC_CT_PROXY (1<<(2))
+#define TRC_CT_INTERNALS (1<<(3))
struct trc_feat_def {
struct curl_trc_feat *feat;
@@ -282,13 +431,15 @@ struct trc_feat_def {
};
static struct trc_feat_def trc_feats[] = {
+ { &Curl_trc_feat_ids, TRC_CT_INTERNALS },
+ { &Curl_trc_feat_multi, TRC_CT_NETWORK },
{ &Curl_trc_feat_read, TRC_CT_NONE },
{ &Curl_trc_feat_write, TRC_CT_NONE },
+ { &Curl_trc_feat_dns, TRC_CT_NETWORK },
#ifndef CURL_DISABLE_FTP
{ &Curl_trc_feat_ftp, TRC_CT_PROTOCOL },
#endif
#ifndef CURL_DISABLE_DOH
- { &Curl_doh_trc, TRC_CT_NETWORK },
#endif
#ifndef CURL_DISABLE_SMTP
{ &Curl_trc_feat_smtp, TRC_CT_PROTOCOL },
@@ -341,18 +492,18 @@ static struct trc_cft_def trc_cfts[] = {
#endif
};
-static void trc_apply_level_by_name(const char * const token, int lvl)
+static void trc_apply_level_by_name(struct Curl_str *token, int lvl)
{
size_t i;
for(i = 0; i < CURL_ARRAYSIZE(trc_cfts); ++i) {
- if(strcasecompare(token, trc_cfts[i].cft->name)) {
+ if(Curl_str_casecompare(token, trc_cfts[i].cft->name)) {
trc_cfts[i].cft->log_level = lvl;
break;
}
}
for(i = 0; i < CURL_ARRAYSIZE(trc_feats); ++i) {
- if(strcasecompare(token, trc_feats[i].feat->name)) {
+ if(Curl_str_casecompare(token, trc_feats[i].feat->name)) {
trc_feats[i].feat->log_level = lvl;
break;
}
@@ -375,42 +526,36 @@ static void trc_apply_level_by_category(int category, int lvl)
static CURLcode trc_opt(const char *config)
{
- char *token, *tok_buf, *tmp;
- int lvl;
-
- tmp = strdup(config);
- if(!tmp)
- return CURLE_OUT_OF_MEMORY;
-
- token = Curl_strtok_r(tmp, ", ", &tok_buf);
- while(token) {
- switch(*token) {
- case '-':
- lvl = CURL_LOG_LVL_NONE;
- ++token;
- break;
- case '+':
- lvl = CURL_LOG_LVL_INFO;
- ++token;
- break;
- default:
- lvl = CURL_LOG_LVL_INFO;
- break;
+ struct Curl_str out;
+ while(!Curl_str_until(&config, &out, 32, ',')) {
+ int lvl = CURL_LOG_LVL_INFO;
+ const char *token = Curl_str(&out);
+
+ if(*token == '-') {
+ lvl = CURL_LOG_LVL_NONE;
+ Curl_str_nudge(&out, 1);
}
- if(strcasecompare(token, "all"))
+ else if(*token == '+')
+ Curl_str_nudge(&out, 1);
+
+ if(Curl_str_casecompare(&out, "all"))
trc_apply_level_by_category(TRC_CT_NONE, lvl);
- else if(strcasecompare(token, "protocol"))
+ else if(Curl_str_casecompare(&out, "protocol"))
trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl);
- else if(strcasecompare(token, "network"))
+ else if(Curl_str_casecompare(&out, "network"))
trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
- else if(strcasecompare(token, "proxy"))
+ else if(Curl_str_casecompare(&out, "proxy"))
trc_apply_level_by_category(TRC_CT_PROXY, lvl);
+ else if(Curl_str_casecompare(&out, "doh")) {
+ struct Curl_str dns = { "dns", 3 };
+ trc_apply_level_by_name(&dns, lvl);
+ }
else
- trc_apply_level_by_name(token, lvl);
+ trc_apply_level_by_name(&out, lvl);
- token = Curl_strtok_r(NULL, ", ", &tok_buf);
+ if(Curl_str_single(&config, ','))
+ break;
}
- free(tmp);
return CURLE_OK;
}
@@ -449,8 +594,7 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
(void)data; (void)fmt;
}
-void Curl_trc_cf_infof(struct Curl_easy *data,
- struct Curl_cfilter *cf,
+void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
const char *fmt, ...)
{
(void)data; (void)cf; (void)fmt;
@@ -458,11 +602,21 @@ void Curl_trc_cf_infof(struct Curl_easy *data,
struct curl_trc_feat;
+void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...)
+{
+ (void)data; (void)fmt;
+}
+
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
{
(void)data; (void)fmt;
}
+void Curl_trc_dns(struct Curl_easy *data, const char *fmt, ...)
+{
+ (void)data; (void)fmt;
+}
+
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
{
(void)data; (void)fmt;
diff --git a/libs/libcurl/src/curl_trc.h b/libs/libcurl/src/curl_trc.h
index 8156165776..1aecf54cc7 100644
--- a/libs/libcurl/src/curl_trc.h
+++ b/libs/libcurl/src/curl_trc.h
@@ -52,7 +52,7 @@ CURLcode Curl_trc_opt(const char *config);
/* the function used to output verbose information */
void Curl_debug(struct Curl_easy *data, curl_infotype type,
- char *ptr, size_t size);
+ const char *ptr, size_t size);
/**
* Output a failure message on registered callbacks for transfer.
@@ -80,12 +80,17 @@ void Curl_infof(struct Curl_easy *data,
* Output an informational message when both transfer's verbose logging
* and connection filters verbose logging are enabled.
*/
-void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
+void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf,
const char *fmt, ...) CURL_PRINTF(3, 4);
+void Curl_trc_multi(struct Curl_easy *data,
+ const char *fmt, ...) CURL_PRINTF(2, 3);
+const char *Curl_trc_mstate_name(int state);
void Curl_trc_write(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
void Curl_trc_read(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
+void Curl_trc_dns(struct Curl_easy *data,
+ const char *fmt, ...) CURL_PRINTF(2, 3);
#ifndef CURL_DISABLE_FTP
extern struct curl_trc_feat Curl_trc_feat_ftp;
@@ -112,6 +117,9 @@ void Curl_trc_ws(struct Curl_easy *data,
#define infof(data, ...) \
do { if(Curl_trc_is_verbose(data)) \
Curl_infof(data, __VA_ARGS__); } while(0)
+#define CURL_TRC_M(data, ...) \
+ do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) \
+ Curl_trc_multi(data, __VA_ARGS__); } while(0)
#define CURL_TRC_CF(data, cf, ...) \
do { if(Curl_trc_cf_is_verbose(cf, data)) \
Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0)
@@ -121,6 +129,9 @@ void Curl_trc_ws(struct Curl_easy *data,
#define CURL_TRC_READ(data, ...) \
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) \
Curl_trc_read(data, __VA_ARGS__); } while(0)
+#define CURL_TRC_DNS(data, ...) \
+ do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) \
+ Curl_trc_dns(data, __VA_ARGS__); } while(0)
#ifndef CURL_DISABLE_FTP
#define CURL_TRC_FTP(data, ...) \
@@ -146,9 +157,11 @@ void Curl_trc_ws(struct Curl_easy *data,
#else /* CURL_HAVE_C99 */
#define infof Curl_infof
+#define CURL_TRC_M Curl_trc_multi
#define CURL_TRC_CF Curl_trc_cf_infof
#define CURL_TRC_WRITE Curl_trc_write
#define CURL_TRC_READ Curl_trc_read
+#define CURL_TRC_DNS Curl_trc_dns
#ifndef CURL_DISABLE_FTP
#define CURL_TRC_FTP Curl_trc_ftp
@@ -165,15 +178,18 @@ void Curl_trc_ws(struct Curl_easy *data,
#endif /* !CURL_HAVE_C99 */
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-/* informational messages enabled */
-
struct curl_trc_feat {
const char *name;
int log_level;
};
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+/* informational messages enabled */
+
+extern struct curl_trc_feat Curl_trc_feat_multi;
extern struct curl_trc_feat Curl_trc_feat_read;
extern struct curl_trc_feat Curl_trc_feat_write;
+extern struct curl_trc_feat Curl_trc_feat_dns;
#define Curl_trc_is_verbose(data) \
((data) && (data)->set.verbose && \
@@ -185,6 +201,7 @@ extern struct curl_trc_feat Curl_trc_feat_write;
#define Curl_trc_ft_is_verbose(data, ft) \
(Curl_trc_is_verbose(data) && \
(ft)->log_level >= CURL_LOG_LVL_INFO)
+#define CURL_MSTATE_NAME(s) Curl_trc_mstate_name((int)(s))
#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
/* All informational messages are not compiled in for size savings */
@@ -192,6 +209,7 @@ extern struct curl_trc_feat Curl_trc_feat_write;
#define Curl_trc_is_verbose(d) (FALSE)
#define Curl_trc_cf_is_verbose(x,y) (FALSE)
#define Curl_trc_ft_is_verbose(x,y) (FALSE)
+#define CURL_MSTATE_NAME(x) ((void)(x), "-")
#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
diff --git a/libs/libcurl/src/curlx.h b/libs/libcurl/src/curlx.h
index f6fb05d02e..b1d79ed7aa 100644
--- a/libs/libcurl/src/curlx.h
+++ b/libs/libcurl/src/curlx.h
@@ -37,11 +37,6 @@
#include "strcase.h"
/* "strcase.h" provides the strcasecompare protos */
-#include "strtoofft.h"
-/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a
- curl_off_t number from a given string.
-*/
-
#include "nonblock.h"
/* "nonblock.h" provides curlx_nonblock() */
@@ -66,4 +61,9 @@
#include "version_win32.h"
/* "version_win32.h" provides curlx_verify_windows_version() */
+#include "strparse.h"
+/* The curlx_str_* parsing functions */
+
+#define curlx_safefree(x) Curl_safefree(x)
+
#endif /* HEADER_CURL_CURLX_H */
diff --git a/libs/libcurl/src/cw-out.c b/libs/libcurl/src/cw-out.c
index 5e8895fae4..213a0c20a6 100644
--- a/libs/libcurl/src/cw-out.c
+++ b/libs/libcurl/src/cw-out.c
@@ -32,6 +32,7 @@
#include "multiif.h"
#include "sendf.h"
#include "cw-out.h"
+#include "cw-pause.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -198,7 +199,7 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
const char *buf, size_t blen,
size_t *pconsumed)
{
- curl_write_callback wcb;
+ curl_write_callback wcb = NULL;
void *wcb_data;
size_t max_write, min_write;
size_t wlen, nwritten;
@@ -220,9 +221,9 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
break;
wlen = max_write ? CURLMIN(blen, max_write) : blen;
Curl_set_in_callback(data, TRUE);
- nwritten = wcb((char *)buf, 1, wlen, wcb_data);
+ nwritten = wcb((char *)CURL_UNCONST(buf), 1, wlen, wcb_data);
Curl_set_in_callback(data, FALSE);
- CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
+ CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes -> %zu",
wlen, (otype == CW_OUT_BODY) ? "body" : "header",
nwritten);
if(CURL_WRITEFUNC_PAUSE == nwritten) {
@@ -236,7 +237,7 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
/* 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");
+ CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
break;
}
else if(CURL_WRITEFUNC_ERROR == nwritten) {
@@ -326,11 +327,16 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
}
static CURLcode cw_out_append(struct cw_out_ctx *ctx,
+ struct Curl_easy *data,
cw_out_type otype,
const char *buf, size_t blen)
{
- if(cw_out_bufs_len(ctx) + blen > DYN_PAUSE_BUFFER)
+ CURL_TRC_WRITE(data, "[OUT] paused, buffering %zu more bytes (%zu/%d)",
+ blen, cw_out_bufs_len(ctx), DYN_PAUSE_BUFFER);
+ if(cw_out_bufs_len(ctx) + blen > DYN_PAUSE_BUFFER) {
+ failf(data, "pause buffer not large enough -> CURLE_TOO_LARGE");
return CURLE_TOO_LARGE;
+ }
/* if we do not have a buffer, or it is of another type, make a new one.
* And for CW_OUT_HDS always make a new one, so we "replay" headers
@@ -364,7 +370,7 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
if(ctx->buf) {
/* still have buffered data, append and flush */
- result = cw_out_append(ctx, otype, buf, blen);
+ result = cw_out_append(ctx, data, otype, buf, blen);
if(result)
return result;
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
@@ -380,7 +386,8 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
return result;
if(consumed < blen) {
/* did not write all, append the rest */
- result = cw_out_append(ctx, otype, buf + consumed, blen - consumed);
+ result = cw_out_append(ctx, data, otype,
+ buf + consumed, blen - consumed);
if(result)
goto out;
}
@@ -430,44 +437,58 @@ bool Curl_cw_out_is_paused(struct Curl_easy *data)
return FALSE;
ctx = (struct cw_out_ctx *)cw_out;
- CURL_TRC_WRITE(data, "cw-out is%spaused", ctx->paused ? "" : " not");
return ctx->paused;
}
static CURLcode cw_out_flush(struct Curl_easy *data,
- bool unpause, bool flush_all)
+ struct Curl_cwriter *cw_out,
+ bool flush_all)
{
- struct Curl_cwriter *cw_out;
+ struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
CURLcode result = CURLE_OK;
- cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
- if(cw_out) {
- struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
- if(ctx->errored)
- return CURLE_WRITE_ERROR;
- if(unpause && ctx->paused)
- ctx->paused = FALSE;
- if(ctx->paused)
- return CURLE_OK; /* not doing it */
+ if(ctx->errored)
+ return CURLE_WRITE_ERROR;
+ if(ctx->paused)
+ return CURLE_OK; /* not doing it */
- result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
- if(result) {
- ctx->errored = TRUE;
- cw_out_bufs_free(ctx);
- return result;
- }
+ result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
+ if(result) {
+ ctx->errored = TRUE;
+ cw_out_bufs_free(ctx);
+ return result;
}
return result;
}
CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
{
- CURL_TRC_WRITE(data, "cw-out unpause");
- return cw_out_flush(data, TRUE, FALSE);
+ struct Curl_cwriter *cw_out;
+ CURLcode result = CURLE_OK;
+
+ cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
+ if(cw_out) {
+ struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
+ CURL_TRC_WRITE(data, "[OUT] unpause");
+ ctx->paused = FALSE;
+ result = Curl_cw_pause_flush(data);
+ if(!result)
+ result = cw_out_flush(data, cw_out, FALSE);
+ }
+ return result;
}
CURLcode Curl_cw_out_done(struct Curl_easy *data)
{
- CURL_TRC_WRITE(data, "cw-out done");
- return cw_out_flush(data, FALSE, TRUE);
+ struct Curl_cwriter *cw_out;
+ CURLcode result = CURLE_OK;
+
+ cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
+ if(cw_out) {
+ CURL_TRC_WRITE(data, "[OUT] done");
+ result = Curl_cw_pause_flush(data);
+ if(!result)
+ result = cw_out_flush(data, cw_out, TRUE);
+ }
+ return result;
}
diff --git a/libs/libcurl/src/cw-pause.c b/libs/libcurl/src/cw-pause.c
new file mode 100644
index 0000000000..7bb6b3b0fd
--- /dev/null
+++ b/libs/libcurl/src/cw-pause.c
@@ -0,0 +1,242 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "bufq.h"
+#include "cfilters.h"
+#include "headers.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "cw-pause.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+/* body dynbuf sizes */
+#define CW_PAUSE_BUF_CHUNK (16 * 1024)
+/* when content decoding, write data in chunks */
+#define CW_PAUSE_DEC_WRITE_CHUNK (4096)
+
+struct cw_pause_buf {
+ struct cw_pause_buf *next;
+ struct bufq b;
+ int type;
+};
+
+static struct cw_pause_buf *cw_pause_buf_create(int type, size_t buflen)
+{
+ struct cw_pause_buf *cwbuf = calloc(1, sizeof(*cwbuf));
+ if(cwbuf) {
+ cwbuf->type = type;
+ if(type & CLIENTWRITE_BODY)
+ Curl_bufq_init2(&cwbuf->b, CW_PAUSE_BUF_CHUNK, 1,
+ (BUFQ_OPT_SOFT_LIMIT|BUFQ_OPT_NO_SPARES));
+ else
+ Curl_bufq_init(&cwbuf->b, buflen, 1);
+ }
+ return cwbuf;
+}
+
+static void cw_pause_buf_free(struct cw_pause_buf *cwbuf)
+{
+ if(cwbuf) {
+ Curl_bufq_free(&cwbuf->b);
+ free(cwbuf);
+ }
+}
+
+struct cw_pause_ctx {
+ struct Curl_cwriter super;
+ struct cw_pause_buf *buf;
+ size_t buf_total;
+};
+
+static CURLcode cw_pause_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes);
+static void cw_pause_close(struct Curl_easy *data,
+ struct Curl_cwriter *writer);
+static CURLcode cw_pause_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer);
+
+struct Curl_cwtype Curl_cwt_pause = {
+ "cw-pause",
+ NULL,
+ cw_pause_init,
+ cw_pause_write,
+ cw_pause_close,
+ sizeof(struct cw_pause_ctx)
+};
+
+static CURLcode cw_pause_init(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
+{
+ struct cw_pause_ctx *ctx = writer->ctx;
+ (void)data;
+ ctx->buf = NULL;
+ return CURLE_OK;
+}
+
+static void cw_pause_bufs_free(struct cw_pause_ctx *ctx)
+{
+ while(ctx->buf) {
+ struct cw_pause_buf *next = ctx->buf->next;
+ cw_pause_buf_free(ctx->buf);
+ ctx->buf = next;
+ }
+}
+
+static void cw_pause_close(struct Curl_easy *data, struct Curl_cwriter *writer)
+{
+ struct cw_pause_ctx *ctx = writer->ctx;
+
+ (void)data;
+ cw_pause_bufs_free(ctx);
+}
+
+static CURLcode cw_pause_flush(struct Curl_easy *data,
+ struct Curl_cwriter *cw_pause)
+{
+ struct cw_pause_ctx *ctx = (struct cw_pause_ctx *)cw_pause;
+ bool decoding = Curl_cwriter_is_content_decoding(data);
+ CURLcode result = CURLE_OK;
+
+ /* write the end of the chain until it blocks or gets empty */
+ while(ctx->buf && !Curl_cwriter_is_paused(data)) {
+ struct cw_pause_buf **plast = &ctx->buf;
+ size_t blen, wlen = 0;
+ const unsigned char *buf = NULL;
+
+ while((*plast)->next) /* got to last in list */
+ plast = &(*plast)->next;
+ if(Curl_bufq_peek(&(*plast)->b, &buf, &blen)) {
+ wlen = (decoding && ((*plast)->type & CLIENTWRITE_BODY)) ?
+ CURLMIN(blen, CW_PAUSE_DEC_WRITE_CHUNK) : blen;
+ result = Curl_cwriter_write(data, cw_pause->next, (*plast)->type,
+ (const char *)buf, wlen);
+ CURL_TRC_WRITE(data, "[PAUSE] flushed %zu/%zu bytes, type=%x -> %d",
+ wlen, ctx->buf_total, (*plast)->type, result);
+ Curl_bufq_skip(&(*plast)->b, wlen);
+ DEBUGASSERT(ctx->buf_total >= wlen);
+ ctx->buf_total -= wlen;
+ if(result)
+ return result;
+ }
+ else if((*plast)->type & CLIENTWRITE_EOS) {
+ result = Curl_cwriter_write(data, cw_pause->next, (*plast)->type,
+ (const char *)buf, 0);
+ CURL_TRC_WRITE(data, "[PAUSE] flushed 0/%zu bytes, type=%x -> %d",
+ ctx->buf_total, (*plast)->type, result);
+ }
+
+ if(Curl_bufq_is_empty(&(*plast)->b)) {
+ cw_pause_buf_free(*plast);
+ *plast = NULL;
+ }
+ }
+ return result;
+}
+
+static CURLcode cw_pause_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t blen)
+{
+ struct cw_pause_ctx *ctx = writer->ctx;
+ CURLcode result = CURLE_OK;
+ size_t wlen = 0;
+ bool decoding = Curl_cwriter_is_content_decoding(data);
+
+ if(ctx->buf && !Curl_cwriter_is_paused(data)) {
+ result = cw_pause_flush(data, writer);
+ if(result)
+ return result;
+ }
+
+ while(!ctx->buf && !Curl_cwriter_is_paused(data)) {
+ int wtype = type;
+ DEBUGASSERT(!ctx->buf);
+ /* content decoding might blow up size considerably, write smaller
+ * chunks to make pausing need buffer less. */
+ wlen = (decoding && (type & CLIENTWRITE_BODY)) ?
+ CURLMIN(blen, CW_PAUSE_DEC_WRITE_CHUNK) : blen;
+ if(wlen < blen)
+ wtype &= ~CLIENTWRITE_EOS;
+ result = Curl_cwriter_write(data, writer->next, wtype, buf, wlen);
+ CURL_TRC_WRITE(data, "[PAUSE] writing %zu/%zu bytes of type %x -> %d",
+ wlen, blen, wtype, result);
+ if(result)
+ return result;
+ buf += wlen;
+ blen -= wlen;
+ if(!blen)
+ return result;
+ }
+
+ do {
+ size_t nwritten = 0;
+ if(ctx->buf && (ctx->buf->type == type) && (type & CLIENTWRITE_BODY)) {
+ /* same type and body, append to current buffer which has a soft
+ * limit and should take everything up to OOM. */
+ result = Curl_bufq_cwrite(&ctx->buf->b, buf, blen, &nwritten);
+ }
+ else {
+ /* Need a new buf, type changed */
+ struct cw_pause_buf *cwbuf = cw_pause_buf_create(type, blen);
+ if(!cwbuf)
+ return CURLE_OUT_OF_MEMORY;
+ cwbuf->next = ctx->buf;
+ ctx->buf = cwbuf;
+ result = Curl_bufq_cwrite(&ctx->buf->b, buf, blen, &nwritten);
+ }
+ CURL_TRC_WRITE(data, "[PAUSE] buffer %zu more bytes of type %x, "
+ "total=%zu -> %d", nwritten, type, ctx->buf_total + wlen,
+ result);
+ if(result)
+ return result;
+ buf += nwritten;
+ blen -= nwritten;
+ ctx->buf_total += nwritten;
+ } while(blen);
+
+ return result;
+}
+
+CURLcode Curl_cw_pause_flush(struct Curl_easy *data)
+{
+ struct Curl_cwriter *cw_pause;
+ CURLcode result = CURLE_OK;
+
+ cw_pause = Curl_cwriter_get_by_type(data, &Curl_cwt_pause);
+ if(cw_pause)
+ result = cw_pause_flush(data, cw_pause);
+
+ return result;
+}
diff --git a/libs/libcurl/src/strtok.h b/libs/libcurl/src/cw-pause.h
index 9890090b56..c514b1029f 100644
--- a/libs/libcurl/src/strtok.h
+++ b/libs/libcurl/src/cw-pause.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_STRTOK_H
-#define HEADER_CURL_STRTOK_H
+#ifndef HEADER_CURL_CW_PAUSE_H
+#define HEADER_CURL_CW_PAUSE_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -23,14 +23,18 @@
* SPDX-License-Identifier: curl
*
***************************************************************************/
+
#include "curl_setup.h"
-#include <stddef.h>
-#ifdef HAVE_STRTOK_R
-#include <string.h>
-#define Curl_strtok_r strtok_r
-#else
-char *Curl_strtok_r(char *s, const char *delim, char **last);
-#endif
+#include "sendf.h"
+
+/**
+ * The client writer type "cw-pause" that buffers writes for
+ * paused transfer writes.
+ */
+extern struct Curl_cwtype Curl_cwt_pause;
+
+CURLcode Curl_cw_pause_flush(struct Curl_easy *data);
+
-#endif /* HEADER_CURL_STRTOK_H */
+#endif /* HEADER_CURL_CW_PAUSE_H */
diff --git a/libs/libcurl/src/dict.c b/libs/libcurl/src/dict.c
index 1e4a05969f..dc849df1a8 100644
--- a/libs/libcurl/src/dict.c
+++ b/libs/libcurl/src/dict.c
@@ -212,16 +212,8 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
if(!word || (*word == (char)0)) {
infof(data, "lookup word is missing");
- word = (char *)"default";
}
- if(!database || (*database == (char)0)) {
- database = (char *)"!";
- }
- if(!strategy || (*strategy == (char)0)) {
- strategy = (char *)".";
- }
-
- eword = unescape_word(word);
+ eword = unescape_word((!word || (*word == (char)0)) ? "default" : word);
if(!eword) {
result = CURLE_OUT_OF_MEMORY;
goto error;
@@ -234,8 +226,8 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
"%s " /* strategy */
"%s\r\n" /* word */
"QUIT\r\n",
- database,
- strategy,
+ (!database || (*database == (char)0)) ? "!" : database,
+ (!strategy || (*strategy == (char)0)) ? "." : strategy,
eword);
if(result) {
@@ -263,13 +255,8 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
if(!word || (*word == (char)0)) {
infof(data, "lookup word is missing");
- word = (char *)"default";
}
- if(!database || (*database == (char)0)) {
- database = (char *)"!";
- }
-
- eword = unescape_word(word);
+ eword = unescape_word((!word || (*word == (char)0)) ? "default" : word);
if(!eword) {
result = CURLE_OUT_OF_MEMORY;
goto error;
@@ -281,7 +268,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
"%s " /* database */
"%s\r\n" /* word */
"QUIT\r\n",
- database,
+ (!database || (*database == (char)0)) ? "!" : database,
eword);
if(result) {
diff --git a/libs/libcurl/src/doh.c b/libs/libcurl/src/doh.c
index dfa7f27e53..9dd8283a1d 100644
--- a/libs/libcurl/src/doh.c
+++ b/libs/libcurl/src/doh.c
@@ -46,9 +46,6 @@
#define DNS_CLASS_IN 0x01
-/* doh_print_buf truncates if the hex string will be more than this */
-#define LOCAL_PB_HEXMAX 400
-
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char * const errors[]={
"",
@@ -74,10 +71,6 @@ static const char *doh_strerror(DOHcode code)
return "bad error code";
}
-struct curl_trc_feat Curl_doh_trc = {
- "DoH",
- CURL_LOG_LVL_NONE,
-};
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
/* @unittest 1655
@@ -192,6 +185,10 @@ doh_write_cb(char *contents, size_t size, size_t nmemb, void *userp)
}
#if defined(USE_HTTPSRR) && defined(DEBUGBUILD)
+
+/* doh_print_buf truncates if the hex string will be more than this */
+#define LOCAL_PB_HEXMAX 400
+
static void doh_print_buf(struct Curl_easy *data,
const char *prefix,
unsigned char *buf, size_t len)
@@ -280,7 +277,7 @@ static CURLcode doh_run_probe(struct Curl_easy *data,
the gcc typecheck helpers */
doh->state.internal = TRUE;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
- doh->state.feat = &Curl_doh_trc;
+ doh->state.feat = &Curl_trc_feat_dns;
#endif
ERROR_CHECK_SETOPT(CURLOPT_URL, url);
ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
@@ -304,7 +301,7 @@ static CURLcode doh_run_probe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_SHARE, (CURLSH *)data->share);
if(data->set.err && data->set.err != stderr)
ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
- if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc))
+ if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns))
ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
if(data->set.no_signal)
ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
@@ -1021,19 +1018,15 @@ static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
char **dnsname)
{
unsigned char *cp = NULL;
- int rem = 0;
+ size_t rem = 0;
unsigned char clen = 0; /* chunk len */
struct dynbuf thename;
DEBUGASSERT(buf && remaining && dnsname);
- if(!buf || !remaining || !dnsname)
- return CURLE_OUT_OF_MEMORY;
- rem = (int)*remaining;
- if(rem <= 0) {
- Curl_dyn_free(&thename);
+ if(!buf || !remaining || !dnsname || !*remaining)
return CURLE_OUT_OF_MEMORY;
- }
Curl_dyn_init(&thename, CURL_MAXLEN_host_name);
+ rem = *remaining;
cp = *buf;
clen = *cp++;
if(clen == 0) {
@@ -1086,12 +1079,15 @@ static CURLcode doh_test_alpn_escapes(void)
}
#endif
-static CURLcode doh_resp_decode_httpsrr(unsigned char *cp, size_t len,
+static CURLcode doh_resp_decode_httpsrr(struct Curl_easy *data,
+ unsigned char *cp, size_t len,
struct Curl_https_rrinfo **hrr)
{
uint16_t pcode = 0, plen = 0;
+ uint32_t expected_min_pcode = 0;
struct Curl_https_rrinfo *lhrr = NULL;
char *dnsname = NULL;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
#ifdef DEBUGBUILD
/* a few tests of escaping, should not be here but ok for now */
@@ -1115,57 +1111,24 @@ static CURLcode doh_resp_decode_httpsrr(unsigned char *cp, size_t len,
plen = doh_get16bit(cp, 2);
cp += 4;
len -= 4;
- switch(pcode) {
- case HTTPS_RR_CODE_ALPN:
- if(Curl_httpsrr_decode_alpn(cp, plen, lhrr->alpns) != CURLE_OK)
- goto err;
- break;
- case HTTPS_RR_CODE_NO_DEF_ALPN:
- lhrr->no_def_alpn = TRUE;
- break;
- case 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;
- break;
- case 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;
- break;
- case 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;
- break;
- case HTTPS_RR_CODE_PORT:
- lhrr->port = doh_get16bit(cp, 0);
- break;
- default:
- break;
- }
- if(plen > 0 && plen <= len) {
- cp += plen;
- len -= plen;
+ if(pcode < expected_min_pcode || plen > len) {
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto err;
}
+ result = Curl_httpsrr_set(data, lhrr, pcode, cp, plen);
+ if(result)
+ goto err;
+ cp += plen;
+ len -= plen;
+ expected_min_pcode = pcode + 1;
}
DEBUGASSERT(!len);
*hrr = lhrr;
return CURLE_OK;
err:
- Curl_safefree(lhrr->target);
- Curl_safefree(lhrr->echconfiglist);
+ Curl_httpsrr_cleanup(lhrr);
Curl_safefree(lhrr);
- return CURLE_OUT_OF_MEMORY;
+ return result;
}
# ifdef DEBUGBUILD
@@ -1218,7 +1181,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
if(dohp->probe[DOH_SLOT_IPV4].easy_mid < 0 &&
dohp->probe[DOH_SLOT_IPV6].easy_mid < 0) {
- failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
+ failf(data, "Could not DoH-resolve: %s", dohp->host);
return CONN_IS_PROXIED(data->conn) ? CURLE_COULDNT_RESOLVE_PROXY :
CURLE_COULDNT_RESOLVE_HOST;
}
@@ -1255,8 +1218,8 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_addrinfo *ai;
- if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
- infof(data, "[DoH] hostname: %s", dohp->host);
+ if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_dns)) {
+ CURL_TRC_DNS(data, "hostname: %s", dohp->host);
doh_show(data, &de);
}
@@ -1290,8 +1253,8 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
#ifdef USE_HTTPSRR
if(de.numhttps_rrs > 0 && result == CURLE_OK && *dnsp) {
struct Curl_https_rrinfo *hrr = NULL;
- result = doh_resp_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
- &hrr);
+ result = doh_resp_decode_httpsrr(data, de.https_rrs->val,
+ de.https_rrs->len, &hrr);
if(result) {
infof(data, "Failed to decode HTTPS RR");
return result;
diff --git a/libs/libcurl/src/doh.h b/libs/libcurl/src/doh.h
index 69c98d5883..4f0e2501b2 100644
--- a/libs/libcurl/src/doh.h
+++ b/libs/libcurl/src/doh.h
@@ -167,8 +167,6 @@ 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
diff --git a/libs/libcurl/src/dynbuf.c b/libs/libcurl/src/dynbuf.c
index 2b65b76336..f756363fea 100644
--- a/libs/libcurl/src/dynbuf.c
+++ b/libs/libcurl/src/dynbuf.c
@@ -32,7 +32,9 @@
#define MIN_FIRST_ALLOC 32
+#ifdef DEBUGBUILD
#define DYNINIT 0xbee51da /* random pattern */
+#endif
/*
* Init a dynbuf struct.
@@ -41,6 +43,7 @@ void Curl_dyn_init(struct dynbuf *s, size_t toobig)
{
DEBUGASSERT(s);
DEBUGASSERT(toobig);
+ DEBUGASSERT(toobig <= MAX_DYNBUF_SIZE); /* catch crazy mistakes */
s->bufr = NULL;
s->leng = 0;
s->allc = 0;
@@ -57,6 +60,7 @@ void Curl_dyn_init(struct dynbuf *s, size_t toobig)
void Curl_dyn_free(struct dynbuf *s)
{
DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
Curl_safefree(s->bufr);
s->leng = s->allc = 0;
}
@@ -181,7 +185,7 @@ CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(!s->leng || s->bufr);
n = strlen(str);
- return dyn_nappend(s, (unsigned char *)str, n);
+ return dyn_nappend(s, (const unsigned char *)str, n);
}
/*
@@ -207,7 +211,7 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
str = vaprintf(fmt, ap); /* this allocs a new string to append */
if(str) {
- CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str));
+ CURLcode result = dyn_nappend(s, (const unsigned char *)str, strlen(str));
free(str);
return result;
}
diff --git a/libs/libcurl/src/dynbuf.h b/libs/libcurl/src/dynbuf.h
index fc3247927a..663bf90141 100644
--- a/libs/libcurl/src/dynbuf.h
+++ b/libs/libcurl/src/dynbuf.h
@@ -81,6 +81,8 @@ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
char *Curl_dyn_take(struct dynbuf *s, size_t *plen);
/* Dynamic buffer max sizes */
+#define MAX_DYNBUF_SIZE (SIZE_T_MAX/2)
+
#define DYN_DOH_RESPONSE 3000
#define DYN_DOH_CNAME 256
#define DYN_PAUSE_BUFFER (64 * 1024 * 1024)
@@ -95,4 +97,6 @@ char *Curl_dyn_take(struct dynbuf *s, size_t *plen);
#define DYN_PINGPPONG_CMD (64*1024)
#define DYN_IMAP_CMD (64*1024)
#define DYN_MQTT_RECV (64*1024)
+#define DYN_MQTT_SEND 0xFFFFFFF
+#define DYN_CRLFILE_SIZE (400*1024*1024) /* 400mb */
#endif
diff --git a/libs/libcurl/src/easy.c b/libs/libcurl/src/easy.c
index 55fe1adb7d..62c3d1556d 100644
--- a/libs/libcurl/src/easy.c
+++ b/libs/libcurl/src/easy.c
@@ -105,7 +105,7 @@ static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT;
* ways, but at this point it must be defined as the system-supplied strdup
* so the callback pointer is initialized correctly.
*/
-#if defined(_WIN32_WCE)
+#if defined(UNDER_CE)
#define system_strdup _strdup
#elif !defined(HAVE_STRDUP)
#define system_strdup Curl_strdup
@@ -542,12 +542,34 @@ static void events_setup(struct Curl_multi *multi, struct events *ev)
curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
}
+/* populate_fds()
+ *
+ * populate the fds[] array
+ */
+static unsigned int populate_fds(struct pollfd *fds, struct events *ev)
+{
+ unsigned int numfds = 0;
+ struct pollfd *f;
+ struct socketmonitor *m;
+
+ f = &fds[0];
+ for(m = ev->list; m; m = m->next) {
+ f->fd = m->socket.fd;
+ f->events = m->socket.events;
+ f->revents = 0;
+#if DEBUG_EV_POLL
+ fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd);
+#endif
+ f++;
+ numfds++;
+ }
+ return numfds;
+}
/* wait_or_timeout()
*
* waits for activity on any of the given sockets, or the timeout to trigger.
*/
-
static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
{
bool done = FALSE;
@@ -556,25 +578,10 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
while(!done) {
CURLMsg *msg;
- struct socketmonitor *m;
- struct pollfd *f;
struct pollfd fds[4];
- int numfds = 0;
int pollrc;
- int i;
struct curltime before;
-
- /* populate the fds[] array */
- for(m = ev->list, f = &fds[0]; m; m = m->next) {
- f->fd = m->socket.fd;
- f->events = m->socket.events;
- f->revents = 0;
-#if DEBUG_EV_POLL
- fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd);
-#endif
- f++;
- numfds++;
- }
+ const unsigned int numfds = populate_fds(fds, ev);
/* get the time stamp to use to figure out how long poll takes */
before = Curl_now();
@@ -582,11 +589,11 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
if(numfds) {
/* wait for activity or timeout */
#if DEBUG_EV_POLL
- fprintf(stderr, "poll(numfds=%d, timeout=%ldms)\n", numfds, ev->ms);
+ fprintf(stderr, "poll(numfds=%u, timeout=%ldms)\n", numfds, ev->ms);
#endif
- pollrc = Curl_poll(fds, (unsigned int)numfds, ev->ms);
+ pollrc = Curl_poll(fds, numfds, ev->ms);
#if DEBUG_EV_POLL
- fprintf(stderr, "poll(numfds=%d, timeout=%ldms) -> %d\n",
+ fprintf(stderr, "poll(numfds=%u, timeout=%ldms) -> %d\n",
numfds, ev->ms, pollrc);
#endif
if(pollrc < 0)
@@ -614,6 +621,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
/* here pollrc is > 0 */
struct Curl_llist_node *e = Curl_llist_head(&multi->process);
struct Curl_easy *data;
+ unsigned int i;
DEBUGASSERT(e);
data = Curl_node_elem(e);
DEBUGASSERT(data);
@@ -770,7 +778,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
Curl_detach_connection(data);
s = Curl_getconnectinfo(data, &c);
if((s != CURL_SOCKET_BAD) && c) {
- Curl_cpool_disconnect(data, c, TRUE);
+ Curl_conn_terminate(data, c, TRUE);
}
DEBUGASSERT(!data->conn);
}
@@ -949,10 +957,6 @@ CURL *curl_easy_duphandle(CURL *d)
*/
outcurl->set.buffer_size = data->set.buffer_size;
- /* copy all userdefined values */
- if(dupset(outcurl, data))
- goto fail;
-
Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
Curl_netrc_init(&outcurl->state.netrc);
@@ -960,6 +964,16 @@ CURL *curl_easy_duphandle(CURL *d)
outcurl->state.lastconnect_id = -1;
outcurl->state.recent_conn_id = -1;
outcurl->id = -1;
+ outcurl->mid = -1;
+
+#ifndef CURL_DISABLE_HTTP
+ Curl_llist_init(&outcurl->state.httphdrs, NULL);
+#endif
+ Curl_initinfo(outcurl);
+
+ /* copy all userdefined values */
+ if(dupset(outcurl, data))
+ goto fail;
outcurl->progress.flags = data->progress.flags;
outcurl->progress.callback = data->progress.callback;
@@ -1053,10 +1067,6 @@ CURL *curl_easy_duphandle(CURL *d)
goto fail;
}
#endif /* USE_ARES */
-#ifndef CURL_DISABLE_HTTP
- Curl_llist_init(&outcurl->state.httphdrs, NULL);
-#endif
- Curl_initinfo(outcurl);
outcurl->magic = CURLEASY_MAGIC_NUMBER;
@@ -1195,10 +1205,10 @@ CURLcode curl_easy_pause(CURL *d, int action)
}
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);
+ if(!result && !data->state.done && keep_changed && data->multi)
+ /* pause/unpausing may result in multi event changes */
+ if(Curl_multi_ev_assess_xfer(data->multi, data))
+ result = CURLE_ABORTED_BY_CALLBACK;
if(recursive)
/* this might have called a callback recursively which might have set this
diff --git a/libs/libcurl/src/easyoptions.c b/libs/libcurl/src/easyoptions.c
index 751ffa58ab..1ed53bc58a 100644
--- a/libs/libcurl/src/easyoptions.c
+++ b/libs/libcurl/src/easyoptions.c
@@ -353,6 +353,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"UPKEEP_INTERVAL_MS", CURLOPT_UPKEEP_INTERVAL_MS, CURLOT_LONG, 0},
{"UPLOAD", CURLOPT_UPLOAD, CURLOT_LONG, 0},
{"UPLOAD_BUFFERSIZE", CURLOPT_UPLOAD_BUFFERSIZE, CURLOT_LONG, 0},
+ {"UPLOAD_FLAGS", CURLOPT_UPLOAD_FLAGS, CURLOT_LONG, 0},
{"URL", CURLOPT_URL, CURLOT_STRING, 0},
{"USERAGENT", CURLOPT_USERAGENT, CURLOT_STRING, 0},
{"USERNAME", CURLOPT_USERNAME, CURLOT_STRING, 0},
@@ -377,6 +378,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
- return (CURLOPT_LASTENTRY % 10000) != (326 + 1);
+ return (CURLOPT_LASTENTRY % 10000) != (327 + 1);
}
#endif
diff --git a/libs/libcurl/src/escape.c b/libs/libcurl/src/escape.c
index e7796713c7..ba403bb466 100644
--- a/libs/libcurl/src/escape.c
+++ b/libs/libcurl/src/escape.c
@@ -223,8 +223,6 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
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;
diff --git a/libs/libcurl/src/file.c b/libs/libcurl/src/file.c
index fe05ad067c..e02686cdb7 100644
--- a/libs/libcurl/src/file.c
+++ b/libs/libcurl/src/file.c
@@ -58,7 +58,6 @@
#include <dirent.h>
#endif
-#include "strtoofft.h"
#include "urldata.h"
#include <curl/curl.h>
#include "progress.h"
@@ -241,7 +240,7 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
file->path = real_path;
#endif
#endif
- Curl_safefree(file->freepath);
+ free(file->freepath);
file->freepath = real_path; /* free this when done */
file->fd = fd;
@@ -548,7 +547,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
if(data->state.resume_from) {
if(!S_ISDIR(statbuf.st_mode)) {
-#ifdef __AMIGA__
+#if defined(__AMIGA__) || defined(__MINGW32CE__)
if(data->state.resume_from !=
lseek(fd, (off_t)data->state.resume_from, SEEK_SET))
#else
diff --git a/libs/libcurl/src/fopen.c b/libs/libcurl/src/fopen.c
index de14f90f30..d47b14d952 100644
--- a/libs/libcurl/src/fopen.c
+++ b/libs/libcurl/src/fopen.c
@@ -105,7 +105,13 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
*fh = fopen(filename, FOPEN_WRITETEXT);
if(!*fh)
goto fail;
- if(fstat(fileno(*fh), &sb) == -1 || !S_ISREG(sb.st_mode)) {
+ if(
+#ifdef UNDER_CE
+ stat(filename, &sb) == -1
+#else
+ fstat(fileno(*fh), &sb) == -1
+#endif
+ || !S_ISREG(sb.st_mode)) {
return CURLE_OK;
}
fclose(*fh);
diff --git a/libs/libcurl/src/formdata.c b/libs/libcurl/src/formdata.c
index 84ad27891d..248db0b27c 100644
--- a/libs/libcurl/src/formdata.c
+++ b/libs/libcurl/src/formdata.c
@@ -31,10 +31,6 @@ struct Curl_easy;
#include "formdata.h"
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
-#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
-#include <libgen.h>
-#endif
-
#include "urldata.h" /* for struct Curl_easy */
#include "mime.h"
#include "vtls/vtls.h"
@@ -241,7 +237,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(array_state && forms) {
/* get the upcoming option from the given array */
option = forms->option;
- array_value = (char *)forms->value;
+ array_value = (char *)CURL_UNCONST(forms->value);
forms++; /* advance this to next entry */
if(CURLFORM_END == option) {
diff --git a/libs/libcurl/src/ftp.c b/libs/libcurl/src/ftp.c
index 9216aee564..450580fa87 100644
--- a/libs/libcurl/src/ftp.c
+++ b/libs/libcurl/src/ftp.c
@@ -54,7 +54,6 @@
#include "ftplistparser.h"
#include "curl_range.h"
#include "curl_krb5.h"
-#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
#include "cfilters.h"
@@ -73,6 +72,7 @@
#include "http_proxy.h"
#include "socks.h"
#include "strdup.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -464,7 +464,7 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data)
if(response) {
infof(data, "Ctrl conn has data while waiting for data conn");
if(pp->overflow > 3) {
- char *r = Curl_dyn_ptr(&pp->recvbuf);
+ const char *r = Curl_dyn_ptr(&pp->recvbuf);
DEBUGASSERT((pp->overflow + pp->nfinal) <=
Curl_dyn_len(&pp->recvbuf));
@@ -472,8 +472,8 @@ static CURLcode ftp_check_ctrl_on_data_wait(struct Curl_easy *data)
r += pp->nfinal;
if(LASTLINE(r)) {
- int status = curlx_sltosi(strtol(r, NULL, 10));
- if(status == 226) {
+ curl_off_t status;
+ if(!Curl_str_number(&r, &status, 999) && (status == 226)) {
/* funny timing situation where we get the final message on the
control connection before traffic on the data connection has been
noticed. Leave the 226 in there and use this as a trigger to read
@@ -541,13 +541,14 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
}
static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
- char *line, size_t len, int *code)
+ const char *line, size_t len, int *code)
{
+ curl_off_t status;
(void)data;
(void)conn;
- if((len > 3) && LASTLINE(line)) {
- *code = curlx_sltosi(strtol(line, NULL, 10));
+ if((len > 3) && LASTLINE(line) && !Curl_str_number(&line, &status, 999)) {
+ *code = (int)status;
return TRUE;
}
@@ -586,8 +587,9 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
}
#endif
- /* store the latest code for later retrieval */
- data->info.httpcode = code;
+ /* store the latest code for later retrieval, except during shutdown */
+ if(!data->conn->proto.ftpc.shutdown)
+ data->info.httpcode = code;
if(ftpcode)
*ftpcode = code;
@@ -911,7 +913,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* either ipv6 or (ipv4|domain|interface):port(-range) */
addrlen = ip_end - string_ftpport;
#ifdef USE_IPV6
- if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
+ if(curlx_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
/* ipv6 */
port_min = port_max = 0;
ip_end = NULL; /* this got no port ! */
@@ -925,13 +927,20 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* parse the port */
if(ip_end) {
- char *port_sep = NULL;
- char *port_start = strchr(ip_end, ':');
- if(port_start) {
- port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
- port_sep = strchr(port_start, '-');
- if(port_sep) {
- port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
+ const char *portp = strchr(ip_end, ':');
+ if(portp) {
+ curl_off_t start;
+ curl_off_t end;
+ portp++;
+ if(!Curl_str_number(&portp, &start, 0xffff)) {
+ /* got the first number */
+ port_min = (unsigned short)start;
+ if(!Curl_str_single(&portp, '-')) {
+ /* got the dash */
+ if(!Curl_str_number(&portp, &end, 0xffff))
+ /* got the second number */
+ port_max = (unsigned short)end;
+ }
}
else
port_max = port_min;
@@ -990,11 +999,11 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
switch(sa->sa_family) {
#ifdef USE_IPV6
case AF_INET6:
- r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
+ r = curlx_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));
+ r = curlx_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
break;
}
if(!r) {
@@ -1054,7 +1063,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(bind(portsock, sa, sslen) ) {
/* It failed. */
error = SOCKERRNO;
- if(possibly_non_local && (error == EADDRNOTAVAIL)) {
+ if(possibly_non_local && (error == SOCKEADDRNOTAVAIL)) {
/* The requested bind address is not local. Use the address used for
* the control connection instead and restart the port loop
*/
@@ -1071,7 +1080,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
possibly_non_local = FALSE; /* do not try this again */
continue;
}
- if(error != EADDRINUSE && error != EACCES) {
+ if(error != SOCKEADDRINUSE && error != SOCKEACCES) {
failf(data, "bind(port=%hu) failed: %s", port,
Curl_strerror(error, buffer, sizeof(buffer)));
goto out;
@@ -1758,20 +1767,15 @@ static bool match_pasv_6nums(const char *p,
{
int i;
for(i = 0; i < 6; i++) {
- unsigned long num;
- char *endp;
+ curl_off_t num;
if(i) {
if(*p != ',')
return FALSE;
p++;
}
- if(!ISDIGIT(*p))
- return FALSE;
- num = strtoul(p, &endp, 10);
- if(num > 255)
+ if(Curl_str_number(&p, &num, 0xff))
return FALSE;
array[i] = (unsigned int)num;
- p = endp;
}
return TRUE;
}
@@ -1801,23 +1805,17 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
ptr++;
/* |||12345| */
sep = ptr[0];
- /* the ISDIGIT() check here is because strtoul() accepts leading minus
- etc */
if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) {
- char *endp;
- unsigned long num = strtoul(&ptr[3], &endp, 10);
- if(*endp != sep)
- ptr = NULL;
- else if(num > 0xffff) {
+ const char *p = &ptr[3];
+ curl_off_t num;
+ if(Curl_str_number(&p, &num, 0xffff) || (*p != sep)) {
failf(data, "Illegal port number in EPSV reply");
return CURLE_FTP_WEIRD_PASV_REPLY;
}
- if(ptr) {
- ftpc->newport = (unsigned short)(num & 0xffff);
- ftpc->newhost = strdup(control_address(conn));
- if(!ftpc->newhost)
- return CURLE_OUT_OF_MEMORY;
- }
+ ftpc->newport = (unsigned short)num;
+ ftpc->newhost = strdup(control_address(conn));
+ if(!ftpc->newhost)
+ return CURLE_OUT_OF_MEMORY;
}
else
ptr = NULL;
@@ -1909,7 +1907,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
/* postponed address resolution in case of tcp fastopen */
if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) {
- Curl_safefree(ftpc->newhost);
+ free(ftpc->newhost);
ftpc->newhost = strdup(control_address(conn));
if(!ftpc->newhost)
return CURLE_OUT_OF_MEMORY;
@@ -1954,7 +1952,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
Curl_resolv_unlink(data, &addr); /* we are done using this address */
- Curl_safefree(conn->secondaryhostname);
+ free(conn->secondaryhostname);
conn->secondary_port = ftpc->newport;
conn->secondaryhostname = strdup(ftpc->newhost);
if(!conn->secondaryhostname)
@@ -2297,7 +2295,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
for all the digits at the end of the response and parse only those as a
number. */
char *start = &buf[4];
- char *fdigit = memchr(start, '\r', len);
+ const char *fdigit = memchr(start, '\r', len);
if(fdigit) {
fdigit--;
if(*fdigit == '\n')
@@ -2307,9 +2305,8 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
}
else
fdigit = start;
- /* ignores parsing errors, which will make the size remain unknown */
- (void)curlx_strtoofft(fdigit, NULL, 10, &filesize);
-
+ if(Curl_str_number(&fdigit, &filesize, CURL_OFF_T_MAX))
+ filesize = -1; /* size remain unknown */
}
else if(ftpcode == 550) { /* "No such file or directory" */
/* allow a SIZE failure for (resumed) uploads, when probing what command
@@ -2471,7 +2468,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
* those cases only confuses us.
*
* Example D above makes this parsing a little tricky */
- char *bytes;
+ const char *bytes;
char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);
bytes = strstr(buf, " bytes");
if(bytes) {
@@ -2493,7 +2490,8 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
if(bytes) {
++bytes;
/* get the number! */
- (void)curlx_strtoofft(bytes, NULL, 10, &size);
+ if(Curl_str_number(&bytes, &size, CURL_OFF_T_MAX))
+ size = 1;
}
}
}
@@ -2904,20 +2902,26 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
free(dir);
return result;
}
- Curl_safefree(ftpc->entrypath);
+ free(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;
+ free(data->state.most_recent_ftp_entrypath);
+ data->state.most_recent_ftp_entrypath = strdup(ftpc->entrypath);
+ if(!data->state.most_recent_ftp_entrypath)
+ return CURLE_OUT_OF_MEMORY;
ftp_state(data, FTP_SYST);
break;
}
- Curl_safefree(ftpc->entrypath);
+ free(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;
+ free(data->state.most_recent_ftp_entrypath);
+ data->state.most_recent_ftp_entrypath = strdup(ftpc->entrypath);
+ if(!data->state.most_recent_ftp_entrypath)
+ return CURLE_OUT_OF_MEMORY;
}
else {
/* could not get the path */
@@ -2956,14 +2960,14 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
return result;
}
/* remember target server OS */
- Curl_safefree(ftpc->server_os);
+ free(ftpc->server_os);
ftpc->server_os = os;
ftp_state(data, FTP_NAMEFMT);
break;
}
/* Nothing special for the target server. */
/* remember target server OS */
- Curl_safefree(ftpc->server_os);
+ free(ftpc->server_os);
ftpc->server_os = os;
}
else {
@@ -3134,6 +3138,8 @@ static CURLcode ftp_block_statemach(struct Curl_easy *data,
CURLcode result = CURLE_OK;
while(ftpc->state != FTP_STOP) {
+ if(ftpc->shutdown)
+ CURL_TRC_FTP(data, "in shutdown, waiting for server response");
result = Curl_pp_statemach(data, pp, TRUE, TRUE /* disconnecting */);
if(result)
break;
@@ -3293,7 +3299,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
/* shut down the socket to inform the server we are done */
-#ifdef _WIN32_WCE
+#ifdef UNDER_CE
shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
#endif
@@ -3371,10 +3377,13 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
use checking further */
;
else if(data->state.upload) {
- if((-1 != data->state.infilesize) &&
- (data->state.infilesize != data->req.writebytecount) &&
- !data->set.crlf &&
- (ftp->transfer == PPTRANSFER_BODY)) {
+ if((ftp->transfer == PPTRANSFER_BODY) &&
+ (data->state.infilesize != -1) && /* upload with known size */
+ ((!data->set.crlf && !data->state.prefer_ascii && /* no conversion */
+ (data->state.infilesize != data->req.writebytecount)) ||
+ ((data->set.crlf || data->state.prefer_ascii) && /* maybe crlf conv */
+ (data->state.infilesize > data->req.writebytecount))
+ )) {
failf(data, "Uploaded unaligned file size (%" FMT_OFF_T
" out of %" FMT_OFF_T " bytes)",
data->req.writebytecount, data->state.infilesize);
@@ -3606,7 +3615,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(ftpc->wait_data_conn) {
bool serv_conned;
- result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &serv_conned);
+ result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &serv_conned);
if(result)
return result; /* Failed to accept data connection */
@@ -4045,6 +4054,7 @@ static CURLcode ftp_quit(struct Curl_easy *data, struct connectdata *conn)
CURLcode result = CURLE_OK;
if(conn->proto.ftpc.ctl_valid) {
+ CURL_TRC_FTP(data, "sending QUIT to close session");
result = Curl_pp_sendf(data, &conn->proto.ftpc.pp, "%s", "QUIT");
if(result) {
failf(data, "Failure sending QUIT command: %s",
@@ -4084,26 +4094,20 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
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.
*/
+ ftpc->shutdown = TRUE;
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 */
- if(ftpc->entrypath) {
- if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
- data->state.most_recent_ftp_entrypath = NULL;
- }
- Curl_safefree(ftpc->entrypath);
- }
-
freedirs(ftpc);
Curl_safefree(ftpc->account);
Curl_safefree(ftpc->alternative_to_user);
+ Curl_safefree(ftpc->entrypath);
Curl_safefree(ftpc->prevpath);
Curl_safefree(ftpc->server_os);
Curl_pp_disconnect(pp);
- Curl_sec_end(conn);
return CURLE_OK;
}
diff --git a/libs/libcurl/src/ftp.h b/libs/libcurl/src/ftp.h
index ebbe2fc48d..ef133a074b 100644
--- a/libs/libcurl/src/ftp.h
+++ b/libs/libcurl/src/ftp.h
@@ -125,7 +125,8 @@ struct ftp_conn {
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 *newhost; /* the (allocated) IP addr or hostname to connect the data
+ connection to */
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) */
@@ -139,9 +140,8 @@ struct ftp_conn {
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;
+ unsigned short newport; /* the port of 'newhost' to connect the data
+ connection to */
ftpstate state; /* always use ftp.c:state() to change state! */
ftpstate state_saved; /* transfer type saved to be reloaded after data
connection is established */
@@ -160,6 +160,7 @@ struct ftp_conn {
BIT(cwdfail); /* set TRUE if a CWD command fails, as then we must prevent
caching the current directory */
BIT(wait_data_conn); /* this is set TRUE if data connection is waited */
+ BIT(shutdown); /* connection is being shutdown, e.g. QUIT */
};
#define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */
diff --git a/libs/libcurl/src/ftplistparser.c b/libs/libcurl/src/ftplistparser.c
index 166f6771b5..31b8d0463e 100644
--- a/libs/libcurl/src/ftplistparser.c
+++ b/libs/libcurl/src/ftplistparser.c
@@ -46,13 +46,15 @@
#include "urldata.h"
#include "fileinfo.h"
#include "llist.h"
-#include "strtoofft.h"
#include "ftp.h"
#include "ftplistparser.h"
#include "curl_fnmatch.h"
-#include "curl_memory.h"
#include "multiif.h"
-/* The last #include file should be: */
+#include "strparse.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
#include "memdebug.h"
typedef enum {
@@ -440,11 +442,10 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
else if(c == '\n') {
mem[parser->item_length - 1] = 0;
if(!strncmp("total ", mem, 6)) {
- char *endptr = mem + 6;
+ const char *endptr = mem + 6;
/* here we can deal with directory size, pass the leading
whitespace and then the digits */
- while(ISBLANK(*endptr))
- endptr++;
+ Curl_str_passblanks(&endptr);
while(ISDIGIT(*endptr))
endptr++;
if(*endptr) {
@@ -543,13 +544,13 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
case PL_UNIX_HLINKS_NUMBER:
parser->item_length ++;
if(c == ' ') {
- char *p;
- long int hlinks;
+ const char *p = &mem[parser->item_offset];
+ curl_off_t hlinks;
mem[parser->item_offset + parser->item_length - 1] = 0;
- hlinks = strtol(mem + parser->item_offset, &p, 10);
- if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
+
+ if(!Curl_str_number(&p, &hlinks, LONG_MAX)) {
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
- parser->file_data->info.hardlinks = hlinks;
+ parser->file_data->info.hardlinks = (long)hlinks;
}
parser->item_length = 0;
parser->item_offset = 0;
@@ -625,13 +626,11 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
case PL_UNIX_SIZE_NUMBER:
parser->item_length++;
if(c == ' ') {
- char *p;
+ const char *p = mem + parser->item_offset;
curl_off_t fsize;
mem[parser->item_offset + parser->item_length - 1] = 0;
- if(!curlx_strtoofft(mem + parser->item_offset,
- &p, 10, &fsize)) {
- if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
- fsize != CURL_OFF_T_MIN) {
+ if(!Curl_str_numblanks(&p, &fsize)) {
+ if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) {
parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
parser->file_data->info.size = fsize;
}
@@ -952,10 +951,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
finfo->size = 0;
}
else {
- char *endptr;
- if(curlx_strtoofft(mem +
- parser->item_offset,
- &endptr, 10, &finfo->size)) {
+ const char *p = mem + parser->item_offset;
+ if(Curl_str_numblanks(&p, &finfo->size)) {
parser->error = CURLE_FTP_BAD_FILE_LIST;
goto fail;
}
diff --git a/libs/libcurl/src/getenv.c b/libs/libcurl/src/getenv.c
index edb085f8cd..0749117a7f 100644
--- a/libs/libcurl/src/getenv.c
+++ b/libs/libcurl/src/getenv.c
@@ -31,7 +31,7 @@
static char *GetEnv(const char *variable)
{
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP) || \
+#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) || \
defined(__ORBIS__) || defined(__PROSPERO__) /* PlayStation 4 and 5 */
(void)variable;
return NULL;
diff --git a/libs/libcurl/src/getinfo.c b/libs/libcurl/src/getinfo.c
index ff75ea13d8..8f0f213213 100644
--- a/libs/libcurl/src/getinfo.c
+++ b/libs/libcurl/src/getinfo.c
@@ -28,10 +28,10 @@
#include "urldata.h"
#include "getinfo.h"
-
#include "vtls/vtls.h"
#include "connect.h" /* Curl_getconnectinfo() */
#include "progress.h"
+#include "strparse.h"
/* The last #include files should be: */
#include "curl_memory.h"
@@ -98,7 +98,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
{
switch(info) {
case CURLINFO_EFFECTIVE_URL:
- *param_charp = data->state.url ? data->state.url : (char *)"";
+ *param_charp = data->state.url ? data->state.url : "";
break;
case CURLINFO_EFFECTIVE_METHOD: {
const char *m = data->set.str[STRING_CUSTOMREQUEST];
@@ -204,9 +204,10 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
} lptr;
#ifdef DEBUGBUILD
- char *timestr = getenv("CURL_TIME");
+ const char *timestr = getenv("CURL_TIME");
if(timestr) {
- unsigned long val = strtoul(timestr, NULL, 10);
+ curl_off_t val;
+ Curl_str_number(&timestr, &val, TIME_T_MAX);
switch(info) {
case CURLINFO_LOCAL_PORT:
*param_longp = (long)val;
@@ -218,7 +219,8 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
/* use another variable for this to allow different values */
timestr = getenv("CURL_DEBUG_SIZE");
if(timestr) {
- unsigned long val = strtoul(timestr, NULL, 10);
+ curl_off_t val;
+ Curl_str_number(&timestr, &val, LONG_MAX);
switch(info) {
case CURLINFO_HEADER_SIZE:
case CURLINFO_REQUEST_SIZE:
@@ -379,9 +381,11 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
curl_off_t *param_offt)
{
#ifdef DEBUGBUILD
- char *timestr = getenv("CURL_TIME");
+ const char *timestr = getenv("CURL_TIME");
if(timestr) {
- unsigned long val = strtoul(timestr, NULL, 10);
+ curl_off_t val;
+ Curl_str_number(&timestr, &val, CURL_OFF_T_MAX);
+
switch(info) {
case CURLINFO_TOTAL_TIME_T:
case CURLINFO_NAMELOOKUP_TIME_T:
@@ -476,9 +480,11 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
double *param_doublep)
{
#ifdef DEBUGBUILD
- char *timestr = getenv("CURL_TIME");
+ const char *timestr = getenv("CURL_TIME");
if(timestr) {
- unsigned long val = strtoul(timestr, NULL, 10);
+ curl_off_t val;
+ Curl_str_number(&timestr, &val, CURL_OFF_T_MAX);
+
switch(info) {
case CURLINFO_TOTAL_TIME:
case CURLINFO_NAMELOOKUP_TIME:
diff --git a/libs/libcurl/src/gopher.c b/libs/libcurl/src/gopher.c
index 3fc6fc0f56..05e7ff8fed 100644
--- a/libs/libcurl/src/gopher.c
+++ b/libs/libcurl/src/gopher.c
@@ -162,7 +162,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
/* Create selector. Degenerate cases: / and /1 => convert to "" */
if(strlen(gopherpath) <= 2) {
- sel = (char *)"";
+ sel = (char *)CURL_UNCONST("");
len = strlen(sel);
free(gopherpath);
}
@@ -236,7 +236,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
failf(data, "Failed sending Gopher request");
return result;
}
- result = Curl_client_write(data, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
+ result = Curl_client_write(data, CLIENTWRITE_HEADER, "\r\n", 2);
if(result)
return result;
diff --git a/libs/libcurl/src/hash.c b/libs/libcurl/src/hash.c
index b531085793..a6551e8bed 100644
--- a/libs/libcurl/src/hash.c
+++ b/libs/libcurl/src/hash.c
@@ -34,29 +34,49 @@
#include "memdebug.h"
/* random patterns for API verification */
+#ifdef DEBUGBUILD
#define HASHINIT 0x7017e781
#define ITERINIT 0x5FEDCBA9
+#endif
-static void
-hash_element_dtor(void *user, void *element)
+
+#if 0 /* useful function for debugging hashes and their contents */
+void Curl_hash_print(struct Curl_hash *h,
+ void (*func)(void *))
{
- struct Curl_hash *h = (struct Curl_hash *) user;
- struct Curl_hash_element *e = (struct Curl_hash_element *) element;
- DEBUGASSERT(h);
- DEBUGASSERT(e);
+ struct Curl_hash_iterator iter;
+ struct Curl_hash_element *he;
+ size_t last_index = UINT_MAX;
- if(e->ptr) {
- if(e->dtor)
- e->dtor(e->key, e->key_len, e->ptr);
- else
- h->dtor(e->ptr);
- e->ptr = NULL;
- }
+ if(!h)
+ return;
+
+ fprintf(stderr, "=Hash dump=\n");
+
+ Curl_hash_start_iterate(h, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ if(iter.slot_index != last_index) {
+ fprintf(stderr, "index %d:", (int)iter.slot_index);
+ if(last_index != UINT_MAX) {
+ fprintf(stderr, "\n");
+ }
+ last_index = iter.slot_index;
+ }
- e->key_len = 0;
+ if(func)
+ func(he->ptr);
+ else
+ fprintf(stderr, " [key=%.*s, he=%p, ptr=%p]",
+ (int)he->key_len, (char *)he->key,
+ (void *)he, (void *)he->ptr);
- free(e);
+ he = Curl_hash_next_element(&iter);
+ }
+ fprintf(stderr, "\n");
}
+#endif
/* Initializes a hash structure.
* Return 1 on error, 0 is fine.
@@ -89,62 +109,96 @@ Curl_hash_init(struct Curl_hash *h,
}
static struct Curl_hash_element *
-mk_hash_element(const void *key, size_t key_len, const void *p,
- Curl_hash_elem_dtor dtor)
+hash_elem_create(const void *key, size_t key_len, const void *p,
+ Curl_hash_elem_dtor dtor)
{
+ struct Curl_hash_element *he;
+
/* allocate the struct plus memory after it to store the key */
- struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) +
- key_len);
+ he = malloc(sizeof(struct Curl_hash_element) + key_len);
if(he) {
+ he->next = NULL;
/* copy the key */
memcpy(he->key, key, key_len);
he->key_len = key_len;
- he->ptr = (void *) p;
+ he->ptr = CURL_UNCONST(p);
he->dtor = dtor;
}
return he;
}
-#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
+static void hash_elem_clear_ptr(struct Curl_hash *h,
+ struct Curl_hash_element *he)
+{
+ DEBUGASSERT(h);
+ DEBUGASSERT(he);
+ if(he->ptr) {
+ if(he->dtor)
+ he->dtor(he->key, he->key_len, he->ptr);
+ else
+ h->dtor(he->ptr);
+ he->ptr = NULL;
+ }
+}
+
+static void hash_elem_destroy(struct Curl_hash *h,
+ struct Curl_hash_element *he)
+{
+ hash_elem_clear_ptr(h, he);
+ free(he);
+}
+
+static void hash_elem_unlink(struct Curl_hash *h,
+ struct Curl_hash_element **he_anchor,
+ struct Curl_hash_element *he)
+{
+ *he_anchor = he->next;
+ --h->size;
+}
+
+static void hash_elem_link(struct Curl_hash *h,
+ struct Curl_hash_element **he_anchor,
+ struct Curl_hash_element *he)
+{
+ he->next = *he_anchor;
+ *he_anchor = he;
+ ++h->size;
+}
+
+#define CURL_HASH_SLOT(x,y,z) x->table[x->hash_func(y, z, x->slots)]
+#define CURL_HASH_SLOT_ADDR(x,y,z) &CURL_HASH_SLOT(x,y,z)
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_node *le;
- struct Curl_llist *l;
+ struct Curl_hash_element *he, **slot;
DEBUGASSERT(h);
DEBUGASSERT(h->slots);
DEBUGASSERT(h->init == HASHINIT);
if(!h->table) {
- size_t i;
- h->table = malloc(h->slots * sizeof(struct Curl_llist));
+ h->table = calloc(h->slots, sizeof(struct Curl_hash_element *));
if(!h->table)
return NULL; /* OOM */
- for(i = 0; i < h->slots; ++i)
- Curl_llist_init(&h->table[i], hash_element_dtor);
}
- l = FETCH_LIST(h, key, key_len);
-
- for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
- he = (struct Curl_hash_element *) Curl_node_elem(le);
+ slot = CURL_HASH_SLOT_ADDR(h, key, key_len);
+ for(he = *slot; he; he = he->next) {
if(h->comp_func(he->key, he->key_len, key, key_len)) {
- Curl_node_uremove(le, (void *)h);
- --h->size;
- break;
+ /* existing key entry, overwrite by clearing old pointer */
+ hash_elem_clear_ptr(h, he);
+ he->ptr = (void *)p;
+ he->dtor = dtor;
+ return p;
}
}
- 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 */
- }
+ he = hash_elem_create(key, key_len, p, dtor);
+ if(!he)
+ return NULL; /* OOM */
- return NULL; /* failure */
+ hash_elem_link(h, slot, he);
+ return p; /* return the new entry */
}
/* Insert the data in the hash. If there already was a match in the hash, that
@@ -172,16 +226,17 @@ int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
DEBUGASSERT(h->slots);
DEBUGASSERT(h->init == HASHINIT);
if(h->table) {
- struct Curl_llist_node *le;
- struct Curl_llist *l = FETCH_LIST(h, key, key_len);
+ struct Curl_hash_element *he, **he_anchor;
- for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
- struct Curl_hash_element *he = Curl_node_elem(le);
+ he_anchor = CURL_HASH_SLOT_ADDR(h, key, key_len);
+ while(*he_anchor) {
+ he = *he_anchor;
if(h->comp_func(he->key, he->key_len, key, key_len)) {
- Curl_node_uremove(le, (void *) h);
- --h->size;
+ hash_elem_unlink(h, he_anchor, he);
+ hash_elem_destroy(h, he);
return 0;
}
+ he_anchor = &he->next;
}
}
return 1;
@@ -197,18 +252,16 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
DEBUGASSERT(h);
DEBUGASSERT(h->init == HASHINIT);
if(h->table) {
- struct Curl_llist_node *le;
- struct Curl_llist *l;
+ struct Curl_hash_element *he;
DEBUGASSERT(h->slots);
- l = FETCH_LIST(h, key, key_len);
- for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
- struct Curl_hash_element *he = Curl_node_elem(le);
+ he = CURL_HASH_SLOT(h, key, key_len);
+ while(he) {
if(h->comp_func(he->key, he->key_len, key, key_len)) {
return he->ptr;
}
+ he = he->next;
}
}
-
return NULL;
}
@@ -224,13 +277,10 @@ Curl_hash_destroy(struct Curl_hash *h)
{
DEBUGASSERT(h->init == HASHINIT);
if(h->table) {
- size_t i;
- for(i = 0; i < h->slots; ++i) {
- Curl_llist_destroy(&h->table[i], (void *) h);
- }
+ Curl_hash_clean(h);
Curl_safefree(h->table);
}
- h->size = 0;
+ DEBUGASSERT(h->size == 0);
h->slots = 0;
}
@@ -238,10 +288,21 @@ Curl_hash_destroy(struct Curl_hash *h)
*
* @unittest: 1602
*/
-void
-Curl_hash_clean(struct Curl_hash *h)
+void Curl_hash_clean(struct Curl_hash *h)
{
- Curl_hash_clean_with_criterium(h, NULL, NULL);
+ if(h && h->table) {
+ struct Curl_hash_element *he, **he_anchor;
+ size_t i;
+ DEBUGASSERT(h->init == HASHINIT);
+ for(i = 0; i < h->slots; ++i) {
+ he_anchor = &h->table[i];
+ while(*he_anchor) {
+ he = *he_anchor;
+ hash_elem_unlink(h, he_anchor, he);
+ hash_elem_destroy(h, he);
+ }
+ }
+ }
}
size_t Curl_hash_count(struct Curl_hash *h)
@@ -262,18 +323,16 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
DEBUGASSERT(h->init == HASHINIT);
for(i = 0; i < h->slots; ++i) {
- struct Curl_llist *list = &h->table[i];
- struct Curl_llist_node *le =
- Curl_llist_head(list); /* get first list entry */
- while(le) {
- struct Curl_hash_element *he = Curl_node_elem(le);
- struct Curl_llist_node *lnext = Curl_node_next(le);
+ struct Curl_hash_element *he, **he_anchor = &h->table[i];
+ while(*he_anchor) {
/* ask the callback function if we shall remove this entry or not */
- if(!comp || comp(user, he->ptr)) {
- Curl_node_uremove(le, (void *) h);
- --h->size; /* one less entry in the hash now */
+ if(!comp || comp(user, (*he_anchor)->ptr)) {
+ he = *he_anchor;
+ hash_elem_unlink(h, he_anchor, he);
+ hash_elem_destroy(h, he);
}
- le = lnext;
+ else
+ he_anchor = &(*he_anchor)->next;
}
}
}
@@ -308,7 +367,7 @@ void Curl_hash_start_iterate(struct Curl_hash *hash,
DEBUGASSERT(hash->init == HASHINIT);
iter->hash = hash;
iter->slot_index = 0;
- iter->current_element = NULL;
+ iter->current = NULL;
#ifdef DEBUGBUILD
iter->init = ITERINIT;
#endif
@@ -324,82 +383,20 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
return NULL; /* empty hash, nothing to return */
/* Get the next element in the current list, if any */
- if(iter->current_element)
- iter->current_element = Curl_node_next(iter->current_element);
+ if(iter->current)
+ iter->current = iter->current->next;
/* If we have reached the end of the list, find the next one */
- if(!iter->current_element) {
+ if(!iter->current) {
size_t i;
for(i = iter->slot_index; i < h->slots; i++) {
- if(Curl_llist_head(&h->table[i])) {
- iter->current_element = Curl_llist_head(&h->table[i]);
+ if(h->table[i]) {
+ iter->current = h->table[i];
iter->slot_index = i + 1;
break;
}
}
}
- if(iter->current_element) {
- struct Curl_hash_element *he = Curl_node_elem(iter->current_element);
- return he;
- }
- return NULL;
-}
-
-#if 0 /* useful function for debugging hashes and their contents */
-void Curl_hash_print(struct Curl_hash *h,
- void (*func)(void *))
-{
- struct Curl_hash_iterator iter;
- struct Curl_hash_element *he;
- size_t last_index = ~0;
-
- if(!h)
- return;
-
- fprintf(stderr, "=Hash dump=\n");
-
- Curl_hash_start_iterate(h, &iter);
-
- he = Curl_hash_next_element(&iter);
- while(he) {
- if(iter.slot_index != last_index) {
- fprintf(stderr, "index %d:", iter.slot_index);
- if(last_index != ~0) {
- fprintf(stderr, "\n");
- }
- last_index = iter.slot_index;
- }
-
- if(func)
- func(he->ptr);
- else
- fprintf(stderr, " [%p]", (void *)he->ptr);
-
- he = Curl_hash_next_element(&iter);
- }
- fprintf(stderr, "\n");
-}
-#endif
-
-void Curl_hash_offt_init(struct Curl_hash *h,
- size_t slots,
- Curl_hash_dtor dtor)
-{
- Curl_hash_init(h, slots, Curl_hash_str, Curl_str_key_compare, dtor);
-}
-
-void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem)
-{
- return Curl_hash_add(h, &id, sizeof(id), elem);
-}
-
-int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id)
-{
- return Curl_hash_delete(h, &id, sizeof(id));
-}
-
-void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id)
-{
- return Curl_hash_pick(h, &id, sizeof(id));
+ return iter->current;
}
diff --git a/libs/libcurl/src/hash.h b/libs/libcurl/src/hash.h
index c3387fbde6..6e1c5790da 100644
--- a/libs/libcurl/src/hash.h
+++ b/libs/libcurl/src/hash.h
@@ -45,14 +45,24 @@ typedef size_t (*comp_function) (void *key1,
typedef void (*Curl_hash_dtor)(void *);
+typedef void (*Curl_hash_elem_dtor)(void *key, size_t key_len, void *p);
+
+struct Curl_hash_element {
+ struct Curl_hash_element *next;
+ void *ptr;
+ Curl_hash_elem_dtor dtor;
+ size_t key_len;
+ char key[1]; /* allocated memory following the struct */
+};
+
struct Curl_hash {
- struct Curl_llist *table;
+ struct Curl_hash_element **table;
/* Hash function to be used for this hash table */
hash_function hash_func;
-
/* Comparator function to compare keys */
comp_function comp_func;
+ /* General element construct, unless element itself carries one */
Curl_hash_dtor dtor;
size_t slots;
size_t size;
@@ -61,23 +71,10 @@ struct Curl_hash {
#endif
};
-typedef void (*Curl_hash_elem_dtor)(void *key, size_t key_len, void *p);
-
-struct Curl_hash_element {
- struct Curl_llist_node list;
- void *ptr;
- Curl_hash_elem_dtor dtor;
- size_t key_len;
-#ifdef DEBUGBUILD
- int init;
-#endif
- char key[1]; /* allocated memory following the struct */
-};
-
struct Curl_hash_iterator {
struct Curl_hash *hash;
size_t slot_index;
- struct Curl_llist_node *current_element;
+ struct Curl_hash_element *current;
#ifdef DEBUGBUILD
int init;
#endif
@@ -111,13 +108,4 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter);
void Curl_hash_print(struct Curl_hash *h,
void (*func)(void *));
-/* Hash for `curl_off_t` as key */
-void Curl_hash_offt_init(struct Curl_hash *h, size_t slots,
- Curl_hash_dtor dtor);
-
-void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem);
-int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id);
-void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id);
-
-
#endif /* HEADER_CURL_HASH_H */
diff --git a/libs/libcurl/src/hash_offt.c b/libs/libcurl/src/hash_offt.c
new file mode 100644
index 0000000000..96ff500307
--- /dev/null
+++ b/libs/libcurl/src/hash_offt.c
@@ -0,0 +1,242 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "hash_offt.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* random patterns for API verification */
+#ifdef DEBUGBUILD
+#define CURL_HASHOFFTINIT 0x7117e781
+#endif
+
+static size_t hash_offt_hash(curl_off_t id, size_t slots)
+{
+ return (size_t)((id >= 0) ? (id % slots) : (-id % slots));
+}
+
+struct Curl_hash_offt_entry {
+ curl_off_t id;
+ struct Curl_hash_offt_entry *next;
+ void *value;
+};
+
+void Curl_hash_offt_init(struct Curl_hash_offt *h,
+ size_t slots,
+ Curl_hash_offt_dtor *dtor)
+{
+ DEBUGASSERT(h);
+ DEBUGASSERT(slots);
+
+ h->table = NULL;
+ h->dtor = dtor;
+ h->size = 0;
+ h->slots = slots;
+#ifdef DEBUGBUILD
+ h->init = CURL_HASHOFFTINIT;
+#endif
+}
+
+static struct Curl_hash_offt_entry *
+hash_offt_mk_entry(curl_off_t id, void *value)
+{
+ struct Curl_hash_offt_entry *e;
+
+ /* allocate the struct for the hash entry */
+ e = malloc(sizeof(*e));
+ if(e) {
+ e->id = id;
+ e->next = NULL;
+ e->value = value;
+ }
+ return e;
+}
+
+static void hash_offt_entry_clear(struct Curl_hash_offt *h,
+ struct Curl_hash_offt_entry *e)
+{
+ DEBUGASSERT(h);
+ DEBUGASSERT(e);
+ if(e->value) {
+ if(h->dtor)
+ h->dtor(e->id, e->value);
+ e->value = NULL;
+ }
+}
+
+static void hash_offt_entry_destroy(struct Curl_hash_offt *h,
+ struct Curl_hash_offt_entry *e)
+{
+ hash_offt_entry_clear(h, e);
+ free(e);
+}
+
+static void hash_offt_entry_unlink(struct Curl_hash_offt *h,
+ struct Curl_hash_offt_entry **he_anchor,
+ struct Curl_hash_offt_entry *he)
+{
+ *he_anchor = he->next;
+ --h->size;
+}
+
+static void hash_offtr_elem_link(struct Curl_hash_offt *h,
+ struct Curl_hash_offt_entry **he_anchor,
+ struct Curl_hash_offt_entry *he)
+{
+ he->next = *he_anchor;
+ *he_anchor = he;
+ ++h->size;
+}
+
+#define CURL_HASH_OFFT_SLOT(h,id) h->table[hash_offt_hash(id, h->slots)]
+#define CURL_HASH_OFFT_SLOT_ADDR(h,id) &CURL_HASH_OFFT_SLOT(h,id)
+
+bool Curl_hash_offt_set(struct Curl_hash_offt *h, curl_off_t id, void *value)
+{
+ struct Curl_hash_offt_entry *he, **slot;
+
+ DEBUGASSERT(h);
+ DEBUGASSERT(h->slots);
+ DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
+ if(!h->table) {
+ h->table = calloc(h->slots, sizeof(*he));
+ if(!h->table)
+ return FALSE; /* OOM */
+ }
+
+ slot = CURL_HASH_OFFT_SLOT_ADDR(h, id);
+ for(he = *slot; he; he = he->next) {
+ if(he->id == id) {
+ /* existing key entry, overwrite by clearing old pointer */
+ hash_offt_entry_clear(h, he);
+ he->value = value;
+ return TRUE;
+ }
+ }
+
+ he = hash_offt_mk_entry(id, value);
+ if(!he)
+ return FALSE; /* OOM */
+
+ hash_offtr_elem_link(h, slot, he);
+ return TRUE;
+}
+
+bool Curl_hash_offt_remove(struct Curl_hash_offt *h, curl_off_t id)
+{
+ DEBUGASSERT(h);
+ DEBUGASSERT(h->slots);
+ DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
+ if(h->table) {
+ struct Curl_hash_offt_entry *he, **he_anchor;
+
+ he_anchor = CURL_HASH_OFFT_SLOT_ADDR(h, id);
+ while(*he_anchor) {
+ he = *he_anchor;
+ if(id == he->id) {
+ hash_offt_entry_unlink(h, he_anchor, he);
+ hash_offt_entry_destroy(h, he);
+ return TRUE;
+ }
+ he_anchor = &he->next;
+ }
+ }
+ return FALSE;
+}
+
+void *Curl_hash_offt_get(struct Curl_hash_offt *h, curl_off_t id)
+{
+ DEBUGASSERT(h);
+ DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
+ if(h->table) {
+ struct Curl_hash_offt_entry *he;
+ DEBUGASSERT(h->slots);
+ he = CURL_HASH_OFFT_SLOT(h, id);
+ while(he) {
+ if(id == he->id) {
+ return he->value;
+ }
+ he = he->next;
+ }
+ }
+ return NULL;
+}
+
+void Curl_hash_offt_clear(struct Curl_hash_offt *h)
+{
+ if(h && h->table) {
+ struct Curl_hash_offt_entry *he, **he_anchor;
+ size_t i;
+ DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
+ for(i = 0; i < h->slots; ++i) {
+ he_anchor = &h->table[i];
+ while(*he_anchor) {
+ he = *he_anchor;
+ hash_offt_entry_unlink(h, he_anchor, he);
+ hash_offt_entry_destroy(h, he);
+ }
+ }
+ }
+}
+
+void
+Curl_hash_offt_destroy(struct Curl_hash_offt *h)
+{
+ DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
+ if(h->table) {
+ Curl_hash_offt_clear(h);
+ Curl_safefree(h->table);
+ }
+ DEBUGASSERT(h->size == 0);
+ h->slots = 0;
+}
+
+size_t Curl_hash_offt_count(struct Curl_hash_offt *h)
+{
+ DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
+ return h->size;
+}
+
+void Curl_hash_offt_visit(struct Curl_hash_offt *h,
+ Curl_hash_offt_visit_cb *cb,
+ void *user_data)
+{
+ if(h && h->table && cb) {
+ struct Curl_hash_offt_entry *he;
+ size_t i;
+ DEBUGASSERT(h->init == CURL_HASHOFFTINIT);
+ for(i = 0; i < h->slots; ++i) {
+ for(he = h->table[i]; he; he = he->next) {
+ if(!cb(he->id, he->value, user_data))
+ return;
+ }
+ }
+ }
+}
diff --git a/libs/libcurl/src/hash_offt.h b/libs/libcurl/src/hash_offt.h
new file mode 100644
index 0000000000..66eb703b11
--- /dev/null
+++ b/libs/libcurl/src/hash_offt.h
@@ -0,0 +1,67 @@
+#ifndef HEADER_CURL_HASH_OFFT_H
+#define HEADER_CURL_HASH_OFFT_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 "curl_setup.h"
+
+#include <stddef.h>
+
+#include "llist.h"
+
+struct Curl_hash_offt_entry;
+typedef void Curl_hash_offt_dtor(curl_off_t id, void *value);
+
+/* Hash for `curl_off_t` as key */
+struct Curl_hash_offt {
+ struct Curl_hash_offt_entry **table;
+ Curl_hash_offt_dtor *dtor;
+ size_t slots;
+ size_t size;
+#ifdef DEBUGBUILD
+ int init;
+#endif
+};
+
+void Curl_hash_offt_init(struct Curl_hash_offt *h,
+ size_t slots,
+ Curl_hash_offt_dtor *dtor);
+void Curl_hash_offt_destroy(struct Curl_hash_offt *h);
+
+bool Curl_hash_offt_set(struct Curl_hash_offt *h, curl_off_t id, void *value);
+bool Curl_hash_offt_remove(struct Curl_hash_offt *h, curl_off_t id);
+void *Curl_hash_offt_get(struct Curl_hash_offt *h, curl_off_t id);
+void Curl_hash_offt_clear(struct Curl_hash_offt *h);
+size_t Curl_hash_offt_count(struct Curl_hash_offt *h);
+
+
+typedef bool Curl_hash_offt_visit_cb(curl_off_t id, void *value,
+ void *user_data);
+
+void Curl_hash_offt_visit(struct Curl_hash_offt *h,
+ Curl_hash_offt_visit_cb *cb,
+ void *user_data);
+
+
+#endif /* HEADER_CURL_HASH_OFFT_H */
diff --git a/libs/libcurl/src/headers.c b/libs/libcurl/src/headers.c
index def9605b47..daae4fe45b 100644
--- a/libs/libcurl/src/headers.c
+++ b/libs/libcurl/src/headers.c
@@ -29,6 +29,7 @@
#include "strcase.h"
#include "sendf.h"
#include "headers.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -208,14 +209,14 @@ static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
else
return CURLE_BAD_FUNCTION_ARGUMENT;
- /* skip all leading space letters */
- while(*header && ISBLANK(*header))
+ /* skip all leading blank letters */
+ while(ISBLANK(*header))
header++;
*value = header;
/* skip all trailing space letters */
- while((end > header) && ISSPACE(*end))
+ while((end > header) && ISBLANK(*end))
*end-- = 0; /* nul terminate */
return CURLE_OK;
}
@@ -235,7 +236,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
oalloc = olen + offset + 1;
/* skip all trailing space letters */
- while(vlen && ISSPACE(value[vlen - 1]))
+ while(vlen && ISBLANK(value[vlen - 1]))
vlen--;
/* save only one leading space */
diff --git a/libs/libcurl/src/hostasyn.c b/libs/libcurl/src/hostasyn.c
index 87b38602fc..96cbc9788d 100644
--- a/libs/libcurl/src/hostasyn.c
+++ b/libs/libcurl/src/hostasyn.c
@@ -70,15 +70,13 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
struct Curl_dns_entry *dns = NULL;
CURLcode result = CURLE_OK;
- data->state.async.status = status;
-
if(CURL_ASYNC_SUCCESS == status) {
if(ai) {
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns = Curl_cache_addr(data, ai,
- data->state.async.hostname, 0,
+ data->conn->host.dispname, 0,
data->state.async.port, FALSE);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
diff --git a/libs/libcurl/src/hostip.c b/libs/libcurl/src/hostip.c
index 7597ab814a..57fd167377 100644
--- a/libs/libcurl/src/hostip.c
+++ b/libs/libcurl/src/hostip.c
@@ -42,7 +42,9 @@
#endif
#include <setjmp.h>
+#ifndef UNDER_CE
#include <signal.h>
+#endif
#include "urldata.h"
#include "sendf.h"
@@ -58,6 +60,8 @@
#include "warnless.h"
#include "strcase.h"
#include "easy_lock.h"
+#include "strparse.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -141,14 +145,14 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
case AF_INET: {
const struct sockaddr_in *sa4 = (const void *)ai->ai_addr;
const struct in_addr *ipaddr4 = &sa4->sin_addr;
- (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
+ (void)curlx_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
break;
}
#ifdef USE_IPV6
case AF_INET6: {
const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr;
const struct in6_addr *ipaddr6 = &sa6->sin6_addr;
- (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
+ (void)curlx_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
break;
}
#endif
@@ -545,7 +549,7 @@ static struct Curl_addrinfo *get_localhost6(int port, const char *name)
sa6.sin6_scope_id = 0;
#endif
- (void)Curl_inet_pton(AF_INET6, "::1", ipv6);
+ (void)curlx_inet_pton(AF_INET6, "::1", ipv6);
memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
ca->ai_flags = 0;
@@ -579,7 +583,7 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name)
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port16);
- if(Curl_inet_pton(AF_INET, "127.0.0.1", (char *)&ipv4) < 1)
+ if(curlx_inet_pton(AF_INET, "127.0.0.1", (char *)&ipv4) < 1)
return NULL;
memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4));
@@ -647,9 +651,9 @@ bool Curl_host_is_ipnum(const char *hostname)
#ifdef USE_IPV6
struct in6_addr in6;
#endif
- if(Curl_inet_pton(AF_INET, hostname, &in) > 0
+ if(curlx_inet_pton(AF_INET, hostname, &in) > 0
#ifdef USE_IPV6
- || Curl_inet_pton(AF_INET6, hostname, &in6) > 0
+ || curlx_inet_pton(AF_INET6, hostname, &in6) > 0
#endif
)
return TRUE;
@@ -743,7 +747,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
int st;
Curl_set_in_callback(data, TRUE);
st = data->set.resolver_start(
-#ifdef USE_CURL_ASYNC
+#ifdef CURLRES_ASYNCH
data->state.async.resolver,
#else
NULL,
@@ -757,7 +761,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
#ifndef USE_RESOLVE_ON_IPS
/* First check if this is an IPv4 address string */
- if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+ if(curlx_inet_pton(AF_INET, hostname, &in) > 0) {
/* This is a dotted IP address 123.123.123.123-style */
addr = Curl_ip2addr(AF_INET, &in, hostname, port);
if(!addr)
@@ -767,7 +771,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
else {
struct in6_addr in6;
/* check if this is an IPv6 address string */
- if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
+ if(curlx_inet_pton(AF_INET6, hostname, &in6) > 0) {
/* This is an IPv6 address literal */
addr = Curl_ip2addr(AF_INET6, &in6, hostname, port);
if(!addr)
@@ -779,14 +783,14 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
#else /* if USE_RESOLVE_ON_IPS */
#ifndef CURL_DISABLE_DOH
/* First check if this is an IPv4 address string */
- if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ if(curlx_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
ipnum = TRUE;
#ifdef USE_IPV6
else {
struct in6_addr in6;
/* check if this is an IPv6 address string */
- if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
+ if(curlx_inet_pton(AF_INET6, hostname, &in6) > 0)
/* This is an IPv6 address literal */
ipnum = TRUE;
}
@@ -928,8 +932,9 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
else
timeout = (timeoutms > LONG_MAX) ? LONG_MAX : (long)timeoutms;
- if(!timeout)
- /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
+ if(!timeout || data->set.doh)
+ /* USE_ALARM_TIMEOUT defined, but no timeout actually requested or resolve
+ done using DoH */
return Curl_resolv(data, hostname, port, TRUE, entry);
if(timeout < 1000) {
@@ -1079,10 +1084,7 @@ static void hostcache_unlink_entry(void *entry)
Curl_freeaddrinfo(dns->addr);
#ifdef USE_HTTPSRR
if(dns->hinfo) {
- free(dns->hinfo->target);
- free(dns->hinfo->ipv4hints);
- free(dns->hinfo->echconfiglist);
- free(dns->hinfo->ipv6hints);
+ Curl_httpsrr_cleanup(dns->hinfo);
free(dns->hinfo);
}
#endif
@@ -1122,43 +1124,47 @@ void Curl_hostcache_clean(struct Curl_easy *data,
CURLcode Curl_loadhostpairs(struct Curl_easy *data)
{
struct curl_slist *hostp;
- char *host_end;
/* Default is no wildcard found */
data->state.wildcard_resolve = FALSE;
for(hostp = data->state.resolve; hostp; hostp = hostp->next) {
char entry_id[MAX_HOSTCACHE_LEN];
- if(!hostp->data)
+ const char *host = hostp->data;
+ struct Curl_str source;
+ if(!host)
continue;
- if(hostp->data[0] == '-') {
- unsigned long num = 0;
+ if(*host == '-') {
+ curl_off_t num = 0;
size_t entry_len;
- size_t hlen = 0;
- host_end = strchr(&hostp->data[1], ':');
-
- if(host_end) {
- hlen = host_end - &hostp->data[1];
- num = strtoul(++host_end, NULL, 10);
- if(!hlen || (num > 0xffff))
- host_end = NULL;
+ host++;
+ if(!Curl_str_single(&host, '[')) {
+ if(Curl_str_until(&host, &source, MAX_IPADR_LEN, ']') ||
+ Curl_str_single(&host, ']') ||
+ Curl_str_single(&host, ':'))
+ continue;
}
- if(!host_end) {
- infof(data, "Bad syntax CURLOPT_RESOLVE removal entry '%s'",
- hostp->data);
- continue;
+ else {
+ if(Curl_str_until(&host, &source, 4096, ':') ||
+ Curl_str_single(&host, ':')) {
+ continue;
+ }
}
- /* 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(!Curl_str_number(&host, &num, 0xffff)) {
+ /* Create an entry id, based upon the hostname and port */
+ entry_len = create_hostcache_id(Curl_str(&source),
+ Curl_strlen(&source), (int)num,
+ entry_id, sizeof(entry_id));
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+ /* 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;
@@ -1166,75 +1172,69 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
size_t entry_len;
char address[64];
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
- char *addresses = NULL;
+ const char *addresses = NULL;
#endif
- char *addr_begin;
- char *addr_end;
- char *port_ptr;
- int port = 0;
- char *end_ptr;
+ curl_off_t port = 0;
bool permanent = TRUE;
- unsigned long tmp_port;
bool error = TRUE;
- char *host_begin = hostp->data;
- size_t hlen = 0;
- if(host_begin[0] == '+') {
- host_begin++;
+ if(*host == '+') {
+ host++;
permanent = FALSE;
}
- host_end = strchr(host_begin, ':');
- if(!host_end)
- goto err;
- hlen = host_end - host_begin;
-
- port_ptr = host_end + 1;
- tmp_port = strtoul(port_ptr, &end_ptr, 10);
- if(tmp_port > USHRT_MAX || end_ptr == port_ptr || *end_ptr != ':')
+ if(!Curl_str_single(&host, '[')) {
+ if(Curl_str_until(&host, &source, MAX_IPADR_LEN, ']') ||
+ Curl_str_single(&host, ']'))
+ continue;
+ }
+ else {
+ if(Curl_str_until(&host, &source, 4096, ':'))
+ continue;
+ }
+ if(Curl_str_single(&host, ':') ||
+ Curl_str_number(&host, &port, 0xffff) ||
+ Curl_str_single(&host, ':'))
goto err;
- port = (int)tmp_port;
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
- addresses = end_ptr + 1;
+ addresses = host;
#endif
- while(*end_ptr) {
- size_t alen;
+ /* start the address section */
+ while(*host) {
+ struct Curl_str target;
struct Curl_addrinfo *ai;
- addr_begin = end_ptr + 1;
- addr_end = strchr(addr_begin, ',');
- if(!addr_end)
- addr_end = addr_begin + strlen(addr_begin);
- end_ptr = addr_end;
-
- /* allow IP(v6) address within [brackets] */
- if(*addr_begin == '[') {
- if(addr_end == addr_begin || *(addr_end - 1) != ']')
+ if(!Curl_str_single(&host, '[')) {
+ if(Curl_str_until(&host, &target, MAX_IPADR_LEN, ']') ||
+ Curl_str_single(&host, ']'))
goto err;
- ++addr_begin;
- --addr_end;
}
-
- alen = addr_end - addr_begin;
- if(!alen)
- continue;
-
- if(alen >= sizeof(address))
- goto err;
-
- memcpy(address, addr_begin, alen);
- address[alen] = '\0';
-
+ else {
+ if(Curl_str_until(&host, &target, 4096, ',')) {
+ if(Curl_str_single(&host, ','))
+ goto err;
+ /* survive nothing but just a comma */
+ continue;
+ }
+ }
#ifndef USE_IPV6
- if(strchr(address, ':')) {
+ if(memchr(target.str, ':', target.len)) {
infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
address);
+ if(Curl_str_single(&host, ','))
+ goto err;
continue;
}
#endif
- ai = Curl_str2addr(address, port);
+ if(Curl_strlen(&target) >= sizeof(address))
+ goto err;
+
+ memcpy(address, Curl_str(&target), Curl_strlen(&target));
+ address[Curl_strlen(&target)] = '\0';
+
+ ai = Curl_str2addr(address, (int)port);
if(!ai) {
infof(data, "Resolve address '%s' found illegal", address);
goto err;
@@ -1247,6 +1247,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
else {
head = tail = ai;
}
+ if(Curl_str_single(&host, ','))
+ break;
}
if(!head)
@@ -1262,7 +1264,8 @@ err:
}
/* Create an entry id, based upon the hostname and port */
- entry_len = create_hostcache_id(host_begin, hlen, port,
+ entry_len = create_hostcache_id(Curl_str(&source), Curl_strlen(&source),
+ (int)port,
entry_id, sizeof(entry_id));
if(data->share)
@@ -1272,8 +1275,9 @@ err:
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);
+ infof(data, "RESOLVE %.*s:%" CURL_FORMAT_CURL_OFF_T
+ " - old addresses discarded", (int)Curl_strlen(&source),
+ Curl_str(&source), port);
/* delete old entry, there are two reasons for this
1. old entry may have different addresses.
2. even if entry with correct addresses is already in the cache,
@@ -1289,7 +1293,8 @@ err:
}
/* put this new host in the cache */
- dns = Curl_cache_addr(data, head, host_begin, hlen, port, permanent);
+ dns = Curl_cache_addr(data, head, Curl_str(&source),
+ Curl_strlen(&source), (int)port, permanent);
if(dns) {
/* release the returned reference; the cache itself will keep the
* entry alive: */
@@ -1304,14 +1309,15 @@ err:
return CURLE_OUT_OF_MEMORY;
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
- infof(data, "Added %.*s:%d:%s to DNS cache%s",
- (int)hlen, host_begin, port, addresses,
+ infof(data, "Added %.*s:%" CURL_FORMAT_CURL_OFF_T ":%s to DNS cache%s",
+ (int)Curl_strlen(&source), Curl_str(&source), port, addresses,
permanent ? "" : " (non-permanent)");
#endif
/* Wildcard hostname */
- if((hlen == 1) && (host_begin[0] == '*')) {
- infof(data, "RESOLVE *:%d using wildcard", port);
+ if(Curl_str_casecompare(&source, "*")) {
+ infof(data, "RESOLVE *:%" CURL_FORMAT_CURL_OFF_T " using wildcard",
+ port);
data->state.wildcard_resolve = TRUE;
}
}
@@ -1445,7 +1451,7 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
if(result) {
Curl_detach_connection(data);
- Curl_cpool_disconnect(data, conn, TRUE);
+ Curl_conn_terminate(data, conn, TRUE);
}
return result;
}
@@ -1475,7 +1481,7 @@ CURLcode Curl_resolver_error(struct Curl_easy *data)
}
failf(data, "Could not resolve %s: %s", host_or_proxy,
- data->state.async.hostname);
+ data->conn->host.dispname);
return result;
}
diff --git a/libs/libcurl/src/hostip.h b/libs/libcurl/src/hostip.h
index 62ea20a3ed..6f28e7eec7 100644
--- a/libs/libcurl/src/hostip.h
+++ b/libs/libcurl/src/hostip.h
@@ -195,12 +195,6 @@ Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr,
const char *hostname, size_t hostlen, int port,
bool permanent);
-#ifndef INADDR_NONE
-#define CURL_INADDR_NONE (in_addr_t) ~0
-#else
-#define CURL_INADDR_NONE INADDR_NONE
-#endif
-
/*
* Function provided by the resolver backend to set DNS servers to use.
*/
diff --git a/libs/libcurl/src/hostip4.c b/libs/libcurl/src/hostip4.c
index 10d91471a1..80ee26f452 100644
--- a/libs/libcurl/src/hostip4.c
+++ b/libs/libcurl/src/hostip4.c
@@ -286,7 +286,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
* getaddrinfo() nor gethostbyname_r() function or for which
* gethostbyname() is the preferred one.
*/
- h = gethostbyname((void *)hostname);
+ h = gethostbyname(CURL_UNCONST(hostname));
#endif /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
HAVE_GETHOSTBYNAME_R */
diff --git a/libs/libcurl/src/hostip6.c b/libs/libcurl/src/hostip6.c
index 8de74abf97..e0c9af56d2 100644
--- a/libs/libcurl/src/hostip6.c
+++ b/libs/libcurl/src/hostip6.c
@@ -126,8 +126,8 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
* The AI_NUMERICHOST must not be set to get synthesized IPv6 address from
* an IPv4 address on iOS and macOS.
*/
- if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
- (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
+ if((1 == curlx_inet_pton(AF_INET, hostname, addrbuf)) ||
+ (1 == curlx_inet_pton(AF_INET6, hostname, addrbuf))) {
/* the given address is numerical only, prevent a reverse lookup */
hints.ai_flags = AI_NUMERICHOST;
}
diff --git a/libs/libcurl/src/hsts.c b/libs/libcurl/src/hsts.c
index cdaaa677e8..f6363ae29d 100644
--- a/libs/libcurl/src/hsts.c
+++ b/libs/libcurl/src/hsts.c
@@ -35,7 +35,6 @@
#include "curl_get_line.h"
#include "strcase.h"
#include "sendf.h"
-#include "strtoofft.h"
#include "parsedate.h"
#include "fopen.h"
#include "rename.h"
@@ -59,13 +58,12 @@
time_t deltatime; /* allow for "adjustments" for unit test purposes */
static time_t hsts_debugtime(void *unused)
{
- char *timestr = getenv("CURL_TIME");
+ const char *timestr = getenv("CURL_TIME");
(void)unused;
if(timestr) {
curl_off_t val;
- (void)curlx_strtoofft(timestr, NULL, 10, &val);
-
- val += (curl_off_t)deltatime;
+ if(!Curl_str_number(&timestr, &val, TIME_T_MAX))
+ val += (curl_off_t)deltatime;
return (time_t)val;
}
return time(NULL);
@@ -85,7 +83,7 @@ struct hsts *Curl_hsts_init(void)
static void hsts_free(struct stsentry *e)
{
- free((char *)e->host);
+ free(CURL_UNCONST(e->host));
free(e);
}
@@ -156,35 +154,30 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
return CURLE_OK;
do {
- while(*p && ISBLANK(*p))
- p++;
+ Curl_str_passblanks(&p);
if(strncasecompare("max-age", p, 7)) {
bool quoted = FALSE;
- CURLofft offt;
- char *endp;
+ int rc;
if(gotma)
return CURLE_BAD_FUNCTION_ARGUMENT;
p += 7;
- while(*p && ISBLANK(*p))
- p++;
- if(*p++ != '=')
+ Curl_str_passblanks(&p);
+ if(Curl_str_single(&p, '='))
return CURLE_BAD_FUNCTION_ARGUMENT;
- while(*p && ISBLANK(*p))
- p++;
+ Curl_str_passblanks(&p);
- if(*p == '\"') {
- p++;
+ if(!Curl_str_single(&p, '\"'))
quoted = TRUE;
- }
- offt = curlx_strtoofft(p, &endp, 10, &expires);
- if(offt == CURL_OFFT_FLOW)
+
+ rc = Curl_str_number(&p, &expires, TIME_T_MAX);
+ if(rc == STRE_OVERFLOW)
expires = CURL_OFF_T_MAX;
- else if(offt)
+ else if(rc)
/* invalid max-age */
return CURLE_BAD_FUNCTION_ARGUMENT;
- p = endp;
+
if(quoted) {
if(*p != '\"')
return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -205,8 +198,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
p++;
}
- while(*p && ISBLANK(*p))
- p++;
+ Curl_str_passblanks(&p);
if(*p == ';')
p++;
} while(*p);
@@ -308,7 +300,7 @@ static CURLcode hsts_push(struct Curl_easy *data,
struct tm stamp;
CURLcode result;
- e.name = (char *)sts->host;
+ e.name = (char *)CURL_UNCONST(sts->host);
e.namelen = strlen(sts->host);
e.includeSubDomains = sts->includeSubDomains;
@@ -416,7 +408,7 @@ skipsave:
}
/* only returns SERIOUS errors */
-static CURLcode hsts_add(struct hsts *h, char *line)
+static CURLcode hsts_add(struct hsts *h, const char *line)
{
/* Example lines:
example.com "20191231 10:00:00"
@@ -436,26 +428,26 @@ static CURLcode hsts_add(struct hsts *h, char *line)
struct stsentry *e;
char dbuf[MAX_HSTS_DATELEN + 1];
time_t expires;
+ const char *hp = Curl_str(&host);
/* The date parser works on a null terminated string. The maximum length
is upheld by Curl_str_quotedword(). */
- memcpy(dbuf, date.str, date.len);
- dbuf[date.len] = 0;
+ memcpy(dbuf, Curl_str(&date), Curl_strlen(&date));
+ dbuf[Curl_strlen(&date)] = 0;
expires = strcmp(dbuf, UNLIMITED) ? Curl_getdate_capped(dbuf) :
TIME_T_MAX;
- if(host.str[0] == '.') {
- host.str++;
- host.len--;
+ if(hp[0] == '.') {
+ Curl_str_nudge(&host, 1);
subdomain = TRUE;
}
/* only add it if not already present */
- e = Curl_hsts(h, host.str, host.len, subdomain);
+ e = Curl_hsts(h, Curl_str(&host), Curl_strlen(&host), subdomain);
if(!e)
- result = hsts_create(h, host.str, host.len, subdomain, expires);
- else if((strlen(e->host) == host.len) &&
- strncasecompare(host.str, e->host, host.len)) {
+ result = hsts_create(h, Curl_str(&host), Curl_strlen(&host),
+ subdomain, expires);
+ else if(Curl_str_casecompare(&host, e->host)) {
/* the same hostname, use the largest expire time */
if(expires > e->expires)
e->expires = expires;
@@ -536,9 +528,9 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
struct dynbuf buf;
Curl_dyn_init(&buf, MAX_HSTS_LINE);
while(Curl_get_line(&buf, fp)) {
- char *lineptr = Curl_dyn_ptr(&buf);
- while(*lineptr && ISBLANK(*lineptr))
- lineptr++;
+ const char *lineptr = Curl_dyn_ptr(&buf);
+ Curl_str_passblanks(&lineptr);
+
/*
* Skip empty or commented lines, since we know the line will have a
* trailing newline from Curl_get_line we can treat length 1 as empty.
diff --git a/libs/libcurl/src/http.c b/libs/libcurl/src/http.c
index 1d6248a042..68e1812cfd 100644
--- a/libs/libcurl/src/http.c
+++ b/libs/libcurl/src/http.c
@@ -72,7 +72,6 @@
#include "headers.h"
#include "select.h"
#include "parsedate.h" /* for the week day and month names */
-#include "strtoofft.h"
#include "multiif.h"
#include "strcase.h"
#include "content_encoding.h"
@@ -86,6 +85,7 @@
#include "hsts.h"
#include "ws.h"
#include "curl_ctype.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -186,19 +186,56 @@ const struct Curl_handler Curl_handler_https = {
#endif
+void Curl_http_neg_init(struct Curl_easy *data, struct http_negotiation *neg)
+{
+ memset(neg, 0, sizeof(*neg));
+ neg->accept_09 = data->set.http09_allowed;
+ switch(data->set.httpwant) {
+ case CURL_HTTP_VERSION_1_0:
+ neg->wanted = neg->allowed = (CURL_HTTP_V1x);
+ neg->only_10 = TRUE;
+ break;
+ case CURL_HTTP_VERSION_1_1:
+ neg->wanted = neg->allowed = (CURL_HTTP_V1x);
+ break;
+ case CURL_HTTP_VERSION_2_0:
+ neg->wanted = neg->allowed = (CURL_HTTP_V1x | CURL_HTTP_V2x);
+ neg->h2_upgrade = TRUE;
+ break;
+ case CURL_HTTP_VERSION_2TLS:
+ neg->wanted = neg->allowed = (CURL_HTTP_V1x | CURL_HTTP_V2x);
+ break;
+ case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
+ neg->wanted = neg->allowed = (CURL_HTTP_V2x);
+ data->state.http_neg.h2_prior_knowledge = TRUE;
+ break;
+ case CURL_HTTP_VERSION_3:
+ neg->wanted = (CURL_HTTP_V1x | CURL_HTTP_V2x | CURL_HTTP_V3x);
+ neg->allowed = neg->wanted;
+ break;
+ case CURL_HTTP_VERSION_3ONLY:
+ neg->wanted = neg->allowed = (CURL_HTTP_V3x);
+ break;
+ case CURL_HTTP_VERSION_NONE:
+ default:
+ neg->wanted = (CURL_HTTP_V1x | CURL_HTTP_V2x);
+ neg->allowed = (CURL_HTTP_V1x | CURL_HTTP_V2x | CURL_HTTP_V3x);
+ break;
+ }
+}
+
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) {
+ if(data->state.http_neg.wanted == CURL_HTTP_V3x) {
+ /* only HTTP/3, needs to work */
CURLcode result = Curl_conn_may_http3(data, conn);
if(result)
return result;
}
-
return CURLE_OK;
}
@@ -235,46 +272,28 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
#endif
/*
- * Strip off leading and trailing whitespace from the value in the
- * given HTTP header line and return a strdupped copy. Returns NULL in
- * case of allocation failure. Returns an empty string if the header value
- * consists entirely of whitespace.
+ * Strip off leading and trailing whitespace from the value in the given HTTP
+ * header line and return a strdup()ed copy. Returns NULL in case of
+ * allocation failure or bad input. Returns an empty string if the header
+ * value consists entirely of whitespace.
+ *
+ * If the header is provided as "name;", ending with a semicolon, it must
+ * return a blank string.
*/
char *Curl_copy_header_value(const char *header)
{
- const char *start;
- const char *end;
- size_t len;
-
- /* Find the end of the header name */
- while(*header && (*header != ':'))
- ++header;
-
- if(*header)
- /* Skip over colon */
- ++header;
-
- /* Find the first non-space letter */
- start = header;
- while(*start && ISSPACE(*start))
- start++;
-
- end = strchr(start, '\r');
- if(!end)
- end = strchr(start, '\n');
- if(!end)
- end = strchr(start, '\0');
- if(!end)
- return NULL;
+ struct Curl_str out;
- /* skip all trailing space letters */
- while((end > start) && ISSPACE(*end))
- end--;
+ /* find the end of the header name */
+ if(!Curl_str_cspn(&header, &out, ";:") &&
+ (!Curl_str_single(&header, ':') || !Curl_str_single(&header, ';'))) {
+ Curl_str_untilnl(&header, &out, MAX_HTTP_RESP_HEADER_SIZE);
+ Curl_str_trimblanks(&out);
- /* get length of the type */
- len = end - start + 1;
-
- return Curl_memdup0(start, len);
+ return Curl_memdup0(Curl_str(&out), Curl_strlen(&out));
+ }
+ /* bad input */
+ return NULL;
}
#ifndef CURL_DISABLE_HTTP_AUTH
@@ -458,7 +477,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
#if defined(USE_NTLM)
if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
(data->state.authhost.picked == CURLAUTH_NTLM)) {
- ongoing_auth = "NTML";
+ ongoing_auth = "NTLM";
if((conn->http_ntlm_state != NTLMSTATE_NONE) ||
(conn->proxy_ntlm_state != NTLMSTATE_NONE)) {
/* The NTLM-negotiation has started, keep on sending.
@@ -537,7 +556,8 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
(data->req.httpversion_sent > 11)) {
infof(data, "Forcing HTTP/1.1 for NTLM");
connclose(conn, "Force HTTP/1.1 connection");
- data->state.httpwant = CURL_HTTP_VERSION_1_1;
+ data->state.http_neg.wanted = CURL_HTTP_V1x;
+ data->state.http_neg.allowed = CURL_HTTP_V1x;
}
}
#ifndef CURL_DISABLE_PROXY
@@ -562,7 +582,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
/* In case this is GSS auth, the newurl field is already allocated so
we must make sure to free it before allocating a new one. As figured
out in bug #2284386 */
- Curl_safefree(data->req.newurl);
+ free(data->req.newurl);
data->req.newurl = strdup(data->state.url); /* clone URL */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
@@ -613,9 +633,10 @@ output_auth_headers(struct Curl_easy *data,
(void)path;
#endif
#ifndef CURL_DISABLE_AWS
- if(authstatus->picked == CURLAUTH_AWS_SIGV4) {
+ if((authstatus->picked == CURLAUTH_AWS_SIGV4) && !proxy) {
+ /* this method is never for proxy */
auth = "AWS_SIGV4";
- result = Curl_output_aws_sigv4(data, proxy);
+ result = Curl_output_aws_sigv4(data);
if(result)
return result;
}
@@ -837,9 +858,137 @@ Curl_http_output_auth(struct Curl_easy *data,
!defined(CURL_DISABLE_DIGEST_AUTH) || \
!defined(CURL_DISABLE_BASIC_AUTH) || \
!defined(CURL_DISABLE_BEARER_AUTH)
-static int is_valid_auth_separator(char ch)
+static bool authcmp(const char *auth, const char *line)
+{
+ /* the auth string must not have an alnum following */
+ size_t n = strlen(auth);
+ return strncasecompare(auth, line, n) && !ISALNUM(line[n]);
+}
+#endif
+
+#ifdef USE_SPNEGO
+static CURLcode auth_spnego(struct Curl_easy *data,
+ bool proxy,
+ const char *auth,
+ struct auth *authp,
+ unsigned long *availp)
+{
+ if((authp->avail & CURLAUTH_NEGOTIATE) || Curl_auth_is_spnego_supported()) {
+ *availp |= CURLAUTH_NEGOTIATE;
+ authp->avail |= CURLAUTH_NEGOTIATE;
+
+ if(authp->picked == CURLAUTH_NEGOTIATE) {
+ struct connectdata *conn = data->conn;
+ CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
+ curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
+ &conn->http_negotiate_state;
+ if(!result) {
+ free(data->req.newurl);
+ data->req.newurl = strdup(data->state.url);
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+ data->state.authproblem = FALSE;
+ /* we received a GSS auth token and we dealt with it fine */
+ *negstate = GSS_AUTHRECV;
+ }
+ else
+ data->state.authproblem = TRUE;
+ }
+ }
+ return CURLE_OK;
+}
+#endif
+
+#ifdef USE_NTLM
+static CURLcode auth_ntlm(struct Curl_easy *data,
+ bool proxy,
+ const char *auth,
+ struct auth *authp,
+ unsigned long *availp)
+{
+ /* NTLM support requires the SSL crypto libs */
+ if((authp->avail & CURLAUTH_NTLM) || Curl_auth_is_ntlm_supported()) {
+ *availp |= CURLAUTH_NTLM;
+ authp->avail |= CURLAUTH_NTLM;
+
+ if(authp->picked == CURLAUTH_NTLM) {
+ /* NTLM authentication is picked and activated */
+ CURLcode result = Curl_input_ntlm(data, proxy, auth);
+ if(!result)
+ data->state.authproblem = FALSE;
+ else {
+ infof(data, "NTLM authentication problem, ignoring.");
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ return CURLE_OK;
+}
+#endif
+
+#ifndef CURL_DISABLE_DIGEST_AUTH
+static CURLcode auth_digest(struct Curl_easy *data,
+ bool proxy,
+ const char *auth,
+ struct auth *authp,
+ unsigned long *availp)
{
- return ch == '\0' || ch == ',' || ISSPACE(ch);
+ if(authp->avail & CURLAUTH_DIGEST)
+ infof(data, "Ignoring duplicate digest auth header.");
+ 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, "Digest authentication problem, ignoring.");
+ data->state.authproblem = TRUE;
+ }
+ }
+ return CURLE_OK;
+}
+#endif
+
+#ifndef CURL_DISABLE_BASIC_AUTH
+static CURLcode auth_basic(struct Curl_easy *data,
+ struct auth *authp,
+ unsigned long *availp)
+{
+ *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, "Basic authentication problem, ignoring.");
+ data->state.authproblem = TRUE;
+ }
+ return CURLE_OK;
+}
+#endif
+
+#ifndef CURL_DISABLE_BEARER_AUTH
+static CURLcode auth_bearer(struct Curl_easy *data,
+ struct auth *authp,
+ unsigned long *availp)
+{
+ *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, "Bearer authentication problem, ignoring.");
+ data->state.authproblem = TRUE;
+ }
+ return CURLE_OK;
}
#endif
@@ -847,6 +996,8 @@ static int is_valid_auth_separator(char ch)
* Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
* headers. They are dealt with both in the transfer.c main loop and in the
* proxy CONNECT loop.
+ *
+ * The 'auth' line ends with a null byte without CR or LF present.
*/
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
const char *auth) /* the first non-space */
@@ -854,11 +1005,6 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
/*
* This resource requires authentication
*/
- struct connectdata *conn = data->conn;
-#ifdef USE_SPNEGO
- curlnegotiate *negstate = proxy ? &conn->proxy_negotiate_state :
- &conn->http_negotiate_state;
-#endif
#if defined(USE_SPNEGO) || \
defined(USE_NTLM) || \
!defined(CURL_DISABLE_DIGEST_AUTH) || \
@@ -867,6 +1013,9 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
unsigned long *availp;
struct auth *authp;
+ CURLcode result = CURLE_OK;
+ DEBUGASSERT(auth);
+ DEBUGASSERT(data);
if(proxy) {
availp = &data->info.proxyauthavail;
@@ -876,11 +1025,6 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
availp = &data->info.httpauthavail;
authp = &data->state.authhost;
}
-#else
- (void) proxy;
-#endif
-
- (void) conn; /* In case conditionals make it unused. */
/*
* Here we check if we want the specific single authentication (using ==) and
@@ -900,126 +1044,43 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
while(*auth) {
#ifdef USE_SPNEGO
- if(checkprefix("Negotiate", auth) && is_valid_auth_separator(auth[9])) {
- if((authp->avail & CURLAUTH_NEGOTIATE) ||
- Curl_auth_is_spnego_supported()) {
- *availp |= CURLAUTH_NEGOTIATE;
- authp->avail |= CURLAUTH_NEGOTIATE;
-
- if(authp->picked == CURLAUTH_NEGOTIATE) {
- CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
- if(!result) {
- free(data->req.newurl);
- data->req.newurl = strdup(data->state.url);
- if(!data->req.newurl)
- return CURLE_OUT_OF_MEMORY;
- data->state.authproblem = FALSE;
- /* we received a GSS auth token and we dealt with it fine */
- *negstate = GSS_AUTHRECV;
- }
- else
- data->state.authproblem = TRUE;
- }
- }
- }
- else
+ if(authcmp("Negotiate", auth))
+ result = auth_spnego(data, proxy, auth, authp, availp);
#endif
#ifdef USE_NTLM
- /* NTLM support requires the SSL crypto libs */
- if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) {
- if((authp->avail & CURLAUTH_NTLM) ||
- Curl_auth_is_ntlm_supported()) {
- *availp |= CURLAUTH_NTLM;
- authp->avail |= CURLAUTH_NTLM;
-
- if(authp->picked == CURLAUTH_NTLM) {
- /* NTLM authentication is picked and activated */
- CURLcode result = Curl_input_ntlm(data, proxy, auth);
- if(!result) {
- data->state.authproblem = FALSE;
- }
- else {
- infof(data, "Authentication problem. Ignoring this.");
- data->state.authproblem = TRUE;
- }
- }
- }
- }
- else
+ if(!result && authcmp("NTLM", auth))
+ result = auth_ntlm(data, proxy, auth, authp, availp);
#endif
#ifndef CURL_DISABLE_DIGEST_AUTH
- if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) {
- if((authp->avail & CURLAUTH_DIGEST) != 0)
- infof(data, "Ignoring duplicate digest auth header.");
- 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
+ if(!result && authcmp("Digest", auth))
+ result = auth_digest(data, proxy, auth, authp, availp);
#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
+ if(!result && authcmp("Basic", auth))
+ result = auth_basic(data, authp, availp);
#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.
- */
- }
+ if(authcmp("Bearer", auth))
+ result = auth_bearer(data, authp, availp);
#endif
+ if(result)
+ break;
+
/* 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 = strchr(auth, ',');
+ if(auth) /* if we are on a comma, skip it */
auth++;
+ else
+ break;
+ Curl_str_passblanks(&auth);
}
+#else
+ (void) proxy;
+ /* nothing to do when disabled */
+#endif
- return CURLE_OK;
+ return result;
}
/**
@@ -1093,6 +1154,21 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
return data->state.authproblem;
}
+static void http_switch_to_get(struct Curl_easy *data, int code)
+{
+ const char *req = data->set.str[STRING_CUSTOMREQUEST];
+ if((req || data->state.httpreq != HTTPREQ_GET) &&
+ (data->set.http_follow_mode == CURLFOLLOW_OBEYCODE)) {
+ infof(data, "Switch to GET because of %d response", code);
+ data->state.http_ignorecustom = TRUE;
+ }
+ else if(req && (data->set.http_follow_mode != CURLFOLLOW_FIRSTONLY))
+ infof(data, "Stick to %s instead of GET", req);
+
+ data->state.httpreq = HTTPREQ_GET;
+ Curl_creader_set_rewind(data, FALSE);
+}
+
CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
followtype type)
{
@@ -1259,6 +1335,12 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
data->state.url_alloc = TRUE;
Curl_req_soft_reset(&data->req, data);
infof(data, "Issue another request to this URL: '%s'", data->state.url);
+ if((data->set.http_follow_mode == CURLFOLLOW_FIRSTONLY) &&
+ data->set.str[STRING_CUSTOMREQUEST] &&
+ !data->state.http_ignorecustom) {
+ data->state.http_ignorecustom = TRUE;
+ infof(data, "Drop custom request method for next request");
+ }
/*
* We get here when the HTTP code is 300-399 (and 401). We need to perform
@@ -1300,11 +1382,8 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
if((data->state.httpreq == HTTPREQ_POST
|| data->state.httpreq == HTTPREQ_POST_FORM
|| data->state.httpreq == HTTPREQ_POST_MIME)
- && !(data->set.keep_post & CURL_REDIR_POST_301)) {
- infof(data, "Switch from POST to GET");
- data->state.httpreq = HTTPREQ_GET;
- Curl_creader_set_rewind(data, FALSE);
- }
+ && !(data->set.keep_post & CURL_REDIR_POST_301))
+ http_switch_to_get(data, 301);
break;
case 302: /* Found */
/* (quote from RFC7231, section 6.4.3)
@@ -1326,11 +1405,8 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
if((data->state.httpreq == HTTPREQ_POST
|| data->state.httpreq == HTTPREQ_POST_FORM
|| data->state.httpreq == HTTPREQ_POST_MIME)
- && !(data->set.keep_post & CURL_REDIR_POST_302)) {
- infof(data, "Switch from POST to GET");
- data->state.httpreq = HTTPREQ_GET;
- Curl_creader_set_rewind(data, FALSE);
- }
+ && !(data->set.keep_post & CURL_REDIR_POST_302))
+ http_switch_to_get(data, 302);
break;
case 303: /* See Other */
@@ -1343,11 +1419,8 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
((data->state.httpreq != HTTPREQ_POST &&
data->state.httpreq != HTTPREQ_POST_FORM &&
data->state.httpreq != HTTPREQ_POST_MIME) ||
- !(data->set.keep_post & CURL_REDIR_POST_303))) {
- data->state.httpreq = HTTPREQ_GET;
- infof(data, "Switch to %s",
- data->req.no_body ? "HEAD" : "GET");
- }
+ !(data->set.keep_post & CURL_REDIR_POST_303)))
+ http_switch_to_get(data, 303);
break;
case 304: /* Not Modified */
/* 304 means we did a conditional request and it was "Not modified".
@@ -1388,9 +1461,8 @@ Curl_compareheader(const char *headerline, /* line to check */
* The field value MAY be preceded by any amount of LWS, though a single SP
* is preferred." */
- size_t len;
- const char *start;
- const char *end;
+ const char *p;
+ struct Curl_str val;
DEBUGASSERT(hlen);
DEBUGASSERT(clen);
DEBUGASSERT(header);
@@ -1400,31 +1472,21 @@ Curl_compareheader(const char *headerline, /* line to check */
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');
- }
+ p = &headerline[hlen];
- len = end-start; /* length of the content part of the input line */
+ if(Curl_str_untilnl(&p, &val, MAX_HTTP_RESP_HEADER_SIZE))
+ return FALSE;
+ Curl_str_trimblanks(&val);
/* find the content string in the rest of the line */
- for(; len >= clen; len--, start++) {
- if(strncasecompare(start, content, clen))
- return TRUE; /* match! */
+ if(Curl_strlen(&val) >= clen) {
+ size_t len;
+ p = Curl_str(&val);
+ for(len = Curl_strlen(&val); len >= Curl_strlen(&val); len--, p++) {
+ if(strncasecompare(p, content, clen))
+ return TRUE; /* match! */
+ }
}
-
return FALSE; /* no match */
}
@@ -1501,29 +1563,28 @@ static bool http_may_use_1_1(const struct Curl_easy *data)
const struct connectdata *conn = data->conn;
/* We have seen a previous response for *this* transfer with 1.0,
* on another connection or the same one. */
- if(data->state.httpversion == 10)
+ if(data->state.http_neg.rcvd_min == 10)
return FALSE;
/* We have seen a previous response on *this* connection with 1.0. */
- if(conn->httpversion_seen == 10)
+ if(conn && conn->httpversion_seen == 10)
return FALSE;
/* We want 1.0 and have seen no previous response on *this* connection
with a higher version (maybe no response at all yet). */
- if((data->state.httpwant == CURL_HTTP_VERSION_1_0) &&
- (conn->httpversion_seen <= 10))
+ if((data->state.http_neg.only_10) &&
+ (!conn || conn->httpversion_seen <= 10))
return FALSE;
- /* We want something newer than 1.0 or have no preferences. */
- return (data->state.httpwant == CURL_HTTP_VERSION_NONE) ||
- (data->state.httpwant >= CURL_HTTP_VERSION_1_1);
+ /* We are not restricted to use 1.0 only. */
+ return !data->state.http_neg.only_10;
}
static unsigned char http_request_version(struct Curl_easy *data)
{
- unsigned char httpversion = Curl_conn_http_version(data);
- if(!httpversion) {
+ unsigned char v = Curl_conn_http_version(data, data->conn);
+ if(!v) {
/* No specific HTTP connection filter installed. */
- httpversion = http_may_use_1_1(data) ? 11 : 10;
+ v = http_may_use_1_1(data) ? 11 : 10;
}
- return httpversion;
+ return v;
}
static const char *get_http_string(int httpversion)
@@ -1544,7 +1605,6 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
bool is_connect, int httpversion,
struct dynbuf *req)
{
- char *ptr;
struct curl_slist *h[2];
struct curl_slist *headers;
int numlists = 1; /* by default */
@@ -1584,98 +1644,81 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
/* loop through one or two lists */
for(i = 0; i < numlists; i++) {
- headers = h[i];
-
- while(headers) {
- char *semicolonp = NULL;
- ptr = strchr(headers->data, ':');
- if(!ptr) {
- char *optr;
- /* no colon, semicolon? */
- ptr = strchr(headers->data, ';');
- if(ptr) {
- optr = ptr;
- ptr++; /* pass the semicolon */
- while(*ptr && ISSPACE(*ptr))
- ptr++;
-
- if(*ptr) {
- /* this may be used for something else in the future */
- optr = NULL;
- }
- else {
- if(*(--ptr) == ';') {
- /* copy the source */
- semicolonp = strdup(headers->data);
- if(!semicolonp) {
- Curl_dyn_free(req);
- return CURLE_OUT_OF_MEMORY;
- }
- /* put a colon where the semicolon is */
- semicolonp[ptr - headers->data] = ':';
- /* point at the colon */
- optr = &semicolonp [ptr - headers->data];
- }
- }
- ptr = optr;
- }
- }
- if(ptr && (ptr != headers->data)) {
- /* we require a colon for this to be a true header */
-
- ptr++; /* pass the colon */
- while(*ptr && ISSPACE(*ptr))
- ptr++;
-
- 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((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))
- ;
- else {
- result = Curl_dyn_addf(req, "%s\r\n", compare);
- }
- if(semicolonp)
- free(semicolonp);
- if(result)
- return result;
+ for(headers = h[i]; headers; headers = headers->next) {
+ CURLcode result = CURLE_OK;
+ bool blankheader = FALSE;
+ struct Curl_str name;
+ const char *p = headers->data;
+ const char *origp = p;
+
+ /* explicitly asked to send header without content is done by a header
+ that ends with a semicolon, but there must be no colon present in the
+ name */
+ if(!Curl_str_until(&p, &name, MAX_HTTP_RESP_HEADER_SIZE, ';') &&
+ !Curl_str_single(&p, ';') &&
+ !Curl_str_single(&p, '\0') &&
+ !memchr(Curl_str(&name), ':', Curl_strlen(&name)))
+ blankheader = TRUE;
+ else {
+ p = origp;
+ if(!Curl_str_until(&p, &name, MAX_HTTP_RESP_HEADER_SIZE, ':') &&
+ !Curl_str_single(&p, ':')) {
+ struct Curl_str val;
+ Curl_str_untilnl(&p, &val, MAX_HTTP_RESP_HEADER_SIZE);
+ Curl_str_trimblanks(&val);
+ if(!Curl_strlen(&val))
+ /* no content, don't send this */
+ continue;
}
+ else
+ /* no colon */
+ continue;
}
- headers = headers->next;
+
+ /* only send this if the contents was non-blank or done special */
+
+ 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! */
+ Curl_str_casecompare(&name, "Host"))
+ ;
+ else if(data->state.httpreq == HTTPREQ_POST_FORM &&
+ /* this header (extended by formdata.c) is sent later */
+ Curl_str_casecompare(&name, "Content-Type"))
+ ;
+ else if(data->state.httpreq == HTTPREQ_POST_MIME &&
+ /* this header is sent later */
+ Curl_str_casecompare(&name, "Content-Type"))
+ ;
+ else if(data->req.authneg &&
+ /* while doing auth neg, do not allow the custom length since
+ we will force length zero then */
+ Curl_str_casecompare(&name, "Content-Length"))
+ ;
+ else if(data->state.aptr.te &&
+ /* when asking for Transfer-Encoding, do not pass on a custom
+ Connection: */
+ Curl_str_casecompare(&name, "Connection"))
+ ;
+ else if((httpversion >= 20) &&
+ Curl_str_casecompare(&name, "Transfer-Encoding"))
+ /* HTTP/2 does not support chunked requests */
+ ;
+ else if((Curl_str_casecompare(&name, "Authorization") ||
+ Curl_str_casecompare(&name, "Cookie")) &&
+ /* be careful of sending this potentially sensitive header to
+ other hosts */
+ !Curl_auth_allowed_to_host(data))
+ ;
+ else if(blankheader)
+ result = Curl_dyn_addf(req, "%.*s:\r\n", (int)Curl_strlen(&name),
+ Curl_str(&name));
+ else
+ result = Curl_dyn_addf(req, "%s\r\n", origp);
+
+ if(result)
+ return result;
}
}
@@ -1771,8 +1814,10 @@ void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
httpreq = HTTPREQ_PUT;
/* Now set the 'request' pointer to the proper request string */
- if(data->set.str[STRING_CUSTOMREQUEST])
+ if(data->set.str[STRING_CUSTOMREQUEST] &&
+ !data->state.http_ignorecustom) {
request = data->set.str[STRING_CUSTOMREQUEST];
+ }
else {
if(data->req.no_body)
request = "HEAD";
@@ -1865,7 +1910,7 @@ static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn)
if(colon)
*colon = 0; /* The host must not include an embedded port number */
}
- Curl_safefree(aptr->cookiehost);
+ free(aptr->cookiehost);
aptr->cookiehost = cookiehost;
}
#endif
@@ -2620,11 +2665,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
switch(conn->alpn) {
case CURL_HTTP_VERSION_3:
- DEBUGASSERT(Curl_conn_http_version(data) == 30);
+ DEBUGASSERT(Curl_conn_http_version(data, conn) == 30);
break;
case CURL_HTTP_VERSION_2:
#ifndef CURL_DISABLE_PROXY
- if((Curl_conn_http_version(data) != 20) &&
+ if((Curl_conn_http_version(data, conn) != 20) &&
conn->bits.proxy && !conn->bits.tunnel_proxy
) {
result = Curl_http2_switch(data);
@@ -2633,7 +2678,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
}
else
#endif
- DEBUGASSERT(Curl_conn_http_version(data) == 20);
+ DEBUGASSERT(Curl_conn_http_version(data, conn) == 20);
break;
case CURL_HTTP_VERSION_1_1:
/* continue with HTTP/1.x when explicitly requested */
@@ -2690,7 +2735,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
data->set.str[STRING_ENCODING]) {
- Curl_safefree(data->state.aptr.accept_encoding);
+ free(data->state.aptr.accept_encoding);
data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
if(!data->state.aptr.accept_encoding)
@@ -2814,7 +2859,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
}
if(!Curl_conn_is_ssl(conn, FIRSTSOCKET) && (httpversion < 20) &&
- (data->state.httpwant == CURL_HTTP_VERSION_2)) {
+ (data->state.http_neg.wanted & CURL_HTTP_V2x) &&
+ data->state.http_neg.h2_upgrade) {
/* append HTTP2 upgrade magic stuff to the HTTP request if it is not done
over SSL */
result = Curl_http2_request_upgrade(&req, data);
@@ -2980,13 +3026,13 @@ static CURLcode http_header(struct Curl_easy *data,
HD_VAL(hd, hdlen, "Content-Length:") : NULL;
if(v) {
curl_off_t contentlength;
- CURLofft offt = curlx_strtoofft(v, NULL, 10, &contentlength);
+ int offt = Curl_str_numblanks(&v, &contentlength);
- if(offt == CURL_OFFT_OK) {
+ if(offt == STRE_OK) {
k->size = contentlength;
k->maxdownload = k->size;
}
- else if(offt == CURL_OFFT_FLOW) {
+ else if(offt == STRE_OVERFLOW) {
/* out of range */
if(data->set.max_filesize) {
failf(data, "Maximum file size exceeded");
@@ -3024,7 +3070,7 @@ static CURLcode http_header(struct Curl_easy *data,
/* ignore empty data */
free(contenttype);
else {
- Curl_safefree(data->info.contenttype);
+ free(data->info.contenttype);
data->info.contenttype = contenttype;
}
return CURLE_OK;
@@ -3072,11 +3118,10 @@ static CURLcode http_header(struct Curl_easy *data,
/* if it truly stopped on a digit */
if(ISDIGIT(*ptr)) {
- if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
- if(data->state.resume_from == k->offset)
- /* we asked for a resume and we got it */
- k->content_range = TRUE;
- }
+ if(!Curl_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) &&
+ (data->state.resume_from == k->offset))
+ /* we asked for a resume and we got it */
+ k->content_range = TRUE;
}
else if(k->httpcode < 300)
data->state.resume_from = 0; /* get everything */
@@ -3106,7 +3151,7 @@ static CURLcode http_header(struct Curl_easy *data,
else {
data->req.location = location;
- if(data->set.http_follow_location) {
+ if(data->set.http_follow_mode) {
DEBUGASSERT(!data->req.newurl);
data->req.newurl = strdup(data->req.location); /* clone */
if(!data->req.newurl)
@@ -3183,18 +3228,22 @@ static CURLcode http_header(struct Curl_easy *data,
if(v) {
/* Retry-After = HTTP-date / delay-seconds */
curl_off_t retry_after = 0; /* zero for unknown or "now" */
- /* Try it as a decimal number, if it works it is not a date */
- (void)curlx_strtoofft(v, NULL, 10, &retry_after);
- if(!retry_after) {
- time_t date = Curl_getdate_capped(v);
+ time_t date;
+ Curl_str_passblanks(&v);
+
+ /* try it as a date first, because a date can otherwise start with and
+ get treated as a number */
+ date = Curl_getdate_capped(v);
+
+ if((time_t)-1 != date) {
time_t current = time(NULL);
- if((time_t)-1 != date && date > current) {
+ if(date >= current)
/* convert date to number of seconds into the future */
retry_after = date - current;
- }
}
- if(retry_after < 0)
- retry_after = 0;
+ else
+ /* Try it as a decimal number */
+ Curl_str_number(&v, &retry_after, CURL_OFF_T_MAX);
/* limit to 6 hours max. this is not documented so that it can be changed
in the future if necessary. */
if(retry_after > 21600)
@@ -3346,9 +3395,10 @@ static CURLcode http_statusline(struct Curl_easy *data,
data->info.httpversion = k->httpversion;
conn->httpversion_seen = (unsigned char)k->httpversion;
- if(!data->state.httpversion || data->state.httpversion > k->httpversion)
+ if(!data->state.http_neg.rcvd_min ||
+ data->state.http_neg.rcvd_min > k->httpversion)
/* store the lowest server version we encounter */
- data->state.httpversion = (unsigned char)k->httpversion;
+ data->state.http_neg.rcvd_min = (unsigned char)k->httpversion;
/*
* This code executes as part of processing the header. As a
@@ -3491,7 +3541,7 @@ static CURLcode http_write_header(struct Curl_easy *data,
/* now, only output this if the header AND body are requested:
*/
- Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
+ Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
writetype = CLIENTWRITE_HEADER |
((data->req.httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
@@ -3847,8 +3897,7 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
*/
const char *p = hd;
- while(*p && ISBLANK(*p))
- p++;
+ Curl_str_passblanks(&p);
if(!strncmp(p, "HTTP/", 5)) {
p += 5;
switch(*p) {
@@ -3861,9 +3910,9 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
(p[2] - '0');
- p += 3;
- if(ISSPACE(*p))
- fine_statusline = TRUE;
+ /* RFC 9112 requires a single space following the status code,
+ but the browsers don't so let's not insist */
+ fine_statusline = TRUE;
}
}
}
@@ -3882,7 +3931,7 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
(p[2] - '0');
p += 3;
- if(!ISSPACE(*p))
+ if(!ISBLANK(*p))
break;
fine_statusline = TRUE;
}
@@ -3907,30 +3956,22 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
}
else if(data->conn->handler->protocol & CURLPROTO_RTSP) {
const char *p = hd;
- while(*p && ISBLANK(*p))
- p++;
- if(!strncmp(p, "RTSP/", 5)) {
- p += 5;
- if(ISDIGIT(*p)) {
- p++;
- if((p[0] == '.') && ISDIGIT(p[1])) {
- if(ISBLANK(p[2])) {
- p += 3;
- if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
- k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
- (p[2] - '0');
- p += 3;
- if(ISSPACE(*p)) {
- fine_statusline = TRUE;
- k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
- }
- }
- }
- }
+ struct Curl_str ver;
+ curl_off_t status;
+ /* we set the max string a little excessive to forgive some leading
+ spaces */
+ if(!Curl_str_until(&p, &ver, 32, ' ') &&
+ !Curl_str_single(&p, ' ') &&
+ !Curl_str_number(&p, &status, 999)) {
+ Curl_str_trimblanks(&ver);
+ if(Curl_str_cmp(&ver, "RTSP/1.0")) {
+ k->httpcode = (int)status;
+ fine_statusline = TRUE;
+ k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
}
- if(!fine_statusline)
- return CURLE_WEIRD_SERVER_REPLY;
}
+ if(!fine_statusline)
+ return CURLE_WEIRD_SERVER_REPLY;
}
if(fine_statusline) {
@@ -3956,7 +3997,7 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
/*
* Taken in one (more) header. Write it to the client.
*/
- Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
+ Curl_debug(data, CURLINFO_HEADER_IN, hd, hdlen);
if(k->httpcode/100 == 1)
writetype |= CLIENTWRITE_1XX;
@@ -4014,7 +4055,7 @@ static CURLcode http_parse_headers(struct Curl_easy *data,
failf(data, "Invalid status line");
return CURLE_WEIRD_SERVER_REPLY;
}
- if(!data->set.http09_allowed) {
+ if(!data->state.http_neg.accept_09) {
failf(data, "Received HTTP/0.9 when not allowed");
return CURLE_UNSUPPORTED_PROTOCOL;
}
@@ -4051,7 +4092,7 @@ static CURLcode http_parse_headers(struct Curl_easy *data,
failf(data, "Invalid status line");
return CURLE_WEIRD_SERVER_REPLY;
}
- if(!data->set.http09_allowed) {
+ if(!data->state.http_neg.accept_09) {
failf(data, "Received HTTP/0.9 when not allowed");
return CURLE_UNSUPPORTED_PROTOCOL;
}
@@ -4157,7 +4198,7 @@ CURLcode Curl_http_write_resp(struct Curl_easy *data,
flags = CLIENTWRITE_BODY;
if(is_eos)
flags |= CLIENTWRITE_EOS;
- result = Curl_client_write(data, flags, (char *)buf, blen);
+ result = Curl_client_write(data, flags, buf, blen);
}
out:
return result;
@@ -4197,11 +4238,9 @@ CURLcode Curl_http_req_make(struct httpreq **preq,
struct httpreq *req;
CURLcode result = CURLE_OUT_OF_MEMORY;
- DEBUGASSERT(method);
- if(m_len + 1 > sizeof(req->method))
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ DEBUGASSERT(method && m_len);
- req = calloc(1, sizeof(*req));
+ req = calloc(1, sizeof(*req) + m_len);
if(!req)
goto out;
memcpy(req->method, method, m_len);
@@ -4353,11 +4392,9 @@ CURLcode Curl_http_req_make2(struct httpreq **preq,
CURLcode result = CURLE_OUT_OF_MEMORY;
CURLUcode uc;
- DEBUGASSERT(method);
- if(m_len + 1 > sizeof(req->method))
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ DEBUGASSERT(method && m_len);
- req = calloc(1, sizeof(*req));
+ req = calloc(1, sizeof(*req) + m_len);
if(!req)
goto out;
memcpy(req->method, method, m_len);
@@ -4420,7 +4457,7 @@ static struct name_const H2_NON_FIELD[] = {
static bool h2_non_field(const char *name, size_t namelen)
{
size_t i;
- for(i = 0; i < sizeof(H2_NON_FIELD)/sizeof(H2_NON_FIELD[0]); ++i) {
+ for(i = 0; i < CURL_ARRAYSIZE(H2_NON_FIELD); ++i) {
if(namelen < H2_NON_FIELD[i].namelen)
return FALSE;
if(namelen == H2_NON_FIELD[i].namelen &&
@@ -4448,8 +4485,7 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
scheme = Curl_checkheaders(data, STRCONST(HTTP_PSEUDO_SCHEME));
if(scheme) {
scheme += sizeof(HTTP_PSEUDO_SCHEME);
- while(*scheme && ISBLANK(*scheme))
- scheme++;
+ Curl_str_passblanks(&scheme);
infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme);
}
else {
diff --git a/libs/libcurl/src/http.h b/libs/libcurl/src/http.h
index 06cb9ae71e..e97abc0a28 100644
--- a/libs/libcurl/src/http.h
+++ b/libs/libcurl/src/http.h
@@ -53,6 +53,12 @@ typedef enum {
FOLLOW_REDIR /* a full true redirect */
} followtype;
+#define CURL_HTTP_V1x (1 << 0)
+#define CURL_HTTP_V2x (1 << 1)
+#define CURL_HTTP_V3x (1 << 2)
+/* bitmask of CURL_HTTP_V* values */
+typedef unsigned char http_majors;
+
#ifndef CURL_DISABLE_HTTP
@@ -68,6 +74,18 @@ extern const struct Curl_handler Curl_handler_https;
struct dynhds;
+struct http_negotiation {
+ unsigned char rcvd_min; /* minimum version seen in responses, 09, 10, 11 */
+ http_majors wanted; /* wanted major versions when talking to server */
+ http_majors allowed; /* allowed major versions when talking to server */
+ BIT(h2_upgrade); /* Do HTTP Upgrade from 1.1 to 2 */
+ BIT(h2_prior_knowledge); /* Directly do HTTP/2 without ALPN/SSL */
+ BIT(accept_09); /* Accept an HTTP/0.9 response */
+ BIT(only_10); /* When using major version 1x, use only 1.0 */
+};
+
+void Curl_http_neg_init(struct Curl_easy *data, struct http_negotiation *neg);
+
CURLcode Curl_bump_headersize(struct Curl_easy *data,
size_t delta,
bool connect_only);
@@ -113,6 +131,7 @@ CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
const char *auth);
+
CURLcode Curl_http_auth_act(struct Curl_easy *data);
/* follow a redirect or not */
@@ -199,12 +218,12 @@ CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len);
* All about a core HTTP request, excluding body and trailers
*/
struct httpreq {
- char method[24];
+ struct dynhds headers;
+ struct dynhds trailers;
char *scheme;
char *authority;
char *path;
- struct dynhds headers;
- struct dynhds trailers;
+ char method[1];
};
/**
diff --git a/libs/libcurl/src/http2.c b/libs/libcurl/src/http2.c
index 7b88aa7a83..a19ce0aff4 100644
--- a/libs/libcurl/src/http2.c
+++ b/libs/libcurl/src/http2.c
@@ -29,7 +29,7 @@
#include <nghttp2/nghttp2.h>
#include "urldata.h"
#include "bufq.h"
-#include "hash.h"
+#include "hash_offt.h"
#include "http1.h"
#include "http2.h"
#include "http.h"
@@ -43,7 +43,6 @@
#include "cfilters.h"
#include "connect.h"
#include "rand.h"
-#include "strtoofft.h"
#include "strdup.h"
#include "transfer.h"
#include "dynbuf.h"
@@ -136,7 +135,7 @@ struct cf_h2_ctx {
struct bufc_pool stream_bufcp; /* spares for stream buffers */
struct dynbuf scratch; /* scratch buffer for temp use */
- struct Curl_hash streams; /* hash of `data->mid` to `h2_stream_ctx` */
+ struct Curl_hash_offt streams; /* hash of `data->mid` 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 */
@@ -156,7 +155,7 @@ struct cf_h2_ctx {
#define CF_CTX_CALL_DATA(cf) \
((struct cf_h2_ctx *)(cf)->ctx)->call_data
-static void h2_stream_hash_free(void *stream);
+static void h2_stream_hash_free(curl_off_t id, void *stream);
static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade)
{
@@ -177,8 +176,7 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
Curl_bufq_free(&ctx->outbufq);
Curl_bufcp_free(&ctx->stream_bufcp);
Curl_dyn_free(&ctx->scratch);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
+ Curl_hash_offt_destroy(&ctx->streams);
memset(ctx, 0, sizeof(*ctx));
}
free(ctx);
@@ -220,6 +218,7 @@ struct h2_stream_ctx {
BIT(bodystarted);
BIT(body_eos); /* the complete body has been added to `sendbuf` and
* is being/has been processed from there. */
+ BIT(write_paused); /* stream write is paused */
};
#define H2_STREAM_CTX(ctx,data) ((struct h2_stream_ctx *)(\
@@ -267,8 +266,9 @@ static void h2_stream_ctx_free(struct h2_stream_ctx *stream)
free(stream);
}
-static void h2_stream_hash_free(void *stream)
+static void h2_stream_hash_free(curl_off_t id, void *stream)
{
+ (void)id;
DEBUGASSERT(stream);
h2_stream_ctx_free((struct h2_stream_ctx *)stream);
}
@@ -290,14 +290,14 @@ static int32_t cf_h2_get_desired_local_win(struct Curl_cfilter *cf,
static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct h2_stream_ctx *stream,
- bool paused)
+ struct h2_stream_ctx *stream)
{
struct cf_h2_ctx *ctx = cf->ctx;
int32_t dwsize;
int rv;
- dwsize = paused ? 0 : cf_h2_get_desired_local_win(cf, data);
+ dwsize = (stream->write_paused || stream->xfer_result) ?
+ 0 : cf_h2_get_desired_local_win(cf, data);
if(dwsize != stream->local_window_size) {
int32_t wsize = nghttp2_session_get_stream_effective_local_window_size(
ctx->h2, stream->id);
@@ -333,13 +333,11 @@ static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct h2_stream_ctx *stream,
- bool paused)
+ struct h2_stream_ctx *stream)
{
(void)cf;
(void)data;
(void)stream;
- (void)paused;
return CURLE_OK;
}
#endif /* !NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE */
@@ -482,6 +480,10 @@ static ssize_t send_callback(nghttp2_session *h2,
void *userp);
static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
void *userp);
+static int cf_h2_on_invalid_frame_recv(nghttp2_session *session,
+ const nghttp2_frame *frame,
+ int lib_error_code,
+ void *user_data);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
void *userp);
@@ -522,6 +524,8 @@ static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
nghttp2_session_callbacks_set_send_callback(cbs, send_callback);
nghttp2_session_callbacks_set_on_frame_recv_callback(cbs, on_frame_recv);
+ nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(cbs,
+ cf_h2_on_invalid_frame_recv);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
nghttp2_session_callbacks_set_on_frame_send_callback(cbs, on_frame_send);
#endif
@@ -644,10 +648,8 @@ static int h2_process_pending_input(struct Curl_cfilter *cf,
rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen);
if(rv < 0) {
- failf(data,
- "process_pending_input: nghttp2_session_mem_recv() returned "
- "%zd:%s", rv, nghttp2_strerror((int)rv));
- *err = CURLE_RECV_ERROR;
+ failf(data, "nghttp2 recv error %zd: %s", rv, nghttp2_strerror((int)rv));
+ *err = CURLE_HTTP2;
return -1;
}
Curl_bufq_skip(&ctx->inbufq, (size_t)rv);
@@ -965,9 +967,6 @@ static int push_promise(struct Curl_cfilter *cf,
goto fail;
}
- /* ask the application */
- CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ask application");
-
stream = H2_STREAM_CTX(ctx, data);
if(!stream) {
failf(data, "Internal NULL stream");
@@ -982,20 +981,13 @@ static int push_promise(struct Curl_cfilter *cf,
rv = set_transfer_url(newhandle, &heads);
if(rv) {
+ CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE, failed to set url -> %d",
+ frame->promised_stream_id, rv);
discard_newhandle(cf, newhandle);
rv = CURL_PUSH_DENY;
goto fail;
}
- result = http2_data_setup(cf, newhandle, &newstream);
- if(result) {
- failf(data, "error setting up stream: %d", result);
- discard_newhandle(cf, newhandle);
- rv = CURL_PUSH_DENY;
- goto fail;
- }
- DEBUGASSERT(stream);
-
Curl_set_in_callback(data, TRUE);
rv = data->multi->push_cb(data, newhandle,
stream->push_headers_used, &heads,
@@ -1008,16 +1000,15 @@ static int push_promise(struct Curl_cfilter *cf,
if(rv) {
DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
/* denied, kill off the new handle again */
+ CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE, denied by application -> %d",
+ frame->promised_stream_id, rv);
discard_newhandle(cf, newhandle);
goto fail;
}
- newstream->id = frame->promised_stream_id;
- newhandle->req.maxdownload = -1;
- newhandle->req.size = -1;
-
- /* approved, add to the multi handle and immediately switch to PERFORM
- state with the given connection !*/
+ /* approved, add to the multi handle for processing. This
+ * assigns newhandle->mid. For the new `mid` we assign the
+ * h2_stream instance and remember the stream_id already known. */
rc = Curl_multi_add_perform(data->multi, newhandle, cf->conn);
if(rc) {
infof(data, "failed to add handle to multi");
@@ -1026,6 +1017,21 @@ static int push_promise(struct Curl_cfilter *cf,
goto fail;
}
+ result = http2_data_setup(cf, newhandle, &newstream);
+ if(result) {
+ failf(data, "error setting up stream: %d", result);
+ discard_newhandle(cf, newhandle);
+ rv = CURL_PUSH_DENY;
+ goto fail;
+ }
+
+ DEBUGASSERT(newstream);
+ newstream->id = frame->promised_stream_id;
+ newhandle->req.maxdownload = -1;
+ newhandle->req.size = -1;
+
+ CURL_TRC_CF(data, cf, "promise easy handle added to multi, mid=%"
+ FMT_OFF_T, newhandle->mid);
rv = nghttp2_session_set_stream_user_data(ctx->h2,
newstream->id,
newhandle);
@@ -1059,7 +1065,7 @@ static void h2_xfer_write_resp_hd(struct Curl_cfilter *cf,
if(!stream->xfer_result) {
stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
if(!stream->xfer_result && !eos)
- stream->xfer_result = cf_h2_update_local_win(cf, data, stream, FALSE);
+ stream->xfer_result = cf_h2_update_local_win(cf, data, stream);
if(stream->xfer_result)
CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of headers",
stream->id, stream->xfer_result, blen);
@@ -1075,8 +1081,6 @@ static void h2_xfer_write_resp(struct Curl_cfilter *cf,
/* If we already encountered an error, skip further writes */
if(!stream->xfer_result)
stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
- if(!stream->xfer_result && !eos)
- stream->xfer_result = cf_h2_update_local_win(cf, data, stream, FALSE);
/* If the transfer write is errored, we do not want any more data */
if(stream->xfer_result) {
struct cf_h2_ctx *ctx = cf->ctx;
@@ -1086,6 +1090,17 @@ static void h2_xfer_write_resp(struct Curl_cfilter *cf,
nghttp2_submit_rst_stream(ctx->h2, 0, stream->id,
(uint32_t)NGHTTP2_ERR_CALLBACK_FAILURE);
}
+ else if(!stream->write_paused && Curl_xfer_write_is_paused(data)) {
+ CURL_TRC_CF(data, cf, "[%d] stream output paused", stream->id);
+ stream->write_paused = TRUE;
+ }
+ else if(stream->write_paused && !Curl_xfer_write_is_paused(data)) {
+ CURL_TRC_CF(data, cf, "[%d] stream output unpaused", stream->id);
+ stream->write_paused = FALSE;
+ }
+
+ if(!stream->xfer_result && !eos)
+ stream->xfer_result = cf_h2_update_local_win(cf, data, stream);
}
static CURLcode on_stream_frame(struct Curl_cfilter *cf,
@@ -1253,7 +1268,7 @@ static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen)
}
case NGHTTP2_GOAWAY: {
char scratch[128];
- size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
+ size_t s_len = CURL_ARRAYSIZE(scratch);
size_t len = (frame->goaway.opaque_data_len < s_len) ?
frame->goaway.opaque_data_len : s_len-1;
if(len)
@@ -1279,6 +1294,7 @@ static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
void *userp)
{
struct Curl_cfilter *cf = userp;
+ struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
(void)session;
@@ -1290,6 +1306,13 @@ static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
buffer[len] = 0;
CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer);
}
+ if((frame->hd.type == NGHTTP2_GOAWAY) && !ctx->sent_goaway) {
+ /* A GOAWAY not initiated by us, but by nghttp2 itself on detecting
+ * a protocol error on the connection */
+ failf(data, "nghttp2 shuts down connection with error %d: %s",
+ frame->goaway.error_code,
+ nghttp2_http2_strerror(frame->goaway.error_code));
+ }
return 0;
}
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
@@ -1372,6 +1395,39 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
return on_stream_frame(cf, data_s, frame) ? NGHTTP2_ERR_CALLBACK_FAILURE : 0;
}
+static int cf_h2_on_invalid_frame_recv(nghttp2_session *session,
+ const nghttp2_frame *frame,
+ int ngerr, void *userp)
+{
+ struct Curl_cfilter *cf = userp;
+ struct cf_h2_ctx *ctx = cf->ctx;
+ struct Curl_easy *data;
+ int32_t stream_id = frame->hd.stream_id;
+
+ data = nghttp2_session_get_stream_user_data(session, stream_id);
+ if(data) {
+ struct h2_stream_ctx *stream;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ char buffer[256];
+ int len;
+ len = fr_print(frame, buffer, sizeof(buffer)-1);
+ buffer[len] = 0;
+ failf(data, "[HTTP2] [%d] received invalid frame: %s, error %d: %s",
+ stream_id, buffer, ngerr, nghttp2_strerror(ngerr));
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+ stream = H2_STREAM_CTX(ctx, data);
+ if(stream) {
+ nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
+ stream->id, NGHTTP2_STREAM_CLOSED);
+ stream->error = ngerr;
+ stream->closed = TRUE;
+ stream->reset = TRUE;
+ return 0; /* keep the connection alive */
+ }
+ }
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+}
+
static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
const uint8_t *mem, size_t len, void *userp)
@@ -1402,7 +1458,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- h2_xfer_write_resp(cf, data_s, stream, (char *)mem, len, FALSE);
+ h2_xfer_write_resp(cf, data_s, stream, (const char *)mem, len, FALSE);
nghttp2_session_consume(ctx->h2, stream_id, len);
stream->nrcvd_data += (curl_off_t)len;
@@ -1493,6 +1549,23 @@ static int on_begin_headers(nghttp2_session *session,
return 0;
}
+static void cf_h2_header_error(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct h2_stream_ctx *stream,
+ CURLcode result)
+{
+ struct cf_h2_ctx *ctx = cf->ctx;
+
+ failf(data, "Error receiving HTTP2 header: %d(%s)", result,
+ curl_easy_strerror(result));
+ if(stream) {
+ nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
+ stream->id, NGHTTP2_STREAM_CLOSED);
+ stream->closed = TRUE;
+ stream->reset = TRUE;
+ }
+}
+
/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
const uint8_t *name, size_t namelen,
@@ -1512,7 +1585,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* get the stream from the hash based on Stream ID */
data_s = nghttp2_session_get_stream_user_data(session, stream_id);
- if(!data_s)
+ if(!GOOD_EASY_HANDLE(data_s))
/* Receiving a Stream ID not in the hash should not happen, this is an
internal error more than anything else! */
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1592,8 +1665,10 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
result = Curl_dynhds_add(&stream->resp_trailers,
(const char *)name, namelen,
(const char *)value, valuelen);
- if(result)
+ if(result) {
+ cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
return 0;
}
@@ -1604,13 +1679,17 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
char buffer[32];
result = Curl_http_decode_status(&stream->status_code,
(const char *)value, valuelen);
- if(result)
+ if(result) {
+ cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%u\r",
stream->status_code);
result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
- if(result)
+ if(result) {
+ cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
Curl_dyn_reset(&ctx->scratch);
result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 "));
if(!result)
@@ -1620,8 +1699,10 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(!result)
h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
Curl_dyn_len(&ctx->scratch), FALSE);
- if(result)
+ if(result) {
+ cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
/* if we receive data for another handle, wake that up */
if(CF_DATA_CURRENT(cf) != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
@@ -1645,8 +1726,10 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(!result)
h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
Curl_dyn_len(&ctx->scratch), FALSE);
- if(result)
+ if(result) {
+ cf_h2_header_error(cf, data_s, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
/* if we receive data for another handle, wake that up */
if(CF_DATA_CURRENT(cf) != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
@@ -1963,6 +2046,11 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
CURLcode result = CURLE_OK;
ssize_t nread;
+ if(should_close_session(ctx)) {
+ CURL_TRC_CF(data, cf, "progress ingress, session is closed");
+ return CURLE_HTTP2;
+ }
+
/* Process network input buffer fist */
if(!Curl_bufq_is_empty(&ctx->inbufq)) {
CURL_TRC_CF(data, cf, "Process %zu bytes in connection buffer",
@@ -2442,7 +2530,7 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_h2_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
@@ -2456,7 +2544,7 @@ static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
/* Connect the lower filters first */
if(!cf->next->connected) {
- result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+ result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
return result;
}
@@ -2537,6 +2625,7 @@ static CURLcode cf_h2_shutdown(struct Curl_cfilter *cf,
CF_DATA_SAVE(save, cf, data);
if(!ctx->sent_goaway) {
+ ctx->sent_goaway = TRUE;
rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
ctx->local_max_sid, 0,
(const uint8_t *)"shutdown",
@@ -2547,7 +2636,6 @@ static CURLcode cf_h2_shutdown(struct Curl_cfilter *cf,
result = CURLE_SEND_ERROR;
goto out;
}
- ctx->sent_goaway = TRUE;
}
/* GOAWAY submitted, process egress and ingress until nghttp2 is done. */
result = CURLE_OK;
@@ -2580,7 +2668,10 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf,
DEBUGASSERT(data);
if(ctx && ctx->h2 && stream) {
- CURLcode result = cf_h2_update_local_win(cf, data, stream, pause);
+ CURLcode result;
+
+ stream->write_paused = pause;
+ result = cf_h2_update_local_win(cf, data, stream);
if(result)
return result;
@@ -2795,8 +2886,9 @@ out:
bool Curl_http2_may_switch(struct Curl_easy *data)
{
- if(Curl_conn_http_version(data) < 20 &&
- data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+ if(Curl_conn_http_version(data, data->conn) < 20 &&
+ (data->state.http_neg.wanted & CURL_HTTP_V2x) &&
+ data->state.http_neg.h2_prior_knowledge) {
#ifndef CURL_DISABLE_PROXY
if(data->conn->bits.httpproxy && !data->conn->bits.tunnel_proxy) {
/* We do not support HTTP/2 proxies yet. Also it is debatable
@@ -2815,7 +2907,7 @@ CURLcode Curl_http2_switch(struct Curl_easy *data)
struct Curl_cfilter *cf;
CURLcode result;
- DEBUGASSERT(Curl_conn_http_version(data) < 20);
+ DEBUGASSERT(Curl_conn_http_version(data, data->conn) < 20);
result = http2_cfilter_add(&cf, data, data->conn, FIRSTSOCKET, FALSE);
if(result)
@@ -2827,7 +2919,7 @@ CURLcode Curl_http2_switch(struct Curl_easy *data)
if(cf->next) {
bool done;
- return Curl_conn_cf_connect(cf, data, FALSE, &done);
+ return Curl_conn_cf_connect(cf, data, &done);
}
return CURLE_OK;
}
@@ -2837,7 +2929,7 @@ CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data)
struct Curl_cfilter *cf_h2;
CURLcode result;
- DEBUGASSERT(Curl_conn_http_version(data) < 20);
+ DEBUGASSERT(Curl_conn_http_version(data, data->conn) < 20);
result = http2_cfilter_insert_after(cf, data, FALSE);
if(result)
@@ -2849,7 +2941,7 @@ CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data)
if(cf_h2->next) {
bool done;
- return Curl_conn_cf_connect(cf_h2, data, FALSE, &done);
+ return Curl_conn_cf_connect(cf_h2, data, &done);
}
return CURLE_OK;
}
@@ -2862,7 +2954,7 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
struct cf_h2_ctx *ctx;
CURLcode result;
- DEBUGASSERT(Curl_conn_http_version(data) < 20);
+ DEBUGASSERT(Curl_conn_http_version(data, conn) < 20);
DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED);
result = http2_cfilter_add(&cf, data, conn, sockindex, TRUE);
@@ -2900,7 +2992,7 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
if(cf->next) {
bool done;
- return Curl_conn_cf_connect(cf, data, FALSE, &done);
+ return Curl_conn_cf_connect(cf, data, &done);
}
return CURLE_OK;
}
@@ -2909,7 +3001,7 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
CURLE_HTTP2_STREAM error! */
bool Curl_h2_http_1_1_error(struct Curl_easy *data)
{
- if(Curl_conn_http_version(data) == 20) {
+ if(Curl_conn_http_version(data, data->conn) == 20) {
int err = Curl_conn_get_stream_error(data, data->conn, FIRSTSOCKET);
return err == NGHTTP2_HTTP_1_1_REQUIRED;
}
diff --git a/libs/libcurl/src/http_aws_sigv4.c b/libs/libcurl/src/http_aws_sigv4.c
index 3c2f67de8b..0c796566f2 100644
--- a/libs/libcurl/src/http_aws_sigv4.c
+++ b/libs/libcurl/src/http_aws_sigv4.c
@@ -46,16 +46,16 @@
#include "slist.h"
-#define HMAC_SHA256(k, kl, d, dl, o) \
- do { \
- result = Curl_hmacit(&Curl_HMAC_SHA256, \
- (unsigned char *)k, \
- kl, \
- (unsigned char *)d, \
- dl, o); \
- if(result) { \
- goto fail; \
- } \
+#define HMAC_SHA256(k, kl, d, dl, o) \
+ do { \
+ result = Curl_hmacit(&Curl_HMAC_SHA256, \
+ (const unsigned char *)k, \
+ kl, \
+ (const unsigned char *)d, \
+ dl, o); \
+ if(result) { \
+ goto fail; \
+ } \
} while(0)
#define TIMESTAMP_SIZE 17
@@ -83,7 +83,7 @@ static void trim_headers(struct curl_slist *head)
{
struct curl_slist *l;
for(l = head; l; l = l->next) {
- char *value; /* to read from */
+ const char *value; /* to read from */
char *store;
size_t colon = strcspn(l->data, ":");
Curl_strntolower(l->data, l->data, colon);
@@ -92,15 +92,14 @@ static void trim_headers(struct curl_slist *head)
if(!*value)
continue;
++value;
- store = value;
+ store = (char *)CURL_UNCONST(value);
/* skip leading whitespace */
- while(*value && ISBLANK(*value))
- value++;
+ Curl_str_passblanks(&value);
while(*value) {
int space = 0;
- while(*value && ISBLANK(*value)) {
+ while(ISBLANK(*value)) {
value++;
space++;
}
@@ -155,6 +154,57 @@ static int compare_header_names(const char *a, const char *b)
return cmp;
}
+/* Merge duplicate header definitions by comma delimiting their values
+ in the order defined the headers are defined, expecting headers to
+ be alpha-sorted and use ':' at this point */
+static CURLcode merge_duplicate_headers(struct curl_slist *head)
+{
+ struct curl_slist *curr = head;
+ CURLcode result = CURLE_OK;
+
+ while(curr) {
+ struct curl_slist *next = curr->next;
+ if(!next)
+ break;
+
+ if(compare_header_names(curr->data, next->data) == 0) {
+ struct dynbuf buf;
+ char *colon_next;
+ char *val_next;
+
+ Curl_dyn_init(&buf, CURL_MAX_HTTP_HEADER);
+
+ result = Curl_dyn_add(&buf, curr->data);
+ if(result)
+ return result;
+
+ colon_next = strchr(next->data, ':');
+ DEBUGASSERT(colon_next);
+ val_next = colon_next + 1;
+
+ result = Curl_dyn_addn(&buf, ",", 1);
+ if(result)
+ return result;
+
+ result = Curl_dyn_add(&buf, val_next);
+ if(result)
+ return result;
+
+ free(curr->data);
+ curr->data = Curl_dyn_ptr(&buf);
+
+ curr->next = next->next;
+ free(next->data);
+ free(next);
+ }
+ else {
+ curr = curr->next;
+ }
+ }
+
+ return CURLE_OK;
+}
+
/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */
static CURLcode make_headers(struct Curl_easy *data,
const char *hostname,
@@ -234,7 +284,7 @@ static CURLcode make_headers(struct Curl_easy *data,
sep = strchr(l->data, ';');
if(!sep || (*sep == ':' && !*(sep + 1)))
continue;
- for(ptr = sep + 1; ISSPACE(*ptr); ++ptr)
+ for(ptr = sep + 1; ISBLANK(*ptr); ++ptr)
;
if(!*ptr && ptr != sep + 1) /* a value of whitespace only */
continue;
@@ -261,16 +311,15 @@ static CURLcode make_headers(struct Curl_easy *data,
*date_header = aprintf("%s: %s\r\n", date_hdr_key, timestamp);
}
else {
- char *value;
- char *endp;
+ const char *value;
+ const char *endp;
value = strchr(*date_header, ':');
if(!value) {
*date_header = NULL;
goto fail;
}
++value;
- while(ISBLANK(*value))
- ++value;
+ Curl_str_passblanks(&value);
endp = value;
while(*endp && ISALNUM(*endp))
++endp;
@@ -301,6 +350,10 @@ static CURLcode make_headers(struct Curl_easy *data,
}
} while(again);
+ ret = merge_duplicate_headers(head);
+ if(ret)
+ goto fail;
+
for(l = head; l; l = l->next) {
char *tmp;
@@ -334,14 +387,14 @@ fail:
SHA256_HEX_LENGTH)
/* try to parse a payload hash from the content-sha256 header */
-static char *parse_content_sha_hdr(struct Curl_easy *data,
- const char *provider1,
- size_t plen,
- size_t *value_len)
+static const char *parse_content_sha_hdr(struct Curl_easy *data,
+ const char *provider1,
+ size_t plen,
+ size_t *value_len)
{
char key[CONTENT_SHA256_KEY_LEN];
size_t key_len;
- char *value;
+ const char *value;
size_t len;
key_len = msnprintf(key, sizeof(key), "x-%.*s-content-sha256",
@@ -356,8 +409,7 @@ static char *parse_content_sha_hdr(struct Curl_easy *data,
return NULL;
++value;
- while(*value && ISBLANK(*value))
- ++value;
+ Curl_str_passblanks(&value);
len = strlen(value);
while(len > 0 && ISBLANK(value[len-1]))
@@ -390,7 +442,8 @@ static CURLcode calc_payload_hash(struct Curl_easy *data,
#define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD"
static CURLcode calc_s3_payload_hash(struct Curl_easy *data,
- Curl_HttpReq httpreq, char *provider1,
+ Curl_HttpReq httpreq,
+ const char *provider1,
size_t plen,
unsigned char *sha_hash,
char *sha_hex, char *header)
@@ -571,12 +624,11 @@ static CURLcode canon_query(struct Curl_easy *data,
}
-CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
{
CURLcode result = CURLE_OUT_OF_MEMORY;
struct connectdata *conn = data->conn;
- size_t len;
- char *line;
+ const char *line;
struct Curl_str provider0;
struct Curl_str provider1;
struct Curl_str region = { NULL, 0};
@@ -593,7 +645,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
char *date_header = NULL;
Curl_HttpReq httpreq;
const char *method = NULL;
- char *payload_hash = NULL;
+ const char *payload_hash = NULL;
size_t payload_hash_len = 0;
unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
char sha_hex[SHA256_HEX_LENGTH];
@@ -608,9 +660,6 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = {0};
char *auth_headers = NULL;
- DEBUGASSERT(!proxy);
- (void)proxy;
-
if(Curl_checkheaders(data, STRCONST("Authorization"))) {
/* Authorization already present, Bailing out */
return CURLE_OK;
@@ -630,7 +679,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
* are still using aws:amz as a prefix.
*/
line = data->set.str[STRING_AWS_SIGV4] ?
- data->set.str[STRING_AWS_SIGV4] : (char *)"aws:amz";
+ data->set.str[STRING_AWS_SIGV4] : "aws:amz";
/* provider0[:provider1[:region[:service]]]
@@ -643,8 +692,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
}
if(Curl_str_single(&line, ':') ||
Curl_str_until(&line, &provider1, MAX_SIGV4_LEN, ':')) {
- provider1.str = provider0.str;
- provider1.len = provider0.len;
+ provider1 = provider0;
}
else if(Curl_str_single(&line, ':') ||
Curl_str_until(&line, &region, MAX_SIGV4_LEN, ':') ||
@@ -653,62 +701,46 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
/* nothing to do */
}
- if(!service.len) {
- char *hostdot = strchr(hostname, '.');
- if(!hostdot) {
+ if(!Curl_strlen(&service)) {
+ const char *p = hostname;
+ if(Curl_str_until(&p, &service, MAX_SIGV4_LEN, '.') ||
+ Curl_str_single(&p, '.')) {
failf(data, "aws-sigv4: service missing in parameters and hostname");
result = CURLE_URL_MALFORMAT;
goto fail;
}
- len = hostdot - hostname;
- if(len > MAX_SIGV4_LEN) {
- failf(data, "aws-sigv4: service too long in hostname");
- result = CURLE_URL_MALFORMAT;
- goto fail;
- }
- service.str = (char *)hostname;
- service.len = len;
infof(data, "aws_sigv4: picked service %.*s from host",
- (int)service.len, service.str);
+ (int)Curl_strlen(&service), Curl_str(&service));
- if(!region.len) {
- const char *reg = hostdot + 1;
- const char *hostreg = strchr(reg, '.');
- if(!hostreg) {
+ if(!Curl_strlen(&region)) {
+ if(Curl_str_until(&p, &region, MAX_SIGV4_LEN, '.') ||
+ Curl_str_single(&p, '.')) {
failf(data, "aws-sigv4: region missing in parameters and hostname");
result = CURLE_URL_MALFORMAT;
goto fail;
}
- len = hostreg - reg;
- if(len > MAX_SIGV4_LEN) {
- failf(data, "aws-sigv4: region too long in hostname");
- result = CURLE_URL_MALFORMAT;
- goto fail;
- }
- region.str = (char *)reg;
- region.len = len;
infof(data, "aws_sigv4: picked region %.*s from host",
- (int)region.len, region.str);
+ (int)Curl_strlen(&region), Curl_str(&region));
}
}
Curl_http_method(data, conn, &method, &httpreq);
- payload_hash = parse_content_sha_hdr(data, provider1.str, provider1.len,
- &payload_hash_len);
+ payload_hash =
+ parse_content_sha_hdr(data, Curl_str(&provider1), Curl_strlen(&provider1),
+ &payload_hash_len);
if(!payload_hash) {
/* AWS S3 requires a x-amz-content-sha256 header, and supports special
* values like UNSIGNED-PAYLOAD */
- bool sign_as_s3 = ((provider0.len == 3) &&
- strncasecompare(provider0.str, "aws", 3)) &&
- ((service.len == 2) && strncasecompare(service.str, "s3", 2));
+ bool sign_as_s3 = Curl_str_casecompare(&provider0, "aws") &&
+ Curl_str_casecompare(&service, "s3");
if(sign_as_s3)
- result = calc_s3_payload_hash(data, httpreq,
- provider1.str, provider1.len,
- sha_hash, sha_hex, content_sha256_hdr);
+ result = calc_s3_payload_hash(data, httpreq, Curl_str(&provider1),
+ Curl_strlen(&provider1), sha_hash, sha_hex,
+ content_sha256_hdr);
else
result = calc_payload_hash(data, sha_hash, sha_hex);
if(result)
@@ -740,7 +772,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
}
result = make_headers(data, hostname, timestamp,
- provider1.str, provider1.len,
+ Curl_str(&provider1), Curl_strlen(&provider1),
&date_header, content_sha256_hdr,
&canonical_headers, &signed_headers);
if(result)
@@ -785,17 +817,18 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
DEBUGF(infof(data, "Canonical request: %s", canonical_request));
- request_type = aprintf("%.*s4_request", (int)provider0.len, provider0.str);
+ request_type = aprintf("%.*s4_request",
+ (int)Curl_strlen(&provider0), Curl_str(&provider0));
if(!request_type)
goto fail;
/* provider0 is lowercased *after* aprintf() so that the buffer can be
written to */
- Curl_strntolower(request_type, request_type, provider0.len);
+ Curl_strntolower(request_type, request_type, Curl_strlen(&provider0));
- credential_scope = aprintf("%s/%.*s/%.*s/%s",
- date, (int)region.len, region.str,
- (int)service.len, service.str,
+ credential_scope = aprintf("%s/%.*s/%.*s/%s", date,
+ (int)Curl_strlen(&region), Curl_str(&region),
+ (int)Curl_strlen(&service), Curl_str(&service),
request_type);
if(!credential_scope)
goto fail;
@@ -814,7 +847,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
"%s\n" /* RequestDateTime */
"%s\n" /* CredentialScope */
"%s", /* HashedCanonicalRequest in hex */
- (int)provider0.len, provider0.str,
+ (int)Curl_strlen(&provider0), Curl_str(&provider0),
timestamp,
credential_scope,
sha_hex);
@@ -822,19 +855,21 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
goto fail;
/* make provider0 part done uppercase */
- Curl_strntoupper(str_to_sign, provider0.str, provider0.len);
+ Curl_strntoupper(str_to_sign, Curl_str(&provider0), Curl_strlen(&provider0));
- secret = aprintf("%.*s4%s", (int)provider0.len, provider0.str,
- data->state.aptr.passwd ?
+ secret = aprintf("%.*s4%s", (int)Curl_strlen(&provider0),
+ Curl_str(&provider0), data->state.aptr.passwd ?
data->state.aptr.passwd : "");
if(!secret)
goto fail;
/* make provider0 part done uppercase */
- Curl_strntoupper(secret, provider0.str, provider0.len);
+ Curl_strntoupper(secret, Curl_str(&provider0), Curl_strlen(&provider0));
HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0);
- HMAC_SHA256(sign0, sizeof(sign0), region.str, region.len, sign1);
- HMAC_SHA256(sign1, sizeof(sign1), service.str, service.len, sign0);
+ HMAC_SHA256(sign0, sizeof(sign0),
+ Curl_str(&region), Curl_strlen(&region), sign1);
+ HMAC_SHA256(sign1, sizeof(sign1),
+ Curl_str(&service), Curl_strlen(&service), sign0);
HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
@@ -851,7 +886,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
*/
"%s"
"%s", /* optional sha256 header includes \r\n */
- (int)provider0.len, provider0.str,
+ (int)Curl_strlen(&provider0), Curl_str(&provider0),
user,
credential_scope,
Curl_dyn_ptr(&signed_headers),
@@ -863,9 +898,9 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
}
/* provider 0 uppercase */
Curl_strntoupper(&auth_headers[sizeof("Authorization: ") - 1],
- provider0.str, provider0.len);
+ Curl_str(&provider0), Curl_strlen(&provider0));
- Curl_safefree(data->state.aptr.userpwd);
+ free(data->state.aptr.userpwd);
data->state.aptr.userpwd = auth_headers;
data->state.authhost.done = TRUE;
result = CURLE_OK;
diff --git a/libs/libcurl/src/http_aws_sigv4.h b/libs/libcurl/src/http_aws_sigv4.h
index 2c2def4246..7d55ba5251 100644
--- a/libs/libcurl/src/http_aws_sigv4.h
+++ b/libs/libcurl/src/http_aws_sigv4.h
@@ -26,6 +26,6 @@
#include "curl_setup.h"
/* this is for creating aws_sigv4 header output */
-CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy);
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data);
#endif /* HEADER_CURL_HTTP_AWS_SIGV4_H */
diff --git a/libs/libcurl/src/http_chunks.c b/libs/libcurl/src/http_chunks.c
index 2d2b3440e2..e1a77e557c 100644
--- a/libs/libcurl/src/http_chunks.c
+++ b/libs/libcurl/src/http_chunks.c
@@ -34,7 +34,7 @@
#include "content_encoding.h"
#include "http.h"
#include "multiif.h"
-#include "strtoofft.h"
+#include "strparse.h"
#include "warnless.h"
/* The last #include files should be: */
@@ -134,7 +134,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
if(cw_next)
result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY, buf, blen);
else
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, blen);
if(result) {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_PASSTHRU_ERROR;
@@ -158,6 +158,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
(*pconsumed)++;
}
else {
+ const char *p;
if(0 == ch->hexindex) {
/* This is illegal data, we received junk where we expected
a hexadecimal digit. */
@@ -166,11 +167,11 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
ch->last_code = CHUNKE_ILLEGAL_HEX;
return CURLE_RECV_ERROR;
}
-
/* blen and buf are unmodified */
ch->hexbuffer[ch->hexindex] = 0;
- if(curlx_strtoofft(ch->hexbuffer, NULL, 16, &ch->datasize)) {
- failf(data, "chunk hex-length not valid: '%s'", ch->hexbuffer);
+ p = &ch->hexbuffer[0];
+ if(Curl_str_hex(&p, &ch->datasize, CURL_OFF_T_MAX)) {
+ failf(data, "invalid chunk size: '%s'", ch->hexbuffer);
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_ILLEGAL_HEX;
return CURLE_RECV_ERROR;
@@ -212,8 +213,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY,
buf, piece);
else
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- (char *)buf, piece);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, piece);
if(result) {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_PASSTHRU_ERROR;
@@ -257,7 +257,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
if(tr) {
size_t trlen;
- result = Curl_dyn_addn(&ch->trailer, (char *)STRCONST("\x0d\x0a"));
+ result = Curl_dyn_addn(&ch->trailer, STRCONST("\x0d\x0a"));
if(result) {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_OUT_OF_MEMORY;
diff --git a/libs/libcurl/src/http_digest.c b/libs/libcurl/src/http_digest.c
index f63006f03b..1b4c6109a4 100644
--- a/libs/libcurl/src/http_digest.c
+++ b/libs/libcurl/src/http_digest.c
@@ -30,6 +30,7 @@
#include "strcase.h"
#include "vauth/vauth.h"
#include "http_digest.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -62,8 +63,7 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
return CURLE_BAD_CONTENT_ENCODING;
header += strlen("Digest");
- while(*header && ISBLANK(*header))
- header++;
+ Curl_str_passblanks(&header);
return Curl_auth_decode_digest_http_message(header, digest);
}
@@ -145,15 +145,15 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
*/
if(authp->iestyle) {
- tmp = strchr((char *)uripath, '?');
+ tmp = strchr((const char *)uripath, '?');
if(tmp) {
- size_t urilen = tmp - (char *)uripath;
+ size_t urilen = tmp - (const char *)uripath;
/* typecast is fine here since the value is always less than 32 bits */
path = (unsigned char *) aprintf("%.*s", (int)urilen, uripath);
}
}
if(!tmp)
- path = (unsigned char *) strdup((char *) uripath);
+ path = (unsigned char *) strdup((const char *) uripath);
if(!path)
return CURLE_OUT_OF_MEMORY;
diff --git a/libs/libcurl/src/http_negotiate.c b/libs/libcurl/src/http_negotiate.c
index a7a98533b3..4ee77718c4 100644
--- a/libs/libcurl/src/http_negotiate.c
+++ b/libs/libcurl/src/http_negotiate.c
@@ -32,6 +32,7 @@
#include "http_negotiate.h"
#include "vauth/vauth.h"
#include "vtls/vtls.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -86,8 +87,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
/* Obtain the input token, if any */
header += strlen("Negotiate");
- while(*header && ISBLANK(*header))
- header++;
+ Curl_str_passblanks(&header);
len = strlen(header);
neg_ctx->havenegdata = len != 0;
@@ -109,9 +109,10 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
neg_ctx->sslContext = conn->sslContext;
#endif
/* Check if the connection is using SSL and get the channel binding data */
-#if defined(USE_SSL) && defined(HAVE_GSSAPI)
+#ifdef HAVE_GSSAPI
+ Curl_dyn_init(&neg_ctx->channel_binding_data, SSL_CB_MAX_SIZE + 1);
+#ifdef USE_SSL
if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
- Curl_dyn_init(&neg_ctx->channel_binding_data, SSL_CB_MAX_SIZE + 1);
result = Curl_ssl_get_channel_binding(
data, FIRSTSOCKET, &neg_ctx->channel_binding_data);
if(result) {
@@ -119,13 +120,14 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
return result;
}
}
-#endif
+#endif /* USE_SSL */
+#endif /* HAVE_GSSAPI */
/* Initialize the security context and decode our challenge */
result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
host, header, neg_ctx);
-#if defined(USE_SSL) && defined(HAVE_GSSAPI)
+#ifdef HAVE_GSSAPI
Curl_dyn_free(&neg_ctx->channel_binding_data);
#endif
@@ -203,12 +205,12 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
if(proxy) {
#ifndef CURL_DISABLE_PROXY
- Curl_safefree(data->state.aptr.proxyuserpwd);
+ free(data->state.aptr.proxyuserpwd);
data->state.aptr.proxyuserpwd = userp;
#endif
}
else {
- Curl_safefree(data->state.aptr.userpwd);
+ free(data->state.aptr.userpwd);
data->state.aptr.userpwd = userp;
}
diff --git a/libs/libcurl/src/http_ntlm.c b/libs/libcurl/src/http_ntlm.c
index 0dee7594c2..cbde614da2 100644
--- a/libs/libcurl/src/http_ntlm.c
+++ b/libs/libcurl/src/http_ntlm.c
@@ -33,8 +33,6 @@
* https://www.innovation.ch/java/ntlm.html
*/
-#define DEBUG_ME 0
-
#include "urldata.h"
#include "sendf.h"
#include "strcase.h"
@@ -43,6 +41,7 @@
#include "curl_base64.h"
#include "vauth/vauth.h"
#include "url.h"
+#include "strparse.h"
/* SSL backend-specific #if branches in this file must be kept in the order
documented in curl_ntlm_core. */
@@ -55,12 +54,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-#if DEBUG_ME
-# define DEBUG_OUT(x) x
-#else
-# define DEBUG_OUT(x) Curl_nop_stmt
-#endif
-
CURLcode Curl_input_ntlm(struct Curl_easy *data,
bool proxy, /* if proxy or not */
const char *header) /* rest of the www-authenticate:
@@ -78,9 +71,7 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
if(checkprefix("NTLM", header)) {
header += strlen("NTLM");
- while(*header && ISSPACE(*header))
- header++;
-
+ Curl_str_passblanks(&header);
if(*header) {
unsigned char *hdr;
size_t hdrlen;
diff --git a/libs/libcurl/src/http_proxy.c b/libs/libcurl/src/http_proxy.c
index 892ac56449..58a157b391 100644
--- a/libs/libcurl/src/http_proxy.c
+++ b/libs/libcurl/src/http_proxy.c
@@ -43,6 +43,7 @@
#include "transfer.h"
#include "multiif.h"
#include "vauth/vauth.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -60,7 +61,7 @@ static CURLcode dynhds_add_custom(struct Curl_easy *data,
struct dynhds *hds)
{
struct connectdata *conn = data->conn;
- char *ptr;
+ const char *ptr;
struct curl_slist *h[2];
struct curl_slist *headers;
int numlists = 1; /* by default */
@@ -108,8 +109,7 @@ static CURLcode dynhds_add_custom(struct Curl_easy *data,
name = headers->data;
namelen = ptr - headers->data;
ptr++; /* pass the colon */
- while(*ptr && ISSPACE(*ptr))
- ptr++;
+ Curl_str_passblanks(&ptr);
if(*ptr) {
value = ptr;
valuelen = strlen(value);
@@ -131,8 +131,7 @@ static CURLcode dynhds_add_custom(struct Curl_easy *data,
name = headers->data;
namelen = ptr - headers->data;
ptr++; /* pass the semicolon */
- while(*ptr && ISSPACE(*ptr))
- ptr++;
+ Curl_str_passblanks(&ptr);
if(!*ptr) {
/* quirk #2, send an empty header */
value = "";
@@ -307,7 +306,7 @@ out:
static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_proxy_ctx *ctx = cf->ctx;
CURLcode result;
@@ -319,7 +318,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "connect");
connect_sub:
- result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+ result = cf->next->cft->do_connect(cf->next, data, done);
if(result || !*done)
return result;
diff --git a/libs/libcurl/src/httpsrr.c b/libs/libcurl/src/httpsrr.c
index 7c50536cc5..a948361ba4 100644
--- a/libs/libcurl/src/httpsrr.c
+++ b/libs/libcurl/src/httpsrr.c
@@ -31,6 +31,7 @@
#include "httpsrr.h"
#include "connect.h"
#include "sendf.h"
+#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -91,44 +92,92 @@ err:
return CURLE_BAD_CONTENT_ENCODING;
}
-#ifdef USE_ARES
-
-static void httpsrr_opt(struct Curl_easy *data,
- const ares_dns_rr_t *rr,
- ares_dns_rr_key_t key, size_t idx)
+CURLcode Curl_httpsrr_set(struct Curl_easy *data,
+ struct Curl_https_rrinfo *hi,
+ uint16_t rrkey, const uint8_t *val, size_t vlen)
{
- size_t len = 0;
- const unsigned char *val = NULL;
- unsigned short code;
- struct thread_data *res = data->state.async.tdata;
- struct Curl_https_rrinfo *hi = &res->hinfo;
- code = ares_dns_rr_get_opt(rr, key, idx, &val, &len);
-
- switch(code) {
+ switch(rrkey) {
case HTTPS_RR_CODE_ALPN: /* str_list */
- Curl_httpsrr_decode_alpn(val, len, hi->alpns);
- infof(data, "HTTPS RR ALPN: %u %u %u %u",
- hi->alpns[0], hi->alpns[1], hi->alpns[2], hi->alpns[3]);
+ Curl_httpsrr_decode_alpn(val, vlen, hi->alpns);
+ CURL_TRC_DNS(data, "HTTPS RR ALPN: %u %u %u %u",
+ hi->alpns[0], hi->alpns[1], hi->alpns[2], hi->alpns[3]);
break;
case HTTPS_RR_CODE_NO_DEF_ALPN:
- infof(data, "HTTPS RR no-def-alpn");
+ hi->no_def_alpn = TRUE;
+ CURL_TRC_DNS(data, "HTTPS RR no-def-alpn");
break;
case HTTPS_RR_CODE_IPV4: /* addr4 list */
- infof(data, "HTTPS RR IPv4");
+ if(!vlen)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ hi->ipv4hints = Curl_memdup(val, vlen);
+ if(!hi->ipv4hints)
+ return CURLE_OUT_OF_MEMORY;
+ hi->ipv4hints_len = vlen;
+ CURL_TRC_DNS(data, "HTTPS RR IPv4");
break;
case HTTPS_RR_CODE_ECH:
- infof(data, "HTTPS RR ECH");
+ if(!vlen)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ hi->echconfiglist = Curl_memdup(val, vlen);
+ if(!hi->echconfiglist)
+ return CURLE_OUT_OF_MEMORY;
+ hi->echconfiglist_len = vlen;
+ CURL_TRC_DNS(data, "HTTPS RR ECH");
break;
case HTTPS_RR_CODE_IPV6: /* addr6 list */
- infof(data, "HTTPS RR IPv6");
+ if(!vlen)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ hi->ipv6hints = Curl_memdup(val, vlen);
+ if(!hi->ipv6hints)
+ return CURLE_OUT_OF_MEMORY;
+ hi->ipv6hints_len = vlen;
+ CURL_TRC_DNS(data, "HTTPS RR IPv6");
break;
case HTTPS_RR_CODE_PORT:
- infof(data, "HTTPS RR port");
+ if(vlen != 2)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ hi->port = (unsigned short)((val[0] << 8) | val[1]);
+ CURL_TRC_DNS(data, "HTTPS RR port %u", hi->port);
break;
default:
- infof(data, "HTTPS RR unknown code");
+ CURL_TRC_DNS(data, "HTTPS RR unknown code");
break;
}
+ return CURLE_OK;
+}
+
+struct Curl_https_rrinfo *
+Curl_httpsrr_dup_move(struct Curl_https_rrinfo *rrinfo)
+{
+ struct Curl_https_rrinfo *dup = Curl_memdup(rrinfo, sizeof(*rrinfo));
+ if(dup)
+ memset(rrinfo, 0, sizeof(*rrinfo));
+ return dup;
+}
+
+void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo)
+{
+ Curl_safefree(rrinfo->target);
+ Curl_safefree(rrinfo->echconfiglist);
+ Curl_safefree(rrinfo->ipv4hints);
+ Curl_safefree(rrinfo->ipv6hints);
+}
+
+
+#ifdef USE_ARES
+
+static CURLcode httpsrr_opt(struct Curl_easy *data,
+ const ares_dns_rr_t *rr,
+ ares_dns_rr_key_t key, size_t idx)
+{
+ size_t len = 0;
+ const unsigned char *val = NULL;
+ unsigned short code;
+ struct thread_data *res = &data->state.async.thdata;
+ struct Curl_https_rrinfo *hi = &res->hinfo;
+
+ code = ares_dns_rr_get_opt(rr, key, idx, &val, &len);
+ return Curl_httpsrr_set(data, hi, code, val, len);
}
void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
@@ -136,17 +185,17 @@ void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
const ares_dns_record_t *dnsrec)
{
struct Curl_easy *data = arg;
+ CURLcode result = CURLE_OK;
size_t i;
-#ifdef CURLRES_ARES
- struct thread_data *res = data->state.async.tdata;
+ struct thread_data *res = &data->state.async.thdata;
res->num_pending--;
-#endif
(void)timeouts;
if((ARES_SUCCESS != status) || !dnsrec)
return;
for(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) {
+ const char *target;
size_t opt;
const ares_dns_rr_t *rr =
ares_dns_record_rr_get_const(dnsrec, ARES_SECTION_ANSWER, i);
@@ -154,12 +203,26 @@ void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
continue;
/* When SvcPriority is 0, the SVCB record is in AliasMode. Otherwise, it
is in ServiceMode */
- infof(data, "HTTPS RR priority: %u",
- ares_dns_rr_get_u16(rr, ARES_RR_HTTPS_PRIORITY));
+ target = ares_dns_rr_get_str(rr, ARES_RR_HTTPS_TARGET);
+ if(target && target[0]) {
+ res->hinfo.target = strdup(target);
+ if(!res->hinfo.target) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ CURL_TRC_DNS(data, "HTTPS RR target: %s", res->hinfo.target);
+ }
+ CURL_TRC_DNS(data, "HTTPS RR priority: %u",
+ ares_dns_rr_get_u16(rr, ARES_RR_HTTPS_PRIORITY));
for(opt = 0; opt < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS);
- opt++)
- httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt);
+ opt++) {
+ result = httpsrr_opt(data, rr, ARES_RR_HTTPS_PARAMS, opt);
+ if(result)
+ break;
+ }
}
+out:
+ res->result = result;
}
#endif /* USE_ARES */
diff --git a/libs/libcurl/src/httpsrr.h b/libs/libcurl/src/httpsrr.h
index a734c9ed6d..ca5a5b3936 100644
--- a/libs/libcurl/src/httpsrr.h
+++ b/libs/libcurl/src/httpsrr.h
@@ -35,6 +35,8 @@
#define CURL_MAXLEN_host_name 253
#define MAX_HTTPSRR_ALPNS 4
+struct Curl_easy;
+
struct Curl_https_rrinfo {
/*
* Fields from HTTPS RR. The only mandatory fields are priority and target.
@@ -53,7 +55,15 @@ struct Curl_https_rrinfo {
uint16_t priority;
bool no_def_alpn; /* keytag = 2 */
};
-#endif
+
+CURLcode Curl_httpsrr_set(struct Curl_easy *data,
+ struct Curl_https_rrinfo *hi,
+ uint16_t rrkey, const uint8_t *val, size_t vlen);
+
+struct Curl_https_rrinfo *
+Curl_httpsrr_dup_move(struct Curl_https_rrinfo *rrinfo);
+
+void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo);
/*
* Code points for DNS wire format SvcParams as per RFC 9460
@@ -68,9 +78,12 @@ struct Curl_https_rrinfo {
CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len,
unsigned char *alpns);
-#if defined(USE_ARES) && defined(USE_HTTPSRR)
+#if defined(USE_ARES)
void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
size_t timeouts,
const ares_dns_record_t *dnsrec);
-#endif
+
+#endif /* USE_ARES */
+#endif /* USE_HTTPSRR */
+
#endif /* HEADER_CURL_HTTPSRR_H */
diff --git a/libs/libcurl/src/idn.c b/libs/libcurl/src/idn.c
index f767906e1d..085417d051 100644
--- a/libs/libcurl/src/idn.c
+++ b/libs/libcurl/src/idn.c
@@ -64,13 +64,14 @@ static CURLcode iconv_to_utf8(const char *in, size_t inlen,
iconv_t cd = iconv_open("UTF-8", nl_langinfo(CODESET));
if(cd != (iconv_t)-1) {
size_t iconv_outlen = *outlen;
- char *iconv_in = (char *)in;
+ char *iconv_in = (char *)CURL_UNCONST(in);
size_t iconv_inlen = inlen;
size_t iconv_result = iconv(cd, &iconv_in, &iconv_inlen,
out, &iconv_outlen);
*outlen -= iconv_outlen;
iconv_close(cd);
if(iconv_result == (size_t)-1) {
+ /* !checksrc! disable ERRNOVAR 1 */
if(errno == ENOMEM)
return CURLE_OUT_OF_MEMORY;
else
@@ -80,6 +81,7 @@ static CURLcode iconv_to_utf8(const char *in, size_t inlen,
return CURLE_OK;
}
else {
+ /* !checksrc! disable ERRNOVAR 1 */
if(errno == ENOMEM)
return CURLE_OUT_OF_MEMORY;
else
diff --git a/libs/libcurl/src/if2ip.c b/libs/libcurl/src/if2ip.c
index a3f07befce..4c1b5453c1 100644
--- a/libs/libcurl/src/if2ip.c
+++ b/libs/libcurl/src/if2ip.c
@@ -67,7 +67,8 @@
unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
{
if(sa->sa_family == AF_INET6) {
- const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa;
+ const struct sockaddr_in6 * sa6 =
+ (const struct sockaddr_in6 *)(const void *) sa;
const unsigned char *b = sa6->sin6_addr.s6_addr;
unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
@@ -161,7 +162,7 @@ if2ip_result_t Curl_if2ip(int af,
addr =
&((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
res = IF2IP_FOUND;
- ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
+ ip = curlx_inet_ntop(af, addr, ipstr, sizeof(ipstr));
msnprintf(buf, buf_size, "%s%s", ip, scope);
break;
}
@@ -234,7 +235,7 @@ if2ip_result_t Curl_if2ip(int af,
s = (struct sockaddr_in *)(void *)&req.ifr_addr;
memcpy(&in, &s->sin_addr, sizeof(in));
- r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
+ r = curlx_inet_ntop(s->sin_family, &in, buf, buf_size);
sclose(dummy);
if(!r)
diff --git a/libs/libcurl/src/imap.c b/libs/libcurl/src/imap.c
index 2ba0a10f25..f28c1a7e75 100644
--- a/libs/libcurl/src/imap.c
+++ b/libs/libcurl/src/imap.c
@@ -36,6 +36,7 @@
***************************************************************************/
#include "curl_setup.h"
+#include "dynbuf.h"
#ifndef CURL_DISABLE_IMAP
@@ -64,7 +65,7 @@
#include "socks.h"
#include "imap.h"
#include "mime.h"
-#include "strtoofft.h"
+#include "strparse.h"
#include "strcase.h"
#include "vtls/vtls.h"
#include "cfilters.h"
@@ -192,6 +193,10 @@ static const struct SASLproto saslimap = {
SASL_FLAG_BASE64 /* Configuration flags */
};
+struct ulbits {
+ int bit;
+ const char *flag;
+};
/***********************************************************************
*
@@ -242,7 +247,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd)
* response which can be processed by the response handler.
*/
static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
- char *line, size_t len, int *resp)
+ const char *line, size_t len, int *resp)
{
struct IMAP *imap = data->req.p.imap;
struct imap_conn *imapc = &conn->proto.imapc;
@@ -473,7 +478,6 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
goto out;
/* Change the connection handler */
conn->handler = &Curl_handler_imaps;
- conn->bits.tls_upgraded = TRUE;
}
DEBUGASSERT(!imapc->ssldone);
@@ -761,6 +765,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
CURLcode result = CURLE_OK;
struct IMAP *imap = data->req.p.imap;
char *mailbox;
+ struct dynbuf flags;
/* Check we have a mailbox */
if(!imap->mailbox) {
@@ -809,10 +814,43 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
if(!mailbox)
return CURLE_OUT_OF_MEMORY;
- /* Send the APPEND command */
- result = imap_sendf(data, "APPEND %s (\\Seen) {%" FMT_OFF_T "}",
- mailbox, data->state.infilesize);
+ /* Generate flags string and send the APPEND command */
+ Curl_dyn_init(&flags, 100);
+ if(data->set.upload_flags) {
+ int i;
+ struct ulbits ulflag[] = {
+ {CURLULFLAG_ANSWERED, "Answered"},
+ {CURLULFLAG_DELETED, "Deleted"},
+ {CURLULFLAG_DRAFT, "Draft"},
+ {CURLULFLAG_FLAGGED, "Flagged"},
+ {CURLULFLAG_SEEN, "Seen"},
+ {0, NULL}
+ };
+
+ result = CURLE_OUT_OF_MEMORY;
+ if(Curl_dyn_add(&flags, " (")) {
+ goto cleanup;
+ }
+
+ for(i = 0; ulflag[i].bit; i++) {
+ if(data->set.upload_flags & ulflag[i].bit) {
+ if((Curl_dyn_len(&flags) > 2 && Curl_dyn_add(&flags, " ")) ||
+ Curl_dyn_add(&flags, "\\") || Curl_dyn_add(&flags, ulflag[i].flag))
+ goto cleanup;
+ }
+ }
+
+ if(Curl_dyn_add(&flags, ")"))
+ goto cleanup;
+ }
+ else if(Curl_dyn_add(&flags, ""))
+ goto cleanup;
+
+ result = imap_sendf(data, "APPEND %s%s {%" FMT_OFF_T "}",
+ mailbox, Curl_dyn_ptr(&flags), data->state.infilesize);
+cleanup:
+ Curl_dyn_free(&flags);
free(mailbox);
if(!result)
@@ -1096,7 +1134,7 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
Curl_dyn_init(&uid, 20);
if(Curl_dyn_addn(&uid, p, len))
return CURLE_OUT_OF_MEMORY;
- Curl_safefree(imapc->mailbox_uidvalidity);
+ free(imapc->mailbox_uidvalidity);
imapc->mailbox_uidvalidity = Curl_dyn_ptr(&uid);
}
}
@@ -1156,9 +1194,9 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
the continuation data contained within the curly brackets */
ptr = memchr(ptr, '{', len);
if(ptr) {
- char *endptr;
- if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) &&
- (endptr - ptr > 1 && *endptr == '}'))
+ ptr++;
+ if(!Curl_str_number(&ptr, &size, CURL_OFF_T_MAX) &&
+ !Curl_str_single(&ptr, '}'))
parsed = TRUE;
}
@@ -1457,14 +1495,17 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done)
/* We always support persistent connections in IMAP */
connkeep(conn, "IMAP default");
- PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp);
+ if(!imapc->initialised) {
+ PINGPONG_SETUP(pp, imap_statemachine, imap_endofresp);
- /* Set the default preferred authentication type and mechanism */
- imapc->preftype = IMAP_TYPE_ANY;
- Curl_sasl_init(&imapc->sasl, data, &saslimap);
+ /* Set the default preferred authentication type and mechanism */
+ imapc->preftype = IMAP_TYPE_ANY;
+ Curl_sasl_init(&imapc->sasl, data, &saslimap);
- Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
- Curl_pp_init(pp);
+ Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
+ Curl_pp_init(pp);
+ imapc->initialised = TRUE;
+ }
/* Parse the URL options */
result = imap_parse_url_options(conn);
@@ -1654,27 +1695,30 @@ static CURLcode imap_disconnect(struct Curl_easy *data,
struct imap_conn *imapc = &conn->proto.imapc;
(void)data;
- /* 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. */
+ if(imapc->initialised) {
+ /* 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. */
- /* The IMAP session may or may not have been allocated/setup at this
- point! */
- if(!dead_connection && conn->bits.protoconnstart) {
- if(!imap_perform_logout(data))
- (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
- }
+ /* The IMAP session may or may not have been allocated/setup at this
+ point! */
+ if(!dead_connection && conn->bits.protoconnstart) {
+ if(!imap_perform_logout(data))
+ (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */
+ }
- /* Disconnect from the server */
- Curl_pp_disconnect(&imapc->pp);
- Curl_dyn_free(&imapc->dyn);
+ /* Disconnect from the server */
+ Curl_pp_disconnect(&imapc->pp);
+ Curl_dyn_free(&imapc->dyn);
- /* Cleanup the SASL module */
- Curl_sasl_cleanup(conn, imapc->sasl.authused);
+ /* Cleanup the SASL module */
+ Curl_sasl_cleanup(conn, imapc->sasl.authused);
- /* Cleanup our connection based variables */
- Curl_safefree(imapc->mailbox);
- Curl_safefree(imapc->mailbox_uidvalidity);
+ /* Cleanup our connection based variables */
+ Curl_safefree(imapc->mailbox);
+ Curl_safefree(imapc->mailbox_uidvalidity);
+ memset(imapc, 0, sizeof(*imapc));
+ }
return CURLE_OK;
}
@@ -1747,14 +1791,8 @@ static CURLcode imap_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
/* Initialise the IMAP layer */
- CURLcode result = imap_init(data);
- if(result)
- return result;
-
- /* Clear the TLS upgraded flag */
- conn->bits.tls_upgraded = FALSE;
-
- return CURLE_OK;
+ (void)conn;
+ return imap_init(data);
}
/***********************************************************************
diff --git a/libs/libcurl/src/imap.h b/libs/libcurl/src/imap.h
index 305d22a148..b83a49ec3f 100644
--- a/libs/libcurl/src/imap.h
+++ b/libs/libcurl/src/imap.h
@@ -85,6 +85,7 @@ struct imap_conn {
BIT(tls_supported); /* StartTLS capability supported by server */
BIT(login_disabled); /* LOGIN command disabled by server */
BIT(ir_supported); /* Initial response supported by server */
+ BIT(initialised); /* members have been initialised */
};
extern const struct Curl_handler Curl_handler_imap;
diff --git a/libs/libcurl/src/inet_ntop.c b/libs/libcurl/src/inet_ntop.c
index b2991f82de..9122e00898 100644
--- a/libs/libcurl/src/inet_ntop.c
+++ b/libs/libcurl/src/inet_ntop.c
@@ -38,7 +38,7 @@
#include "curl_printf.h"
#define IN6ADDRSZ 16
-#define INADDRSZ 4
+/* #define INADDRSZ 4 */
#define INT16SZ 2
/*
@@ -74,7 +74,11 @@ static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
len = strlen(tmp);
if(len == 0 || len >= size) {
- errno = ENOSPC;
+#ifdef USE_WINSOCK
+ CURL_SETERRNO(WSAEINVAL);
+#else
+ CURL_SETERRNO(ENOSPC);
+#endif
return NULL;
}
strcpy(dst, tmp);
@@ -153,7 +157,6 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
if(i == 6 && best.base == 0 &&
(best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
if(!inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
- errno = ENOSPC;
return NULL;
}
tp += strlen(tp);
@@ -171,7 +174,11 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
/* Check for overflow, copy, and we are done.
*/
if((size_t)(tp - tmp) > size) {
- errno = ENOSPC;
+#ifdef USE_WINSOCK
+ CURL_SETERRNO(WSAEINVAL);
+#else
+ CURL_SETERRNO(ENOSPC);
+#endif
return NULL;
}
strcpy(dst, tmp);
@@ -189,7 +196,7 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
* 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)
+char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size)
{
switch(af) {
case AF_INET:
@@ -197,7 +204,7 @@ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
case AF_INET6:
return inet_ntop6((const unsigned char *)src, buf, size);
default:
- errno = EAFNOSUPPORT;
+ CURL_SETERRNO(SOCKEAFNOSUPPORT);
return NULL;
}
}
diff --git a/libs/libcurl/src/inet_ntop.h b/libs/libcurl/src/inet_ntop.h
index 63c0a97424..dd32bb656d 100644
--- a/libs/libcurl/src/inet_ntop.h
+++ b/libs/libcurl/src/inet_ntop.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+char *curlx_inet_ntop(int af, const void *addr, char *buf, size_t size);
#ifdef HAVE_INET_NTOP
#ifdef HAVE_NETINET_IN_H
@@ -38,18 +38,12 @@ char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#ifdef _WIN32
-#if defined(_MSC_VER) && (_MSC_VER <= 1900)
-#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af, (void *)addr, buf, size)
-#else
-#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af, addr, buf, size)
-#endif
-#elif defined(__AMIGA__)
-#define Curl_inet_ntop(af,addr,buf,size) \
- (char *)inet_ntop(af, (void *)addr, (unsigned char *)buf, \
+#ifdef __AMIGA__
+#define curlx_inet_ntop(af,addr,buf,size) \
+ (char *)inet_ntop(af, CURL_UNCONST(addr), (unsigned char *)buf, \
(curl_socklen_t)(size))
#else
-#define Curl_inet_ntop(af,addr,buf,size) \
+#define curlx_inet_ntop(af,addr,buf,size) \
inet_ntop(af, addr, buf, (curl_socklen_t)(size))
#endif
#endif
diff --git a/libs/libcurl/src/inet_pton.c b/libs/libcurl/src/inet_pton.c
index 1a0259864a..9db20c559c 100644
--- a/libs/libcurl/src/inet_pton.c
+++ b/libs/libcurl/src/inet_pton.c
@@ -72,7 +72,7 @@ static int inet_pton6(const char *src, unsigned char *dst);
* Paul Vixie, 1996.
*/
int
-Curl_inet_pton(int af, const char *src, void *dst)
+curlx_inet_pton(int af, const char *src, void *dst)
{
switch(af) {
case AF_INET:
@@ -80,7 +80,7 @@ Curl_inet_pton(int af, const char *src, void *dst)
case AF_INET6:
return inet_pton6(src, (unsigned char *)dst);
default:
- errno = EAFNOSUPPORT;
+ CURL_SETERRNO(SOCKEAFNOSUPPORT);
return -1;
}
/* NOTREACHED */
diff --git a/libs/libcurl/src/inet_pton.h b/libs/libcurl/src/inet_pton.h
index 449ec47cf7..a33c50ee3f 100644
--- a/libs/libcurl/src/inet_pton.h
+++ b/libs/libcurl/src/inet_pton.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-int Curl_inet_pton(int, const char *, void *);
+int curlx_inet_pton(int, const char *, void *);
#ifdef HAVE_INET_PTON
#ifdef HAVE_NETINET_IN_H
@@ -38,10 +38,10 @@ int Curl_inet_pton(int, const char *, void *);
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#if defined(__AMIGA__)
-#define Curl_inet_pton(x,y,z) inet_pton(x,(unsigned char *)y,z)
+#ifdef __AMIGA__
+#define curlx_inet_pton(x,y,z) inet_pton(x,(unsigned char *)CURL_UNCONST(y),z)
#else
-#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+#define curlx_inet_pton(x,y,z) inet_pton(x,y,z)
#endif
#endif
diff --git a/libs/libcurl/src/krb5.c b/libs/libcurl/src/krb5.c
index ee86de0d9f..ec2bc21ead 100644
--- a/libs/libcurl/src/krb5.c
+++ b/libs/libcurl/src/krb5.c
@@ -173,7 +173,7 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to)
/* 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.value = CURL_UNCONST(from);
dec.length = (size_t)length;
maj = gss_wrap(&min, *context,
level == PROT_PRIVATE,
@@ -215,7 +215,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
struct gss_channel_bindings_struct chan;
size_t base64_sz = 0;
struct sockaddr_in *remote_addr =
- (struct sockaddr_in *)(void *)&conn->remote_addr->curl_sa_addr;
+ (struct sockaddr_in *)CURL_UNCONST(&conn->remote_addr->curl_sa_addr);
char *stringp;
if(getsockname(conn->sock[FIRSTSOCKET],
@@ -855,7 +855,6 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
mech->name);
return CURLE_FAILED_INIT;
}
- Curl_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH);
}
infof(data, "Trying mechanism %s...", mech->name);
@@ -914,9 +913,16 @@ Curl_sec_login(struct Curl_easy *data, struct connectdata *conn)
return choose_mech(data, conn);
}
+void
+Curl_sec_conn_init(struct connectdata *conn)
+{
+ Curl_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH);
+ conn->in_buffer.index = 0;
+ conn->in_buffer.eof_flag = 0;
+}
void
-Curl_sec_end(struct connectdata *conn)
+Curl_sec_conn_destroy(struct connectdata *conn)
{
if(conn->mech && conn->mech->end)
conn->mech->end(conn->app_data);
diff --git a/libs/libcurl/src/ldap.c b/libs/libcurl/src/ldap.c
index a463bfb47e..27b2b66845 100644
--- a/libs/libcurl/src/ldap.c
+++ b/libs/libcurl/src/ldap.c
@@ -89,7 +89,7 @@
#include "progress.h"
#include "transfer.h"
#include "strcase.h"
-#include "strtok.h"
+#include "strparse.h"
#include "curl_ldap.h"
#include "curl_multibyte.h"
#include "curl_base64.h"
@@ -285,8 +285,8 @@ static int ldap_win_bind(struct Curl_easy *data, LDAP *server,
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);
+ inuser = curlx_convert_UTF8_to_tchar(user);
+ inpass = curlx_convert_UTF8_to_tchar(passwd);
rc = (int)ldap_simple_bind_s(server, inuser, inpass);
@@ -543,7 +543,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
#endif
name_len = strlen(name);
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, "DN: ", 4);
if(result) {
FREE_ON_WINLDAP(name);
ldap_memfree(dn);
@@ -557,7 +557,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
if(result) {
FREE_ON_WINLDAP(name);
ldap_memfree(dn);
@@ -593,7 +593,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
vals = ldap_get_values_len(server, entryIterator, attribute);
if(vals) {
for(i = 0; (vals[i] != NULL); i++) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, "\t", 1);
if(result) {
ldap_value_free_len(vals);
FREE_ON_WINLDAP(attr);
@@ -615,7 +615,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, ": ", 2);
if(result) {
ldap_value_free_len(vals);
FREE_ON_WINLDAP(attr);
@@ -670,7 +670,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
}
}
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
if(result) {
ldap_value_free_len(vals);
FREE_ON_WINLDAP(attr);
@@ -690,7 +690,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
FREE_ON_WINLDAP(attr);
ldap_memfree(attribute);
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
if(result)
goto quit;
}
@@ -728,7 +728,9 @@ static void _ldap_trace(const char *fmt, ...)
if(do_trace == -1) {
const char *env = getenv("CURL_TRACE");
- do_trace = (env && strtol(env, NULL, 10) > 0);
+ curl_off_t e = 0;
+ if(!Curl_str_number(&env, &e, INT_MAX))
+ do_trace = e > 0;
}
if(!do_trace)
return;
@@ -759,36 +761,17 @@ static int str2scope(const char *p)
return -1;
}
-/*
- * Split 'str' into strings separated by commas.
- * Note: out[] points into 'str'.
- */
-static bool split_str(char *str, char ***out, size_t *count)
+/* number of entries in the attributes list */
+static size_t num_entries(const char *s)
{
- char **res;
- char *lasts;
- char *s;
- size_t i;
size_t items = 1;
- s = strchr(str, ',');
+ s = strchr(s, ',');
while(s) {
items++;
- s = strchr(++s, ',');
+ s = strchr(s + 1, ',');
}
-
- res = calloc(items, sizeof(char *));
- if(!res)
- return FALSE;
-
- for(i = 0, s = Curl_strtok_r(str, ",", &lasts); s && i < items;
- s = Curl_strtok_r(NULL, ",", &lasts), i++)
- res[i] = s;
-
- *out = res;
- *count = items;
-
- return TRUE;
+ return items;
}
/*
@@ -882,15 +865,8 @@ static int _ldap_url_parse2(struct Curl_easy *data,
*q++ = '\0';
if(*p) {
- char **attributes;
- size_t count = 0;
-
- /* Split the string into an array of attributes */
- if(!split_str(p, &attributes, &count)) {
- rc = LDAP_NO_MEMORY;
-
- goto quit;
- }
+ size_t count = num_entries(p); /* at least one */
+ const char *atp = p;
/* Allocate our array (+1 for the NULL entry) */
#if defined(USE_WIN32_LDAP)
@@ -899,27 +875,25 @@ static int _ldap_url_parse2(struct Curl_easy *data,
ludp->lud_attrs = calloc(count + 1, sizeof(char *));
#endif
if(!ludp->lud_attrs) {
- free(attributes);
-
rc = LDAP_NO_MEMORY;
-
goto quit;
}
for(i = 0; i < count; i++) {
char *unescaped;
CURLcode result;
+ struct Curl_str out;
- LDAP_TRACE(("attr[%zu] '%s'\n", i, attributes[i]));
+ if(Curl_str_until(&atp, &out, 1024, ','))
+ break;
+
+ LDAP_TRACE(("attr[%zu] '%.*s'\n", i, (int)out.len, out.str));
/* Unescape the attribute */
- result = Curl_urldecode(attributes[i], 0, &unescaped, NULL,
+ result = Curl_urldecode(out.str, out.len, &unescaped, NULL,
REJECT_ZERO);
if(result) {
- free(attributes);
-
rc = LDAP_NO_MEMORY;
-
goto quit;
}
@@ -931,10 +905,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
free(unescaped);
if(!ludp->lud_attrs[i]) {
- free(attributes);
-
rc = LDAP_NO_MEMORY;
-
goto quit;
}
#else
@@ -942,9 +913,9 @@ static int _ldap_url_parse2(struct Curl_easy *data,
#endif
ludp->lud_attrs_dups++;
+ if(Curl_str_single(&atp, ','))
+ break;
}
-
- free(attributes);
}
p = q;
diff --git a/libs/libcurl/src/llist.c b/libs/libcurl/src/llist.c
index 61348b1809..fa9fe1d556 100644
--- a/libs/libcurl/src/llist.c
+++ b/libs/libcurl/src/llist.c
@@ -32,12 +32,11 @@
/* this must be the last include file */
#include "memdebug.h"
+#ifdef DEBUGBUILD
#define LLISTINIT 0x100cc001 /* random pattern */
#define NODEINIT 0x12344321 /* random pattern */
#define NODEREM 0x54321012 /* random pattern */
-
-#ifdef DEBUGBUILD
#define VERIFYNODE(x) verifynode(x)
static struct Curl_llist_node *verifynode(struct Curl_llist_node *n)
{
@@ -86,7 +85,7 @@ Curl_llist_insert_next(struct Curl_llist *list,
#ifdef DEBUGBUILD
ne->_init = NODEINIT;
#endif
- ne->_ptr = (void *) p;
+ ne->_ptr = CURL_UNCONST(p);
ne->_list = list;
if(list->_size == 0) {
list->_head = ne;
diff --git a/libs/libcurl/src/md4.c b/libs/libcurl/src/md4.c
index f7e5865bae..2b28b08bd3 100644
--- a/libs/libcurl/src/md4.c
+++ b/libs/libcurl/src/md4.c
@@ -170,7 +170,12 @@ static int MD4_Init(MD4_CTX *ctx)
static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
{
- CryptHashData(ctx->hHash, (BYTE *)data, (unsigned int) size, 0);
+#ifdef __MINGW32CE__
+ CryptHashData(ctx->hHash, (BYTE *)CURL_UNCONST(data),
+ (unsigned int) size, 0);
+#else
+ CryptHashData(ctx->hHash, (const BYTE *)data, (unsigned int) size, 0);
+#endif
}
static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
@@ -308,16 +313,16 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx);
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define MD4_SET(n) \
- (*(MD4_u32plus *)(void *)&ptr[(n) * 4])
+ (*(const MD4_u32plus *)(const 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))
+ (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
diff --git a/libs/libcurl/src/md5.c b/libs/libcurl/src/md5.c
index ed0f801aa2..abcdd0b093 100644
--- a/libs/libcurl/src/md5.c
+++ b/libs/libcurl/src/md5.c
@@ -252,7 +252,11 @@ static void my_md5_update(void *in,
unsigned int inputLen)
{
my_md5_ctx *ctx = in;
- CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
+#ifdef __MINGW32CE__
+ CryptHashData(ctx->hHash, (BYTE *)CURL_UNCONST(input), inputLen, 0);
+#else
+ CryptHashData(ctx->hHash, (const BYTE *)input, inputLen, 0);
+#endif
}
static void my_md5_final(unsigned char *digest, void *in)
@@ -356,7 +360,7 @@ static void my_md5_final(unsigned char *result, void *ctx);
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define MD5_SET(n) \
- (*(MD5_u32plus *)(void *)&ptr[(n) * 4])
+ (*(const MD5_u32plus *)(const void *)&ptr[(n) * 4])
#define MD5_GET(n) \
MD5_SET(n)
#else
diff --git a/libs/libcurl/src/memdebug.c b/libs/libcurl/src/memdebug.c
index 78cd579aee..fa7bb66257 100644
--- a/libs/libcurl/src/memdebug.c
+++ b/libs/libcurl/src/memdebug.c
@@ -117,20 +117,19 @@ static bool countcheck(const char *func, int line, const char *source)
fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
source, line, func);
fflush(curl_dbg_logfile); /* because it might crash now */
- errno = ENOMEM;
+ /* !checksrc! disable ERRNOVAR 1 */
+ CURL_SETERRNO(ENOMEM);
return TRUE; /* RETURN ERROR! */
}
else
memsize--; /* countdown */
-
-
}
return FALSE; /* allow this */
}
-ALLOC_FUNC void *curl_dbg_malloc(size_t wantedsize,
- int line, const char *source)
+ALLOC_FUNC
+void *curl_dbg_malloc(size_t wantedsize, int line, const char *source)
{
struct memdebug *mem;
size_t size;
@@ -156,8 +155,9 @@ ALLOC_FUNC void *curl_dbg_malloc(size_t wantedsize,
return mem ? mem->mem : NULL;
}
-ALLOC_FUNC void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size,
- int line, const char *source)
+ALLOC_FUNC
+void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size,
+ int line, const char *source)
{
struct memdebug *mem;
size_t size, user_size;
@@ -184,8 +184,8 @@ ALLOC_FUNC void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size,
return mem ? mem->mem : NULL;
}
-ALLOC_FUNC char *curl_dbg_strdup(const char *str,
- int line, const char *source)
+ALLOC_FUNC
+char *curl_dbg_strdup(const char *str, int line, const char *source)
{
char *mem;
size_t len;
@@ -209,8 +209,8 @@ ALLOC_FUNC char *curl_dbg_strdup(const char *str,
}
#if defined(_WIN32) && defined(UNICODE)
-ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
- int line, const char *source)
+ALLOC_FUNC
+wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source)
{
wchar_t *mem;
size_t wsiz, bsiz;
@@ -229,7 +229,7 @@ ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
if(source)
curl_dbg_log("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
- source, line, (void *)str, bsiz, (void *)mem);
+ source, line, (const void *)str, bsiz, (void *)mem);
return mem;
}
@@ -238,7 +238,7 @@ ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
/* We provide a realloc() that accepts a NULL as pointer, which then
performs a malloc(). In order to work with ares. */
void *curl_dbg_realloc(void *ptr, size_t wantedsize,
- int line, const char *source)
+ int line, const char *source)
{
struct memdebug *mem = NULL;
@@ -394,8 +394,9 @@ int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source)
return res;
}
-ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode,
- int line, const char *source)
+ALLOC_FUNC
+FILE *curl_dbg_fopen(const char *file, const char *mode,
+ int line, const char *source)
{
FILE *res = fopen(file, mode);
@@ -406,8 +407,9 @@ ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode,
return res;
}
-ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode,
- int line, const char *source)
+ALLOC_FUNC
+FILE *curl_dbg_fdopen(int filedes, const char *mode,
+ int line, const char *source)
{
FILE *res = fdopen(filedes, mode);
if(source)
@@ -431,33 +433,25 @@ int curl_dbg_fclose(FILE *file, int line, const char *source)
return res;
}
-#define LOGLINE_BUFSIZE 1024
-
/* this does the writing to the memory tracking log file */
void curl_dbg_log(const char *format, ...)
{
- char *buf;
+ char buf[1024];
int nchars;
va_list ap;
if(!curl_dbg_logfile)
return;
- buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
- if(!buf)
- return;
-
va_start(ap, format);
- nchars = mvsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
+ nchars = mvsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
- if(nchars > LOGLINE_BUFSIZE - 1)
- nchars = LOGLINE_BUFSIZE - 1;
+ if(nchars > (int)sizeof(buf) - 1)
+ nchars = (int)sizeof(buf) - 1;
if(nchars > 0)
fwrite(buf, 1, (size_t)nchars, curl_dbg_logfile);
-
- (Curl_cfree)(buf);
}
#endif /* CURLDEBUG */
diff --git a/libs/libcurl/src/memdebug.h b/libs/libcurl/src/memdebug.h
index f33acfb657..d4fa5f8e77 100644
--- a/libs/libcurl/src/memdebug.h
+++ b/libs/libcurl/src/memdebug.h
@@ -33,12 +33,21 @@
#include <curl/curl.h>
#include "functypes.h"
-#if defined(__GNUC__) && __GNUC__ >= 3
-# define ALLOC_FUNC __attribute__((__malloc__))
-# define ALLOC_SIZE(s) __attribute__((__alloc_size__(s)))
-# define ALLOC_SIZE2(n, s) __attribute__((__alloc_size__(n, s)))
+#ifdef __clang__
+# define ALLOC_FUNC __attribute__((__malloc__))
+# if __clang_major__ >= 4
+# define ALLOC_SIZE(s) __attribute__((__alloc_size__(s)))
+# define ALLOC_SIZE2(n, s) __attribute__((__alloc_size__(n, s)))
+# else
+# define ALLOC_SIZE(s)
+# define ALLOC_SIZE2(n, s)
+# endif
+#elif defined(__GNUC__) && __GNUC__ >= 3
+# define ALLOC_FUNC __attribute__((__malloc__))
+# define ALLOC_SIZE(s) __attribute__((__alloc_size__(s)))
+# define ALLOC_SIZE2(n, s) __attribute__((__alloc_size__(n, s)))
#elif defined(_MSC_VER)
-# define ALLOC_FUNC __declspec(restrict)
+# define ALLOC_FUNC __declspec(restrict)
# define ALLOC_SIZE(s)
# define ALLOC_SIZE2(n, s)
#else
@@ -49,25 +58,25 @@
#define CURL_MT_LOGFNAME_BUFSIZE 512
+/* Avoid redundant redeclaration warnings with modern compilers, when including
+ this header multiple times. */
+#ifndef HEADER_CURL_MEMDEBUG_H_EXTERNS
+#define HEADER_CURL_MEMDEBUG_H_EXTERNS
extern FILE *curl_dbg_logfile;
/* memory functions */
-CURL_EXTERN ALLOC_FUNC ALLOC_SIZE(1) void *curl_dbg_malloc(size_t size,
- int line,
- const char *source);
-CURL_EXTERN ALLOC_FUNC ALLOC_SIZE2(1, 2) void *curl_dbg_calloc(size_t elements,
- size_t size, int line, const char *source);
-CURL_EXTERN ALLOC_SIZE(2) void *curl_dbg_realloc(void *ptr,
- size_t size,
- int line,
- const char *source);
CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source);
-CURL_EXTERN ALLOC_FUNC char *curl_dbg_strdup(const char *str, int line,
- const char *src);
+CURL_EXTERN ALLOC_FUNC ALLOC_SIZE(1)
+ void *curl_dbg_malloc(size_t size, int line, const char *source);
+CURL_EXTERN ALLOC_FUNC ALLOC_SIZE2(1, 2)
+ void *curl_dbg_calloc(size_t n, size_t size, int line, const char *source);
+CURL_EXTERN ALLOC_SIZE(2)
+ void *curl_dbg_realloc(void *ptr, size_t size, int line, const char *source);
+CURL_EXTERN ALLOC_FUNC
+ char *curl_dbg_strdup(const char *str, int line, const char *src);
#if defined(_WIN32) && defined(UNICODE)
-CURL_EXTERN ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
- int line,
- const char *source);
+CURL_EXTERN ALLOC_FUNC
+ wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source);
#endif
CURL_EXTERN void curl_dbg_memdebug(const char *logname);
@@ -102,12 +111,15 @@ CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd,
const char *source);
/* FILE functions */
-CURL_EXTERN ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode,
- int line, const char *source);
-CURL_EXTERN ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode,
- int line, const char *source);
-
CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
+CURL_EXTERN ALLOC_FUNC
+ FILE *curl_dbg_fopen(const char *file, const char *mode,
+ int line, const char *source);
+CURL_EXTERN ALLOC_FUNC
+ FILE *curl_dbg_fdopen(int filedes, const char *mode,
+ int line, const char *source);
+
+#endif /* HEADER_CURL_MEMDEBUG_H_EXTERNS */
#ifndef MEMDEBUG_NODEFINES
@@ -153,28 +165,6 @@ CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
__LINE__, __FILE__)
#endif
-#ifndef CURL_NO_GETADDRINFO_OVERRIDE
-#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! */
-#define ogetaddrinfo(host,serv,hint,res) \
- curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
-#else
-#undef getaddrinfo
-#define getaddrinfo(host,serv,hint,res) \
- curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
-#endif
-#endif /* HAVE_GETADDRINFO */
-
-#ifdef HAVE_FREEADDRINFO
-#undef freeaddrinfo
-#define freeaddrinfo(data) \
- curl_dbg_freeaddrinfo(data, __LINE__, __FILE__)
-#endif /* HAVE_FREEADDRINFO */
-#endif /* !CURL_NO_GETADDRINFO_OVERRIDE */
-
/* sclose is probably already defined, redefine it! */
#undef sclose
#define sclose(sockfd) curl_dbg_sclose(sockfd,__LINE__,__FILE__)
diff --git a/libs/libcurl/src/mime.c b/libs/libcurl/src/mime.c
index 66dd0f2ed2..16e63d0ef9 100644
--- a/libs/libcurl/src/mime.c
+++ b/libs/libcurl/src/mime.c
@@ -1742,7 +1742,7 @@ const char *Curl_mime_contenttype(const char *filename)
const char *nameend = filename + len1;
unsigned int i;
- for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
+ for(i = 0; i < CURL_ARRAYSIZE(ctts); i++) {
size_t len2 = strlen(ctts[i].extension);
if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
diff --git a/libs/libcurl/src/mprintf.c b/libs/libcurl/src/mprintf.c
index 572ba1980d..28f0844e66 100644
--- a/libs/libcurl/src/mprintf.c
+++ b/libs/libcurl/src/mprintf.c
@@ -25,6 +25,7 @@
#include "curl_setup.h"
#include "dynbuf.h"
#include "curl_printf.h"
+#include "strparse.h"
#include "curl_memory.h"
/* The last #include file should be: */
@@ -134,7 +135,7 @@ enum {
struct va_input {
FormatType type; /* FormatType */
union {
- char *str;
+ const char *str;
void *ptr;
mp_intmax_t nums; /* signed */
mp_uintmax_t numu; /* unsigned */
@@ -150,7 +151,7 @@ struct outsegment {
int precision; /* precision OR precision parameter number */
unsigned int flags;
unsigned int input; /* input argument array index */
- char *start; /* format string start to output */
+ const char *start; /* format string start to output */
size_t outlen; /* number of bytes from the format string to output */
};
@@ -169,26 +170,19 @@ struct asprintf {
returns -1 if no valid number was provided.
*/
-static int dollarstring(char *input, char **end)
+static int dollarstring(const char *p, const char **end)
{
- if(ISDIGIT(*input)) {
- int number = 0;
- do {
- if(number < MAX_PARAMETERS) {
- number *= 10;
- number += *input - '0';
- }
- input++;
- } while(ISDIGIT(*input));
-
- if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) {
- *end = ++input;
- return number - 1;
- }
- }
- return -1;
+ curl_off_t num;
+ if(Curl_str_number(&p, &num, MAX_PARAMETERS) ||
+ Curl_str_single(&p, '$') || !num)
+ return -1;
+ *end = p;
+ return (int)num - 1;
}
+#define is_arg_used(x,y) ((x)[(y)/8] & (1 << ((y)&7)))
+#define mark_arg_used(x,y) ((x)[y/8] |= (unsigned char)(1 << ((y)&7)))
+
/*
* Parse the format string.
*
@@ -216,13 +210,8 @@ static int parsefmt(const char *format,
int *opieces,
int *ipieces, va_list arglist)
{
- char *fmt = (char *)format;
+ const char *fmt = format;
int param_num = 0;
- int param;
- int width;
- int precision;
- unsigned int flags;
- FormatType type;
int max_param = -1;
int i;
int ocount = 0;
@@ -230,7 +219,7 @@ static int parsefmt(const char *format,
size_t outlen = 0;
struct outsegment *optr;
int use_dollar = DOLLAR_UNKNOWN;
- char *start = fmt;
+ const char *start = fmt;
/* clear, set a bit for each used input */
memset(usedinput, 0, sizeof(usedinput));
@@ -239,6 +228,11 @@ static int parsefmt(const char *format,
if(*fmt == '%') {
struct va_input *iptr;
bool loopit = TRUE;
+ FormatType type;
+ unsigned int flags = 0;
+ int width = 0;
+ int precision = 0;
+ int param = -1;
fmt++;
outlen = (size_t)(fmt - start - 1);
if(*fmt == '%') {
@@ -258,9 +252,6 @@ static int parsefmt(const char *format,
continue; /* while */
}
- flags = 0;
- width = precision = 0;
-
if(use_dollar != DOLLAR_NOPE) {
param = dollarstring(fmt, &fmt);
if(param < 0) {
@@ -275,8 +266,6 @@ static int parsefmt(const char *format,
else
use_dollar = DOLLAR_USE;
}
- else
- param = -1;
/* Handle the flags */
while(loopit) {
@@ -311,20 +300,15 @@ static int parsefmt(const char *format,
precision = -1;
}
else {
- bool is_neg = FALSE;
+ bool is_neg;
+ curl_off_t num;
flags |= FLAGS_PREC;
- precision = 0;
- if('-' == *fmt) {
- is_neg = TRUE;
- fmt++;
- }
- while(ISDIGIT(*fmt)) {
- int n = *fmt - '0';
- if(precision > (INT_MAX - n) / 10)
- return PFMT_PREC;
- precision = precision * 10 + n;
+ is_neg = ('-' == *fmt);
+ if(is_neg)
fmt++;
- }
+ if(Curl_str_number(&fmt, &num, INT_MAX))
+ return PFMT_PREC;
+ precision = (int)num;
if(is_neg)
precision = -precision;
}
@@ -337,7 +321,7 @@ static int parsefmt(const char *format,
case 'h':
flags |= FLAGS_SHORT;
break;
-#if defined(_WIN32) || defined(_WIN32_WCE)
+#ifdef _WIN32
case 'I':
/* Non-ANSI integer extensions I32 I64 */
if((fmt[0] == '3') && (fmt[1] == '2')) {
@@ -356,7 +340,7 @@ static int parsefmt(const char *format,
#endif
}
break;
-#endif /* _WIN32 || _WIN32_WCE */
+#endif /* _WIN32 */
case 'l':
if(flags & FLAGS_LONG)
flags |= FLAGS_LONGLONG;
@@ -390,18 +374,15 @@ static int parsefmt(const char *format,
flags |= FLAGS_PAD_NIL;
FALLTHROUGH();
case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
+ case '5': case '6': case '7': case '8': case '9': {
+ curl_off_t num;
flags |= FLAGS_WIDTH;
- width = 0;
fmt--;
- do {
- int n = *fmt - '0';
- if(width > (INT_MAX - n) / 10)
- return PFMT_WIDTH;
- width = width * 10 + n;
- fmt++;
- } while(ISDIGIT(*fmt));
+ if(Curl_str_number(&fmt, &num, INT_MAX))
+ return PFMT_WIDTH;
+ width = (int)num;
break;
+ }
case '*': /* read width from argument list */
flags |= FLAGS_WIDTHPARAM;
if(use_dollar == DOLLAR_USE) {
@@ -511,9 +492,8 @@ static int parsefmt(const char *format,
if(width < 0)
width = param_num++;
else {
- /* if this identifies a parameter already used, this
- is illegal */
- if(usedinput[width/8] & (1 << (width&7)))
+ /* if this identifies a parameter already used, this is illegal */
+ if(is_arg_used(usedinput, width))
return PFMT_WIDTHARG;
}
if(width >= MAX_PARAMETERS)
@@ -523,16 +503,15 @@ static int parsefmt(const char *format,
in[width].type = FORMAT_WIDTH;
/* mark as used */
- usedinput[width/8] |= (unsigned char)(1 << (width&7));
+ mark_arg_used(usedinput, width);
}
if(flags & FLAGS_PRECPARAM) {
if(precision < 0)
precision = param_num++;
else {
- /* if this identifies a parameter already used, this
- is illegal */
- if(usedinput[precision/8] & (1 << (precision&7)))
+ /* if this identifies a parameter already used, this is illegal */
+ if(is_arg_used(usedinput, precision))
return PFMT_PRECARG;
}
if(precision >= MAX_PARAMETERS)
@@ -541,7 +520,7 @@ static int parsefmt(const char *format,
max_param = precision;
in[precision].type = FORMAT_PRECISION;
- usedinput[precision/8] |= (unsigned char)(1 << (precision&7));
+ mark_arg_used(usedinput, precision);
}
/* Handle the specifier */
@@ -556,7 +535,7 @@ static int parsefmt(const char *format,
iptr->type = type;
/* mark this input as used */
- usedinput[param/8] |= (unsigned char)(1 << (param&7));
+ mark_arg_used(usedinput, param);
fmt++;
optr = &out[ocount++];
@@ -589,14 +568,14 @@ static int parsefmt(const char *format,
/* Read the arg list parameters into our data list */
for(i = 0; i < max_param + 1; i++) {
struct va_input *iptr = &in[i];
- if(!(usedinput[i/8] & (1 << (i&7))))
+ if(!is_arg_used(usedinput, i))
/* bad input */
return PFMT_INPUTGAP;
/* based on the type, read the correct argument */
switch(iptr->type) {
case FORMAT_STRING:
- iptr->val.str = va_arg(arglist, char *);
+ iptr->val.str = va_arg(arglist, const char *);
break;
case FORMAT_INTPTR:
@@ -704,7 +683,7 @@ static int formatf(
unsigned int flags = optr->flags;
if(outlen) {
- char *str = optr->start;
+ const char *str = optr->start;
for(; outlen && *str; outlen--)
OUTCHAR(*str++);
if(optr->flags & FLAGS_SUBSTR)
@@ -873,7 +852,7 @@ number:
const char *str;
size_t len;
- str = (char *)iptr->val.str;
+ str = iptr->val.str;
if(!str) {
/* Write null string if there is space. */
if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
@@ -1014,7 +993,9 @@ number:
/* NOTE NOTE NOTE!! Not all sprintf implementations return number of
output characters */
#ifdef HAVE_SNPRINTF
- (snprintf)(work, BUFFSIZE, formatbuf, iptr->val.dnum); /* NOLINT */
+ /* !checksrc! disable LONGLINE */
+ /* NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling) */
+ (snprintf)(work, BUFFSIZE, formatbuf, iptr->val.dnum);
#ifdef _WIN32
/* Old versions of the Windows CRT do not terminate the snprintf output
buffer if it reaches the max size so we do that here. */
@@ -1189,7 +1170,6 @@ int curl_mprintf(const char *format, ...)
int retcode;
va_list ap_save; /* argument pointer */
va_start(ap_save, format);
-
retcode = formatf(stdout, fputc_wrapper, format, ap_save);
va_end(ap_save);
return retcode;
diff --git a/libs/libcurl/src/mqtt.c b/libs/libcurl/src/mqtt.c
index fa064ebedc..eae4b4ceb7 100644
--- a/libs/libcurl/src/mqtt.c
+++ b/libs/libcurl/src/mqtt.c
@@ -46,11 +46,11 @@
/* The last #include file should be: */
#include "memdebug.h"
-#define MQTT_MSG_CONNECT 0x10
-#define MQTT_MSG_CONNACK 0x20
-#define MQTT_MSG_PUBLISH 0x30
-#define MQTT_MSG_SUBSCRIBE 0x82
-#define MQTT_MSG_SUBACK 0x90
+#define MQTT_MSG_CONNECT 0x10
+/* #define MQTT_MSG_CONNACK 0x20 */
+#define MQTT_MSG_PUBLISH 0x30
+#define MQTT_MSG_SUBSCRIBE 0x82
+#define MQTT_MSG_SUBACK 0x90
#define MQTT_MSG_DISCONNECT 0xe0
#define MQTT_CONNACK_LEN 2
@@ -112,32 +112,32 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data,
if(!mq)
return CURLE_OUT_OF_MEMORY;
Curl_dyn_init(&mq->recvbuf, DYN_MQTT_RECV);
+ Curl_dyn_init(&mq->sendbuf, DYN_MQTT_SEND);
data->req.p.mqtt = mq;
return CURLE_OK;
}
static CURLcode mqtt_send(struct Curl_easy *data,
- char *buf, size_t len)
+ const char *buf, size_t len)
{
- CURLcode result = CURLE_OK;
struct MQTT *mq = data->req.p.mqtt;
size_t n;
- result = Curl_xfer_send(data, buf, len, FALSE, &n);
+ CURLcode result = Curl_xfer_send(data, buf, len, FALSE, &n);
if(result)
return result;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
if(len != n) {
size_t nsend = len - n;
- char *sendleftovers = Curl_memdup(&buf[n], nsend);
- if(!sendleftovers)
- return CURLE_OUT_OF_MEMORY;
- mq->sendleftovers = sendleftovers;
- mq->nsend = nsend;
- }
- else {
- mq->sendleftovers = NULL;
- mq->nsend = 0;
+ if(Curl_dyn_len(&mq->sendbuf)) {
+ DEBUGASSERT(Curl_dyn_len(&mq->sendbuf) >= nsend);
+ result = Curl_dyn_tail(&mq->sendbuf, nsend); /* keep this much */
+ }
+ else {
+ result = Curl_dyn_addn(&mq->sendbuf, &buf[n], nsend);
+ }
}
+ else
+ Curl_dyn_reset(&mq->sendbuf);
return result;
}
@@ -257,7 +257,6 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
int remain_pos = 0;
char remain[4] = {0};
size_t packetlen = 0;
- size_t payloadlen = 0;
size_t start_user = 0;
size_t start_pwd = 0;
char client_id[MQTT_CLIENTID_LEN + 1] = "curl";
@@ -272,14 +271,11 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
const char *passwd = data->state.aptr.passwd ?
data->state.aptr.passwd : "";
const size_t plen = strlen(passwd);
-
- payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2;
- /* The plus 2 are for the MSB and LSB describing the length of the string to
- * be added on the payload. Refer to spec 1.5.2 and 1.5.4 */
- if(ulen)
- payloadlen += 2;
- if(plen)
- payloadlen += 2;
+ const size_t payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2 +
+ /* The plus 2s below are for the MSB and LSB describing the length of the
+ string to be added on the payload. Refer to spec 1.5.2 and 1.5.4 */
+ (ulen ? 2 : 0) +
+ (plen ? 2 : 0);
/* getting how much occupy the remain length */
remain_pos = mqtt_encode_len(remain, payloadlen + 10);
@@ -288,12 +284,11 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
packetlen = payloadlen + 10 + remain_pos + 1;
/* allocating packet */
- if(packetlen > 268435455)
+ if(packetlen > 0xFFFFFFF)
return CURLE_WEIRD_SERVER_REPLY;
- packet = malloc(packetlen);
+ packet = calloc(1, packetlen);
if(!packet)
return CURLE_OUT_OF_MEMORY;
- memset(packet, 0, packetlen);
/* set initial values for the CONNECT packet */
pos = init_connpack(packet, remain, remain_pos);
@@ -309,9 +304,9 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
}
infof(data, "Using client id '%s'", client_id);
- /* position where starts the user payload */
+ /* position where the user payload starts */
start_user = pos + 3 + MQTT_CLIENTID_LEN;
- /* position where starts the password payload */
+ /* position where the password payload starts */
start_pwd = start_user + ulen;
/* if username was provided, add it to the packet */
if(ulen) {
@@ -320,7 +315,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
rc = add_user(username, ulen,
(unsigned char *)packet, start_user, remain_pos);
if(rc) {
- failf(data, "Username is too large: [%zu]", ulen);
+ failf(data, "Username too long: [%zu]", ulen);
result = CURLE_WEIRD_SERVER_REPLY;
goto end;
}
@@ -330,7 +325,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
if(plen) {
rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos);
if(rc) {
- failf(data, "Password is too large: [%zu]", plen);
+ failf(data, "Password too long: [%zu]", plen);
result = CURLE_WEIRD_SERVER_REPLY;
goto end;
}
@@ -351,8 +346,8 @@ static CURLcode mqtt_disconnect(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
struct MQTT *mq = data->req.p.mqtt;
- result = mqtt_send(data, (char *)"\xe0\x00", 2);
- Curl_safefree(mq->sendleftovers);
+ result = mqtt_send(data, "\xe0\x00", 2);
+ Curl_dyn_free(&mq->sendbuf);
Curl_dyn_free(&mq->recvbuf);
return result;
}
@@ -471,7 +466,7 @@ static CURLcode mqtt_subscribe(struct Curl_easy *data)
memcpy(&packet[5 + n], topic, topiclen);
packet[5 + n + topiclen] = 0; /* QoS zero */
- result = mqtt_send(data, (char *)packet, packetlen);
+ result = mqtt_send(data, (const char *)packet, packetlen);
fail:
free(topic);
@@ -558,7 +553,7 @@ static CURLcode mqtt_publish(struct Curl_easy *data)
i += topiclen;
memcpy(&pkt[i], payload, payloadlen);
i += payloadlen;
- result = mqtt_send(data, (char *)pkt, i);
+ result = mqtt_send(data, (const char *)pkt, i);
fail:
free(pkt);
@@ -732,7 +727,7 @@ static CURLcode mqtt_done(struct Curl_easy *data,
struct MQTT *mq = data->req.p.mqtt;
(void)status;
(void)premature;
- Curl_safefree(mq->sendleftovers);
+ Curl_dyn_free(&mq->sendbuf);
Curl_dyn_free(&mq->recvbuf);
return CURLE_OK;
}
@@ -740,19 +735,17 @@ static CURLcode mqtt_done(struct Curl_easy *data,
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_conn *mqtt = &data->conn->proto.mqtt;
struct MQTT *mq = data->req.p.mqtt;
ssize_t nread;
unsigned char recvbyte;
*done = FALSE;
- if(mq->nsend) {
+ if(Curl_dyn_len(&mq->sendbuf)) {
/* send the remainder of an outgoing packet */
- char *ptr = mq->sendleftovers;
- result = mqtt_send(data, mq->sendleftovers, mq->nsend);
- free(ptr);
+ result = mqtt_send(data, Curl_dyn_ptr(&mq->sendbuf),
+ Curl_dyn_len(&mq->sendbuf));
if(result)
return result;
}
@@ -770,7 +763,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
result = CURLE_RECV_ERROR;
break;
}
- Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
+ Curl_debug(data, CURLINFO_HEADER_IN, (const char *)&mq->firstbyte, 1);
/* remember the first byte */
mq->npacket = 0;
mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
@@ -780,7 +773,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
result = Curl_xfer_recv(data, (char *)&recvbyte, 1, &nread);
if(result || !nread)
break;
- Curl_debug(data, CURLINFO_HEADER_IN, (char *)&recvbyte, 1);
+ Curl_debug(data, CURLINFO_HEADER_IN, (const char *)&recvbyte, 1);
mq->pkt_hd[mq->npacket++] = recvbyte;
} while((recvbyte & 0x80) && (mq->npacket < 4));
if(!result && nread && (recvbyte & 0x80))
diff --git a/libs/libcurl/src/mqtt.h b/libs/libcurl/src/mqtt.h
index ea81f40448..6393e0c552 100644
--- a/libs/libcurl/src/mqtt.h
+++ b/libs/libcurl/src/mqtt.h
@@ -49,15 +49,13 @@ struct mqtt_conn {
/* protocol-specific transfer-related data */
struct MQTT {
- char *sendleftovers;
- size_t nsend; /* size of sendleftovers */
-
+ struct dynbuf sendbuf;
/* when receiving */
+ struct dynbuf recvbuf;
size_t npacket; /* byte counter */
- unsigned char firstbyte;
size_t remaining_length;
- struct dynbuf recvbuf;
unsigned char pkt_hd[4]; /* for decoding the arriving packet length */
+ unsigned char firstbyte;
};
#endif /* HEADER_CURL_MQTT_H */
diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c
index fa130b23fe..1e63e54a45 100644
--- a/libs/libcurl/src/multi.c
+++ b/libs/libcurl/src/multi.c
@@ -36,6 +36,7 @@
#include "share.h"
#include "psl.h"
#include "multiif.h"
+#include "multi_ev.h"
#include "sendf.h"
#include "timeval.h"
#include "http.h"
@@ -94,8 +95,6 @@
static void move_pending_to_connect(struct Curl_multi *multi,
struct Curl_easy *data);
-static CURLMcode singlesocket(struct Curl_multi *multi,
- struct Curl_easy *data);
static CURLMcode add_next_timeout(struct curltime now,
struct Curl_multi *multi,
struct Curl_easy *d);
@@ -104,31 +103,6 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
long *timeout_ms);
static void process_pending_handles(struct Curl_multi *multi);
static void multi_xfer_bufs_free(struct Curl_multi *multi);
-static void expire_ex(struct Curl_easy *data, const struct curltime *nowp,
- timediff_t milli, expire_id id);
-
-#if defined( DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-static const char * const multi_statename[]={
- "INIT",
- "PENDING",
- "SETUP",
- "CONNECT",
- "RESOLVING",
- "CONNECTING",
- "TUNNELING",
- "PROTOCONNECT",
- "PROTOCONNECTING",
- "DO",
- "DOING",
- "DOING_MORE",
- "DID",
- "PERFORMING",
- "RATELIMITING",
- "DONE",
- "COMPLETED",
- "MSGSENT",
-};
-#endif
/* function pointer called once when switching TO a state */
typedef void (*init_multistate_func)(struct Curl_easy *data);
@@ -179,26 +153,18 @@ static void mstate(struct Curl_easy *data, CURLMstate state
NULL /* MSGSENT */
};
-#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);
- }
+#ifdef DEBUGBUILD
+ CURL_TRC_M(data, "-> [%s] (line %d)", CURL_MSTATE_NAME(state), lineno);
+#else
+ CURL_TRC_M(data, "-> [%s]", CURL_MSTATE_NAME(state));
#endif
+ data->mstate = state;
+
if(state == MSTATE_COMPLETED) {
/* changing to COMPLETED means there is one less easy handle 'alive' */
DEBUGASSERT(data->multi->num_alive > 0);
@@ -220,163 +186,6 @@ static void mstate(struct Curl_easy *data, CURLMstate state
#define multistate(x,y) mstate(x,y, __LINE__)
#endif
-/*
- * We add one of these structs to the sockhash for each socket
- */
-
-struct Curl_sh_entry {
- struct Curl_hash transfers; /* hash of transfers using this socket */
- unsigned int action; /* what combined action READ/WRITE this socket waits
- for */
- unsigned int users; /* number of transfers using this */
- void *socketp; /* settable by users with curl_multi_assign() */
- unsigned int readers; /* this many transfers want to read */
- unsigned int writers; /* this many transfers want to write */
-};
-
-/* look up a given socket in the socket hash, skip invalid sockets */
-static struct Curl_sh_entry *sh_getentry(struct Curl_hash *sh,
- curl_socket_t s)
-{
- if(s != CURL_SOCKET_BAD) {
- /* only look for proper sockets */
- return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
- }
- return NULL;
-}
-
-#define TRHASH_SIZE 13
-
-/* the given key here is a struct Curl_easy pointer */
-static size_t trhash(void *key, size_t key_length, size_t slots_num)
-{
- unsigned char bytes = ((unsigned char *)key)[key_length - 1] ^
- ((unsigned char *)key)[0];
- return (bytes % slots_num);
-}
-
-static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
-{
- (void)k2_len;
- return !memcmp(k1, k2, k1_len);
-}
-
-static void trhash_dtor(void *nada)
-{
- (void)nada;
-}
-
-/*
- * The sockhash has its own separate subhash in each entry that need to be
- * safely destroyed first.
- */
-static void sockhash_destroy(struct Curl_hash *h)
-{
- struct Curl_hash_iterator iter;
- struct Curl_hash_element *he;
-
- DEBUGASSERT(h);
- Curl_hash_start_iterate(h, &iter);
- he = Curl_hash_next_element(&iter);
- while(he) {
- struct Curl_sh_entry *sh = (struct Curl_sh_entry *)he->ptr;
- Curl_hash_destroy(&sh->transfers);
- he = Curl_hash_next_element(&iter);
- }
- Curl_hash_destroy(h);
-}
-
-
-/* make sure this socket is present in the hash for this handle */
-static struct Curl_sh_entry *sh_addentry(struct Curl_hash *sh,
- curl_socket_t s)
-{
- struct Curl_sh_entry *there = sh_getentry(sh, s);
- struct Curl_sh_entry *check;
-
- if(there) {
- /* it is present, return fine */
- return there;
- }
-
- /* not present, add it */
- check = calloc(1, sizeof(struct Curl_sh_entry));
- if(!check)
- return NULL; /* major failure */
-
- Curl_hash_init(&check->transfers, TRHASH_SIZE, trhash, trhash_compare,
- trhash_dtor);
-
- /* make/add new hash entry */
- if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
- Curl_hash_destroy(&check->transfers);
- free(check);
- return NULL; /* major failure */
- }
-
- return check; /* things are good in sockhash land */
-}
-
-
-/* delete the given socket + handle from the hash */
-static void sh_delentry(struct Curl_sh_entry *entry,
- struct Curl_hash *sh, curl_socket_t s)
-{
- Curl_hash_destroy(&entry->transfers);
-
- /* We remove the hash entry. This will end up in a call to
- sh_freeentry(). */
- Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
-}
-
-/*
- * free a sockhash entry
- */
-static void sh_freeentry(void *freethis)
-{
- struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
-
- free(p);
-}
-
-static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
-{
- (void) k1_len; (void) k2_len;
-
- return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
-}
-
-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 */
@@ -400,7 +209,7 @@ static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg)
Curl_llist_append(&multi->msglist, msg, &msg->list);
}
-struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
+struct Curl_multi *Curl_multi_handle(size_t ev_hashsize, /* event hash */
size_t chashsize, /* connection hash */
size_t dnssize, /* dns hash */
size_t sesssize) /* TLS session cache */
@@ -413,14 +222,27 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
multi->magic = CURL_MULTI_HANDLE;
Curl_init_dnscache(&multi->hostcache, dnssize);
-
- sh_init(&multi->sockhash, hashsize);
+ Curl_multi_ev_init(multi, ev_hashsize);
Curl_hash_init(&multi->proto_hash, 23,
Curl_hash_str, Curl_str_key_compare, ph_freeentry);
- if(Curl_cpool_init(&multi->cpool, Curl_on_disconnect,
- multi, NULL, chashsize))
+ multi->admin = curl_easy_init();
+ if(!multi->admin)
+ goto error;
+ /* Initialize admin handle to operate inside this multi */
+ multi->admin->multi = multi;
+ multi->admin->state.internal = TRUE;
+ Curl_llist_init(&multi->admin->state.timeoutlist, NULL);
+#ifdef DEBUGBUILD
+ if(getenv("CURL_DEBUG"))
+ multi->admin->set.verbose = TRUE;
+#endif
+
+ if(Curl_cshutdn_init(&multi->cshutdn, multi))
+ goto error;
+
+ if(Curl_cpool_init(&multi->cpool, multi->admin, NULL, chashsize))
goto error;
if(Curl_ssl_scache_create(sesssize, 2, &multi->ssl_scache))
@@ -452,11 +274,17 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
error:
- sockhash_destroy(&multi->sockhash);
+ Curl_multi_ev_cleanup(multi);
Curl_hash_destroy(&multi->proto_hash);
Curl_hash_destroy(&multi->hostcache);
Curl_cpool_destroy(&multi->cpool);
+ Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
Curl_ssl_scache_destroy(multi->ssl_scache);
+ if(multi->admin) {
+ multi->admin->multi = NULL;
+ Curl_close(&multi->admin);
+ }
+
free(multi);
return NULL;
}
@@ -588,6 +416,16 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d)
Curl_cpool_xfer_init(data);
multi_warn_debug(multi, data);
+ /* The admin handle only ever has default timeouts set. To improve the
+ state somewhat we clone the timeouts from each added handle so that the
+ admin handle always has the same timeouts as the most recently added
+ easy handle. */
+ multi->admin->set.timeout = data->set.timeout;
+ multi->admin->set.server_response_timeout =
+ data->set.server_response_timeout;
+ multi->admin->set.no_signal = data->set.no_signal;
+
+ CURL_TRC_M(data, "added, transfers=%u", multi->num_easy);
return CURLM_OK;
}
@@ -621,9 +459,8 @@ static void multi_done_locked(struct connectdata *conn,
if(CONN_INUSE(conn)) {
/* Stop if still used. */
- DEBUGF(infof(data, "Connection still in use %zu, "
- "no more multi_done now!",
- Curl_llist_count(&conn->easyq)));
+ CURL_TRC_M(data, "Connection still in use %zu, no more multi_done now!",
+ Curl_llist_count(&conn->easyq));
return;
}
@@ -660,14 +497,14 @@ static void multi_done_locked(struct connectdata *conn,
#endif
) || conn->bits.close
|| (mdctx->premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
- DEBUGF(infof(data, "multi_done, not reusing connection=%"
- FMT_OFF_T ", forbid=%d"
- ", close=%d, premature=%d, conn_multiplex=%d",
- conn->connection_id, data->set.reuse_forbid,
- conn->bits.close, mdctx->premature,
- Curl_conn_is_multiplex(conn, FIRSTSOCKET)));
+ CURL_TRC_M(data, "multi_done, not reusing connection=%"
+ FMT_OFF_T ", forbid=%d"
+ ", close=%d, premature=%d, conn_multiplex=%d",
+ conn->connection_id, data->set.reuse_forbid,
+ conn->bits.close, mdctx->premature,
+ Curl_conn_is_multiplex(conn, FIRSTSOCKET));
connclose(conn, "disconnecting");
- Curl_cpool_disconnect(data, conn, mdctx->premature);
+ Curl_conn_terminate(data, conn, mdctx->premature);
}
else {
/* the connection is no longer in use by any transfer */
@@ -703,14 +540,8 @@ static CURLcode multi_done(struct Curl_easy *data,
memset(&mdctx, 0, sizeof(mdctx));
-#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d",
- multi_statename[data->mstate],
- (int)status, (int)premature, data->state.done));
-#else
- DEBUGF(infof(data, "multi_done: status: %d prem: %d done: %d",
- (int)status, (int)premature, data->state.done));
-#endif
+ CURL_TRC_M(data, "multi_done: status: %d prem: %d done: %d",
+ (int)status, (int)premature, data->state.done);
if(data->state.done)
/* Stop if multi_done() has already been called */
@@ -738,7 +569,7 @@ static CURLcode multi_done(struct Curl_easy *data,
}
/* this calls the protocol-specific function pointer previously set */
- if(conn->handler->done)
+ if(conn->handler->done && (data->mstate >= MSTATE_PROTOCONNECT))
result = conn->handler->done(data, status, premature);
else
result = status;
@@ -861,18 +692,14 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
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, data); /* 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);
+ /* Tell event handling that this transfer is definitely going away */
+ Curl_multi_ev_xfer_done(multi, 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
@@ -886,7 +713,7 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
curl_socket_t s;
s = Curl_getconnectinfo(data, &c);
if((s != CURL_SOCKET_BAD) && c) {
- Curl_cpool_disconnect(data, c, TRUE);
+ Curl_conn_terminate(data, c, TRUE);
}
}
@@ -927,6 +754,8 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d)
if(rc)
return rc;
}
+
+ CURL_TRC_M(data, "removed, transfers=%u", multi->num_easy);
return CURLM_OK;
}
@@ -1068,13 +897,15 @@ static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
/* 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)
+void Curl_multi_getsock(struct Curl_easy *data,
+ struct easy_pollset *ps,
+ const char *caller)
{
bool expect_sockets = TRUE;
- /* The no connection case can happen when this is called from
- curl_multi_remove_handle() => singlesocket() => multi_getsock().
- */
+
+ /* If the transfer has no connection, this is fine. Happens when
+ called via curl_multi_remove_handle() => Curl_multi_ev_assess() =>
+ Curl_multi_getsock(). */
Curl_pollset_reset(data, ps);
if(!data->conn)
return;
@@ -1098,30 +929,30 @@ static void multi_getsock(struct Curl_easy *data,
case MSTATE_CONNECTING:
case MSTATE_TUNNELING:
Curl_pollset_add_socks(data, ps, connecting_getsock);
- Curl_conn_adjust_pollset(data, ps);
+ Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_PROTOCONNECT:
case MSTATE_PROTOCONNECTING:
Curl_pollset_add_socks(data, ps, protocol_getsock);
- Curl_conn_adjust_pollset(data, ps);
+ Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_DO:
case MSTATE_DOING:
Curl_pollset_add_socks(data, ps, doing_getsock);
- Curl_conn_adjust_pollset(data, ps);
+ Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_DOING_MORE:
Curl_pollset_add_socks(data, ps, domore_getsock);
- Curl_conn_adjust_pollset(data, ps);
+ Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_DID: /* same as PERFORMING in regard to polling */
case MSTATE_PERFORMING:
Curl_pollset_add_socks(data, ps, perform_getsock);
- Curl_conn_adjust_pollset(data, ps);
+ Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_RATELIMITING:
@@ -1143,6 +974,35 @@ static void multi_getsock(struct Curl_easy *data,
break;
}
+ switch(ps->num) {
+ case 0:
+ CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)",
+ caller, Curl_llist_count(&data->state.timeoutlist),
+ Curl_creader_is_paused(data), Curl_cwriter_is_paused(data));
+ break;
+ case 1:
+ CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu",
+ caller, ps->sockets[0],
+ (ps->actions[0] & CURL_POLL_IN) ? "IN" : "",
+ (ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "",
+ Curl_llist_count(&data->state.timeoutlist));
+ break;
+ case 2:
+ CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s, "
+ "fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu",
+ caller, ps->sockets[0],
+ (ps->actions[0] & CURL_POLL_IN) ? "IN" : "",
+ (ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "",
+ ps->sockets[1],
+ (ps->actions[1] & CURL_POLL_IN) ? "IN" : "",
+ (ps->actions[1] & CURL_POLL_OUT) ? "OUT" : "",
+ Curl_llist_count(&data->state.timeoutlist));
+ break;
+ default:
+ CURL_TRC_M(data, "%s pollset[fds=%u], timeouts=%zu",
+ caller, ps->num, Curl_llist_count(&data->state.timeoutlist));
+ break;
+ }
if(expect_sockets && !ps->num &&
!Curl_llist_count(&data->state.timeoutlist) &&
!Curl_cwriter_is_paused(data) && !Curl_creader_is_paused(data) &&
@@ -1177,30 +1037,32 @@ CURLMcode curl_multi_fdset(CURLM *m,
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
+ struct easy_pollset ps;
- multi_getsock(data, &data->last_poll);
+ Curl_multi_getsock(data, &ps, "curl_multi_fdset");
- for(i = 0; i < data->last_poll.num; i++) {
- if(!FDSET_SOCK(data->last_poll.sockets[i]))
+ for(i = 0; i < ps.num; i++) {
+ if(!FDSET_SOCK(ps.sockets[i]))
/* pretend it does not exist */
continue;
#if defined(__DJGPP__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warith-conversion"
#endif
- if(data->last_poll.actions[i] & CURL_POLL_IN)
- FD_SET(data->last_poll.sockets[i], read_fd_set);
- if(data->last_poll.actions[i] & CURL_POLL_OUT)
- FD_SET(data->last_poll.sockets[i], write_fd_set);
+ 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 defined(__DJGPP__)
#pragma GCC diagnostic pop
#endif
- if((int)data->last_poll.sockets[i] > this_max_fd)
- this_max_fd = (int)data->last_poll.sockets[i];
+ if((int)ps.sockets[i] > this_max_fd)
+ this_max_fd = (int)ps.sockets[i];
}
}
- Curl_cpool_setfds(&multi->cpool, read_fd_set, write_fd_set, &this_max_fd);
+ Curl_cshutdn_setfds(&multi->cshutdn, multi->admin,
+ read_fd_set, write_fd_set, &this_max_fd);
*max_fd = this_max_fd;
@@ -1230,11 +1092,13 @@ CURLMcode curl_multi_waitfds(CURLM *m,
Curl_waitfds_init(&cwfds, ufds, size);
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
- multi_getsock(data, &data->last_poll);
- need += Curl_waitfds_add_ps(&cwfds, &data->last_poll);
+ struct easy_pollset ps;
+
+ Curl_multi_getsock(data, &ps, "curl_multi_waitfds");
+ need += Curl_waitfds_add_ps(&cwfds, &ps);
}
- need += Curl_cpool_add_waitfds(&multi->cpool, &cwfds);
+ need += Curl_cshutdn_add_waitfds(&multi->cshutdn, multi->admin, &cwfds);
if(need != cwfds.n && ufds) {
result = CURLM_OUT_OF_MEMORY;
@@ -1303,15 +1167,16 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
/* Add the curl handles to our pollfds first */
for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
struct Curl_easy *data = Curl_node_elem(e);
+ struct easy_pollset ps;
- multi_getsock(data, &data->last_poll);
- if(Curl_pollfds_add_ps(&cpfds, &data->last_poll)) {
+ Curl_multi_getsock(data, &ps, "multi_wait");
+ if(Curl_pollfds_add_ps(&cpfds, &ps)) {
result = CURLM_OUT_OF_MEMORY;
goto out;
}
}
- if(Curl_cpool_add_pollfds(&multi->cpool, &cpfds)) {
+ if(Curl_cshutdn_add_pollfds(&multi->cshutdn, multi->admin, &cpfds)) {
result = CURLM_OUT_OF_MEMORY;
goto out;
}
@@ -1440,23 +1305,14 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#ifdef USE_WINSOCK
/* Count up all our own sockets that had activity,
and remove them from the event. */
- if(curl_nfds) {
- for(e = Curl_llist_head(&multi->process); e && !result;
- e = Curl_node_next(e)) {
- struct Curl_easy *data = Curl_node_elem(e);
-
- for(i = 0; i < data->last_poll.num; i++) {
- wsa_events.lNetworkEvents = 0;
- if(WSAEnumNetworkEvents(data->last_poll.sockets[i], NULL,
- &wsa_events) == 0) {
- if(ret && !pollrc && wsa_events.lNetworkEvents)
- retcode++;
- }
- WSAEventSelect(data->last_poll.sockets[i], multi->wsa_event, 0);
- }
+ for(i = 0; i < curl_nfds; ++i) {
+ wsa_events.lNetworkEvents = 0;
+ if(WSAEnumNetworkEvents(cpfds.pfds[i].fd, NULL, &wsa_events) == 0) {
+ if(ret && !pollrc && wsa_events.lNetworkEvents)
+ retcode++;
}
+ WSAEventSelect(cpfds.pfds[i].fd, multi->wsa_event, 0);
}
-
WSAResetEvent(multi->wsa_event);
#else
#ifdef ENABLE_WAKEUP
@@ -1471,7 +1327,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
when there is no more data, breaking the loop. */
nread = wakeup_read(multi->wakeup_pair[0], buf, sizeof(buf));
if(nread <= 0) {
- if(nread < 0 && EINTR == SOCKERRNO)
+ if(nread < 0 && SOCKEINTR == SOCKERRNO)
continue;
break;
}
@@ -1552,7 +1408,7 @@ CURLMcode curl_multi_wakeup(CURLM *m)
and before cleanup */
if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
while(1) {
-#ifdef USE_EVENTFD
+#ifdef HAVE_EVENTFD
/* eventfd has a stringent rule of requiring the 8-byte buffer when
calling write(2) on it */
const uint64_t buf[1] = { 1 };
@@ -1572,11 +1428,11 @@ CURLMcode curl_multi_wakeup(CURLM *m)
int err = SOCKERRNO;
int return_success;
#ifdef USE_WINSOCK
- return_success = WSAEWOULDBLOCK == err;
+ return_success = SOCKEWOULDBLOCK == err;
#else
- if(EINTR == err)
+ if(SOCKEINTR == err)
continue;
- return_success = EWOULDBLOCK == err || EAGAIN == err;
+ return_success = SOCKEWOULDBLOCK == err || EAGAIN == err;
#endif
if(!return_success)
return CURLM_WAKEUP_FAILURE;
@@ -1910,6 +1766,7 @@ static CURLMcode state_performing(struct Curl_easy *data,
data->req.done = TRUE;
}
}
+#ifndef CURL_DISABLE_HTTP
else if((CURLE_HTTP2_STREAM == result) &&
Curl_h2_http_1_1_error(data)) {
CURLcode ret = Curl_retry_request(data, &newurl);
@@ -1917,7 +1774,8 @@ static CURLMcode state_performing(struct Curl_easy *data,
if(!ret) {
infof(data, "Downgrades to HTTP/1.1");
streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
- data->state.httpwant = CURL_HTTP_VERSION_1_1;
+ data->state.http_neg.wanted = CURL_HTTP_V1x;
+ data->state.http_neg.allowed = CURL_HTTP_V1x;
/* clear the error message bit too as we ignore the one we got */
data->state.errorbuf = FALSE;
if(!newurl)
@@ -1932,6 +1790,7 @@ static CURLMcode state_performing(struct Curl_easy *data,
else
result = ret;
}
+#endif
if(result) {
/*
@@ -2227,7 +2086,7 @@ static CURLMcode state_resolving(struct Curl_multi *multi,
dns = Curl_fetch_addr(data, hostname, conn->primary.remote_port);
if(dns) {
-#ifdef CURLRES_ASYNCH
+#ifdef USE_CURL_ASYNC
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
@@ -2243,7 +2102,7 @@ static CURLMcode state_resolving(struct Curl_multi *multi,
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);
+ rc = Curl_multi_ev_assess_xfer(multi, data);
if(rc)
return rc;
@@ -2362,7 +2221,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_OK;
if(multi_ischanged(multi, TRUE)) {
- DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue"));
+ CURL_TRC_M(data, "multi changed, check CONNECT_PEND queue");
process_pending_handles(multi); /* multiplexed */
}
@@ -2618,7 +2477,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case MSTATE_PENDING:
case MSTATE_MSGSENT:
/* handles in these states should NOT be in this list */
- DEBUGASSERT(0);
break;
default:
@@ -2663,7 +2521,7 @@ statemachine_end:
We do not have to do this in every case block above where a
failure is detected */
Curl_detach_connection(data);
- Curl_cpool_disconnect(data, conn, dead_connection);
+ Curl_conn_terminate(data, conn, dead_connection);
}
}
else if(data->mstate == MSTATE_CONNECT) {
@@ -2728,6 +2586,7 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
struct Curl_llist_node *e;
struct Curl_llist_node *n = NULL;
struct Curl_multi *multi = m;
+ bool first = TRUE;
SIGPIPE_VARIABLE(pipe_st);
if(!GOOD_MULTI_HANDLE(multi))
@@ -2740,24 +2599,35 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
for(e = Curl_llist_head(&multi->process); e; e = n) {
struct Curl_easy *data = Curl_node_elem(e);
CURLMcode result;
+ unsigned int num_alive = multi->num_alive;
/* Do the loop and only alter the signal ignore state if the next handle
has a different NO_SIGNAL state than the previous */
+ if(first) {
+ CURL_TRC_M(data, "multi_perform(running=%u)", multi->num_alive);
+ first = FALSE;
+ }
/* the current node might be unlinked in multi_runsingle(), get the next
pointer now */
n = Curl_node_next(e);
- if(data != multi->cpool.idata) {
+ if(data && data != multi->admin) {
/* connection pool handle is processed below */
sigpipe_apply(data, &pipe_st);
result = multi_runsingle(multi, &now, data);
if(result)
returncode = result;
}
+ if(num_alive != multi->num_alive)
+ /* Since more than one handle can be removed in a single call to
+ multi_runsingle(), we cannot easily continue on the next node when a
+ node has been removed since that node might ALSO have been
+ removed. */
+ n = Curl_llist_head(&multi->process);
}
- sigpipe_apply(multi->cpool.idata, &pipe_st);
- Curl_cpool_multi_perform(multi);
+ sigpipe_apply(multi->admin, &pipe_st);
+ Curl_cshutdn_perform(&multi->cshutdn, multi->admin, CURL_SOCKET_TIMEOUT);
sigpipe_restore(&pipe_st);
if(multi_ischanged(m, TRUE))
@@ -2804,8 +2674,10 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles)
static void unlink_all_msgsent_handles(struct Curl_multi *multi)
{
struct Curl_llist_node *e;
- for(e = Curl_llist_head(&multi->msgsent); e; e = Curl_node_next(e)) {
+ struct Curl_llist_node *n;
+ for(e = Curl_llist_head(&multi->msgsent); e; e = n) {
struct Curl_easy *data = Curl_node_elem(e);
+ n = Curl_node_next(e);
if(data) {
DEBUGASSERT(data->mstate == MSTATE_MSGSENT);
Curl_node_remove(&data->multi_queue);
@@ -2853,13 +2725,19 @@ CURLMcode curl_multi_cleanup(CURLM *m)
if(data->psl == &multi->psl)
data->psl = NULL;
#endif
+ if(data->state.internal)
+ Curl_close(&data);
}
-
Curl_cpool_destroy(&multi->cpool);
+ Curl_cshutdn_destroy(&multi->cshutdn, multi->admin);
+ if(multi->admin) {
+ multi->admin->multi = NULL;
+ Curl_close(&multi->admin);
+ }
multi->magic = 0; /* not good anymore */
- sockhash_destroy(&multi->sockhash);
+ Curl_multi_ev_cleanup(multi);
Curl_hash_destroy(&multi->proto_hash);
Curl_hash_destroy(&multi->hostcache);
Curl_psl_destroy(&multi->psl);
@@ -2870,7 +2748,7 @@ CURLMcode curl_multi_cleanup(CURLM *m)
#else
#ifdef ENABLE_WAKEUP
wakeup_close(multi->wakeup_pair[0]);
-#ifndef USE_EVENTFD
+#ifndef HAVE_EVENTFD
wakeup_close(multi->wakeup_pair[1]);
#endif
#endif
@@ -2922,233 +2800,14 @@ CURLMsg *curl_multi_info_read(CURLM *m, int *msgs_in_queue)
return NULL;
}
-/*
- * singlesocket() checks what sockets we deal with and their "action state"
- * 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) {
- DEBUGASSERT(entry->readers);
- entry->readers--;
- }
- if(last_action & CURL_POLL_OUT) {
- DEBUGASSERT(entry->writers);
- 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 *))) {
- DEBUGASSERT(entry->users < 100000); /* detect weird values */
- /* 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;
- }
- }
-
- comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
- (entry->readers ? CURL_POLL_IN : 0);
-
- /* socket existed before and has the same action set as before */
- if(last_action && ((int)entry->action == comboaction))
- /* same, continue */
- continue;
-
- if(multi->socket_cb) {
- set_in_callback(multi, TRUE);
- rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
- entry->socketp);
-
- 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 */
- DEBUGASSERT(entry->users);
- entry->users--;
- if(oldactions & CURL_POLL_OUT)
- entry->writers--;
- if(oldactions & CURL_POLL_IN)
- entry->readers--;
- if(!entry->users) {
- bool dead = FALSE;
- if(multi->socket_cb) {
- set_in_callback(multi, TRUE);
- rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
- multi->socket_userp, entry->socketp);
- set_in_callback(multi, FALSE);
- if(rc == -1)
- dead = TRUE;
- }
- sh_delentry(entry, &multi->sockhash, s);
- if(dead) {
- multi->dead = TRUE;
- return CURLM_ABORTED_BY_CALLBACK;
- }
- }
- else {
- /* still users, but remove this handle as a user of this socket */
- if(Curl_hash_delete(&entry->transfers, (char *)&data,
- 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)
+void Curl_multi_will_close(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;
- DEBUGF(infof(data, "Curl_multi_closed, fd=%" FMT_SOCKET_T
- " multi is %p", s, (void *)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);
-
- DEBUGF(infof(data, "Curl_multi_closed, fd=%" FMT_SOCKET_T
- " entry is %p", s, (void *)entry));
- if(entry) {
- int rc = 0;
- if(multi->socket_cb) {
- set_in_callback(multi, TRUE);
- rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
- multi->socket_userp, entry->socketp);
- set_in_callback(multi, FALSE);
- }
-
- /* now remove it from the socket hash */
- sh_delentry(entry, &multi->sockhash, s);
- if(rc == -1)
- /* This just marks the multi handle as "dead" without returning an
- error code primarily because this function is used from many
- places where propagating an error back is tricky. */
- multi->dead = TRUE;
- }
+ CURL_TRC_M(data, "Curl_multi_will_close fd=%" FMT_SOCKET_T, s);
+ Curl_multi_ev_socket_done(multi, data, s);
}
}
}
@@ -3240,7 +2899,7 @@ static CURLMcode multi_run_expired(struct multi_run_ctx *mrc)
continue;
(void)add_next_timeout(mrc->now, multi, data);
- if(data == multi->cpool.idata) {
+ if(data == multi->admin) {
mrc->run_cpool = TRUE;
continue;
}
@@ -3250,9 +2909,8 @@ static CURLMcode multi_run_expired(struct multi_run_ctx *mrc)
result = multi_runsingle(multi, &mrc->now, data);
if(CURLM_OK >= result) {
- /* get the socket(s) and check if the state has been changed since
- last */
- result = singlesocket(multi, data);
+ /* reassess event handling of data */
+ result = Curl_multi_ev_assess_xfer(multi, data);
if(result)
goto out;
}
@@ -3268,7 +2926,6 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
int *running_handles)
{
CURLMcode result = CURLM_OK;
- struct Curl_easy *data = NULL;
struct multi_run_ctx mrc;
(void)ev_bitmask;
@@ -3278,56 +2935,19 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
sigpipe_init(&mrc.pipe_st);
if(checkall) {
- struct Curl_llist_node *e;
/* *perform() deals with running_handles on its own */
result = curl_multi_perform(multi, running_handles);
- /* walk through each easy handle and do the socket state change magic
- and callbacks */
if(result != CURLM_BAD_HANDLE) {
- for(e = Curl_llist_head(&multi->process); e && !result;
- e = Curl_node_next(e)) {
- result = singlesocket(multi, Curl_node_elem(e));
- }
+ /* Reassess event status of all active transfers */
+ result = Curl_multi_ev_assess_xfer_list(multi, &multi->process);
}
mrc.run_cpool = TRUE;
goto out;
}
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 connection pool. */
- Curl_cpool_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 == multi->cpool.idata)
- mrc.run_cpool = TRUE;
- else {
- /* Expire with out current now, so we will get it below when
- * asking the splaytree for expired transfers. */
- expire_ex(data, &mrc.now, 0, EXPIRE_RUN_NOW);
- }
- }
- }
+ Curl_multi_ev_expire_xfers(multi, s, &mrc.now, &mrc.run_cpool);
}
else {
/* Asked to run due to time-out. Clear the 'last_expire_ts' variable to
@@ -3336,6 +2956,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
handles the case when the application asks libcurl to run the timeout
prematurely. */
memset(&multi->last_expire_ts, 0, sizeof(multi->last_expire_ts));
+ mrc.run_cpool = TRUE;
}
result = multi_run_expired(&mrc);
@@ -3354,8 +2975,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
out:
if(mrc.run_cpool) {
- sigpipe_apply(multi->cpool.idata, &mrc.pipe_st);
- Curl_cpool_multi_perform(multi);
+ sigpipe_apply(multi->admin, &mrc.pipe_st);
+ Curl_cshutdn_perform(&multi->cshutdn, multi->admin, s);
}
sigpipe_restore(&mrc.pipe_st);
@@ -3672,9 +3293,9 @@ multi_addtimeout(struct Curl_easy *data,
return CURLM_OK;
}
-static void expire_ex(struct Curl_easy *data,
- const struct curltime *nowp,
- timediff_t milli, expire_id id)
+void Curl_expire_ex(struct Curl_easy *data,
+ const struct curltime *nowp,
+ timediff_t milli, expire_id id)
{
struct Curl_multi *multi = data->multi;
struct curltime *curr_expire = &data->state.expiretime;
@@ -3746,7 +3367,7 @@ static void expire_ex(struct Curl_easy *data,
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
{
struct curltime now = Curl_now();
- expire_ex(data, &now, milli, id);
+ Curl_expire_ex(data, &now, milli, id);
}
/*
@@ -3790,9 +3411,7 @@ bool Curl_expire_clear(struct Curl_easy *data)
/* clear the timeout list too */
Curl_llist_destroy(list, NULL);
-#ifdef DEBUGBUILD
- infof(data, "Expire cleared");
-#endif
+ CURL_TRC_M(data, "Expire cleared");
nowp->tv_sec = 0;
nowp->tv_usec = 0;
return TRUE;
@@ -3803,19 +3422,11 @@ bool Curl_expire_clear(struct Curl_easy *data)
CURLMcode curl_multi_assign(CURLM *m, curl_socket_t s,
void *hashp)
{
- struct Curl_sh_entry *there = NULL;
struct Curl_multi *multi = m;
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
- there = sh_getentry(&multi->sockhash, s);
-
- if(!there)
- return CURLM_BAD_SOCKET;
-
- there->socketp = hashp;
-
- return CURLM_OK;
+ return Curl_multi_ev_assign(multi, s, hashp);
}
static void move_pending_to_connect(struct Curl_multi *multi,
diff --git a/libs/libcurl/src/multi_ev.c b/libs/libcurl/src/multi_ev.c
new file mode 100644
index 0000000000..541bc0a739
--- /dev/null
+++ b/libs/libcurl/src/multi_ev.c
@@ -0,0 +1,621 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "cfilters.h"
+#include "curl_trc.h"
+#include "multiif.h"
+#include "timeval.h"
+#include "multi_ev.h"
+#include "select.h"
+#include "warnless.h"
+#include "multihandle.h"
+#include "socks.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+static void mev_in_callback(struct Curl_multi *multi, bool value)
+{
+ multi->in_callback = value;
+}
+
+#define CURL_MEV_XFER_HASH_SIZE 13
+#define CURL_MEV_CONN_HASH_SIZE 3
+
+/* Information about a socket for which we inform the libcurl application
+ * what to supervise (CURL_POLL_IN/CURL_POLL_OUT/CURL_POLL_REMOVE)
+ */
+struct mev_sh_entry {
+ struct Curl_hash_offt xfers; /* hash of transfers using this socket */
+ struct Curl_hash_offt conns; /* hash of connections using this socket */
+ void *user_data; /* libcurl app data via curl_multi_assign() */
+ unsigned int action; /* CURL_POLL_IN/CURL_POLL_OUT we last told the
+ * libcurl application to watch out for */
+ unsigned int readers; /* this many transfers want to read */
+ unsigned int writers; /* this many transfers want to write */
+};
+
+static size_t mev_sh_entry_hash(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);
+}
+
+static size_t mev_sh_entry_compare(void *k1, size_t k1_len,
+ void *k2, size_t k2_len)
+{
+ (void) k1_len; (void) k2_len;
+ return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
+}
+
+/* sockhash entry destructor callback */
+static void mev_sh_entry_dtor(void *freethis)
+{
+ struct mev_sh_entry *entry = (struct mev_sh_entry *)freethis;
+ Curl_hash_offt_destroy(&entry->xfers);
+ Curl_hash_offt_destroy(&entry->conns);
+ free(entry);
+}
+
+/* look up a given socket in the socket hash, skip invalid sockets */
+static struct mev_sh_entry *
+mev_sh_entry_get(struct Curl_hash *sh, curl_socket_t s)
+{
+ if(s != CURL_SOCKET_BAD) {
+ /* only look for proper sockets */
+ return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+ }
+ return NULL;
+}
+
+/* make sure this socket is present in the hash for this handle */
+static struct mev_sh_entry *
+mev_sh_entry_add(struct Curl_hash *sh, curl_socket_t s)
+{
+ struct mev_sh_entry *there = mev_sh_entry_get(sh, s);
+ struct mev_sh_entry *check;
+
+ if(there) {
+ /* it is present, return fine */
+ return there;
+ }
+
+ /* not present, add it */
+ check = calloc(1, sizeof(struct mev_sh_entry));
+ if(!check)
+ return NULL; /* major failure */
+
+ Curl_hash_offt_init(&check->xfers, CURL_MEV_XFER_HASH_SIZE, NULL);
+ Curl_hash_offt_init(&check->conns, CURL_MEV_CONN_HASH_SIZE, NULL);
+
+ /* make/add new hash entry */
+ if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
+ mev_sh_entry_dtor(check);
+ return NULL; /* major failure */
+ }
+
+ return check; /* things are good in sockhash land */
+}
+
+/* delete the given socket entry from the hash */
+static void mev_sh_entry_kill(struct Curl_multi *multi, curl_socket_t s)
+{
+ Curl_hash_delete(&multi->ev.sh_entries, (char *)&s, sizeof(curl_socket_t));
+}
+
+static size_t mev_sh_entry_user_count(struct mev_sh_entry *e)
+{
+ return Curl_hash_offt_count(&e->xfers) + Curl_hash_offt_count(&e->conns);
+}
+
+static bool mev_sh_entry_xfer_known(struct mev_sh_entry *e,
+ struct Curl_easy *data)
+{
+ return !!Curl_hash_offt_get(&e->xfers, data->mid);
+}
+
+static bool mev_sh_entry_conn_known(struct mev_sh_entry *e,
+ struct connectdata *conn)
+{
+ return !!Curl_hash_offt_get(&e->conns, conn->connection_id);
+}
+
+static bool mev_sh_entry_xfer_add(struct mev_sh_entry *e,
+ struct Curl_easy *data)
+{
+ /* detect weird values */
+ DEBUGASSERT(mev_sh_entry_user_count(e) < 100000);
+ return !!Curl_hash_offt_set(&e->xfers, data->mid, data);
+}
+
+static bool mev_sh_entry_conn_add(struct mev_sh_entry *e,
+ struct connectdata *conn)
+{
+ /* detect weird values */
+ DEBUGASSERT(mev_sh_entry_user_count(e) < 100000);
+ return !!Curl_hash_offt_set(&e->conns, conn->connection_id, conn);
+}
+
+
+static bool mev_sh_entry_xfer_remove(struct mev_sh_entry *e,
+ struct Curl_easy *data)
+{
+ return Curl_hash_offt_remove(&e->xfers, data->mid);
+}
+
+static bool mev_sh_entry_conn_remove(struct mev_sh_entry *e,
+ struct connectdata *conn)
+{
+ return Curl_hash_offt_remove(&e->conns, conn->connection_id);
+}
+
+/* Purge any information about socket `s`.
+ * Let the socket callback know as well when necessary */
+static CURLMcode mev_forget_socket(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ curl_socket_t s,
+ const char *cause)
+{
+ struct mev_sh_entry *entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
+ int rc = 0;
+
+ if(!entry) /* we never knew or already forgot about this socket */
+ return CURLM_OK;
+
+ /* We managed this socket before, tell the socket callback to forget it. */
+ if(multi->socket_cb) {
+ CURL_TRC_M(data, "ev %s, call(fd=%" FMT_SOCKET_T ", ev=REMOVE)",
+ cause, s);
+ mev_in_callback(multi, TRUE);
+ rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
+ multi->socket_userp, entry->user_data);
+ mev_in_callback(multi, FALSE);
+ }
+
+ mev_sh_entry_kill(multi, s);
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
+ }
+ return CURLM_OK;
+}
+
+static CURLMcode mev_sh_entry_update(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct mev_sh_entry *entry,
+ curl_socket_t s,
+ unsigned char last_action,
+ unsigned char cur_action)
+{
+ int rc, comboaction;
+
+ /* we should only be called when the callback exists */
+ DEBUGASSERT(multi->socket_cb);
+ if(!multi->socket_cb)
+ return CURLM_OK;
+
+ /* Transfer `data` goes from `last_action` to `cur_action` on socket `s`
+ * with `multi->ev.sh_entries` entry `entry`. Update `entry` and trigger
+ * `multi->socket_cb` on change, if the callback is set. */
+ if(last_action == cur_action) /* nothing from `data` changed */
+ return CURLM_OK;
+
+ if(last_action & CURL_POLL_IN) {
+ DEBUGASSERT(entry->readers);
+ if(!(cur_action & CURL_POLL_IN))
+ entry->readers--;
+ }
+ else if(cur_action & CURL_POLL_IN)
+ entry->readers++;
+
+ if(last_action & CURL_POLL_OUT) {
+ DEBUGASSERT(entry->writers);
+ if(!(cur_action & CURL_POLL_OUT))
+ entry->writers--;
+ }
+ else if(cur_action & CURL_POLL_OUT)
+ entry->writers++;
+
+ DEBUGASSERT(entry->readers <= mev_sh_entry_user_count(entry));
+ DEBUGASSERT(entry->writers <= mev_sh_entry_user_count(entry));
+ DEBUGASSERT(entry->writers + entry->readers);
+
+ CURL_TRC_M(data, "ev update fd=%" FMT_SOCKET_T ", action '%s%s' -> '%s%s'"
+ " (%d/%d r/w)", s,
+ (last_action & CURL_POLL_IN) ? "IN" : "",
+ (last_action & CURL_POLL_OUT) ? "OUT" : "",
+ (cur_action & CURL_POLL_IN) ? "IN" : "",
+ (cur_action & CURL_POLL_OUT) ? "OUT" : "",
+ entry->readers, entry->writers);
+
+ comboaction = (entry->writers ? CURL_POLL_OUT : 0) |
+ (entry->readers ? CURL_POLL_IN : 0);
+ if(((int)entry->action == comboaction)) /* nothing for socket changed */
+ return CURLM_OK;
+
+ CURL_TRC_M(data, "ev update call(fd=%" FMT_SOCKET_T ", ev=%s%s)",
+ s, (comboaction & CURL_POLL_IN) ? "IN" : "",
+ (comboaction & CURL_POLL_OUT) ? "OUT" : "");
+ mev_in_callback(multi, TRUE);
+ rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
+ entry->user_data);
+
+ mev_in_callback(multi, FALSE);
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
+ }
+ entry->action = (unsigned int)comboaction;
+ return CURLM_OK;
+}
+
+static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn,
+ struct easy_pollset *ps,
+ struct easy_pollset *prev_ps)
+{
+ struct mev_sh_entry *entry;
+ curl_socket_t s;
+ unsigned int i, j;
+ CURLMcode mresult;
+
+ /* The transfer `data` reports in `ps` the sockets it is interested
+ * in and which combinatino of CURL_POLL_IN/CURL_POLL_OUT it wants
+ * to have monitored for events.
+ * There can be more than 1 transfer interested in the same socket
+ * and 1 transfer might be interested in more than 1 socket.
+ * `prev_ps` is the pollset copy from the previous call here. On
+ * the 1st call it will be empty.
+ */
+ DEBUGASSERT(ps);
+ DEBUGASSERT(prev_ps);
+
+ /* Handle changes to sockets the transfer is interested in. */
+ for(i = 0; i < ps->num; i++) {
+ unsigned char last_action;
+ bool first_time = FALSE; /* data/conn appears first time on socket */
+
+ s = ps->sockets[i];
+ /* Have we handled this socket before? */
+ entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
+ if(!entry) {
+ /* new socket, add new entry */
+ first_time = TRUE;
+ entry = mev_sh_entry_add(&multi->ev.sh_entries, s);
+ if(!entry) /* fatal */
+ return CURLM_OUT_OF_MEMORY;
+ CURL_TRC_M(data, "ev new entry fd=%" FMT_SOCKET_T, s);
+ }
+ else if(conn) {
+ first_time = !mev_sh_entry_conn_known(entry, conn);
+ }
+ else {
+ first_time = !mev_sh_entry_xfer_known(entry, data);
+ }
+
+ /* What was the previous action the transfer had regarding this socket?
+ * If the transfer is new to the socket, disregard the information
+ * in `last_poll`, because the socket might have been destroyed and
+ * reopened. We'd have cleared the sh_entry for that, but the socket
+ * might still be mentioned in the hashed pollsets. */
+ last_action = 0;
+ if(first_time) {
+ if(conn) {
+ if(!mev_sh_entry_conn_add(entry, conn))
+ return CURLM_OUT_OF_MEMORY;
+ }
+ else {
+ if(!mev_sh_entry_xfer_add(entry, data))
+ return CURLM_OUT_OF_MEMORY;
+ }
+ CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", added %s #%" FMT_OFF_T
+ ", total=%zu/%zu (xfer/conn)", s,
+ conn ? "connection" : "transfer",
+ conn ? conn->connection_id : data->mid,
+ Curl_hash_offt_count(&entry->xfers),
+ Curl_hash_offt_count(&entry->conns));
+ }
+ else {
+ for(j = 0; j < prev_ps->num; j++) {
+ if(s == prev_ps->sockets[j]) {
+ last_action = prev_ps->actions[j];
+ break;
+ }
+ }
+ }
+ /* track readers/writers changes and report to socket callback */
+ mresult = mev_sh_entry_update(multi, data, entry, s,
+ last_action, ps->actions[i]);
+ if(mresult)
+ return mresult;
+ }
+
+ /* Handle changes to sockets the transfer is NO LONGER interested in. */
+ for(i = 0; i < prev_ps->num; i++) {
+ bool stillused = FALSE;
+
+ s = prev_ps->sockets[i];
+ for(j = 0; j < ps->num; j++) {
+ if(s == ps->sockets[j]) {
+ /* socket is still supervised */
+ stillused = TRUE;
+ break;
+ }
+ }
+ if(stillused)
+ continue;
+
+ entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
+ /* if entry does not exist, we were either never told about it or
+ * have already cleaned up this socket via Curl_multi_ev_socket_done().
+ * In other words: this is perfectly normal */
+ if(!entry)
+ continue;
+
+ if(conn && !mev_sh_entry_conn_remove(entry, conn)) {
+ /* `conn` says in `prev_ps` that it had been using a socket,
+ * but `conn` has not been registered for it.
+ * This should not happen if our book-keeping is correct? */
+ CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", conn lost "
+ "interest but is not registered", s);
+ DEBUGASSERT(NULL);
+ continue;
+ }
+
+ if(!conn && !mev_sh_entry_xfer_remove(entry, data)) {
+ /* `data` says in `prev_ps` that it had been using a socket,
+ * but `data` has not been registered for it.
+ * This should not happen if our book-keeping is correct? */
+ CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", transfer lost "
+ "interest but is not registered", s);
+ DEBUGASSERT(NULL);
+ continue;
+ }
+
+ if(mev_sh_entry_user_count(entry)) {
+ /* track readers/writers changes and report to socket callback */
+ mresult = mev_sh_entry_update(multi, data, entry, s,
+ prev_ps->actions[i], 0);
+ if(mresult)
+ return mresult;
+ CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", removed transfer, "
+ "total=%zu/%zu (xfer/conn)", s,
+ Curl_hash_offt_count(&entry->xfers),
+ Curl_hash_offt_count(&entry->conns));
+ }
+ else {
+ mresult = mev_forget_socket(multi, data, s, "last user gone");
+ if(mresult)
+ return mresult;
+ }
+ } /* for loop over num */
+
+ /* Remember for next time */
+ memcpy(prev_ps, ps, sizeof(*prev_ps));
+ return CURLM_OK;
+}
+
+static struct easy_pollset*
+mev_add_new_pollset(struct Curl_hash_offt *h, curl_off_t id)
+{
+ struct easy_pollset *ps;
+
+ ps = calloc(1, sizeof(*ps));
+ if(!ps)
+ return NULL;
+ if(!Curl_hash_offt_set(h, id, ps)) {
+ free(ps);
+ return NULL;
+ }
+ return ps;
+}
+
+static struct easy_pollset *
+mev_get_last_pollset(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ if(data) {
+ if(conn)
+ return Curl_hash_offt_get(&multi->ev.conn_pollsets,
+ conn->connection_id);
+ return Curl_hash_offt_get(&multi->ev.xfer_pollsets, data->mid);
+ }
+ return NULL;
+}
+
+static void mev_init_cur_pollset(struct easy_pollset *ps,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ memset(ps, 0, sizeof(*ps));
+ if(conn)
+ Curl_conn_adjust_pollset(data, conn, ps);
+ else if(data)
+ Curl_multi_getsock(data, ps, "ev assess");
+}
+
+static CURLMcode mev_assess(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ if(multi && multi->socket_cb) {
+ struct easy_pollset ps, *last_ps;
+
+ mev_init_cur_pollset(&ps, data, conn);
+ last_ps = mev_get_last_pollset(multi, data, conn);
+
+ if(!last_ps && ps.num) {
+ if(conn)
+ last_ps = mev_add_new_pollset(&multi->ev.conn_pollsets,
+ conn->connection_id);
+ else
+ last_ps = mev_add_new_pollset(&multi->ev.xfer_pollsets, data->mid);
+ if(!last_ps)
+ return CURLM_OUT_OF_MEMORY;
+ }
+
+ if(last_ps)
+ return mev_pollset_diff(multi, data, conn, &ps, last_ps);
+ else
+ DEBUGASSERT(!ps.num);
+ }
+ return CURLM_OK;
+}
+
+CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ return mev_assess(multi, data, NULL);
+}
+
+CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ return mev_assess(multi, data, conn);
+}
+
+CURLMcode Curl_multi_ev_assess_xfer_list(struct Curl_multi *multi,
+ struct Curl_llist *list)
+{
+ struct Curl_llist_node *e;
+ CURLMcode result = CURLM_OK;
+
+ if(multi && multi->socket_cb) {
+ for(e = Curl_llist_head(list); e && !result; e = Curl_node_next(e)) {
+ result = Curl_multi_ev_assess_xfer(multi, Curl_node_elem(e));
+ }
+ }
+ return result;
+}
+
+
+CURLMcode Curl_multi_ev_assign(struct Curl_multi *multi,
+ curl_socket_t s,
+ void *user_data)
+{
+ struct mev_sh_entry *e = mev_sh_entry_get(&multi->ev.sh_entries, s);
+ if(!e)
+ return CURLM_BAD_SOCKET;
+ e->user_data = user_data;
+ return CURLM_OK;
+}
+
+static bool mev_xfer_expire_cb(curl_off_t id, void *value, void *user_data)
+{
+ const struct curltime *nowp = user_data;
+ struct Curl_easy *data = value;
+
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
+ if(data && id >= 0) {
+ /* Expire with out current now, so we will get it below when
+ * asking the splaytree for expired transfers. */
+ Curl_expire_ex(data, nowp, 0, EXPIRE_RUN_NOW);
+ }
+ return TRUE;
+}
+
+void Curl_multi_ev_expire_xfers(struct Curl_multi *multi,
+ curl_socket_t s,
+ const struct curltime *nowp,
+ bool *run_cpool)
+{
+ struct mev_sh_entry *entry;
+
+ DEBUGASSERT(s != CURL_SOCKET_TIMEOUT);
+ entry = mev_sh_entry_get(&multi->ev.sh_entries, s);
+
+ /* 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. */
+ if(entry) {
+ Curl_hash_offt_visit(&entry->xfers, mev_xfer_expire_cb,
+ CURL_UNCONST(nowp));
+
+ if(Curl_hash_offt_count(&entry->conns))
+ *run_cpool = TRUE;
+ }
+}
+
+void Curl_multi_ev_socket_done(struct Curl_multi *multi,
+ struct Curl_easy *data, curl_socket_t s)
+{
+ mev_forget_socket(multi, data, s, "socket done");
+}
+
+void Curl_multi_ev_xfer_done(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ DEBUGASSERT(!data->conn); /* transfer should have been detached */
+ if(data->mid >= 0) {
+ (void)mev_assess(multi, data, NULL);
+ Curl_hash_offt_remove(&multi->ev.xfer_pollsets, data->mid);
+ }
+}
+
+void Curl_multi_ev_conn_done(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ (void)mev_assess(multi, data, conn);
+ Curl_hash_offt_remove(&multi->ev.conn_pollsets, conn->connection_id);
+}
+
+#define CURL_MEV_PS_HASH_SLOTS (991) /* nice prime */
+
+static void mev_hash_pollset_free(curl_off_t id, void *entry)
+{
+ (void)id;
+ free(entry);
+}
+
+void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize)
+{
+ Curl_hash_init(&multi->ev.sh_entries, hashsize, mev_sh_entry_hash,
+ mev_sh_entry_compare, mev_sh_entry_dtor);
+ Curl_hash_offt_init(&multi->ev.xfer_pollsets,
+ CURL_MEV_PS_HASH_SLOTS, mev_hash_pollset_free);
+ Curl_hash_offt_init(&multi->ev.conn_pollsets,
+ CURL_MEV_PS_HASH_SLOTS, mev_hash_pollset_free);
+}
+
+void Curl_multi_ev_cleanup(struct Curl_multi *multi)
+{
+ Curl_hash_destroy(&multi->ev.sh_entries);
+ Curl_hash_offt_destroy(&multi->ev.xfer_pollsets);
+ Curl_hash_offt_destroy(&multi->ev.conn_pollsets);
+}
diff --git a/libs/libcurl/src/multi_ev.h b/libs/libcurl/src/multi_ev.h
new file mode 100644
index 0000000000..50761f6639
--- /dev/null
+++ b/libs/libcurl/src/multi_ev.h
@@ -0,0 +1,82 @@
+#ifndef HEADER_CURL_MULTI_EV_H
+#define HEADER_CURL_MULTI_EV_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 "hash.h"
+#include "hash_offt.h"
+
+struct Curl_easy;
+struct Curl_multi;
+struct easy_pollset;
+
+struct curl_multi_ev {
+ struct Curl_hash sh_entries;
+ struct Curl_hash_offt xfer_pollsets;
+ struct Curl_hash_offt conn_pollsets;
+};
+
+/* Setup/teardown of multi event book-keeping. */
+void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize);
+void Curl_multi_ev_cleanup(struct Curl_multi *multi);
+
+/* Assign a 'user_data' to be passed to the socket callback when
+ * invoked with the given socket. This will fail if this socket
+ * is not active, e.g. the application has not been told to monitor it. */
+CURLMcode Curl_multi_ev_assign(struct Curl_multi *multi, curl_socket_t s,
+ void *user_data);
+
+/* Assess the transfer by getting its current pollset, compute
+ * any changes to the last one and inform the application's socket
+ * callback if things have changed. */
+CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi,
+ struct Curl_easy *data);
+/* Assess all easy handles on the list */
+CURLMcode Curl_multi_ev_assess_xfer_list(struct Curl_multi *multi,
+ struct Curl_llist *list);
+/* Assess the connection by getting its current pollset */
+CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn);
+
+/* Expire all transfers tied to the given socket */
+void Curl_multi_ev_expire_xfers(struct Curl_multi *multi,
+ curl_socket_t s,
+ const struct curltime *nowp,
+ bool *run_cpool);
+
+/* Socket will be closed, forget anything we know about it. */
+void Curl_multi_ev_socket_done(struct Curl_multi *multi,
+ struct Curl_easy *data, curl_socket_t s);
+
+/* Transfer is removed from the multi */
+void Curl_multi_ev_xfer_done(struct Curl_multi *multi,
+ struct Curl_easy *data);
+
+/* Connection is being destroyed */
+void Curl_multi_ev_conn_done(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn);
+
+#endif /* HEADER_CURL_MULTI_EV_H */
diff --git a/libs/libcurl/src/multihandle.h b/libs/libcurl/src/multihandle.h
index 410bf3f53f..1bf77b7822 100644
--- a/libs/libcurl/src/multihandle.h
+++ b/libs/libcurl/src/multihandle.h
@@ -27,10 +27,13 @@
#include "llist.h"
#include "hash.h"
#include "conncache.h"
+#include "cshutdn.h"
+#include "multi_ev.h"
#include "psl.h"
#include "socketpair.h"
struct connectdata;
+struct Curl_easy;
struct Curl_message {
struct Curl_llist_node list;
@@ -38,9 +41,9 @@ struct Curl_message {
struct CURLMsg extmsg;
};
-/* NOTE: if you add a state here, add the name to the statename[] array as
- well!
-*/
+/* NOTE: if you add a state here, add the name to the statenames[] array
+ * in curl_trc.c as well!
+ */
typedef enum {
MSTATE_INIT, /* 0 - start in this state */
MSTATE_PENDING, /* 1 - no connections, waiting for one */
@@ -98,6 +101,8 @@ struct Curl_multi {
struct Curl_llist msgsent; /* in MSGSENT */
curl_off_t next_easy_mid; /* next multi-id for easy handle added */
+ struct Curl_easy *admin; /* internal easy handle for admin operations */
+
/* callback function and user data pointer for the *socket() API */
curl_socket_callback socket_cb;
void *socket_userp;
@@ -128,10 +133,9 @@ struct Curl_multi {
char *xfer_sockbuf; /* the actual buffer */
size_t xfer_sockbuf_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;
+ /* multi event related things */
+ struct curl_multi_ev ev;
+
/* `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
@@ -140,8 +144,8 @@ struct Curl_multi {
* the multi handle is cleaned up (see Curl_hash_add2()).*/
struct Curl_hash proto_hash;
- /* Shared connection cache (bundles)*/
- struct cpool cpool;
+ struct cshutdn cshutdn; /* connection shutdown handling */
+ struct cpool cpool; /* connection pool (bundles) */
long max_host_connections; /* if >0, a fixed limit of the maximum number
of connections per host */
diff --git a/libs/libcurl/src/multiif.h b/libs/libcurl/src/multiif.h
index acabdee604..d70a4549fd 100644
--- a/libs/libcurl/src/multiif.h
+++ b/libs/libcurl/src/multiif.h
@@ -28,8 +28,10 @@
* Prototypes for library-wide functions provided by multi.c
*/
-CURLcode Curl_updatesocket(struct Curl_easy *data);
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id);
+void Curl_expire_ex(struct Curl_easy *data,
+ const struct curltime *nowp,
+ timediff_t milli, expire_id id);
bool Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id);
CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT;
@@ -64,26 +66,13 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize,
/* mask for checking if read and/or write is set for index x */
#define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x))
-/*
- * 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.
+/**
+ * Let the multi handle know that the socket is about to be closed.
+ * The multi will then remove anything it knows about the socket, so
+ * when the OS is using this socket (number) again subsequently,
+ * the internal book keeping will not get confused.
*/
-CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
- struct Curl_easy *data,
- struct easy_pollset *ps,
- struct easy_pollset *last_ps);
+void Curl_multi_will_close(struct Curl_easy *data, curl_socket_t s);
/*
* Add a handle and move it into PERFORM state at once. For pushed streams.
@@ -96,6 +85,10 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi);
+void Curl_multi_getsock(struct Curl_easy *data,
+ struct easy_pollset *ps,
+ const char *caller);
+
/**
* Borrow the transfer buffer from the multi, suitable
* for the given transfer `data`. The buffer may only be used in one
diff --git a/libs/libcurl/src/netrc.c b/libs/libcurl/src/netrc.c
index 1586f76fd1..7ed1ea204a 100644
--- a/libs/libcurl/src/netrc.c
+++ b/libs/libcurl/src/netrc.c
@@ -26,15 +26,20 @@
#ifndef CURL_DISABLE_NETRC
#ifdef HAVE_PWD_H
+#ifdef __AMIGA__
#undef __NO_NET_API /* required for AmigaOS to declare getpwuid() */
+#endif
#include <pwd.h>
+#ifdef __AMIGA__
#define __NO_NET_API
#endif
+#endif
#include <curl/curl.h>
#include "netrc.h"
#include "strcase.h"
#include "curl_get_line.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -81,8 +86,7 @@ static NETRCcode file2memory(const char *filename, struct dynbuf *filebuf)
CURLcode result;
const char *line = Curl_dyn_ptr(&linebuf);
/* skip comments on load */
- while(ISBLANK(*line))
- line++;
+ Curl_str_passblanks(&line);
if(*line == '#')
continue;
result = Curl_dyn_add(filebuf, line);
@@ -134,13 +138,12 @@ static NETRCcode parsenetrc(struct store_netrc *store,
netrcbuffer = Curl_dyn_ptr(filebuf);
while(!done) {
- char *tok = netrcbuffer;
+ const char *tok = netrcbuffer;
while(tok && !done) {
- char *tok_end;
+ const char *tok_end;
bool quoted;
Curl_dyn_reset(&token);
- while(ISBLANK(*tok))
- tok++;
+ Curl_str_passblanks(&tok);
/* tok is first non-space letter */
if(state == MACDEF) {
if((*tok == '\n') || (*tok == '\r'))
@@ -158,7 +161,7 @@ static NETRCcode parsenetrc(struct store_netrc *store,
if(!quoted) {
size_t len = 0;
CURLcode result;
- while(!ISSPACE(*tok_end)) {
+ while(*tok_end > ' ') {
tok_end++;
len++;
}
diff --git a/libs/libcurl/src/noproxy.c b/libs/libcurl/src/noproxy.c
index ab2a210b7b..9ba35e8780 100644
--- a/libs/libcurl/src/noproxy.c
+++ b/libs/libcurl/src/noproxy.c
@@ -29,6 +29,7 @@
#include "inet_pton.h"
#include "strcase.h"
#include "noproxy.h"
+#include "strparse.h"
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
@@ -53,9 +54,9 @@ UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */
/* strange input */
return FALSE;
- if(1 != Curl_inet_pton(AF_INET, ipv4, &address))
+ if(1 != curlx_inet_pton(AF_INET, ipv4, &address))
return FALSE;
- if(1 != Curl_inet_pton(AF_INET, network, &check))
+ if(1 != curlx_inet_pton(AF_INET, network, &check))
return FALSE;
if(bits && (bits != 32)) {
@@ -91,9 +92,9 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
rest = bits & 0x07;
if((bytes > 16) || ((bytes == 16) && rest))
return FALSE;
- if(1 != Curl_inet_pton(AF_INET6, ipv6, address))
+ if(1 != curlx_inet_pton(AF_INET6, ipv6, address))
return FALSE;
- if(1 != Curl_inet_pton(AF_INET6, network, check))
+ if(1 != curlx_inet_pton(AF_INET6, network, check))
return FALSE;
if(bytes && memcmp(address, check, bytes))
return FALSE;
@@ -162,7 +163,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
else {
unsigned int address;
namelen = strlen(name);
- if(1 == Curl_inet_pton(AF_INET, name, &address))
+ if(1 == curlx_inet_pton(AF_INET, name, &address))
type = TYPE_IPV4;
else {
/* ignore trailing dots in the hostname */
@@ -177,8 +178,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
bool match = FALSE;
/* pass blanks */
- while(*p && ISBLANK(*p))
- p++;
+ Curl_str_passblanks(&p);
token = p;
/* pass over the pattern */
@@ -247,8 +247,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
return TRUE;
} /* if(tokenlen) */
/* pass blanks after pattern */
- while(ISBLANK(*p))
- p++;
+ Curl_str_passblanks(&p);
/* if not a comma, this ends the loop */
if(*p != ',')
break;
diff --git a/libs/libcurl/src/openldap.c b/libs/libcurl/src/openldap.c
index 8c4caf1c0b..acfc9a8f05 100644
--- a/libs/libcurl/src/openldap.c
+++ b/libs/libcurl/src/openldap.c
@@ -277,7 +277,7 @@ static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
result = rc == LDAP_URL_ERR_MEM ? CURLE_OUT_OF_MEMORY :
CURLE_URL_MALFORMAT;
rc -= LDAP_URL_SUCCESS;
- if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0]))
+ if((size_t) rc < CURL_ARRAYSIZE(url_errs))
msg = url_errs[rc];
failf(data, "LDAP local: %s", msg);
}
@@ -354,7 +354,7 @@ static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
struct berval *pcred = &cred;
int rc;
- cred.bv_val = (char *) Curl_bufref_ptr(initresp);
+ cred.bv_val = (char *)CURL_UNCONST(Curl_bufref_ptr(initresp));
cred.bv_len = Curl_bufref_len(initresp);
if(!cred.bv_val)
pcred = NULL;
@@ -376,7 +376,7 @@ static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
struct berval *pcred = &cred;
int rc;
- cred.bv_val = (char *) Curl_bufref_ptr(resp);
+ cred.bv_val = (char *)CURL_UNCONST(Curl_bufref_ptr(resp));
cred.bv_len = Curl_bufref_len(resp);
if(!cred.bv_val)
pcred = NULL;
@@ -440,7 +440,7 @@ static CURLcode oldap_perform_mechs(struct Curl_easy *data)
};
rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
- (char **) supportedSASLMechanisms, 0,
+ (char **)CURL_UNCONST(supportedSASLMechanisms), 0,
NULL, NULL, NULL, 0, &li->msgid);
if(rc != LDAP_SUCCESS)
return oldap_map_error(rc, CURLE_LOGIN_DENIED);
@@ -530,9 +530,6 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
/* Initialize the SASL storage */
Curl_sasl_init(&li->sasl, data, &saslldap);
- /* Clear the TLS upgraded flag */
- conn->bits.tls_upgraded = FALSE;
-
result = oldap_parse_login_options(conn);
if(result)
return result;
@@ -560,7 +557,9 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
#ifdef CURL_OPENLDAP_DEBUG
if(do_trace < 0) {
const char *env = getenv("CURL_OPENLDAP_TRACE");
- do_trace = (env && strtol(env, NULL, 10) > 0);
+ curl_off_t e = 0;
+ if(!Curl_str_number(&env, &e, INT_MAX))
+ do_trace = e > 0;
}
if(do_trace)
ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
@@ -795,7 +794,6 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
if(result)
result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
else if(ssl_installed(conn)) {
- conn->bits.tls_upgraded = TRUE;
if(li->sasl.prefmech != SASL_AUTH_NONE)
result = oldap_perform_mechs(data);
else if(data->state.aptr.user)
@@ -952,13 +950,13 @@ static CURLcode client_write(struct Curl_easy *data,
separator, drop the latter. */
if(!len && plen && prefix[plen - 1] == ' ')
plen--;
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, plen);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, prefix, plen);
}
if(!result && value) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, value, len);
}
if(!result && suffix) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, slen);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, suffix, slen);
}
return result;
}
@@ -1172,7 +1170,7 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
if(ret < 0 && err == CURLE_AGAIN) {
- SET_SOCKERRNO(EWOULDBLOCK);
+ SET_SOCKERRNO(SOCKEWOULDBLOCK);
}
}
}
@@ -1191,7 +1189,7 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
CURLcode err = CURLE_SEND_ERROR;
ret = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &err);
if(ret < 0 && err == CURLE_AGAIN) {
- SET_SOCKERRNO(EWOULDBLOCK);
+ SET_SOCKERRNO(SOCKEWOULDBLOCK);
}
}
}
diff --git a/libs/libcurl/src/parsedate.c b/libs/libcurl/src/parsedate.c
index 7cbb139c9b..46c9feb14f 100644
--- a/libs/libcurl/src/parsedate.c
+++ b/libs/libcurl/src/parsedate.c
@@ -83,6 +83,7 @@
#include "strcase.h"
#include "warnless.h"
#include "parsedate.h"
+#include "strparse.h"
/*
* parsedate()
@@ -100,7 +101,9 @@ static int parsedate(const char *date, time_t *output);
#define PARSEDATE_OK 0
#define PARSEDATE_FAIL -1
#define PARSEDATE_LATER 1
+#if defined(HAVE_TIME_T_UNSIGNED) || (SIZEOF_TIME_T < 5)
#define PARSEDATE_SOONER 2
+#endif
#if !defined(CURL_DISABLE_PARSEDATE) || !defined(CURL_DISABLE_FTP) || \
!defined(CURL_DISABLE_FILE)
@@ -253,7 +256,7 @@ static int checktz(const char *check, size_t len)
if(len > 4) /* longer than any valid timezone */
return -1;
- for(i = 0; i < sizeof(tz)/sizeof(tz[0]); i++) {
+ for(i = 0; i < CURL_ARRAYSIZE(tz); i++) {
size_t ilen = strlen(what->name);
if((ilen == len) &&
strncasecompare(check, what->name, len))
@@ -336,7 +339,7 @@ match:
*h = hh;
*m = mm;
*s = ss;
- *endp = (char *)p;
+ *endp = (char *)CURL_UNCONST(p);
return TRUE;
}
@@ -409,7 +412,7 @@ static int parsedate(const char *date, time_t *output)
}
else if(ISDIGIT(*date)) {
/* a digit */
- int val;
+ unsigned int val;
char *end;
if((secnum == -1) &&
match_time(date, &hournum, &minnum, &secnum, &end)) {
@@ -417,29 +420,18 @@ static int parsedate(const char *date, time_t *output)
date = end;
}
else {
- long lval;
- int error;
- int old_errno;
-
- old_errno = errno;
- errno = 0;
- lval = strtol(date, &end, 10);
- error = errno;
- if(errno != old_errno)
- errno = old_errno;
-
- if(error)
+ curl_off_t lval;
+ int num_digits = 0;
+ const char *p = date;
+ if(Curl_str_number(&p, &lval, 99999999))
return PARSEDATE_FAIL;
-#if LONG_MAX != INT_MAX
- if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
- return PARSEDATE_FAIL;
-#endif
-
- val = curlx_sltosi(lval);
+ /* we know num_digits cannot be larger than 8 */
+ num_digits = (int)(p - date);
+ val = (unsigned int)lval;
if((tzoff == -1) &&
- ((end - date) == 4) &&
+ (num_digits == 4) &&
(val <= 1400) &&
(indate < date) &&
((date[-1] == '+' || date[-1] == '-'))) {
@@ -459,10 +451,10 @@ static int parsedate(const char *date, time_t *output)
tzoff = date[-1]=='+' ? -tzoff : tzoff;
}
- if(((end - date) == 8) &&
- (yearnum == -1) &&
- (monnum == -1) &&
- (mdaynum == -1)) {
+ else if((num_digits == 8) &&
+ (yearnum == -1) &&
+ (monnum == -1) &&
+ (mdaynum == -1)) {
/* 8 digits, no year, month or day yet. This is YYYYMMDD */
found = TRUE;
yearnum = val/10000;
@@ -494,7 +486,7 @@ static int parsedate(const char *date, time_t *output)
if(!found)
return PARSEDATE_FAIL;
- date = end;
+ date = p;
}
}
diff --git a/libs/libcurl/src/pingpong.c b/libs/libcurl/src/pingpong.c
index a7c458e0dd..f4ac9e163c 100644
--- a/libs/libcurl/src/pingpong.c
+++ b/libs/libcurl/src/pingpong.c
@@ -29,6 +29,7 @@
#include "urldata.h"
#include "cfilters.h"
+#include "connect.h"
#include "sendf.h"
#include "select.h"
#include "progress.h"
@@ -50,10 +51,10 @@
timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
struct pingpong *pp, bool disconnecting)
{
- struct connectdata *conn = data->conn;
timediff_t timeout_ms; /* in milliseconds */
timediff_t response_time = (data->set.server_response_timeout) ?
data->set.server_response_timeout : pp->response_time;
+ struct curltime now = Curl_now();
/* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
@@ -62,18 +63,20 @@ timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
/* Without a requested timeout, we only wait 'response_time' seconds for the
full response to arrive before we bail out */
- timeout_ms = response_time -
- Curl_timediff(Curl_now(), pp->response); /* spent time */
+ timeout_ms = response_time - Curl_timediff(now, pp->response);
if(data->set.timeout && !disconnecting) {
- /* if timeout is requested, find out how much remaining time we have */
- timediff_t timeout2_ms = data->set.timeout - /* timeout time */
- Curl_timediff(Curl_now(), conn->now); /* spent time */
-
+ /* if timeout is requested, find out how much overall remains */
+ timediff_t timeout2_ms = Curl_timeleft(data, &now, FALSE);
/* pick the lowest number */
timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
}
+ if(disconnecting) {
+ timediff_t total_left_ms = Curl_timeleft(data, NULL, FALSE);
+ timeout_ms = CURLMIN(timeout_ms, CURLMAX(total_left_ms, 0));
+ }
+
return timeout_ms;
}
@@ -96,6 +99,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT; /* already too little time */
}
+ DEBUGF(infof(data, "pp_statematch, timeout=%" FMT_TIMEDIFF_T, timeout_ms));
if(block) {
interval_ms = 1000; /* use 1 second timeout intervals */
if(timeout_ms < interval_ms)
@@ -135,6 +139,8 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
}
else if(rc)
result = pp->statemachine(data, data->conn);
+ else if(disconnecting)
+ return CURLE_OPERATION_TIMEDOUT;
return result;
}
@@ -142,11 +148,13 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
/* initialize stuff to prepare for reading a fresh new response */
void Curl_pp_init(struct pingpong *pp)
{
+ DEBUGASSERT(!pp->initialised);
pp->nread_resp = 0;
pp->response = Curl_now(); /* start response time-out now! */
pp->pending_resp = TRUE;
Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD);
Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD);
+ pp->initialised = TRUE;
}
/***********************************************************************
@@ -441,8 +449,11 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
CURLcode Curl_pp_disconnect(struct pingpong *pp)
{
- Curl_dyn_free(&pp->sendbuf);
- Curl_dyn_free(&pp->recvbuf);
+ if(pp->initialised) {
+ Curl_dyn_free(&pp->sendbuf);
+ Curl_dyn_free(&pp->recvbuf);
+ memset(pp, 0, sizeof(*pp));
+ }
return CURLE_OK;
}
diff --git a/libs/libcurl/src/pingpong.h b/libs/libcurl/src/pingpong.h
index ffd1fd7741..bc29c15175 100644
--- a/libs/libcurl/src/pingpong.h
+++ b/libs/libcurl/src/pingpong.h
@@ -69,7 +69,8 @@ struct pingpong {
CURLcode (*statemachine)(struct Curl_easy *data, struct connectdata *conn);
bool (*endofresp)(struct Curl_easy *data, struct connectdata *conn,
- char *ptr, size_t len, int *code);
+ const char *ptr, size_t len, int *code);
+ BIT(initialised);
};
#define PINGPONG_SETUP(pp,s,e) \
diff --git a/libs/libcurl/src/pop3.c b/libs/libcurl/src/pop3.c
index 8aa1bafc22..3df22dae84 100644
--- a/libs/libcurl/src/pop3.c
+++ b/libs/libcurl/src/pop3.c
@@ -65,7 +65,6 @@
#include "http.h" /* for HTTP proxy tunnel stuff */
#include "socks.h"
#include "pop3.h"
-#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
#include "cfilters.h"
@@ -245,7 +244,7 @@ static bool pop3_is_multiline(const char *cmdline)
* types and allowed SASL mechanisms.
*/
static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
- char *line, size_t len, int *resp)
+ const char *line, size_t len, int *resp)
{
struct pop3_conn *pop3c = &conn->proto.pop3c;
(void)data;
@@ -420,7 +419,6 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
goto out;
/* Change the connection handler */
conn->handler = &Curl_handler_pop3s;
- conn->bits.tls_upgraded = TRUE;
}
DEBUGASSERT(!pop3c->ssldone);
@@ -1392,14 +1390,8 @@ static CURLcode pop3_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
/* Initialise the POP3 layer */
- CURLcode result = pop3_init(data);
- if(result)
- return result;
-
- /* Clear the TLS upgraded flag */
- conn->bits.tls_upgraded = FALSE;
-
- return CURLE_OK;
+ (void)conn;
+ return pop3_init(data);
}
/***********************************************************************
@@ -1588,11 +1580,11 @@ static CURLcode pop3_write(struct Curl_easy *data, const char *str,
/* If the partial match was the CRLF and dot then only write the CRLF
as the server would have inserted the dot */
if(strip_dot && prev - 1 > 0) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
+ result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB,
prev - 1);
}
else if(!strip_dot) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
+ result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB,
prev);
}
else {
@@ -1612,7 +1604,7 @@ static CURLcode pop3_write(struct Curl_easy *data, const char *str,
/* We have a full match so the transfer is done, however we must transfer
the CRLF at the start of the EOB as this is considered to be part of the
message as per RFC-1939, sect. 3 */
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, POP3_EOB, 2);
k->keepon &= ~KEEP_RECV;
pop3c->eob = 0;
diff --git a/libs/libcurl/src/psl.c b/libs/libcurl/src/psl.c
index 4e9ce22f3f..605abe61cc 100644
--- a/libs/libcurl/src/psl.c
+++ b/libs/libcurl/src/psl.c
@@ -40,7 +40,7 @@ void Curl_psl_destroy(struct PslCache *pslcache)
{
if(pslcache->psl) {
if(pslcache->dynamic)
- psl_free((psl_ctx_t *) pslcache->psl);
+ psl_free((psl_ctx_t *)CURL_UNCONST(pslcache->psl));
pslcache->psl = NULL;
pslcache->dynamic = FALSE;
}
diff --git a/libs/libcurl/src/rename.c b/libs/libcurl/src/rename.c
index a35f6ce76e..89eab2e057 100644
--- a/libs/libcurl/src/rename.c
+++ b/libs/libcurl/src/rename.c
@@ -40,14 +40,14 @@
/* return 0 on success, 1 on error */
int Curl_rename(const char *oldpath, const char *newpath)
{
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(UNDER_CE)
/* 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);
+ TCHAR *tchar_oldpath = curlx_convert_UTF8_to_tchar(oldpath);
+ TCHAR *tchar_newpath = curlx_convert_UTF8_to_tchar(newpath);
for(;;) {
timediff_t diff;
if(MoveFileEx(tchar_oldpath, tchar_newpath, MOVEFILE_REPLACE_EXISTING)) {
diff --git a/libs/libcurl/src/request.c b/libs/libcurl/src/request.c
index a4fa833e93..2a6239eb41 100644
--- a/libs/libcurl/src/request.c
+++ b/libs/libcurl/src/request.c
@@ -34,6 +34,7 @@
#include "sendf.h"
#include "transfer.h"
#include "url.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -68,6 +69,8 @@ CURLcode Curl_req_soft_reset(struct SingleRequest *req,
req->deductheadercount = 0;
req->httpversion_sent = 0;
req->httpversion = 0;
+ req->sendbuf_hds_len = 0;
+
result = Curl_client_start(data);
if(result)
return result;
@@ -140,6 +143,7 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
req->httpcode = 0;
req->keepon = 0;
req->upgr101 = UPGR101_INIT;
+ req->sendbuf_hds_len = 0;
req->timeofdoc = 0;
req->location = NULL;
req->newurl = NULL;
@@ -194,11 +198,13 @@ static CURLcode xfer_send(struct Curl_easy *data,
/* Allow debug builds to override this logic to force short initial
sends */
size_t body_len = blen - hds_len;
- char *p = getenv("CURL_SMALLREQSEND");
- if(p) {
- size_t body_small = (size_t)strtoul(p, NULL, 10);
- if(body_small && body_small < body_len)
- blen = hds_len + body_small;
+ if(body_len) {
+ const char *p = getenv("CURL_SMALLREQSEND");
+ if(p) {
+ curl_off_t body_small;
+ if(!Curl_str_number(&p, &body_small, body_len))
+ blen = hds_len + (size_t)body_small;
+ }
}
}
#endif
@@ -222,11 +228,11 @@ static CURLcode xfer_send(struct Curl_easy *data,
data->req.eos_sent = TRUE;
if(*pnwritten) {
if(hds_len)
- Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
+ Curl_debug(data, CURLINFO_HEADER_OUT, buf,
CURLMIN(hds_len, *pnwritten));
if(*pnwritten > hds_len) {
size_t body_len = *pnwritten - hds_len;
- Curl_debug(data, CURLINFO_DATA_OUT, (char *)buf + hds_len, body_len);
+ Curl_debug(data, CURLINFO_DATA_OUT, buf + hds_len, body_len);
data->req.writebytecount += body_len;
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
}
diff --git a/libs/libcurl/src/rtsp.c b/libs/libcurl/src/rtsp.c
index cc649b67db..d625c539c3 100644
--- a/libs/libcurl/src/rtsp.c
+++ b/libs/libcurl/src/rtsp.c
@@ -40,6 +40,7 @@
#include "connect.h"
#include "cfilters.h"
#include "strdup.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -129,14 +130,19 @@ const struct Curl_handler Curl_handler_rtsp = {
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
+ struct rtsp_conn *rtspc = &conn->proto.rtspc;
struct RTSP *rtsp;
(void)conn;
+ if(!rtspc->initialised) {
+ Curl_dyn_init(&rtspc->buf, MAX_RTP_BUFFERSIZE);
+ rtspc->initialised = TRUE;
+ }
+
data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
if(!rtsp)
return CURLE_OUT_OF_MEMORY;
- Curl_dyn_init(&conn->proto.rtspc.buf, MAX_RTP_BUFFERSIZE);
return CURLE_OK;
}
@@ -181,9 +187,13 @@ static CURLcode rtsp_connect(struct Curl_easy *data, bool *done)
static CURLcode rtsp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead)
{
+ struct rtsp_conn *rtspc = &conn->proto.rtspc;
(void) dead;
(void) data;
- Curl_dyn_free(&conn->proto.rtspc.buf);
+ if(rtspc->initialised) {
+ Curl_dyn_free(&conn->proto.rtspc.buf);
+ rtspc->initialised = FALSE;
+ }
return CURLE_OK;
}
@@ -345,8 +355,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(rtspreq == RTSPREQ_SETUP && !p_transport) {
/* New Transport: setting? */
if(data->set.str[STRING_RTSP_TRANSPORT]) {
- Curl_safefree(data->state.aptr.rtsp_transport);
-
+ free(data->state.aptr.rtsp_transport);
data->state.aptr.rtsp_transport =
aprintf("Transport: %s\r\n",
data->set.str[STRING_RTSP_TRANSPORT]);
@@ -372,7 +381,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
/* Accept-Encoding header */
if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
data->set.str[STRING_ENCODING]) {
- Curl_safefree(data->state.aptr.accept_encoding);
+ free(data->state.aptr.accept_encoding);
data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
@@ -426,7 +435,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
/* Check to see if there is a range set in the custom headers */
if(!Curl_checkheaders(data, STRCONST("Range")) && data->state.range) {
- Curl_safefree(data->state.aptr.rangeline);
+ free(data->state.aptr.rangeline);
data->state.aptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
p_range = data->state.aptr.rangeline;
}
@@ -627,7 +636,7 @@ static CURLcode rtp_write_body_junk(struct Curl_easy *data,
if(body_remain) {
if((curl_off_t)blen > body_remain)
blen = (size_t)body_remain;
- return Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen);
+ return Curl_client_write(data, CLIENTWRITE_BODY, buf, blen);
}
return CURLE_OK;
}
@@ -674,8 +683,7 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
/* possible start of an RTP message, buffer */
if(skip_len) {
/* end of junk/BODY bytes, flush */
- result = rtp_write_body_junk(data,
- (char *)(buf - skip_len), skip_len);
+ result = rtp_write_body_junk(data, buf - skip_len, skip_len);
skip_len = 0;
if(result)
goto out;
@@ -791,7 +799,7 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
}
out:
if(!result && skip_len)
- result = rtp_write_body_junk(data, (char *)(buf - skip_len), skip_len);
+ result = rtp_write_body_junk(data, buf - skip_len, skip_len);
return result;
}
@@ -865,8 +873,7 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
data->req.size));
if(!result && (is_eos || blen)) {
result = Curl_client_write(data, CLIENTWRITE_BODY|
- (is_eos ? CLIENTWRITE_EOS : 0),
- (char *)buf, blen);
+ (is_eos ? CLIENTWRITE_EOS : 0), buf, blen);
}
out:
@@ -906,7 +913,7 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
}
Curl_set_in_callback(data, TRUE);
- wrote = writeit((char *)ptr, 1, len, user_ptr);
+ wrote = writeit((char *)CURL_UNCONST(ptr), 1, len, user_ptr);
Curl_set_in_callback(data, FALSE);
if(CURL_WRITEFUNC_PAUSE == wrote) {
@@ -925,21 +932,16 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
{
if(checkprefix("CSeq:", header)) {
- long CSeq = 0;
- char *endp;
+ curl_off_t CSeq = 0;
+ struct RTSP *rtsp = data->req.p.rtsp;
const char *p = &header[5];
- while(ISBLANK(*p))
- p++;
- CSeq = strtol(p, &endp, 10);
- if(p != endp) {
- struct RTSP *rtsp = data->req.p.rtsp;
- rtsp->CSeq_recv = CSeq; /* mark the request */
- data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
- }
- else {
+ Curl_str_passblanks(&p);
+ if(Curl_str_number(&p, &CSeq, LONG_MAX)) {
failf(data, "Unable to read the CSeq header: [%s]", header);
return CURLE_RTSP_CSEQ_ERROR;
}
+ rtsp->CSeq_recv = (long)CSeq; /* mark the request */
+ data->state.rtsp_CSeq_recv = (long)CSeq; /* update the handle */
}
else if(checkprefix("Session:", header)) {
const char *start, *end;
@@ -947,8 +949,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
/* Find the first non-space letter */
start = header + 8;
- while(*start && ISBLANK(*start))
- start++;
+ Curl_str_passblanks(&start);
if(!*start) {
failf(data, "Got a blank Session ID");
@@ -962,7 +963,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
* gstreamer does url-encoded session ID's not covered by the standard.
*/
end = start;
- while(*end && *end != ';' && !ISSPACE(*end))
+ while((*end > ' ') && (*end != ';'))
end++;
idlen = end - start;
@@ -1006,29 +1007,24 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport)
const char *start, *end;
start = transport;
while(start && *start) {
- while(*start && ISBLANK(*start) )
- start++;
+ Curl_str_passblanks(&start);
end = strchr(start, ';');
if(checkprefix("interleaved=", start)) {
- long chan1, chan2, chan;
- char *endp;
+ curl_off_t chan1, chan2, chan;
const char *p = start + 12;
- chan1 = strtol(p, &endp, 10);
- if(p != endp && chan1 >= 0 && chan1 <= 255) {
+ if(!Curl_str_number(&p, &chan1, 255)) {
unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
chan2 = chan1;
- if(*endp == '-') {
- p = endp + 1;
- chan2 = strtol(p, &endp, 10);
- if(p == endp || chan2 < 0 || chan2 > 255) {
+ if(!Curl_str_single(&p, '-')) {
+ if(Curl_str_number(&p, &chan2, 255)) {
infof(data, "Unable to read the interleaved parameter from "
"Transport header: [%s]", transport);
chan2 = chan1;
}
}
for(chan = chan1; chan <= chan2; chan++) {
- long idx = chan / 8;
- long off = chan % 8;
+ int idx = (int)chan / 8;
+ int off = (int)chan % 8;
rtp_channel_mask[idx] |= (unsigned char)(1 << off);
}
}
diff --git a/libs/libcurl/src/rtsp.h b/libs/libcurl/src/rtsp.h
index e442676f25..0aeaa45e9d 100644
--- a/libs/libcurl/src/rtsp.h
+++ b/libs/libcurl/src/rtsp.h
@@ -53,6 +53,7 @@ struct rtsp_conn {
size_t rtp_len;
rtp_parse_st state;
BIT(in_header);
+ BIT(initialised);
};
/****************************************************************************
diff --git a/libs/libcurl/src/select.c b/libs/libcurl/src/select.c
index e4e66e17d2..ba8c00153d 100644
--- a/libs/libcurl/src/select.c
+++ b/libs/libcurl/src/select.c
@@ -74,7 +74,7 @@ int Curl_wait_ms(timediff_t timeout_ms)
if(!timeout_ms)
return 0;
if(timeout_ms < 0) {
- SET_SOCKERRNO(EINVAL);
+ SET_SOCKERRNO(SOCKEINVAL);
return -1;
}
#if defined(MSDOS)
@@ -86,7 +86,7 @@ int Curl_wait_ms(timediff_t timeout_ms)
timeout_ms = ULONG_MAX-1;
/* do not use ULONG_MAX, because that is equal to INFINITE */
#endif
- Sleep((ULONG)timeout_ms);
+ Sleep((DWORD)timeout_ms);
#else
/* avoid using poll() for this since it behaves incorrectly with no sockets
on Apple operating systems */
@@ -96,7 +96,7 @@ int Curl_wait_ms(timediff_t timeout_ms)
}
#endif /* _WIN32 */
if(r) {
- if((r == -1) && (SOCKERRNO == EINTR))
+ if((r == -1) && (SOCKERRNO == SOCKEINTR))
/* make EINTR from select or poll not a "lethal" error */
r = 0;
else
@@ -312,7 +312,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
pending_ms = 0;
r = poll(ufds, nfds, pending_ms);
if(r <= 0) {
- if((r == -1) && (SOCKERRNO == EINTR))
+ if((r == -1) && (SOCKERRNO == SOCKEINTR))
/* make EINTR from select or poll not a "lethal" error */
r = 0;
return r;
@@ -360,7 +360,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
*/
r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
if(r <= 0) {
- if((r == -1) && (SOCKERRNO == EINTR))
+ if((r == -1) && (SOCKERRNO == SOCKEINTR))
/* make EINTR from select or poll not a "lethal" error */
r = 0;
return r;
@@ -410,6 +410,11 @@ void Curl_pollfds_init(struct curl_pollfds *cpfds,
}
}
+void Curl_pollfds_reset(struct curl_pollfds *cpfds)
+{
+ cpfds->n = 0;
+}
+
void Curl_pollfds_cleanup(struct curl_pollfds *cpfds)
{
DEBUGASSERT(cpfds);
diff --git a/libs/libcurl/src/select.h b/libs/libcurl/src/select.h
index 899c9c9b67..d1d3d8564b 100644
--- a/libs/libcurl/src/select.h
+++ b/libs/libcurl/src/select.h
@@ -93,7 +93,7 @@ int Curl_wait_ms(timediff_t timeout_ms);
#define FDSET_SOCK(x) 1
#define VERIFY_SOCK(x) do { \
if(!VALID_SOCK(x)) { \
- SET_SOCKERRNO(WSAEINVAL); \
+ SET_SOCKERRNO(SOCKEINVAL); \
return -1; \
} \
} while(0)
@@ -105,7 +105,7 @@ int Curl_wait_ms(timediff_t timeout_ms);
#define VERIFY_SOCK(x) do { \
if(!VALID_SOCK(x) || !FDSET_SOCK(x)) { \
- SET_SOCKERRNO(EINVAL); \
+ SET_SOCKERRNO(SOCKEINVAL); \
return -1; \
} \
} while(0)
@@ -122,6 +122,8 @@ void Curl_pollfds_init(struct curl_pollfds *cpfds,
struct pollfd *static_pfds,
unsigned int static_count);
+void Curl_pollfds_reset(struct curl_pollfds *cpfds);
+
void Curl_pollfds_cleanup(struct curl_pollfds *cpfds);
CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
diff --git a/libs/libcurl/src/sendf.c b/libs/libcurl/src/sendf.c
index a4fcb5b224..c576febd1c 100644
--- a/libs/libcurl/src/sendf.c
+++ b/libs/libcurl/src/sendf.c
@@ -42,6 +42,7 @@
#include "connect.h"
#include "content_encoding.h"
#include "cw-out.h"
+#include "cw-pause.h"
#include "vtls/vtls.h"
#include "vssh/ssh.h"
#include "easyif.h"
@@ -359,7 +360,7 @@ static CURLcode cw_raw_write(struct Curl_easy *data,
const char *buf, size_t nbytes)
{
if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
- Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
+ Curl_debug(data, CURLINFO_DATA_IN, buf, nbytes);
}
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
}
@@ -433,21 +434,37 @@ static CURLcode do_init_writer_stack(struct Curl_easy *data)
if(result)
return result;
- result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
+ /* This places the "pause" writer behind the "download" writer that
+ * is added below. Meaning the "download" can do checks on content length
+ * and other things *before* write outs are buffered for paused transfers. */
+ result = Curl_cwriter_create(&writer, data, &Curl_cwt_pause,
+ CURL_CW_PROTOCOL);
+ if(!result) {
+ result = Curl_cwriter_add(data, writer);
+ if(result)
+ Curl_cwriter_free(data, writer);
+ }
if(result)
return result;
- result = Curl_cwriter_add(data, writer);
- if(result) {
- Curl_cwriter_free(data, writer);
+
+ result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
+ if(!result) {
+ result = Curl_cwriter_add(data, writer);
+ if(result)
+ Curl_cwriter_free(data, writer);
}
+ if(result)
+ return result;
result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
+ if(!result) {
+ result = Curl_cwriter_add(data, writer);
+ if(result)
+ Curl_cwriter_free(data, writer);
+ }
if(result)
return result;
- result = Curl_cwriter_add(data, writer);
- if(result) {
- Curl_cwriter_free(data, writer);
- }
+
return result;
}
@@ -494,6 +511,16 @@ struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
return NULL;
}
+bool Curl_cwriter_is_content_decoding(struct Curl_easy *data)
+{
+ struct Curl_cwriter *writer;
+ for(writer = data->req.writer_stack; writer; writer = writer->next) {
+ if(writer->phase == CURL_CW_CONTENT_DECODE)
+ return TRUE;
+ }
+ return FALSE;
+}
+
bool Curl_cwriter_is_paused(struct Curl_easy *data)
{
return Curl_cw_out_is_paused(data);
@@ -1003,13 +1030,6 @@ static CURLcode cr_lc_read(struct Curl_easy *data,
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 */
@@ -1286,6 +1306,15 @@ static bool cr_buf_needs_rewind(struct Curl_easy *data,
return ctx->index > 0;
}
+static CURLcode cr_buf_rewind(struct Curl_easy *data,
+ struct Curl_creader *reader)
+{
+ struct cr_buf_ctx *ctx = reader->ctx;
+ (void)data;
+ ctx->index = 0;
+ return CURLE_OK;
+}
+
static curl_off_t cr_buf_total_length(struct Curl_easy *data,
struct Curl_creader *reader)
{
@@ -1325,7 +1354,7 @@ static const struct Curl_crtype cr_buf = {
cr_buf_needs_rewind,
cr_buf_total_length,
cr_buf_resume_from,
- Curl_creader_def_rewind,
+ cr_buf_rewind,
Curl_creader_def_unpause,
Curl_creader_def_is_paused,
Curl_creader_def_done,
diff --git a/libs/libcurl/src/sendf.h b/libs/libcurl/src/sendf.h
index cefd58dfa3..e4ed646475 100644
--- a/libs/libcurl/src/sendf.h
+++ b/libs/libcurl/src/sendf.h
@@ -182,6 +182,8 @@ CURLcode Curl_cwriter_write(struct Curl_easy *data,
*/
bool Curl_cwriter_is_paused(struct Curl_easy *data);
+bool Curl_cwriter_is_content_decoding(struct Curl_easy *data);
+
/**
* Unpause client writer and flush any buffered date to the client.
*/
diff --git a/libs/libcurl/src/setopt.c b/libs/libcurl/src/setopt.c
index 3c1bb803f4..d853e3effa 100644
--- a/libs/libcurl/src/setopt.c
+++ b/libs/libcurl/src/setopt.c
@@ -438,7 +438,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
*/
if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.timecondition = (unsigned char)(curl_TimeCond)arg;
+ data->set.timecondition = (unsigned char)arg;
break;
case CURLOPT_TIMEVALUE:
/*
@@ -477,10 +477,10 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
primary->version = (unsigned char)version;
primary->version_max = (unsigned int)version_max;
}
+ break;
#else
return CURLE_NOT_BUILT_IN;
#endif
- break;
case CURLOPT_POSTFIELDSIZE:
/*
* The size of the POSTFIELD data to prevent libcurl to do strlen() to
@@ -525,7 +525,9 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
/*
* Follow Location: header hints on an HTTP-server.
*/
- data->set.http_follow_location = enabled;
+ if(uarg > 3)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.http_follow_mode = (unsigned char)uarg;
break;
case CURLOPT_UNRESTRICTED_AUTH:
@@ -600,11 +602,6 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
*/
switch(arg) {
case CURL_HTTP_VERSION_NONE:
-#ifdef USE_HTTP2
- /* This seems an undesirable quirk to force a behaviour on lower
- * implementations that they should recognize independently? */
- arg = CURL_HTTP_VERSION_2TLS;
-#endif
/* accepted */
break;
case CURL_HTTP_VERSION_1_0:
@@ -692,7 +689,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
data->set.proxy_transfer_mode = (bool)uarg;
break;
case CURLOPT_SOCKS5_AUTH:
- if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
+ if(uarg & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
return CURLE_NOT_BUILT_IN;
data->set.socks5auth = (unsigned char)uarg;
break;
@@ -1406,7 +1403,9 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
*/
Curl_safefree(data->set.str[STRING_SSL_ENGINE]);
return Curl_ssl_set_engine_default(data);
-
+ case CURLOPT_UPLOAD_FLAGS:
+ data->set.upload_flags = (unsigned char)arg;
+ break;
default:
/* unknown option */
return CURLE_UNKNOWN_OPTION;
@@ -1534,7 +1533,7 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option,
#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \
!defined(CURL_DISABLE_IMAP)
# ifndef CURL_DISABLE_MIME
- case CURLOPT_MIMEPOST:
+ case CURLOPT_MIMEPOST:
/*
* Set to make us do MIME POST
*/
@@ -1662,8 +1661,8 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST))
/* set a list of cipher we want to use in the SSL connection */
return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], ptr);
- return CURLE_NOT_BUILT_IN;
- break;
+ else
+ return CURLE_NOT_BUILT_IN;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_CIPHER_LIST:
if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) {
@@ -1673,7 +1672,6 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
}
else
return CURLE_NOT_BUILT_IN;
- break;
#endif
case CURLOPT_TLS13_CIPHERS:
if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) {
@@ -1682,7 +1680,6 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
}
else
return CURLE_NOT_BUILT_IN;
- break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_TLS13_CIPHERS:
if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES))
@@ -1691,7 +1688,6 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
ptr);
else
return CURLE_NOT_BUILT_IN;
- break;
#endif
case CURLOPT_RANDOM_FILE:
break;
@@ -1944,7 +1940,6 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
*/
return Curl_setstropt(&data->set.str[STRING_PROXY], ptr);
- break;
case CURLOPT_PRE_PROXY:
/*
@@ -1969,95 +1964,95 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
*/
return Curl_setstropt(&data->set.str[STRING_SERVICE_NAME], ptr);
- break;
case CURLOPT_HEADERDATA:
/*
* Custom pointer to pass the header write callback function
*/
- data->set.writeheader = (void *)ptr;
+ data->set.writeheader = ptr;
break;
case CURLOPT_READDATA:
/*
* FILE pointer to read the file to be uploaded from. Or possibly used as
* argument to the read callback.
*/
- data->set.in_set = (void *)ptr;
+ data->set.in_set = ptr;
break;
case CURLOPT_WRITEDATA:
/*
* FILE pointer to write to. Or possibly used as argument to the write
* callback.
*/
- data->set.out = (void *)ptr;
+ data->set.out = ptr;
break;
case CURLOPT_DEBUGDATA:
/*
* Set to a void * that should receive all error writes. This
* defaults to CURLOPT_STDERR for normal operations.
*/
- data->set.debugdata = (void *)ptr;
+ data->set.debugdata = ptr;
break;
case CURLOPT_PROGRESSDATA:
/*
* Custom client data to pass to the progress callback
*/
- data->set.progress_client = (void *)ptr;
+ data->set.progress_client = ptr;
break;
case CURLOPT_SEEKDATA:
/*
* Seek control callback. Might be NULL.
*/
- data->set.seek_client = (void *)ptr;
+ data->set.seek_client = ptr;
break;
case CURLOPT_IOCTLDATA:
/*
* I/O control data pointer. Might be NULL.
*/
- data->set.ioctl_client = (void *)ptr;
+ data->set.ioctl_client = ptr;
break;
case CURLOPT_SSL_CTX_DATA:
/*
* Set a SSL_CTX callback parameter pointer
*/
#ifdef USE_SSL
- if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
- data->set.ssl.fsslctxp = (void *)ptr;
+ if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) {
+ data->set.ssl.fsslctxp = ptr;
+ break;
+ }
else
#endif
return CURLE_NOT_BUILT_IN;
- break;
case CURLOPT_SOCKOPTDATA:
/*
* socket callback data pointer. Might be NULL.
*/
- data->set.sockopt_client = (void *)ptr;
+ data->set.sockopt_client = ptr;
break;
case CURLOPT_OPENSOCKETDATA:
/*
* socket callback data pointer. Might be NULL.
*/
- data->set.opensocket_client = (void *)ptr;
+ data->set.opensocket_client = ptr;
break;
case CURLOPT_RESOLVER_START_DATA:
/*
* resolver start callback data pointer. Might be NULL.
*/
- data->set.resolver_start_client = (void *)ptr;
+ data->set.resolver_start_client = ptr;
break;
case CURLOPT_CLOSESOCKETDATA:
/*
* socket callback data pointer. Might be NULL.
*/
- data->set.closesocket_client = (void *)ptr;
+ data->set.closesocket_client = ptr;
break;
case CURLOPT_TRAILERDATA:
#ifndef CURL_DISABLE_HTTP
- data->set.trailer_data = (void *)ptr;
+ data->set.trailer_data = ptr;
#endif
break;
case CURLOPT_PREREQDATA:
- data->set.prereq_userp = (void *)ptr;
+ data->set.prereq_userp = ptr;
break;
case CURLOPT_ERRORBUFFER:
@@ -2146,12 +2141,16 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
result = setstropt_userpwd(ptr, &u, &p);
/* URL decode the components */
- if(!result && u)
+ if(!result && u) {
+ Curl_safefree(data->set.str[STRING_PROXYUSERNAME]);
result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL,
REJECT_ZERO);
- if(!result && p)
+ }
+ if(!result && p) {
+ Curl_safefree(data->set.str[STRING_PROXYPASSWORD]);
result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL,
REJECT_ZERO);
+ }
free(u);
free(p);
}
@@ -2220,6 +2219,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* String that holds file type of the SSL certificate to use for proxy
*/
return Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], ptr);
+
#endif
case CURLOPT_SSLKEY:
/*
@@ -2240,7 +2240,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* String that holds file type of the SSL key to use
*/
return Curl_setstropt(&data->set.str[STRING_KEY_TYPE], ptr);
- break;
+
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLKEYTYPE:
/*
@@ -2261,6 +2261,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* String that holds the SSL private key password for proxy.
*/
return Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], ptr);
+
#endif
case CURLOPT_SSLENGINE:
/*
@@ -2283,6 +2284,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/* enable the HAProxy protocol */
data->set.haproxyprotocol = TRUE;
break;
+
#endif
case CURLOPT_INTERFACE:
/*
@@ -2331,8 +2333,8 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* CA certificate
*/
return Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], ptr);
-#endif
+#endif
case CURLOPT_CAPATH:
/*
* Set CA path info for SSL connection. Specify directory name of the CA
@@ -2371,6 +2373,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* CRL to check certificates revocation
*/
return Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], ptr);
+
#endif
case CURLOPT_ISSUERCERT:
/*
@@ -2388,12 +2391,11 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
return Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY], ptr);
#endif
-
case CURLOPT_PRIVATE:
/*
* Set private data pointer.
*/
- data->set.private_data = (void *)ptr;
+ data->set.private_data = ptr;
break;
#ifdef USE_SSL
@@ -2403,6 +2405,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* Specify colon-delimited list of curve algorithm names.
*/
return Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], ptr);
+
#endif
#ifdef USE_SSH
case CURLOPT_SSH_PUBLIC_KEYFILE:
@@ -2435,7 +2438,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/*
* Custom client data to pass to the SSH keyfunc callback
*/
- data->set.ssh_keyfunc_userp = (void *)ptr;
+ data->set.ssh_keyfunc_userp = ptr;
break;
#ifdef USE_LIBSSH2
case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
@@ -2450,7 +2453,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/*
* Custom client data to pass to the SSH keyfunc callback
*/
- data->set.ssh_hostkeyfunc_userp = (void *)ptr;
+ data->set.ssh_hostkeyfunc_userp = ptr;
break;
#endif /* USE_LIBSSH2 */
#endif /* USE_SSH */
@@ -2481,7 +2484,6 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
/* Set the SMTP auth originator */
return Curl_setstropt(&data->set.str[STRING_MAIL_AUTH], ptr);
#endif
-
case CURLOPT_SASL_AUTHZID:
/* Authorization identity (identity to act as) */
return Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], ptr);
@@ -2500,7 +2502,6 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
* for generic server options, the application will need to set this.
*/
return Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI], ptr);
- break;
case CURLOPT_RTSP_TRANSPORT:
/*
@@ -2509,15 +2510,15 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
return Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT], ptr);
case CURLOPT_INTERLEAVEDATA:
- data->set.rtp_out = (void *)ptr;
+ data->set.rtp_out = ptr;
break;
#endif /* ! CURL_DISABLE_RTSP */
#ifndef CURL_DISABLE_FTP
case CURLOPT_CHUNK_DATA:
- data->set.wildcardptr = (void *)ptr;
+ data->set.wildcardptr = ptr;
break;
case CURLOPT_FNMATCH_DATA:
- data->set.fnmatch_data = (void *)ptr;
+ data->set.fnmatch_data = ptr;
break;
#endif
#ifdef USE_TLS_SRP
@@ -2592,10 +2593,10 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
#endif
#ifndef CURL_DISABLE_HSTS
case CURLOPT_HSTSREADDATA:
- data->set.hsts_read_userp = (void *)ptr;
+ data->set.hsts_read_userp = ptr;
break;
case CURLOPT_HSTSWRITEDATA:
- data->set.hsts_write_userp = (void *)ptr;
+ data->set.hsts_write_userp = ptr;
break;
case CURLOPT_HSTS: {
struct curl_slist *h;
@@ -2770,12 +2771,13 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option,
* Set a SSL_CTX callback
*/
#ifdef USE_SSL
- if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX))
+ if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) {
data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+ break;
+ }
else
#endif
return CURLE_NOT_BUILT_IN;
- break;
case CURLOPT_SOCKOPTFUNCTION:
/*
@@ -2808,7 +2810,6 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option,
data->set.resolver_start = va_arg(param, curl_resolver_start_callback);
break;
-
#ifdef USE_SSH
#ifdef USE_LIBSSH2
case CURLOPT_SSH_HOSTKEYFUNCTION:
diff --git a/libs/libcurl/src/setup-vms.h b/libs/libcurl/src/setup-vms.h
index a75b4130d3..509766ff08 100644
--- a/libs/libcurl/src/setup-vms.h
+++ b/libs/libcurl/src/setup-vms.h
@@ -394,51 +394,11 @@ static struct passwd *vms_getpwuid(uid_t uid)
/* that way a newer port will also work if some one has one */
#ifdef __VAX
-# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
-# define des_set_odd_parity DES_SET_ODD_PARITY
-# define des_set_key DES_SET_KEY
-# define des_ecb_encrypt DES_ECB_ENCRYPT
-
-# endif
# include <openssl/evp.h>
# ifndef OpenSSL_add_all_algorithms
# define OpenSSL_add_all_algorithms OPENSSL_ADD_ALL_ALGORITHMS
void OPENSSL_ADD_ALL_ALGORITHMS(void);
# endif
-
- /* Curl defines these to lower case and VAX needs them in upper case */
- /* So we need static routines */
-# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
-
-# undef des_set_odd_parity
-# undef DES_set_odd_parity
-# undef des_set_key
-# undef DES_set_key
-# undef des_ecb_encrypt
-# undef DES_ecb_encrypt
-
- static void des_set_odd_parity(des_cblock *key) {
- DES_SET_ODD_PARITY(key);
- }
-
- static int des_set_key(const_des_cblock *key,
- des_key_schedule schedule) {
- return DES_SET_KEY(key, schedule);
- }
-
- static void des_ecb_encrypt(const_des_cblock *input,
- des_cblock *output,
- des_key_schedule ks, int enc) {
- DES_ECB_ENCRYPT(input, output, ks, enc);
- }
-#endif
-/* Need this to stop a macro redefinition error */
-#if OPENSSL_VERSION_NUMBER < 0x00907000L
-# ifdef X509_STORE_set_flags
-# undef X509_STORE_set_flags
-# define X509_STORE_set_flags(x,y) Curl_nop_stmt
-# endif
-#endif
#endif
#endif /* HEADER_CURL_SETUP_VMS_H */
diff --git a/libs/libcurl/src/setup-win32.h b/libs/libcurl/src/setup-win32.h
index ee5996fe2e..3f8a28ef67 100644
--- a/libs/libcurl/src/setup-win32.h
+++ b/libs/libcurl/src/setup-win32.h
@@ -93,12 +93,6 @@
* newer symbols.
*/
-#ifndef _WIN32_WINNT_NT4
-#define _WIN32_WINNT_NT4 0x0400 /* Windows NT 4.0 */
-#endif
-#ifndef _WIN32_WINNT_WIN2K
-#define _WIN32_WINNT_WIN2K 0x0500 /* Windows 2000 */
-#endif
#ifndef _WIN32_WINNT_WINXP
#define _WIN32_WINNT_WINXP 0x0501 /* Windows XP */
#endif
diff --git a/libs/libcurl/src/sha256.c b/libs/libcurl/src/sha256.c
index 3b4258752c..e53d0c24d3 100644
--- a/libs/libcurl/src/sha256.c
+++ b/libs/libcurl/src/sha256.c
@@ -32,41 +32,16 @@
#include "curl_sha256.h"
#include "curl_hmac.h"
-#ifdef USE_WOLFSSL
-#include <wolfssl/options.h>
-#endif
-
-#if defined(USE_OPENSSL)
-
-#include <openssl/opensslv.h>
-
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
-#define USE_OPENSSL_SHA256
-#endif
-
-#endif /* USE_OPENSSL */
-
-#ifdef USE_MBEDTLS
+#ifdef USE_OPENSSL
+#include <openssl/evp.h>
+#elif defined(USE_GNUTLS)
+#include <nettle/sha.h>
+#elif defined(USE_MBEDTLS)
#include <mbedtls/version.h>
-
#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
(MBEDTLS_VERSION_NUMBER < 0x03000000)
#define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
#endif
-#endif /* USE_MBEDTLS */
-
-#if defined(USE_OPENSSL_SHA256)
-
-/* When OpenSSL or wolfSSL is available we use their SHA256-functions. */
-#if defined(USE_OPENSSL)
-#include <openssl/evp.h>
-#elif defined(USE_WOLFSSL)
-#include <wolfssl/openssl/evp.h>
-#endif
-
-#elif defined(USE_GNUTLS)
-#include <nettle/sha.h>
-#elif defined(USE_MBEDTLS)
#include <mbedtls/sha256.h>
#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
(__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
@@ -95,7 +70,7 @@
* file even if multiple backends are enabled at the same time.
*/
-#if defined(USE_OPENSSL_SHA256)
+#ifdef USE_OPENSSL
struct ossl_sha256_ctx {
EVP_MD_CTX *openssl_ctx;
@@ -241,7 +216,11 @@ static void my_sha256_update(void *in,
unsigned int length)
{
my_sha256_ctx *ctx = (my_sha256_ctx *)in;
- CryptHashData(ctx->hHash, (unsigned char *) data, length, 0);
+#ifdef __MINGW32CE__
+ CryptHashData(ctx->hHash, (BYTE *)CURL_UNCONST(data), length, 0);
+#else
+ CryptHashData(ctx->hHash, (const BYTE *)data, length, 0);
+#endif
}
static void my_sha256_final(unsigned char *digest, void *in)
@@ -348,7 +327,7 @@ static const unsigned long K[64] = {
/* Compress 512-bits */
static int sha256_compress(struct sha256_state *md,
- unsigned char *buf)
+ const unsigned char *buf)
{
unsigned long S[8], W[64];
int i;
@@ -426,7 +405,7 @@ static void my_sha256_update(void *ctx,
return;
while(inlen > 0) {
if(md->curlen == 0 && inlen >= CURL_SHA256_BLOCK_SIZE) {
- if(sha256_compress(md, (unsigned char *)in) < 0)
+ if(sha256_compress(md, in) < 0)
return;
md->length += CURL_SHA256_BLOCK_SIZE * 8;
in += CURL_SHA256_BLOCK_SIZE;
@@ -533,5 +512,4 @@ const struct HMAC_params Curl_HMAC_SHA256 = {
32 /* Result size. */
};
-
#endif /* AWS, DIGEST, or libssh2 */
diff --git a/libs/libcurl/src/share.c b/libs/libcurl/src/share.c
index 917a315628..0dc2b146a6 100644
--- a/libs/libcurl/src/share.c
+++ b/libs/libcurl/src/share.c
@@ -47,6 +47,16 @@ curl_share_init(void)
share->magic = CURL_GOOD_SHARE;
share->specifier |= (1 << CURL_LOCK_DATA_SHARE);
Curl_init_dnscache(&share->hostcache, 23);
+ share->admin = curl_easy_init();
+ if(!share->admin) {
+ free(share);
+ return NULL;
+ }
+ share->admin->state.internal = TRUE;
+#ifdef DEBUGBUILD
+ if(getenv("CURL_DEBUG"))
+ share->admin->set.verbose = TRUE;
+#endif
}
return share;
@@ -125,9 +135,8 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
case CURL_LOCK_DATA_CONNECT:
/* It is safe to set this option several times on a share. */
- if(!share->cpool.idata) {
- if(Curl_cpool_init(&share->cpool, Curl_on_disconnect,
- NULL, share, 103))
+ if(!share->cpool.initialised) {
+ if(Curl_cpool_init(&share->cpool, share->admin, share, 103))
res = CURLSHE_NOMEM;
}
break;
@@ -257,6 +266,7 @@ curl_share_cleanup(CURLSH *sh)
#endif
Curl_psl_destroy(&share->psl);
+ Curl_close(&share->admin);
if(share->unlockfunc)
share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
diff --git a/libs/libcurl/src/share.h b/libs/libcurl/src/share.h
index 4d68020629..920a30af0a 100644
--- a/libs/libcurl/src/share.h
+++ b/libs/libcurl/src/share.h
@@ -31,6 +31,7 @@
#include "urldata.h"
#include "conncache.h"
+struct Curl_easy;
struct Curl_ssl_scache;
#define CURL_GOOD_SHARE 0x7e117a1e
@@ -48,6 +49,7 @@ struct Curl_share {
curl_lock_function lockfunc;
curl_unlock_function unlockfunc;
void *clientdata;
+ struct Curl_easy *admin;
struct cpool cpool;
struct Curl_hash hostcache;
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
diff --git a/libs/libcurl/src/smb.c b/libs/libcurl/src/smb.c
index f4808e5756..7f81f6ec80 100644
--- a/libs/libcurl/src/smb.c
+++ b/libs/libcurl/src/smb.c
@@ -77,7 +77,7 @@
#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10
#define SMB_FLAGS_CASELESS_PATHNAMES 0x08
-#define SMB_FLAGS2_UNICODE_STRINGS 0x8000
+/* #define SMB_FLAGS2_UNICODE_STRINGS 0x8000 */
#define SMB_FLAGS2_IS_LONG_NAME 0x0040
#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001
@@ -544,7 +544,7 @@ static void smb_format_message(struct Curl_easy *data, struct smb_header *h,
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)Curl_getpid();
+ pid = (unsigned int)curlx_getpid();
h->pid_high = smb_swap16((unsigned short)(pid >> 16));
h->pid = smb_swap16((unsigned short) pid);
}
diff --git a/libs/libcurl/src/smtp.c b/libs/libcurl/src/smtp.c
index b23b74ae60..e35b22f4b1 100644
--- a/libs/libcurl/src/smtp.c
+++ b/libs/libcurl/src/smtp.c
@@ -68,7 +68,6 @@
#include "mime.h"
#include "socks.h"
#include "smtp.h"
-#include "strtoofft.h"
#include "strcase.h"
#include "vtls/vtls.h"
#include "cfilters.h"
@@ -81,6 +80,8 @@
#include "curl_sasl.h"
#include "warnless.h"
#include "idn.h"
+#include "strparse.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -198,7 +199,7 @@ static const struct SASLproto saslsmtp = {
* supported authentication mechanisms.
*/
static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
- char *line, size_t len, int *resp)
+ const char *line, size_t len, int *resp)
{
struct smtp_conn *smtpc = &conn->proto.smtpc;
bool result = FALSE;
@@ -214,11 +215,14 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
only send the response code instead as per Section 4.2. */
if(line[3] == ' ' || len == 5) {
char tmpline[6];
-
+ curl_off_t code;
+ const char *p = tmpline;
result = TRUE;
- memset(tmpline, '\0', sizeof(tmpline));
memcpy(tmpline, line, (len == 5 ? 5 : 3));
- *resp = curlx_sltosi(strtol(tmpline, NULL, 10));
+ tmpline[len == 5 ? 5 : 3 ] = 0;
+ if(Curl_str_number(&p, &code, len == 5 ? 99999 : 999))
+ return FALSE;
+ *resp = (int) code;
/* Make sure real server never sends internal value */
if(*resp == 1)
@@ -397,7 +401,6 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
goto out;
/* Change the connection handler and SMTP state */
conn->handler = &Curl_handler_smtps;
- conn->bits.tls_upgraded = TRUE;
}
DEBUGASSERT(!smtpc->ssldone);
@@ -1610,10 +1613,8 @@ static CURLcode smtp_setup_connection(struct Curl_easy *data,
{
CURLcode result;
- /* Clear the TLS upgraded flag */
- conn->bits.tls_upgraded = FALSE;
-
/* Initialise the SMTP layer */
+ (void)conn;
result = smtp_init(data);
CURL_TRC_SMTP(data, "smtp_setup_connection() -> %d", result);
return result;
diff --git a/libs/libcurl/src/socketpair.c b/libs/libcurl/src/socketpair.c
index b7adf20bfc..a7cf171a97 100644
--- a/libs/libcurl/src/socketpair.c
+++ b/libs/libcurl/src/socketpair.c
@@ -27,7 +27,7 @@
#include "urldata.h"
#include "rand.h"
-#if defined(USE_EVENTFD)
+#ifdef HAVE_EVENTFD
#ifdef HAVE_SYS_EVENTFD_H
#include <sys/eventfd.h>
#endif
@@ -103,7 +103,9 @@ int Curl_socketpair(int domain, int type, int protocol,
* This is a socketpair() implementation for Windows.
*/
#include <string.h>
+#ifdef HAVE_IO_H
#include <io.h>
+#endif
#else
#ifdef HAVE_NETDB_H
#include <netdb.h>
@@ -221,15 +223,15 @@ int Curl_socketpair(int domain, int type, int protocol,
if(Curl_timediff(Curl_now(), start) > (60 * 1000))
goto error;
if(
-#ifdef WSAEWOULDBLOCK
+#ifdef USE_WINSOCK
/* This is how Windows does it */
- (WSAEWOULDBLOCK == sockerr)
+ (SOCKEWOULDBLOCK == 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) || (EINPROGRESS == sockerr)
+ (SOCKEWOULDBLOCK == sockerr) || (EAGAIN == sockerr) ||
+ (SOCKEINTR == sockerr) || (SOCKEINPROGRESS == sockerr)
#endif
) {
continue;
diff --git a/libs/libcurl/src/socketpair.h b/libs/libcurl/src/socketpair.h
index a8a011d753..68dfa5288b 100644
--- a/libs/libcurl/src/socketpair.h
+++ b/libs/libcurl/src/socketpair.h
@@ -26,24 +26,7 @@
#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
+#ifdef HAVE_EVENTFD
#define wakeup_write write
#define wakeup_read read
@@ -63,7 +46,7 @@ int Curl_eventfd(curl_socket_t socks[2], bool nonblocking);
#include <curl/curl.h>
int Curl_pipe(curl_socket_t socks[2], bool nonblocking);
-#else /* !USE_EVENTFD && !HAVE_PIPE */
+#else /* !HAVE_EVENTFD && !HAVE_PIPE */
#define wakeup_write swrite
#define wakeup_read sread
@@ -86,7 +69,7 @@ int Curl_pipe(curl_socket_t socks[2], bool nonblocking);
#define wakeup_create(p,nb)\
Curl_socketpair(SOCKETPAIR_FAMILY, SOCKETPAIR_TYPE, 0, p, nb)
-#endif /* USE_EVENTFD */
+#endif /* HAVE_EVENTFD */
#ifndef CURL_DISABLE_SOCKETPAIR
#include <curl/curl.h>
diff --git a/libs/libcurl/src/socks.c b/libs/libcurl/src/socks.c
index 57ad6e1363..c586b158b6 100644
--- a/libs/libcurl/src/socks.c
+++ b/libs/libcurl/src/socks.c
@@ -344,7 +344,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
dns = Curl_fetch_addr(data, sx->hostname, conn->primary.remote_port);
if(dns) {
-#ifdef CURLRES_ASYNCH
+#ifdef USE_CURL_ASYNC
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
@@ -590,7 +590,6 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
bool allow_gssapi = FALSE;
struct Curl_dns_entry *dns = NULL;
- DEBUGASSERT(auth & (CURLAUTH_BASIC | CURLAUTH_GSSAPI));
switch(sx->state) {
case CONNECT_SOCKS_INIT:
if(conn->bits.httpproxy)
@@ -815,7 +814,7 @@ CONNECT_REQ_INIT:
dns = Curl_fetch_addr(data, sx->hostname, sx->remote_port);
if(dns) {
-#ifdef CURLRES_ASYNCH
+#ifdef USE_CURL_ASYNC
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
@@ -912,7 +911,7 @@ CONNECT_RESOLVE_REMOTE:
#ifdef USE_IPV6
if(conn->bits.ipv6_ip) {
char ip6[16];
- if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6))
+ if(1 != curlx_inet_pton(AF_INET6, sx->hostname, ip6))
return CURLPX_BAD_ADDRESS_TYPE;
socksreq[len++] = 4;
memcpy(&socksreq[len], ip6, sizeof(ip6));
@@ -920,7 +919,7 @@ CONNECT_RESOLVE_REMOTE:
}
else
#endif
- if(1 == Curl_inet_pton(AF_INET, sx->hostname, ip4)) {
+ if(1 == curlx_inet_pton(AF_INET, sx->hostname, ip4)) {
socksreq[len++] = 1;
memcpy(&socksreq[len], ip4, sizeof(ip4));
len += sizeof(ip4);
@@ -1128,7 +1127,7 @@ static void socks_proxy_cf_free(struct Curl_cfilter *cf)
*/
static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
CURLcode result;
struct connectdata *conn = cf->conn;
@@ -1140,7 +1139,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
- result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+ result = cf->next->cft->do_connect(cf->next, data, done);
if(result || !*done)
return result;
diff --git a/libs/libcurl/src/socks_sspi.c b/libs/libcurl/src/socks_sspi.c
index cd140c4858..5c0254d490 100644
--- a/libs/libcurl/src/socks_sspi.c
+++ b/libs/libcurl/src/socks_sspi.c
@@ -140,14 +140,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
cred_handle.dwUpper = 0;
status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
- (TCHAR *) TEXT("Kerberos"),
- SECPKG_CRED_OUTBOUND,
- NULL,
- NULL,
- NULL,
- NULL,
- &cred_handle,
- &expiry);
+ (TCHAR *)CURL_UNCONST(TEXT("Kerberos")),
+ SECPKG_CRED_OUTBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred_handle,
+ &expiry);
if(check_sspi_err(data, status, "AcquireCredentialsHandle")) {
failf(data, "Failed to acquire credentials.");
diff --git a/libs/libcurl/src/strcase.c b/libs/libcurl/src/strcase.c
index 0b3fb773ff..efdaa7911c 100644
--- a/libs/libcurl/src/strcase.c
+++ b/libs/libcurl/src/strcase.c
@@ -82,65 +82,6 @@ char Curl_raw_tolower(char in)
return (char)tolowermap[(unsigned char) in];
}
-/*
- * curl_strequal() is for doing "raw" case insensitive strings. This is meant
- * to be locale independent and only compare strings we know are safe for
- * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
- * 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 --- */
-int curl_strequal(const char *first, const char *second)
-{
- if(first && second)
- /* both pointers point to something then compare them */
- return casecompare(first, second);
-
- /* if both pointers are NULL then treat them as equal */
- return NULL == first && NULL == second;
-}
-
-static int ncasecompare(const char *first, const char *second, size_t max)
-{
- while(*first && *second && max) {
- if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
- return 0;
- max--;
- first++;
- second++;
- }
- if(0 == max)
- return 1; /* they are equal this far */
-
- return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
-}
-
-/* --- public function --- */
-int curl_strnequal(const char *first, const char *second, size_t max)
-{
- 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
diff --git a/libs/libcurl/src/strdup.c b/libs/libcurl/src/strdup.c
index f3d8ed3846..e9f8535c6d 100644
--- a/libs/libcurl/src/strdup.c
+++ b/libs/libcurl/src/strdup.c
@@ -114,7 +114,10 @@ void *Curl_memdup0(const char *src, size_t length)
char *buf = malloc(length + 1);
if(!buf)
return NULL;
- memcpy(buf, src, length);
+ if(length) {
+ DEBUGASSERT(src); /* must never be NULL */
+ memcpy(buf, src, length);
+ }
buf[length] = 0;
return buf;
}
diff --git a/libs/libcurl/src/strequal.c b/libs/libcurl/src/strequal.c
new file mode 100644
index 0000000000..fb8e718e4c
--- /dev/null
+++ b/libs/libcurl/src/strequal.c
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "curl_setup.h"
+
+#include <curl/curl.h>
+#include "strcase.h"
+
+/*
+ * curl_strequal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * further explanations as to why this function is necessary.
+ */
+
+static int casecompare(const char *first, const char *second)
+{
+ while(*first) {
+ 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;
+}
+
+static int ncasecompare(const char *first, const char *second, size_t max)
+{
+ while(*first && max) {
+ if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
+ return 0;
+ max--;
+ first++;
+ second++;
+ }
+ if(0 == max)
+ return 1; /* they are equal this far */
+
+ return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
+}
+
+/* --- public function --- */
+int curl_strequal(const char *first, const char *second)
+{
+ if(first && second)
+ /* both pointers point to something then compare them */
+ return casecompare(first, second);
+
+ /* if both pointers are NULL then treat them as equal */
+ return NULL == first && NULL == second;
+}
+
+/* --- public function --- */
+int curl_strnequal(const char *first, const char *second, size_t max)
+{
+ 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;
+}
diff --git a/libs/libcurl/src/strerror.c b/libs/libcurl/src/strerror.c
index ab702e0efc..b9f29ea096 100644
--- a/libs/libcurl/src/strerror.c
+++ b/libs/libcurl/src/strerror.c
@@ -48,7 +48,7 @@
#include "curl_memory.h"
#include "memdebug.h"
-#if defined(_WIN32) || defined(_WIN32_WCE)
+#ifdef _WIN32
#define PRESERVE_WINDOWS_ERROR_CODE
#endif
@@ -335,6 +335,20 @@ curl_easy_strerror(CURLcode error)
case CURLE_OBSOLETE62:
case CURLE_OBSOLETE75:
case CURLE_OBSOLETE76:
+
+ /* error codes used by curl tests */
+ case CURLE_RESERVED115:
+ case CURLE_RESERVED116:
+ case CURLE_RESERVED117:
+ case CURLE_RESERVED118:
+ case CURLE_RESERVED119:
+ case CURLE_RESERVED120:
+ case CURLE_RESERVED121:
+ case CURLE_RESERVED122:
+ case CURLE_RESERVED123:
+ case CURLE_RESERVED124:
+ case CURLE_RESERVED125:
+ case CURLE_RESERVED126:
case CURL_LAST:
break;
}
@@ -768,7 +782,7 @@ get_winsock_error(int err, char *buf, size_t len)
}
#endif /* USE_WINSOCK */
-#if defined(_WIN32) || defined(_WIN32_WCE)
+#ifdef _WIN32
/* This is a helper function for Curl_strerror that converts Windows API error
* codes (GetLastError) to error messages.
* Returns NULL if no error message was found for error code.
@@ -791,7 +805,7 @@ get_winapi_error(int err, char *buf, size_t buflen)
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)) {
+ LANG_NEUTRAL, wbuf, CURL_ARRAYSIZE(wbuf), NULL)) {
size_t written = wcstombs(buf, wbuf, buflen - 1);
if(written != (size_t)-1)
buf[written] = '\0';
@@ -810,7 +824,7 @@ get_winapi_error(int err, char *buf, size_t buflen)
return *buf ? buf : NULL;
}
-#endif /* _WIN32 || _WIN32_WCE */
+#endif /* _WIN32 */
/*
* Our thread-safe and smart strerror() replacement.
@@ -829,7 +843,7 @@ get_winapi_error(int err, char *buf, size_t buflen)
*
* It may be more correct to call one of the variant functions instead:
* Call Curl_sspi_strerror if the error code is definitely Windows SSPI.
- * Call Curl_winapi_strerror if the error code is definitely Windows API.
+ * Call curlx_winapi_strerror if the error code is definitely Windows API.
*/
const char *Curl_strerror(int err, char *buf, size_t buflen)
{
@@ -848,8 +862,8 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
*buf = '\0';
-#if defined(_WIN32) || defined(_WIN32_WCE)
-#if defined(_WIN32)
+#ifdef _WIN32
+#ifndef UNDER_CE
/* 'sys_nerr' is the maximum errno number, it is not widely portable */
if(err >= 0 && err < sys_nerr)
msnprintf(buf, buflen, "%s", sys_errlist[err]);
@@ -911,7 +925,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
*p = '\0';
if(errno != old_errno)
- errno = old_errno;
+ CURL_SETERRNO(old_errno);
#ifdef PRESERVE_WINDOWS_ERROR_CODE
if(old_win_err != GetLastError())
@@ -922,11 +936,11 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
}
/*
- * Curl_winapi_strerror:
+ * curlx_winapi_strerror:
* Variant of Curl_strerror if the error code is definitely Windows API.
*/
-#if defined(_WIN32) || defined(_WIN32_WCE)
-const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
+#ifdef _WIN32
+const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen)
{
#ifdef PRESERVE_WINDOWS_ERROR_CODE
DWORD old_win_err = GetLastError();
@@ -951,7 +965,7 @@ const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
#endif
if(errno != old_errno)
- errno = old_errno;
+ CURL_SETERRNO(old_errno);
#ifdef PRESERVE_WINDOWS_ERROR_CODE
if(old_win_err != GetLastError())
@@ -960,7 +974,7 @@ const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
return buf;
}
-#endif /* _WIN32 || _WIN32_WCE */
+#endif /* _WIN32 */
#ifdef USE_WINDOWS_SSPI
/*
@@ -1100,7 +1114,7 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
#endif
if(errno != old_errno)
- errno = old_errno;
+ CURL_SETERRNO(old_errno);
#ifdef PRESERVE_WINDOWS_ERROR_CODE
if(old_win_err != GetLastError())
diff --git a/libs/libcurl/src/strerror.h b/libs/libcurl/src/strerror.h
index 1fd423fc17..6b9b8e358a 100644
--- a/libs/libcurl/src/strerror.h
+++ b/libs/libcurl/src/strerror.h
@@ -29,8 +29,8 @@
#define STRERROR_LEN 256 /* a suitable length */
const char *Curl_strerror(int err, char *buf, size_t buflen);
-#if defined(_WIN32) || defined(_WIN32_WCE)
-const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen);
+#ifdef _WIN32
+const char *curlx_winapi_strerror(DWORD err, char *buf, size_t buflen);
#endif
#ifdef USE_WINDOWS_SSPI
const char *Curl_sspi_strerror(int err, char *buf, size_t buflen);
diff --git a/libs/libcurl/src/strparse.c b/libs/libcurl/src/strparse.c
index e057598732..2c1ec20517 100644
--- a/libs/libcurl/src/strparse.c
+++ b/libs/libcurl/src/strparse.c
@@ -23,18 +23,30 @@
***************************************************************************/
#include "strparse.h"
+#include "strcase.h"
+
+void Curl_str_init(struct Curl_str *out)
+{
+ out->str = NULL;
+ out->len = 0;
+}
+
+void Curl_str_assign(struct Curl_str *out, const char *str, size_t len)
+{
+ out->str = str;
+ out->len = len;
+}
/* Get a word until the first DELIM or end of string. At least one byte long.
return non-zero on error */
-int Curl_str_until(char **linep, struct Curl_str *out,
+int Curl_str_until(const char **linep, struct Curl_str *out,
const size_t max, char delim)
{
- char *s = *linep;
+ const char *s = *linep;
size_t len = 0;
DEBUGASSERT(linep && *linep && out && max && delim);
- out->str = NULL;
- out->len = 0;
+ Curl_str_init(out);
while(*s && (*s != delim)) {
s++;
if(++len > max) {
@@ -51,24 +63,46 @@ int Curl_str_until(char **linep, struct Curl_str *out,
/* Get a word until the first space or end of string. At least one byte long.
return non-zero on error */
-int Curl_str_word(char **linep, struct Curl_str *out,
+int Curl_str_word(const char **linep, struct Curl_str *out,
const size_t max)
{
return Curl_str_until(linep, out, max, ' ');
}
+/* Get a word until a newline byte or end of string. At least one byte long.
+ return non-zero on error */
+int Curl_str_untilnl(const char **linep, struct Curl_str *out,
+ const size_t max)
+{
+ const char *s = *linep;
+ size_t len = 0;
+ DEBUGASSERT(linep && *linep && out && max);
+
+ Curl_str_init(out);
+ while(*s && !ISNEWLINE(*s)) {
+ s++;
+ if(++len > max)
+ return STRE_BIG;
+ }
+ if(!len)
+ return STRE_SHORT;
+ out->str = *linep;
+ out->len = len;
+ *linep = s; /* point to the first byte after the word */
+ return STRE_OK;
+}
+
/* Get a "quoted" word. No escaping possible.
return non-zero on error */
-int Curl_str_quotedword(char **linep, struct Curl_str *out,
+int Curl_str_quotedword(const char **linep, struct Curl_str *out,
const size_t max)
{
- char *s = *linep;
+ const char *s = *linep;
size_t len = 0;
DEBUGASSERT(linep && *linep && out && max);
- out->str = NULL;
- out->len = 0;
+ Curl_str_init(out);
if(*s != '\"')
return STRE_BEGQUOTE;
s++;
@@ -87,7 +121,7 @@ int Curl_str_quotedword(char **linep, struct Curl_str *out,
/* Advance over a single character.
return non-zero on error */
-int Curl_str_single(char **linep, char byte)
+int Curl_str_single(const char **linep, char byte)
{
DEBUGASSERT(linep && *linep);
if(**linep != byte)
@@ -98,34 +132,99 @@ int Curl_str_single(char **linep, char byte)
/* Advance over a single space.
return non-zero on error */
-int Curl_str_singlespace(char **linep)
+int Curl_str_singlespace(const char **linep)
{
return Curl_str_single(linep, ' ');
}
-/* Get an unsigned number. Leading zeroes are accepted.
- return non-zero on error */
-int Curl_str_number(char **linep, size_t *nump, size_t max)
+/* given an ASCII character and max ascii, return TRUE if valid */
+#define valid_digit(x,m) \
+ (((x) >= '0') && ((x) <= m) && hexasciitable[(x)-'0'])
+
+/* no support for 0x prefix nor leading spaces */
+static int str_num_base(const char **linep, curl_off_t *nump, curl_off_t max,
+ int base) /* 8, 10 or 16, nothing else */
{
- size_t num = 0;
+ /* We use 16 for the zero index (and the necessary bitwise AND in the loop)
+ to be able to have a non-zero value there to make valid_digit() able to
+ use the info */
+ static const unsigned char hexasciitable[] = {
+ 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* 0x30: 0 - 9 */
+ 0, 0, 0, 0, 0, 0, 0,
+ 10, 11, 12, 13, 14, 15, /* 0x41: A - F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 10, 11, 12, 13, 14, 15 /* 0x61: a - f */
+ };
+
+ curl_off_t num = 0;
+ const char *p;
+ int m = (base == 10) ? '9' : /* the largest digit possible */
+ (base == 16) ? 'f' : '7';
DEBUGASSERT(linep && *linep && nump);
+ DEBUGASSERT((base == 8) || (base == 10) || (base == 16));
+ DEBUGASSERT(max >= 0); /* mostly to catch SIZE_T_MAX, which is too large */
*nump = 0;
- while(ISDIGIT(**linep)) {
- int n = **linep - '0';
- if(num > ((SIZE_T_MAX - n) / 10))
- return STRE_OVERFLOW;
- num = num * 10 + n;
- if(num > max)
- return STRE_BIG; /** too big */
- (*linep)++;
+ p = *linep;
+ if(!valid_digit(*p, m))
+ return STRE_NO_NUM;
+ if(max < base) {
+ /* special-case low max scenario because check needs to be different */
+ do {
+ int n = hexasciitable[*p++ - '0'] & 0x0f;
+ num = num * base + n;
+ if(num > max)
+ return STRE_OVERFLOW;
+ } while(valid_digit(*p, m));
+ }
+ else {
+ do {
+ int n = hexasciitable[*p++ - '0'] & 0x0f;
+ if(num > ((max - n) / base))
+ return STRE_OVERFLOW;
+ num = num * base + n;
+ } while(valid_digit(*p, m));
}
*nump = num;
+ *linep = p;
return STRE_OK;
}
+/* Get an unsigned decimal number with no leading space or minus. Leading
+ zeroes are accepted. return non-zero on error */
+int Curl_str_number(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+ return str_num_base(linep, nump, max, 10);
+}
+
+/* Get an unsigned hexadecimal number with no leading space or minus and no
+ "0x" support. Leading zeroes are accepted. return non-zero on error */
+int Curl_str_hex(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+ return str_num_base(linep, nump, max, 16);
+}
+
+/* Get an unsigned octal number with no leading space or minus and no "0"
+ prefix support. Leading zeroes are accepted. return non-zero on error */
+int Curl_str_octal(const char **linep, curl_off_t *nump, curl_off_t max)
+{
+ return str_num_base(linep, nump, max, 8);
+}
+
+/*
+ * Parse a positive number up to 63-bit number written in ASCII. Skip leading
+ * blanks. No support for prefixes.
+ */
+int Curl_str_numblanks(const char **str, curl_off_t *num)
+{
+ Curl_str_passblanks(str);
+ return Curl_str_number(str, num, CURL_OFF_T_MAX);
+}
+
/* CR or LF
return non-zero on error */
-int Curl_str_newline(char **linep)
+int Curl_str_newline(const char **linep)
{
DEBUGASSERT(linep && *linep);
if(ISNEWLINE(**linep)) {
@@ -134,3 +233,70 @@ int Curl_str_newline(char **linep)
}
return STRE_NEWLINE;
}
+
+/* case insensitive compare that the parsed string matches the
+ given string. Returns non-zero on match. */
+int Curl_str_casecompare(struct Curl_str *str, const char *check)
+{
+ size_t clen = check ? strlen(check) : 0;
+ return ((str->len == clen) && strncasecompare(str->str, check, clen));
+}
+
+/* case sensitive string compare. Returns non-zero on match. */
+int Curl_str_cmp(struct Curl_str *str, const char *check)
+{
+ if(check) {
+ size_t clen = strlen(check);
+ return ((str->len == clen) && !strncmp(str->str, check, clen));
+ }
+ return !!(str->len);
+}
+
+/* Trim off 'num' number of bytes from the beginning (left side) of the
+ string. If 'num' is larger than the string, return error. */
+int Curl_str_nudge(struct Curl_str *str, size_t num)
+{
+ if(num <= str->len) {
+ str->str += num;
+ str->len -= num;
+ return STRE_OK;
+ }
+ return STRE_OVERFLOW;
+}
+
+/* Get the following character sequence that consists only of bytes not
+ present in the 'reject' string. Like strcspn(). */
+int Curl_str_cspn(const char **linep, struct Curl_str *out, const char *reject)
+{
+ const char *s = *linep;
+ size_t len;
+ DEBUGASSERT(linep && *linep);
+
+ len = strcspn(s, reject);
+ if(len) {
+ out->str = s;
+ out->len = len;
+ *linep = &s[len];
+ return STRE_OK;
+ }
+ Curl_str_init(out);
+ return STRE_SHORT;
+}
+
+/* remove ISBLANK()s from both ends of the string */
+void Curl_str_trimblanks(struct Curl_str *out)
+{
+ while(out->len && ISBLANK(*out->str))
+ Curl_str_nudge(out, 1);
+
+ /* trim trailing spaces and tabs */
+ while(out->len && ISBLANK(out->str[out->len - 1]))
+ out->len--;
+}
+
+/* increase the pointer until it has moved over all blanks */
+void Curl_str_passblanks(const char **linep)
+{
+ while(ISBLANK(**linep))
+ (*linep)++; /* move over it */
+}
diff --git a/libs/libcurl/src/strparse.h b/libs/libcurl/src/strparse.h
index 1d4d02638d..01c696c277 100644
--- a/libs/libcurl/src/strparse.h
+++ b/libs/libcurl/src/strparse.h
@@ -33,39 +33,79 @@
#define STRE_BYTE 5
#define STRE_NEWLINE 6
#define STRE_OVERFLOW 7
+#define STRE_NO_NUM 8
+/* public struct, but all accesses should be done using the provided
+ functions */
struct Curl_str {
- char *str;
+ const char *str;
size_t len;
};
+void Curl_str_init(struct Curl_str *out);
+void Curl_str_assign(struct Curl_str *out, const char *str, size_t len);
+
+#define Curl_str(x) ((x)->str)
+#define Curl_strlen(x) ((x)->len)
+
/* Get a word until the first space
return non-zero on error */
-int Curl_str_word(char **linep, struct Curl_str *out, const size_t max);
+int Curl_str_word(const char **linep, struct Curl_str *out, const size_t max);
/* Get a word until the first DELIM or end of string
return non-zero on error */
-int Curl_str_until(char **linep, struct Curl_str *out, const size_t max,
+int Curl_str_until(const char **linep, struct Curl_str *out, const size_t max,
char delim);
+/* Get a word until a newline byte or end of string. At least one byte long.
+ return non-zero on error */
+int Curl_str_untilnl(const char **linep, struct Curl_str *out,
+ const size_t max);
+
/* Get a "quoted" word. No escaping possible.
return non-zero on error */
-int Curl_str_quotedword(char **linep, struct Curl_str *out, const size_t max);
+int Curl_str_quotedword(const char **linep, struct Curl_str *out,
+ const size_t max);
/* Advance over a single character.
return non-zero on error */
-int Curl_str_single(char **linep, char byte);
+int Curl_str_single(const char **linep, char byte);
/* Advance over a single space.
return non-zero on error */
-int Curl_str_singlespace(char **linep);
+int Curl_str_singlespace(const char **linep);
-/* Get an unsigned number
- return non-zero on error */
-int Curl_str_number(char **linep, size_t *nump, size_t max);
+/* Get an unsigned decimal number. Return non-zero on error */
+int Curl_str_number(const char **linep, curl_off_t *nump, curl_off_t max);
+
+/* As above with CURL_OFF_T_MAX but also pass leading blanks */
+int Curl_str_numblanks(const char **str, curl_off_t *num);
+
+/* Get an unsigned hexadecimal number. Return non-zero on error */
+int Curl_str_hex(const char **linep, curl_off_t *nump, curl_off_t max);
+
+/* Get an unsigned octal number. Return non-zero on error */
+int Curl_str_octal(const char **linep, curl_off_t *nump, curl_off_t max);
/* Check for CR or LF
return non-zero on error */
-int Curl_str_newline(char **linep);
+int Curl_str_newline(const char **linep);
+
+/* case insensitive compare that the parsed string matches the
+ given string. */
+int Curl_str_casecompare(struct Curl_str *str, const char *check);
+int Curl_str_cmp(struct Curl_str *str, const char *check);
+
+int Curl_str_nudge(struct Curl_str *str, size_t num);
+
+int Curl_str_cspn(const char **linep, struct Curl_str *out, const char *cspn);
+void Curl_str_trimblanks(struct Curl_str *out);
+void Curl_str_passblanks(const char **linep);
+
+#define curlx_str_number(x,y,z) Curl_str_number(x,y,z)
+#define curlx_str_octal(x,y,z) Curl_str_octal(x,y,z)
+#define curlx_str_single(x,y) Curl_str_single(x,y)
+#define curlx_str_passblanks(x) Curl_str_passblanks(x)
+#define curlx_str_numblanks(x,y) Curl_str_numblanks(x,y)
#endif /* HEADER_CURL_STRPARSE_H */
diff --git a/libs/libcurl/src/strtok.c b/libs/libcurl/src/strtok.c
deleted file mode 100644
index ffd546170c..0000000000
--- a/libs/libcurl/src/strtok.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * 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 "curl_setup.h"
-
-#ifndef HAVE_STRTOK_R
-#include <stddef.h>
-
-#include "strtok.h"
-
-char *
-Curl_strtok_r(char *ptr, const char *sep, char **end)
-{
- if(!ptr)
- /* we got NULL input so then we get our last position instead */
- ptr = *end;
-
- /* pass all letters that are including in the separator string */
- while(*ptr && strchr(sep, *ptr))
- ++ptr;
-
- if(*ptr) {
- /* so this is where the next piece of string starts */
- char *start = ptr;
-
- /* set the end pointer to the first byte after the start */
- *end = start + 1;
-
- /* scan through the string to find where it ends, it ends on a
- null byte or a character that exists in the separator string */
- while(**end && !strchr(sep, **end))
- ++*end;
-
- if(**end) {
- /* the end is not a null byte */
- **end = '\0'; /* null-terminate it! */
- ++*end; /* advance the last pointer to beyond the null byte */
- }
-
- 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 */
diff --git a/libs/libcurl/src/strtoofft.c b/libs/libcurl/src/strtoofft.c
deleted file mode 100644
index 6d3f63bec0..0000000000
--- a/libs/libcurl/src/strtoofft.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * 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 <errno.h>
-#include "curl_setup.h"
-
-#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
-# if defined(_MSC_VER) && (_MSC_VER >= 1300)
-# if defined(_SAL_VERSION)
- _Check_return_ _CRTIMP __int64 __cdecl _strtoi64(
- _In_z_ const char *_String,
- _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix);
-# else
- _CRTIMP __int64 __cdecl _strtoi64(const char *_String,
- char **_EndPtr, int _Radix);
-# endif
-# define strtooff _strtoi64
-# else
-# define PRIVATE_STRTOOFF 1
-# endif
-# endif
-#else
-# define strtooff strtol
-#endif
-
-#ifdef PRIVATE_STRTOOFF
-
-/* Range tests can be used for alphanum decoding if characters are consecutive,
- like in ASCII. Else an array is scanned. Determine this condition now. */
-
-#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
-
-#define NO_RANGE_TEST
-
-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;
- int i;
- curl_off_t value = 0;
-
- /* Skip leading whitespace. */
- end = (char *)nptr;
- while(ISBLANK(end[0])) {
- end++;
- }
-
- /* Handle the sign, if any. */
- if(end[0] == '-') {
- is_negative = TRUE;
- end++;
- }
- else if(end[0] == '+') {
- end++;
- }
- else if(end[0] == '\0') {
- /* We had nothing but perhaps some whitespace -- there was no number. */
- if(endptr) {
- *endptr = end;
- }
- return 0;
- }
-
- /* Handle special beginnings, if present and allowed. */
- if(end[0] == '0' && end[1] == 'x') {
- if(base == 16 || base == 0) {
- end += 2;
- base = 16;
- }
- }
- 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);
- i != -1;
- end++, i = get_char(end[0], base)) {
-
- if(value > (CURL_OFF_T_MAX - i) / base) {
- overflow = TRUE;
- break;
- }
- value = base * value + i;
- }
-
- if(!overflow) {
- if(is_negative) {
- /* Fix the sign. */
- value *= -1;
- }
- }
- else {
- if(is_negative)
- value = CURL_OFF_T_MIN;
- else
- value = CURL_OFF_T_MAX;
-
- errno = ERANGE;
- }
-
- if(endptr)
- *endptr = end;
-
- return value;
-}
-
-/**
- * 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';
- }
- else if(c <= 'Z' && c >= 'A') {
- value = c - 'A' + 10;
- }
- else if(c <= 'z' && c >= 'a') {
- value = c - 'a' + 10;
- }
-#else
- const char *cp;
- int value;
-
- cp = memchr(valchars, c, 10 + 26 + 26);
-
- if(!cp)
- return -1;
-
- value = cp - valchars;
-
- if(value >= 10 + 26)
- value -= 26; /* Lowercase. */
-#endif
-
- 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 */
- return CURL_OFFT_FLOW;
- else if(str == end)
- /* nothing parsed */
- return CURL_OFFT_INVAL;
-
- *num = number;
- return CURL_OFFT_OK;
-}
diff --git a/libs/libcurl/src/strtoofft.h b/libs/libcurl/src/strtoofft.h
deleted file mode 100644
index e6ef31a870..0000000000
--- a/libs/libcurl/src/strtoofft.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef HEADER_CURL_STRTOOFFT_H
-#define HEADER_CURL_STRTOOFFT_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 "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.
- *
- * On systems where the size of curl_off_t is smaller or equal than the size
- * of 'long' the conversion function to use is strtol().
- */
-
-typedef enum {
- CURL_OFFT_OK, /* parsed fine */
- CURL_OFFT_FLOW, /* over or underflow */
- CURL_OFFT_INVAL /* nothing was parsed */
-} CURLofft;
-
-CURLofft curlx_strtoofft(const char *str, char **endp, int base,
- curl_off_t *num);
-
-#endif /* HEADER_CURL_STRTOOFFT_H */
diff --git a/libs/libcurl/src/system_win32.c b/libs/libcurl/src/system_win32.c
index c5599ce20f..1a3744001c 100644
--- a/libs/libcurl/src/system_win32.c
+++ b/libs/libcurl/src/system_win32.c
@@ -24,7 +24,7 @@
#include "curl_setup.h"
-#if defined(_WIN32)
+#ifdef _WIN32
#include <curl/curl.h>
#include "system_win32.h"
@@ -96,9 +96,15 @@ CURLcode Curl_win32_init(long flags)
s_hIpHlpApiDll = Curl_load_library(TEXT("iphlpapi.dll"));
if(s_hIpHlpApiDll) {
/* Get the address of the if_nametoindex function */
+#ifdef UNDER_CE
+ #define CURL_TEXT(n) TEXT(n)
+#else
+ #define CURL_TEXT(n) (n)
+#endif
IF_NAMETOINDEX_FN pIfNameToIndex =
CURLX_FUNCTION_CAST(IF_NAMETOINDEX_FN,
- (GetProcAddress(s_hIpHlpApiDll, "if_nametoindex")));
+ (GetProcAddress(s_hIpHlpApiDll,
+ CURL_TEXT("if_nametoindex"))));
if(pIfNameToIndex)
Curl_if_nametoindex = pIfNameToIndex;
@@ -150,7 +156,7 @@ typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
/* See function definitions in winbase.h */
#ifdef UNICODE
-# ifdef _WIN32_WCE
+# ifdef UNDER_CE
# define LOADLIBARYEX L"LoadLibraryExW"
# else
# define LOADLIBARYEX "LoadLibraryExW"
@@ -175,7 +181,7 @@ typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
*/
HMODULE Curl_load_library(LPCTSTR filename)
{
-#ifndef CURL_WINDOWS_UWP
+#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
HMODULE hModule = NULL;
LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
diff --git a/libs/libcurl/src/system_win32.h b/libs/libcurl/src/system_win32.h
index 4ba748d381..0568450713 100644
--- a/libs/libcurl/src/system_win32.h
+++ b/libs/libcurl/src/system_win32.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-#if defined(_WIN32)
+#ifdef _WIN32
#include <curl/curl.h>
diff --git a/libs/libcurl/src/telnet.c b/libs/libcurl/src/telnet.c
index f57addbefe..fa475fc4e2 100644
--- a/libs/libcurl/src/telnet.c
+++ b/libs/libcurl/src/telnet.c
@@ -58,6 +58,7 @@
#include "select.h"
#include "strcase.h"
#include "warnless.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -862,22 +863,20 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
case 2:
/* Window Size */
if(strncasecompare(option, "WS", 2)) {
- char *p;
- unsigned long x = strtoul(arg, &p, 10);
- unsigned long y = 0;
- if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') {
- p++;
- y = strtoul(p, NULL, 10);
- if(y && (y <= 0xffff)) {
- tn->subopt_wsx = (unsigned short)x;
- tn->subopt_wsy = (unsigned short)y;
- tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
- }
- }
- if(!y) {
+ const char *p = arg;
+ curl_off_t x = 0;
+ curl_off_t y = 0;
+ if(Curl_str_number(&p, &x, 0xffff) ||
+ Curl_str_single(&p, 'x') ||
+ Curl_str_number(&p, &y, 0xffff)) {
failf(data, "Syntax error in telnet option: %s", head->data);
result = CURLE_SETOPT_OPTION_SYNTAX;
}
+ else {
+ tn->subopt_wsx = (unsigned short)x;
+ tn->subopt_wsy = (unsigned short)y;
+ tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
+ }
}
else
result = CURLE_UNKNOWN_OPTION;
@@ -1067,15 +1066,15 @@ CURLcode telrcv(struct Curl_easy *data,
int startwrite = -1;
struct TELNET *tn = data->req.p.telnet;
-#define startskipping() \
- if(startwrite >= 0) { \
- result = Curl_client_write(data, \
- CLIENTWRITE_BODY, \
- (char *)&inbuf[startwrite], \
- in-startwrite); \
- if(result) \
- return result; \
- } \
+#define startskipping() \
+ if(startwrite >= 0) { \
+ result = Curl_client_write(data, \
+ CLIENTWRITE_BODY, \
+ (const char *)&inbuf[startwrite], \
+ in-startwrite); \
+ if(result) \
+ return result; \
+ } \
startwrite = -1
#define writebyte() \
@@ -1450,7 +1449,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
events.lNetworkEvents = 0;
if(WSAEnumNetworkEvents(sockfd, event_handle, &events) == SOCKET_ERROR) {
err = SOCKERRNO;
- if(err != EINPROGRESS) {
+ if(err != SOCKEINPROGRESS) {
infof(data, "WSAEnumNetworkEvents failed (%d)", err);
keepon = FALSE;
result = CURLE_READ_ERROR;
@@ -1555,7 +1554,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
/* In test 1452, macOS sees a ECONNRESET sometimes? Is this the
* telnet test server not shutting down the socket in a clean way?
* Seems to be timing related, happens more on slow debug build */
- if(data->state.os_errno == ECONNRESET) {
+ if(data->state.os_errno == SOCKECONNRESET) {
DEBUGF(infof(data, "telnet_do, unexpected ECONNRESET on recv"));
}
break;
diff --git a/libs/libcurl/src/tftp.c b/libs/libcurl/src/tftp.c
index 15342cd8b8..c1a25d7092 100644
--- a/libs/libcurl/src/tftp.c
+++ b/libs/libcurl/src/tftp.c
@@ -62,6 +62,7 @@
#include "speedcheck.h"
#include "select.h"
#include "escape.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -135,9 +136,9 @@ struct tftp_state_data {
struct Curl_sockaddr_storage remote_addr;
curl_socklen_t remote_addrlen;
int rbytes;
- int sbytes;
- int blksize;
- int requested_blksize;
+ size_t sbytes;
+ unsigned int blksize;
+ unsigned int requested_blksize;
unsigned short block;
struct tftp_packet rpacket;
struct tftp_packet spacket;
@@ -330,19 +331,16 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
infof(data, "got option=(%s) value=(%s)", option, value);
if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
- long blksize;
-
- blksize = strtol(value, NULL, 10);
-
- if(!blksize) {
- failf(data, "invalid blocksize value in OACK packet");
- return CURLE_TFTP_ILLEGAL;
- }
- if(blksize > TFTP_BLKSIZE_MAX) {
+ curl_off_t blksize;
+ if(Curl_str_number(&value, &blksize, TFTP_BLKSIZE_MAX)) {
failf(data, "%s (%d)", "blksize is larger than max supported",
TFTP_BLKSIZE_MAX);
return CURLE_TFTP_ILLEGAL;
}
+ if(!blksize) {
+ failf(data, "invalid blocksize value in OACK packet");
+ return CURLE_TFTP_ILLEGAL;
+ }
else if(blksize < TFTP_BLKSIZE_MIN) {
failf(data, "%s (%d)", "blksize is smaller than min supported",
TFTP_BLKSIZE_MIN);
@@ -352,28 +350,27 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
/* 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);
+ failf(data, "server requested blksize larger than allocated (%"
+ CURL_FORMAT_CURL_OFF_T ")", blksize);
return CURLE_TFTP_ILLEGAL;
}
state->blksize = (int)blksize;
- infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
- state->blksize, "requested", state->requested_blksize);
+ infof(data, "blksize parsed from OACK (%d) requested (%d)",
+ state->blksize, state->requested_blksize);
}
else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
- long tsize = 0;
-
- tsize = strtol(value, NULL, 10);
- infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
-
+ curl_off_t tsize = 0;
/* tsize should be ignored on upload: Who cares about the size of the
remote file? */
- if(!data->state.upload) {
+ if(!data->state.upload &&
+ !Curl_str_number(&value, &tsize, CURL_OFF_T_MAX)) {
if(!tsize) {
failf(data, "invalid tsize -:%s:- value in OACK packet", value);
return CURLE_TFTP_ILLEGAL;
}
+ infof(data, "tsize parsed from OACK (%" CURL_FORMAT_CURL_OFF_T ")",
+ tsize);
Curl_pgrsSetDownloadSize(data, tsize);
}
}
@@ -523,9 +520,14 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
/* 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' */
+#ifdef __AMIGA__
+#define CURL_SENDTO_ARG5(x) CURL_UNCONST(x)
+#else
+#define CURL_SENDTO_ARG5(x) (x)
+#endif
senddata = sendto(state->sockfd, (void *)state->spacket.data,
(SEND_TYPE_ARG3)sbytes, 0,
- (struct sockaddr *)&data->conn->remote_addr->curl_sa_addr,
+ CURL_SENDTO_ARG5(&data->conn->remote_addr->curl_sa_addr),
(curl_socklen_t)data->conn->remote_addr->addrlen);
if(senddata != (ssize_t)sbytes) {
char buffer[STRERROR_LEN];
@@ -776,7 +778,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
&cb, &eos);
if(result)
return result;
- state->sbytes += (int)cb;
+ state->sbytes += cb;
bufptr += cb;
} while(state->sbytes < state->blksize && cb);
diff --git a/libs/libcurl/src/timediff.c b/libs/libcurl/src/timediff.c
index a98d5782c1..641a15c404 100644
--- a/libs/libcurl/src/timediff.c
+++ b/libs/libcurl/src/timediff.c
@@ -44,7 +44,7 @@ struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms)
if(ms > 0) {
timediff_t tv_sec = ms / 1000;
- timediff_t tv_usec = (ms % 1000) * 1000; /* max=999999 */
+ timediff_t tv_usec = (ms % 1000) * 1000; /* max=999000 */
#ifdef HAVE_SUSECONDS_T
#if TIMEDIFF_T_MAX > TIME_T_MAX
/* tv_sec overflow check in case time_t is signed */
@@ -84,5 +84,5 @@ struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms)
*/
timediff_t curlx_tvtoms(struct timeval *tv)
{
- return (tv->tv_sec*1000) + (timediff_t)(((double)tv->tv_usec)/1000.0);
+ return (tv->tv_sec*1000) + (timediff_t)(tv->tv_usec/1000);
}
diff --git a/libs/libcurl/src/timeval.c b/libs/libcurl/src/timeval.c
index cf7a0b055c..582bf09344 100644
--- a/libs/libcurl/src/timeval.c
+++ b/libs/libcurl/src/timeval.c
@@ -24,30 +24,62 @@
#include "timeval.h"
-#if defined(_WIN32)
+#ifdef _WIN32
#include <curl/curl.h>
+#ifdef BUILDING_LIBCURL
#include "system_win32.h"
+#else
+#include "version_win32.h"
+
+static LARGE_INTEGER s_freq;
+static bool s_isVistaOrGreater;
+
+/* For tool or tests, we must initialize before calling Curl_now() */
+void curlx_now_init(void)
+{
+ if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL))
+ s_isVistaOrGreater = true;
+ else
+ s_isVistaOrGreater = false;
+
+ QueryPerformanceFrequency(&s_freq);
+}
+#endif
/* In case of bug fix this function has a counterpart in tool_util.c */
struct curltime Curl_now(void)
{
struct curltime now;
- if(Curl_isVistaOrGreater) { /* QPC timer might have issues pre-Vista */
+ bool isVistaOrGreater;
+#ifdef BUILDING_LIBCURL
+ isVistaOrGreater = Curl_isVistaOrGreater;
+#else
+ isVistaOrGreater = s_isVistaOrGreater;
+#endif
+ if(isVistaOrGreater) { /* QPC timer might have issues pre-Vista */
LARGE_INTEGER count;
+ LARGE_INTEGER freq;
+#ifdef BUILDING_LIBCURL
+ freq = Curl_freq;
+#else
+ freq = s_freq;
+#endif
+ DEBUGASSERT(freq.QuadPart);
QueryPerformanceCounter(&count);
- now.tv_sec = (time_t)(count.QuadPart / Curl_freq.QuadPart);
- now.tv_usec = (int)((count.QuadPart % Curl_freq.QuadPart) * 1000000 /
- Curl_freq.QuadPart);
+ now.tv_sec = (time_t)(count.QuadPart / freq.QuadPart);
+ now.tv_usec = (int)((count.QuadPart % freq.QuadPart) * 1000000 /
+ freq.QuadPart);
}
else {
/* Disable /analyze warning that GetTickCount64 is preferred */
-#if defined(_MSC_VER)
+#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:28159)
#endif
DWORD milliseconds = GetTickCount();
-#if defined(_MSC_VER)
+#ifdef _MSC_VER
#pragma warning(pop)
#endif
diff --git a/libs/libcurl/src/timeval.h b/libs/libcurl/src/timeval.h
index 510688944a..b610f51935 100644
--- a/libs/libcurl/src/timeval.h
+++ b/libs/libcurl/src/timeval.h
@@ -28,6 +28,18 @@
#include "timediff.h"
+#ifndef BUILDING_LIBCURL
+/* this renames the functions so that the tool code can use the same code
+ without getting symbol collisions */
+#define Curl_now curlx_now
+#define Curl_timediff(a,b) curlx_timediff(a,b)
+#define Curl_timediff_ceil(a,b) curlx_timediff_ceil(a,b)
+#define Curl_timediff_us(a,b) curlx_timediff_us(a,b)
+
+/* For tool or tests, we must initialize before calling Curl_now() */
+void curlx_now_init(void);
+#endif
+
struct curltime {
time_t tv_sec; /* seconds */
int tv_usec; /* microseconds */
diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c
index 98385a6d3e..c8434592df 100644
--- a/libs/libcurl/src/transfer.c
+++ b/libs/libcurl/src/transfer.c
@@ -23,7 +23,6 @@
***************************************************************************/
#include "curl_setup.h"
-#include "strtoofft.h"
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
@@ -40,7 +39,9 @@
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
+#ifndef UNDER_CE
#include <signal.h>
+#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
@@ -571,8 +572,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
data->state.followlocation = 0; /* reset the location-follow counter */
data->state.this_is_a_follow = FALSE; /* reset this */
data->state.errorbuf = FALSE; /* no error has occurred */
- data->state.httpwant = data->set.httpwant;
- data->state.httpversion = 0;
+#ifndef CURL_DISABLE_HTTP
+ Curl_http_neg_init(data, &data->state.http_neg);
+#endif
data->state.authproblem = FALSE;
data->state.authhost.want = data->set.httpauth;
data->state.authproxy.want = data->set.proxyauth;
@@ -654,7 +656,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
- Curl_safefree(data->state.aptr.uagent);
+ free(data->state.aptr.uagent);
data->state.aptr.uagent =
aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
if(!data->state.aptr.uagent)
@@ -880,6 +882,11 @@ CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
return result;
}
+bool Curl_xfer_write_is_paused(struct Curl_easy *data)
+{
+ return Curl_cwriter_is_paused(data);
+}
+
CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
const char *hd0, size_t hdlen, bool is_eos)
{
diff --git a/libs/libcurl/src/transfer.h b/libs/libcurl/src/transfer.h
index 40ed03eae5..bc39b0181b 100644
--- a/libs/libcurl/src/transfer.h
+++ b/libs/libcurl/src/transfer.h
@@ -55,6 +55,8 @@ CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos);
+bool Curl_xfer_write_is_paused(struct Curl_easy *data);
+
/**
* Write a single "header" line from a server response.
* @param hd0 the 0-terminated, single header line
diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c
index fe8d61aeda..dcd4b25d38 100644
--- a/libs/libcurl/src/url.c
+++ b/libs/libcurl/src/url.c
@@ -75,7 +75,6 @@
#include "strcase.h"
#include "strerror.h"
#include "escape.h"
-#include "strtok.h"
#include "share.h"
#include "content_encoding.h"
#include "http_digest.h"
@@ -91,6 +90,7 @@
#include "hsts.h"
#include "noproxy.h"
#include "cfilters.h"
+#include "curl_krb5.h"
#include "idn.h"
/* And now for the protocols */
@@ -119,7 +119,7 @@
#include "altsvc.h"
#include "dynbuf.h"
#include "headers.h"
-
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -286,6 +286,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
Curl_http_auth_cleanup_digest(data);
#endif
+ Curl_safefree(data->state.most_recent_ftp_entrypath);
Curl_safefree(data->info.contenttype);
Curl_safefree(data->info.wouldredirect);
@@ -428,7 +429,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
*/
if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL &&
Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) {
-#if defined(CURL_CA_BUNDLE)
+#ifdef CURL_CA_BUNDLE
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
if(result)
return result;
@@ -439,7 +440,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
return result;
#endif
#endif
-#if defined(CURL_CA_PATH)
+#ifdef CURL_CA_PATH
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
if(result)
return result;
@@ -474,11 +475,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->maxage_conn = 118;
set->maxlifetime_conn = 0;
set->http09_allowed = FALSE;
-#ifdef USE_HTTP2
- set->httpwant = CURL_HTTP_VERSION_2TLS
-#else
- set->httpwant = CURL_HTTP_VERSION_1_1
-#endif
+ set->httpwant = CURL_HTTP_VERSION_NONE
;
#if defined(USE_HTTP2) || defined(USE_HTTP3)
memset(&set->priority, 0, sizeof(set->priority));
@@ -510,39 +507,38 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER;
+ Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
Curl_req_init(&data->req);
+ Curl_initinfo(data);
+#ifndef CURL_DISABLE_HTTP
+ Curl_llist_init(&data->state.httphdrs, NULL);
+#endif
+ Curl_netrc_init(&data->state.netrc);
result = Curl_resolver_init(data, &data->state.async.resolver);
if(result) {
DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
- Curl_req_free(&data->req, data);
- free(data);
- return result;
+ goto out;
}
result = Curl_init_userdefined(data);
- if(!result) {
- Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
- Curl_initinfo(data);
-
- /* most recent connection is not yet defined */
- data->state.lastconnect_id = -1;
- data->state.recent_conn_id = -1;
- /* and not assigned an id yet */
- data->id = -1;
- data->mid = -1;
+ if(result)
+ goto out;
+
+ /* most recent connection is not yet defined */
+ data->state.lastconnect_id = -1;
+ data->state.recent_conn_id = -1;
+ /* and not assigned an id yet */
+ data->id = -1;
+ data->mid = -1;
#ifndef CURL_DISABLE_DOH
- data->set.dohfor_mid = -1;
+ data->set.dohfor_mid = -1;
#endif
- data->progress.flags |= PGRS_HIDE;
- data->state.current_speed = -1; /* init to negative == impossible */
-#ifndef CURL_DISABLE_HTTP
- Curl_llist_init(&data->state.httphdrs, NULL);
-#endif
- Curl_netrc_init(&data->state.netrc);
- }
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
+out:
if(result) {
Curl_resolver_cleanup(data->state.async.resolver);
Curl_dyn_free(&data->state.headerb);
@@ -562,6 +558,10 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
DEBUGASSERT(conn);
+ if(conn->handler && conn->handler->disconnect &&
+ !conn->bits.shutdown_handler)
+ conn->handler->disconnect(data, conn, TRUE);
+
for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) {
Curl_conn_cf_discard_all(data, conn, (int)i);
}
@@ -578,6 +578,7 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
#endif
+ Curl_sec_conn_destroy(conn);
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
Curl_safefree(conn->sasl_authzid);
@@ -599,52 +600,6 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
}
/*
- * Disconnects the given connection. Note the connection may not be the
- * primary connection, like when freeing room in the connection pool 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.
- */
-bool Curl_on_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 pool */
- DEBUGASSERT(!conn->bits.in_cpool);
-
- /* 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 #%" FMT_OFF_T ", aborted=%d)",
- conn->connection_id, aborted));
-
- if(conn->dns_entry)
- Curl_resolv_unlink(data, &conn->dns_entry);
-
- /* 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;
-
- return aborted;
-}
-
-/*
* xfer_may_multiplex()
*
* Return a TRUE, iff the transfer can be done over an (appropriate)
@@ -653,15 +608,20 @@ bool Curl_on_disconnect(struct Curl_easy *data,
static bool xfer_may_multiplex(const struct Curl_easy *data,
const struct connectdata *conn)
{
+#ifndef CURL_DISABLE_HTTP
/* If an HTTP protocol and multiplexing is enabled */
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
(!conn->bits.protoconnstart || !conn->bits.close)) {
if(Curl_multiplex_wanted(data->multi) &&
- (data->state.httpwant >= CURL_HTTP_VERSION_2))
+ (data->state.http_neg.allowed & (CURL_HTTP_V2x|CURL_HTTP_V3x)))
/* allows HTTP/2 or newer */
return TRUE;
}
+#else
+ (void)data;
+ (void)conn;
+#endif
return FALSE;
}
@@ -836,8 +796,6 @@ static bool ssh_config_matches(struct connectdata *one,
return Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) &&
Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub);
}
-#else
-#define ssh_config_matches(x,y) FALSE
#endif
struct url_conn_match {
@@ -952,13 +910,17 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
return FALSE;
#endif
- if((!(needle->handler->flags&PROTOPT_SSL) !=
- !Curl_conn_is_ssl(conn, FIRSTSOCKET)) &&
- !(get_protocol_family(conn->handler) == needle->handler->protocol &&
- conn->bits.tls_upgraded))
- /* Deny `conn` if it is not fit for `needle`'s SSL needs,
- * UNLESS `conn` is the same protocol family and was upgraded to SSL. */
+ if(needle->handler->flags&PROTOPT_SSL) {
+ /* We are looking for SSL, if `conn` does not do it, not a match. */
+ if(!Curl_conn_is_ssl(conn, FIRSTSOCKET))
return FALSE;
+ }
+ else if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+ /* We are not *requiring* SSL, however `conn` has it. If the
+ * protocol *family* is not the same, not a match. */
+ if(get_protocol_family(conn->handler) != needle->handler->protocol)
+ return FALSE;
+ }
#ifndef CURL_DISABLE_PROXY
if(needle->bits.httpproxy != conn->bits.httpproxy ||
@@ -995,8 +957,9 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
}
#endif
+#ifndef CURL_DISABLE_HTTP
if(match->may_multiplex &&
- (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
+ (data->state.http_neg.allowed & (CURL_HTTP_V2x|CURL_HTTP_V3x)) &&
(needle->handler->protocol & CURLPROTO_HTTP) &&
!conn->httpversion_seen) {
if(data->set.pipewait) {
@@ -1008,6 +971,7 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
infof(data, "Server upgrade cannot be used");
return FALSE;
}
+#endif
if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
/* This protocol requires credentials per connection,
@@ -1028,27 +992,36 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
return FALSE;
#endif
- /* If looking for HTTP and the HTTP version we want is less
- * than the HTTP version of conn, continue looking.
- * CURL_HTTP_VERSION_2TLS is default which indicates no preference,
- * so we take any existing connection. */
- if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
- (data->state.httpwant != CURL_HTTP_VERSION_2TLS)) {
- unsigned char httpversion = Curl_conn_http_version(data);
- if((httpversion >= 20) &&
- (data->state.httpwant < CURL_HTTP_VERSION_2_0)) {
- DEBUGF(infof(data, "nor reusing conn #%" CURL_FORMAT_CURL_OFF_T
- " with httpversion=%d, we want a version less than h2",
- conn->connection_id, httpversion));
- }
- if((httpversion >= 30) &&
- (data->state.httpwant < CURL_HTTP_VERSION_3)) {
- DEBUGF(infof(data, "nor reusing conn #%" CURL_FORMAT_CURL_OFF_T
- " with httpversion=%d, we want a version less than h3",
- conn->connection_id, httpversion));
- return FALSE;
+#ifndef CURL_DISABLE_HTTP
+ /* If looking for HTTP and the HTTP versions allowed do not include
+ * the HTTP version of conn, continue looking. */
+ if((needle->handler->protocol & PROTO_FAMILY_HTTP)) {
+ switch(Curl_conn_http_version(data, conn)) {
+ case 30:
+ if(!(data->state.http_neg.allowed & CURL_HTTP_V3x)) {
+ DEBUGF(infof(data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
+ ", we do not want h3", conn->connection_id));
+ return FALSE;
+ }
+ break;
+ case 20:
+ if(!(data->state.http_neg.allowed & CURL_HTTP_V2x)) {
+ DEBUGF(infof(data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
+ ", we do not want h2", conn->connection_id));
+ return FALSE;
+ }
+ break;
+ default:
+ if(!(data->state.http_neg.allowed & CURL_HTTP_V1x)) {
+ DEBUGF(infof(data, "not reusing conn #%" CURL_FORMAT_CURL_OFF_T
+ ", we do not want h1", conn->connection_id));
+ return FALSE;
+ }
+ break;
}
}
+#endif
+
#ifdef USE_SSH
else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
if(!ssh_config_matches(needle, conn))
@@ -1075,12 +1048,21 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
|| !needle->bits.httpproxy || needle->bits.tunnel_proxy
#endif
) {
- /* Talking the same protocol scheme or a TLS upgraded protocol in the
- * same protocol family? */
- if(!strcasecompare(needle->handler->scheme, conn->handler->scheme) &&
- (get_protocol_family(conn->handler) !=
- needle->handler->protocol || !conn->bits.tls_upgraded))
- return FALSE;
+ if(!strcasecompare(needle->handler->scheme, conn->handler->scheme)) {
+ /* `needle` and `conn` do not have the same scheme... */
+ if(get_protocol_family(conn->handler) != needle->handler->protocol) {
+ /* and `conn`s protocol family is not the protocol `needle` wants.
+ * IMAPS would work for IMAP, but no vice versa. */
+ return FALSE;
+ }
+ /* We are in an IMAPS vs IMAP like case. We expect `conn` to have SSL */
+ if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
+ DEBUGF(infof(data,
+ "Connection #%" FMT_OFF_T " has compatible protocol famiy, "
+ "but no SSL, no match", conn->connection_id));
+ return FALSE;
+ }
+ }
/* If needle has "conn_to_*" set, conn must match this */
if((needle->bits.conn_to_host && !strcasecompare(
@@ -1105,7 +1087,7 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
}
}
-#if defined(USE_NTLM)
+#ifdef USE_NTLM
/* If we are looking for an HTTP+NTLM connection, check if this is
already authenticating with the right credentials. If not, keep
looking so that we can reuse NTLM connections if
@@ -1187,7 +1169,7 @@ static bool url_match_conn(struct connectdata *conn, void *userdata)
}
else if(Curl_conn_seems_dead(conn, data, NULL)) {
/* removed and disconnect. Do not treat as aborted. */
- Curl_cpool_disconnect(data, conn, FALSE);
+ Curl_conn_terminate(data, conn, FALSE);
return FALSE;
}
@@ -1260,7 +1242,7 @@ ConnectionExists(struct Curl_easy *data,
/* Find a connection in the pool that matches what "data + needle"
* requires. If a suitable candidate is found, it is attached to "data". */
- result = Curl_cpool_find(data, needle->destination, needle->destination_len,
+ result = Curl_cpool_find(data, needle->destination,
url_match_conn, url_match_result, &match);
/* wait_pipe is TRUE if we encounter a bundle that is undecided. There
@@ -1285,7 +1267,7 @@ void Curl_verboseconnect(struct Curl_easy *data,
infof(data, "Connected to %s (%s) port %u",
CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip,
conn->primary.remote_port);
-#if !defined(CURL_DISABLE_HTTP)
+#ifndef CURL_DISABLE_HTTP
if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
switch(conn->alpn) {
case CURL_HTTP_VERSION_3:
@@ -1440,7 +1422,7 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
#else
NULL,
#endif
-#if defined(USE_SSH)
+#ifdef USE_SSH
&Curl_handler_sftp,
#else
NULL,
@@ -1682,12 +1664,12 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
#endif
if(!uc && zoneid) {
- char *endp;
- unsigned long scope = strtoul(zoneid, &endp, 10);
- if(!*endp && (scope < UINT_MAX))
+ const char *p = zoneid;
+ curl_off_t scope;
+ if(!Curl_str_number(&p, &scope, UINT_MAX))
/* A plain number, use it directly as a scope id. */
conn->scope_id = (unsigned int)scope;
-#if defined(HAVE_IF_NAMETOINDEX)
+#ifdef HAVE_IF_NAMETOINDEX
else {
#elif defined(_WIN32)
else if(Curl_if_nametoindex) {
@@ -1696,7 +1678,7 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
#if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32)
/* Zone identifier is not numeric */
unsigned int scopeidx = 0;
-#if defined(_WIN32)
+#ifdef _WIN32
scopeidx = Curl_if_nametoindex(zoneid);
#else
scopeidx = if_nametoindex(zoneid);
@@ -1921,10 +1903,17 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
else {
- unsigned long port = strtoul(data->state.up.port, NULL, 10);
- conn->primary.remote_port = conn->remote_port =
- (data->set.use_port && data->state.allow_port) ?
- data->set.use_port : curlx_ultous(port);
+ curl_off_t port;
+ bool valid = TRUE;
+ if(data->set.use_port && data->state.allow_port)
+ port = data->set.use_port;
+ else {
+ const char *p = data->state.up.port;
+ if(Curl_str_number(&p, &port, 0xffff))
+ valid = FALSE;
+ }
+ if(valid)
+ conn->primary.remote_port = conn->remote_port = (unsigned short)port;
}
(void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
@@ -2029,9 +2018,8 @@ static CURLcode setup_connection_internals(struct Curl_easy *data,
if(!conn->destination)
return CURLE_OUT_OF_MEMORY;
- conn->destination_len = strlen(conn->destination) + 1;
Curl_strntolower(conn->destination, conn->destination,
- conn->destination_len - 1);
+ strlen(conn->destination));
return CURLE_OK;
}
@@ -2068,7 +2056,7 @@ static char *detect_proxy(struct Curl_easy *data,
* checked if the lowercase versions do not exist.
*/
char proxy_env[20];
- char *envp = proxy_env;
+ const char *envp = proxy_env;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)data;
#endif
@@ -2109,10 +2097,10 @@ static char *detect_proxy(struct Curl_easy *data,
}
if(!proxy) {
#endif
- envp = (char *)"all_proxy";
+ envp = "all_proxy";
proxy = curl_getenv(envp); /* default proxy to use */
if(!proxy) {
- envp = (char *)"ALL_PROXY";
+ envp = "ALL_PROXY";
proxy = curl_getenv(envp);
}
#ifndef CURL_DISABLE_WEBSOCKETS
@@ -2228,7 +2216,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
goto error;
if(proxyuser || proxypasswd) {
- Curl_safefree(proxyinfo->user);
+ free(proxyinfo->user);
proxyinfo->user = proxyuser;
result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
proxyuser = NULL;
@@ -2253,7 +2241,10 @@ static CURLcode parse_proxy(struct Curl_easy *data,
(void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
if(portptr) {
- port = (int)strtol(portptr, NULL, 10);
+ curl_off_t num;
+ const char *p = portptr;
+ if(!Curl_str_number(&p, &num, 0xffff))
+ port = (int)num;
free(portptr);
}
else {
@@ -2297,7 +2288,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
goto error;
}
- Curl_safefree(proxyinfo->host.rawalloc);
+ free(proxyinfo->host.rawalloc);
proxyinfo->host.rawalloc = host;
proxyinfo->host.name = host;
host = NULL;
@@ -2306,7 +2297,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
if(!is_unix_proxy) {
#endif
- Curl_safefree(proxyinfo->host.rawalloc);
+ free(proxyinfo->host.rawalloc);
proxyinfo->host.rawalloc = host;
if(host[0] == '[') {
/* this is a numerical IPv6, strip off the brackets */
@@ -2493,7 +2484,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
if(!conn->socks_proxy.user) {
conn->socks_proxy.user = conn->http_proxy.user;
conn->http_proxy.user = NULL;
- Curl_safefree(conn->socks_proxy.passwd);
+ free(conn->socks_proxy.passwd);
conn->socks_proxy.passwd = conn->http_proxy.passwd;
conn->http_proxy.passwd = NULL;
}
@@ -2728,7 +2719,7 @@ static CURLcode override_login(struct Curl_easy *data,
}
}
if(url_provided) {
- Curl_safefree(conn->user);
+ free(conn->user);
conn->user = strdup(*userp);
if(!conn->user)
return CURLE_OUT_OF_MEMORY;
@@ -2836,7 +2827,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
int port = -1;
CURLcode result = CURLE_OK;
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void) data;
#endif
@@ -2891,19 +2882,18 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
/* 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)) {
+ curl_off_t portparse;
+ const char *p = host_portno;
+ if(Curl_str_number(&p, &portparse, 0xffff)) {
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 */
+ port = (int)portparse; /* we know it will fit */
}
}
@@ -2974,12 +2964,11 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data,
/* check whether the URL's port matches */
char *ptr_next = strchr(ptr, ':');
if(ptr_next) {
- char *endp = NULL;
- long port_to_match = strtol(ptr, &endp, 10);
- if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
+ curl_off_t port_to_match;
+ if(!Curl_str_number(&ptr, &port_to_match, 0xffff) &&
+ (port_to_match == (curl_off_t)conn->remote_port))
port_match = TRUE;
- ptr = ptr_next + 1;
- }
+ ptr = ptr_next + 1;
}
}
}
@@ -3049,75 +3038,50 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
)) {
/* no connect_to match, try alt-svc! */
enum alpnid srcalpnid = ALPN_none;
- bool use_alt_svc = FALSE;
bool hit = FALSE;
struct altsvc *as = NULL;
- const int allowed_versions = ( ALPN_h1
-#ifdef USE_HTTP2
- | ALPN_h2
-#endif
-#ifdef USE_HTTP3
- | ALPN_h3
-#endif
- ) & data->asi->flags;
- static enum alpnid alpn_ids[] = {
-#ifdef USE_HTTP3
- ALPN_h3,
-#endif
-#ifdef USE_HTTP2
- ALPN_h2,
-#endif
- ALPN_h1,
- };
- size_t i;
-
- switch(data->state.httpwant) {
- case CURL_HTTP_VERSION_1_0:
- break;
- case CURL_HTTP_VERSION_1_1:
- use_alt_svc = TRUE;
- srcalpnid = ALPN_h1; /* only regard alt-svc advice for http/1.1 */
- break;
- case CURL_HTTP_VERSION_2_0:
- use_alt_svc = TRUE;
- srcalpnid = ALPN_h2; /* only regard alt-svc advice for h2 */
- break;
- case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
- break;
- case CURL_HTTP_VERSION_3:
- use_alt_svc = TRUE;
- srcalpnid = ALPN_h3; /* only regard alt-svc advice for h3 */
- break;
- case CURL_HTTP_VERSION_3ONLY:
- break;
- default: /* no specific HTTP version wanted, look at all of alt-svc */
- use_alt_svc = TRUE;
- srcalpnid = ALPN_none;
- break;
- }
- if(!use_alt_svc)
- return CURLE_OK;
+ int allowed_alpns = ALPN_none;
+ struct http_negotiation *neg = &data->state.http_neg;
+
+ DEBUGF(infof(data, "Alt-svc check wanted=%x, allowed=%x",
+ neg->wanted, neg->allowed));
+ if(neg->allowed & CURL_HTTP_V3x)
+ allowed_alpns |= ALPN_h3;
+ if(neg->allowed & CURL_HTTP_V2x)
+ allowed_alpns |= ALPN_h2;
+ if(neg->allowed & CURL_HTTP_V1x)
+ allowed_alpns |= ALPN_h1;
+ allowed_alpns &= (int)data->asi->flags;
host = conn->host.rawalloc;
DEBUGF(infof(data, "check Alt-Svc for host %s", host));
- if(srcalpnid == ALPN_none) {
- /* scan all alt-svc protocol ids in order or relevance */
- for(i = 0; !hit && (i < CURL_ARRAYSIZE(alpn_ids)); ++i) {
- srcalpnid = alpn_ids[i];
- hit = Curl_altsvc_lookup(data->asi,
- srcalpnid, host, conn->remote_port, /* from */
- &as /* to */,
- allowed_versions);
- }
+#ifdef USE_HTTP3
+ if(!hit && (neg->wanted & CURL_HTTP_V3x)) {
+ srcalpnid = ALPN_h3;
+ hit = Curl_altsvc_lookup(data->asi,
+ ALPN_h3, host, conn->remote_port, /* from */
+ &as /* to */,
+ allowed_alpns);
}
- else {
- /* look for a specific alt-svc protocol id */
+ #endif
+ #ifdef USE_HTTP2
+ if(!hit && (neg->wanted & CURL_HTTP_V2x) &&
+ !neg->h2_prior_knowledge) {
+ srcalpnid = ALPN_h2;
hit = Curl_altsvc_lookup(data->asi,
- srcalpnid, host, conn->remote_port, /* from */
+ ALPN_h2, host, conn->remote_port, /* from */
&as /* to */,
- allowed_versions);
+ allowed_alpns);
+ }
+ #endif
+ if(!hit && (neg->wanted & CURL_HTTP_V1x) &&
+ !neg->only_10) {
+ srcalpnid = ALPN_h1;
+ hit = Curl_altsvc_lookup(data->asi,
+ ALPN_h1, host, conn->remote_port, /* from */
+ &as /* to */,
+ allowed_alpns);
}
-
if(hit) {
char *hostd = strdup((char *)as->dst.host);
@@ -3136,14 +3100,15 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
/* protocol version switch */
switch(as->dst.alpnid) {
case ALPN_h1:
- data->state.httpwant = CURL_HTTP_VERSION_1_1;
+ neg->wanted = neg->allowed = CURL_HTTP_V1x;
+ neg->only_10 = FALSE;
break;
case ALPN_h2:
- data->state.httpwant = CURL_HTTP_VERSION_2_0;
+ neg->wanted = neg->allowed = CURL_HTTP_V2x;
break;
case ALPN_h3:
conn->transport = TRNSPRT_QUIC;
- data->state.httpwant = CURL_HTTP_VERSION_3;
+ neg->wanted = neg->allowed = CURL_HTTP_V3x;
break;
default: /* should not be possible */
break;
@@ -3273,8 +3238,8 @@ static void reuse_conn(struct Curl_easy *data,
* 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);
+ free(existing->user);
+ free(existing->passwd);
existing->user = temp->user;
existing->passwd = temp->passwd;
temp->user = NULL;
@@ -3285,10 +3250,10 @@ static void reuse_conn(struct Curl_easy *data,
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);
+ free(existing->http_proxy.user);
+ free(existing->socks_proxy.user);
+ free(existing->http_proxy.passwd);
+ free(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;
@@ -3325,8 +3290,7 @@ static void reuse_conn(struct Curl_easy *data,
temp->conn_to_host.rawalloc = NULL;
existing->conn_to_port = temp->conn_to_port;
existing->remote_port = temp->remote_port;
- Curl_safefree(existing->hostname_resolve);
-
+ free(existing->hostname_resolve);
existing->hostname_resolve = temp->hostname_resolve;
temp->hostname_resolve = NULL;
@@ -3390,6 +3354,10 @@ static CURLcode create_conn(struct Curl_easy *data,
any failure */
*in_connect = conn;
+ /* Do the unfailable inits first, before checks that may early return */
+ /* GSSAPI related inits */
+ Curl_sec_conn_init(conn);
+
result = parseurlandfillconn(data, conn);
if(result)
goto out;
@@ -3534,14 +3502,12 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Setup a "faked" transfer that will do nothing */
if(!result) {
Curl_attach_connection(data, conn);
- result = Curl_cpool_add_conn(data, conn);
- if(result)
- goto out;
+ result = Curl_cpool_add(data, conn);
+ if(!result) {
+ /* Setup whatever necessary for a resumed transfer */
+ result = setup_range(data);
+ }
- /*
- * 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 */
@@ -3597,18 +3563,25 @@ static CURLcode create_conn(struct Curl_easy *data,
* `existing` and thus we need to cleanup the one we just
* allocated before we can move along and use `existing`.
*/
+ bool tls_upgraded = (!(conn->given->flags & PROTOPT_SSL) &&
+ Curl_conn_is_ssl(conn, FIRSTSOCKET));
+
reuse_conn(data, conn, existing);
conn = existing;
*in_connect = conn;
#ifndef CURL_DISABLE_PROXY
- infof(data, "Re-using existing connection with %s %s",
+ infof(data, "Re-using existing %s: connection%s with %s %s",
+ conn->given->scheme,
+ tls_upgraded ? " (upgraded to SSL)" : "",
conn->bits.proxy ? "proxy" : "host",
conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
conn->host.dispname);
#else
- infof(data, "Re-using existing connection with host %s",
+ infof(data, "Re-using existing %s: connection%s with host %s",
+ conn->given->scheme,
+ tls_upgraded ? " (upgraded to SSL)" : "",
conn->host.dispname);
#endif
}
@@ -3671,12 +3644,12 @@ static CURLcode create_conn(struct Curl_easy *data,
}
Curl_attach_connection(data, conn);
- result = Curl_cpool_add_conn(data, conn);
+ result = Curl_cpool_add(data, conn);
if(result)
goto out;
}
-#if defined(USE_NTLM)
+#ifdef 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. */
@@ -3762,9 +3735,6 @@ CURLcode Curl_setup_conn(struct Curl_easy *data,
return result;
}
- /* set start time here for timeout purposes in the connect procedure, it
- is later set again for the progress meter purpose */
- conn->now = Curl_now();
if(!conn->bits.reuse)
result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
CURL_CF_SSL_DEFAULT);
@@ -3810,7 +3780,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
/* We are not allowed to return failure with memory left allocated in the
connectdata struct, free those here */
Curl_detach_connection(data);
- Curl_cpool_disconnect(data, conn, TRUE);
+ Curl_conn_terminate(data, conn, TRUE);
}
return result;
diff --git a/libs/libcurl/src/url.h b/libs/libcurl/src/url.h
index d09bf14137..30db5c78b5 100644
--- a/libs/libcurl/src/url.h
+++ b/libs/libcurl/src/url.h
@@ -37,8 +37,6 @@ 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);
-bool Curl_on_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);
diff --git a/libs/libcurl/src/urlapi.c b/libs/libcurl/src/urlapi.c
index 6198d1aa04..cd00a9f0f8 100644
--- a/libs/libcurl/src/urlapi.c
+++ b/libs/libcurl/src/urlapi.c
@@ -34,6 +34,8 @@
#include "inet_ntop.h"
#include "strdup.h"
#include "idn.h"
+#include "strparse.h"
+#include "curl_memrchr.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -109,35 +111,23 @@ static void free_urlhandle(struct Curl_URL *u)
*/
static const char *find_host_sep(const char *url)
{
- const char *sep;
- const char *query;
-
/* Find the start of the hostname */
- sep = strstr(url, "//");
+ const char *sep = strstr(url, "//");
if(!sep)
sep = url;
else
sep += 2;
- query = strchr(sep, '?');
- sep = strchr(sep, '/');
-
- if(!sep)
- sep = url + strlen(url);
-
- if(!query)
- query = url + strlen(url);
+ /* Find first / or ? */
+ while(*sep && *sep != '/' && *sep != '?')
+ sep++;
- return sep < query ? sep : query;
+ return sep;
}
/* convert CURLcode to CURLUcode */
#define cc2cu(x) ((x) == CURLE_TOO_LARGE ? CURLUE_TOO_LARGE : \
CURLUE_OUT_OF_MEMORY)
-/*
- * Decide whether a character in a URL must be escaped.
- */
-#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
@@ -154,46 +144,40 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
bool left = !query;
const unsigned char *iptr;
const unsigned char *host_sep = (const unsigned char *) url;
- CURLcode result;
+ CURLcode result = CURLE_OK;
- if(!relative)
+ if(!relative) {
+ size_t n;
host_sep = (const unsigned char *) find_host_sep(url);
- for(iptr = (unsigned char *)url; /* read from here */
- len; iptr++, len--) {
-
- if(iptr < host_sep) {
- result = Curl_dyn_addn(o, iptr, 1);
- if(result)
- return cc2cu(result);
- continue;
- }
+ /* output the first piece as-is */
+ n = (const char *)host_sep - url;
+ result = Curl_dyn_addn(o, url, n);
+ len -= n;
+ }
+ for(iptr = host_sep; len && !result; iptr++, len--) {
if(*iptr == ' ') {
if(left)
result = Curl_dyn_addn(o, "%20", 3);
else
result = Curl_dyn_addn(o, "+", 1);
- if(result)
- return cc2cu(result);
- continue;
}
-
- if(*iptr == '?')
- left = FALSE;
-
- if(urlchar_needs_escaping(*iptr)) {
+ else if((*iptr < ' ') || (*iptr >= 0x7f)) {
char out[3]={'%'};
out[1] = hexdigits[*iptr >> 4];
out[2] = hexdigits[*iptr & 0xf];
result = Curl_dyn_addn(o, out, 3);
}
- else
+ else {
result = Curl_dyn_addn(o, iptr, 1);
- if(result)
- return cc2cu(result);
+ if(*iptr == '?')
+ left = FALSE;
+ }
}
+ if(result)
+ return cc2cu(result);
return CURLUE_OK;
}
@@ -246,113 +230,95 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
}
/*
- * Concatenate a relative URL to a base URL making it absolute.
- *
- * Note that this function destroys the 'base' string.
+ * Concatenate a relative URL onto a base URL making it absolute.
*/
-static CURLUcode redirect_url(char *base, const char *relurl,
+static CURLUcode redirect_url(const char *base, const char *relurl,
CURLU *u, unsigned int flags)
{
struct dynbuf urlbuf;
bool host_changed = FALSE;
const char *useurl = relurl;
- CURLcode result = CURLE_OK;
+ const char *cutoff = NULL;
+ size_t prelen;
CURLUcode uc;
- /* protsep points to the start of the hostname */
- char *protsep = strstr(base, "//");
- DEBUGASSERT(protsep);
- if(!protsep)
- protsep = base;
- else
- protsep += 2; /* pass the slashes */
-
- if(('/' != relurl[0]) && ('#' != relurl[0])) {
- /* First we need to find out if there is a ?-letter in the original URL,
- and cut it and the right-side of that off */
- char *pathsep = strchr(protsep, '?');
- if(pathsep)
- *pathsep = 0;
- else {
- /* if not, cut off the potential fragment */
- pathsep = strchr(protsep, '#');
- if(pathsep)
- *pathsep = 0;
- }
- /* if the redirect-to piece is not just a query, cut the path after the
- last slash */
- if(useurl[0] != '?') {
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- pathsep[1] = 0; /* leave the slash */
- }
- }
- else if('/' == relurl[0]) {
- /* We got a new absolute path for this server */
+ /* protsep points to the start of the hostname, after [scheme]:// */
+ const char *protsep = base + strlen(u->scheme) + 3;
+ DEBUGASSERT(base && relurl && u); /* all set here */
+ if(!base)
+ return CURLUE_MALFORMED_INPUT; /* should never happen */
+ /* handle different relative URL types */
+ switch(relurl[0]) {
+ case '/':
if(relurl[1] == '/') {
- /* the new URL starts with //, just keep the protocol part from the
- original one */
- *protsep = 0;
- useurl = &relurl[2]; /* we keep the slashes from the original, so we
- skip the new ones */
+ /* protocol-relative URL: //example.com/path */
+ cutoff = protsep;
+ useurl = &relurl[2];
host_changed = TRUE;
}
- else {
- /* cut the original URL at first slash */
- char *pathsep = strchr(protsep, '/');
- if(pathsep)
- *pathsep = 0;
+ else
+ /* absolute /path */
+ cutoff = strchr(protsep, '/');
+ break;
+
+ case '#':
+ /* fragment-only change */
+ if(u->fragment)
+ cutoff = strchr(protsep, '#');
+ break;
+
+ default:
+ /* path or query-only change */
+ if(u->query && u->query[0])
+ /* remove existing query */
+ cutoff = strchr(protsep, '?');
+ else if(u->fragment && u->fragment[0])
+ /* Remove existing fragment */
+ cutoff = strchr(protsep, '#');
+
+ if(relurl[0] != '?') {
+ /* append a relative path after the last slash */
+ cutoff = memrchr(protsep, '/',
+ cutoff ? (size_t)(cutoff - protsep) : strlen(protsep));
+ if(cutoff)
+ cutoff++; /* truncate after last slash */
}
+ break;
}
- else {
- /* the relative piece starts with '#' */
- /* If there is a fragment in the original URL, cut it off */
- char *pathsep = strchr(protsep, '#');
- if(pathsep)
- *pathsep = 0;
- }
+ prelen = cutoff ? (size_t)(cutoff - base) : strlen(base);
+ /* build new URL */
Curl_dyn_init(&urlbuf, CURL_MAX_INPUT_LENGTH);
- /* copy over the root URL part */
- result = Curl_dyn_add(&urlbuf, base);
- if(result)
- return cc2cu(result);
-
- /* then append the new piece on the right side */
- uc = urlencode_str(&urlbuf, useurl, strlen(useurl), !host_changed,
- FALSE);
- if(!uc)
+ if(!Curl_dyn_addn(&urlbuf, base, prelen) &&
+ !urlencode_str(&urlbuf, useurl, strlen(useurl), !host_changed, FALSE)) {
uc = parseurl_and_replace(Curl_dyn_ptr(&urlbuf), u,
- flags&~CURLU_PATH_AS_IS);
+ flags & ~CURLU_PATH_AS_IS);
+ }
+ else
+ uc = CURLUE_OUT_OF_MEMORY;
+
Curl_dyn_free(&urlbuf);
return uc;
}
/* scan for byte values <= 31, 127 and sometimes space */
-static CURLUcode junkscan(const char *url, size_t *urllen, unsigned int flags)
+static CURLUcode junkscan(const char *url, size_t *urllen, bool allowspace)
{
- static const char badbytes[]={
- /* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x7f, 0x00 /* null-terminate */
- };
size_t n = strlen(url);
- size_t nfine;
-
+ size_t i;
+ unsigned char control;
+ const unsigned char *p = (const unsigned char *)url;
if(n > CURL_MAX_INPUT_LENGTH)
- /* excessive input length */
- return CURLUE_MALFORMED_INPUT;
-
- nfine = strcspn(url, badbytes);
- if((nfine != n) ||
- (!(flags & CURLU_ALLOW_SPACE) && strchr(url, ' ')))
return CURLUE_MALFORMED_INPUT;
+ control = allowspace ? 0x1f : 0x20;
+ for(i = 0; i < n; i++) {
+ if(p[i] <= control || p[i] == 127)
+ return CURLUE_MALFORMED_INPUT;
+ }
*urllen = n;
return CURLUE_OK;
}
@@ -452,7 +418,7 @@ out:
UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
bool has_scheme)
{
- char *portptr;
+ const char *portptr;
char *hostname = Curl_dyn_ptr(host);
/*
* Find the end of an IPv6 address on the ']' ending bracket.
@@ -474,8 +440,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
portptr = strchr(hostname, ':');
if(portptr) {
- char *rest = NULL;
- unsigned long port;
+ curl_off_t port;
size_t keep = portptr - hostname;
/* Browser behavior adaptation. If there is a colon with no digits after,
@@ -490,19 +455,13 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
if(!*portptr)
return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER;
- if(!ISDIGIT(*portptr))
- return CURLUE_BAD_PORT_NUMBER;
-
- errno = 0;
- port = strtoul(portptr, &rest, 10); /* Port number must be decimal */
-
- if(errno || (port > 0xffff) || *rest)
+ if(Curl_str_number(&portptr, &port, 0xffff) || *portptr)
return CURLUE_BAD_PORT_NUMBER;
u->portnum = (unsigned short) port;
/* generate a new port number string to get rid of leading zeroes etc */
free(u->port);
- u->port = aprintf("%ld", port);
+ u->port = aprintf("%" CURL_FORMAT_CURL_OFF_T, port);
if(!u->port)
return CURLUE_OUT_OF_MEMORY;
}
@@ -554,9 +513,9 @@ static CURLUcode ipv6_parse(struct Curl_URL *u, char *hostname,
{
char dest[16]; /* fits a binary IPv6 address */
hostname[hlen] = 0; /* end the address there */
- if(1 != Curl_inet_pton(AF_INET6, hostname, dest))
+ if(1 != curlx_inet_pton(AF_INET6, hostname, dest))
return CURLUE_BAD_IPV6;
- if(Curl_inet_ntop(AF_INET6, dest, hostname, hlen)) {
+ if(curlx_inet_ntop(AF_INET6, dest, hostname, hlen)) {
hlen = strlen(hostname); /* might be shorter now */
hostname[hlen + 1] = 0;
}
@@ -609,30 +568,30 @@ static int ipv4_normalize(struct dynbuf *host)
bool done = FALSE;
int n = 0;
const char *c = Curl_dyn_ptr(host);
- unsigned long parts[4] = {0, 0, 0, 0};
+ unsigned int parts[4] = {0, 0, 0, 0};
CURLcode result = CURLE_OK;
if(*c == '[')
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)
+ int rc;
+ curl_off_t l;
+ if(*c == '0') {
+ if(c[1] == 'x') {
+ c += 2; /* skip the prefix */
+ rc = Curl_str_hex(&c, &l, UINT_MAX);
+ }
+ else
+ rc = Curl_str_octal(&c, &l, UINT_MAX);
+ }
+ else
+ rc = Curl_str_number(&c, &l, UINT_MAX);
+
+ if(rc)
return HOST_NAME;
-#endif
- parts[n] = l;
- c = endp;
+ parts[n] = (unsigned int)l;
switch(*c) {
case '.':
@@ -656,30 +615,30 @@ static int ipv4_normalize(struct dynbuf *host)
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
- (unsigned int)(parts[0] >> 24),
- (unsigned int)((parts[0] >> 16) & 0xff),
- (unsigned int)((parts[0] >> 8) & 0xff),
- (unsigned int)(parts[0] & 0xff));
+ (parts[0] >> 24),
+ ((parts[0] >> 16) & 0xff),
+ ((parts[0] >> 8) & 0xff),
+ (parts[0] & 0xff));
break;
case 1: /* a.b -- 8.24 bits */
if((parts[0] > 0xff) || (parts[1] > 0xffffff))
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
- (unsigned int)(parts[0]),
- (unsigned int)((parts[1] >> 16) & 0xff),
- (unsigned int)((parts[1] >> 8) & 0xff),
- (unsigned int)(parts[1] & 0xff));
+ (parts[0]),
+ ((parts[1] >> 16) & 0xff),
+ ((parts[1] >> 8) & 0xff),
+ (parts[1] & 0xff));
break;
case 2: /* a.b.c -- 8.8.16 bits */
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff))
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
- (unsigned int)(parts[0]),
- (unsigned int)(parts[1]),
- (unsigned int)((parts[2] >> 8) & 0xff),
- (unsigned int)(parts[2] & 0xff));
+ (parts[0]),
+ (parts[1]),
+ ((parts[2] >> 8) & 0xff),
+ (parts[2] & 0xff));
break;
case 3: /* a.b.c.d -- 8.8.8.8 bits */
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) ||
@@ -687,10 +646,10 @@ static int ipv4_normalize(struct dynbuf *host)
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
- (unsigned int)(parts[0]),
- (unsigned int)(parts[1]),
- (unsigned int)(parts[2]),
- (unsigned int)(parts[3]));
+ (parts[0]),
+ (parts[1]),
+ (parts[2]),
+ (parts[3]));
break;
}
if(result)
@@ -803,6 +762,25 @@ CURLUcode Curl_url_set_authority(CURLU *u, const char *authority)
* https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
*/
+static bool is_dot(const char **str, size_t *clen)
+{
+ const char *p = *str;
+ if(*p == '.') {
+ (*str)++;
+ (*clen)--;
+ return TRUE;
+ }
+ else if((*clen >= 3) &&
+ (p[0] == '%') && (p[1] == '2') && ((p[2] | 0x20) == 'e')) {
+ *str += 3;
+ *clen -= 3;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define ISSLASH(x) ((x) == '/')
+
/*
* dedotdotify()
* @unittest: 1395
@@ -811,8 +789,7 @@ CURLUcode Curl_url_set_authority(CURLU *u, const char *authority)
* passed in and strips them off according to the rules in RFC 3986 section
* 5.2.4.
*
- * The function handles a query part ('?' + stuff) appended but it expects
- * that fragments ('#' + stuff) have already been cut off.
+ * The function handles a path. It should not contain the query nor fragment.
*
* RETURNS
*
@@ -821,112 +798,109 @@ CURLUcode Curl_url_set_authority(CURLU *u, const char *authority)
UNITTEST int dedotdotify(const char *input, size_t clen, char **outp);
UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
{
- char *outptr;
- const char *endp = &input[clen];
- char *out;
+ struct dynbuf out;
+ CURLcode result = CURLE_OK;
*outp = NULL;
/* the path always starts with a slash, and a slash has not dot */
- if((clen < 2) || !memchr(input, '.', clen))
+ if(clen < 2)
return 0;
- out = malloc(clen + 1);
- if(!out)
- return 1; /* out of memory */
-
- *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, */
+ Curl_dyn_init(&out, clen + 1);
+
+ /* A. If the input buffer begins with a prefix of "../" or "./", then
+ remove that prefix from the input buffer; otherwise, */
+ if(is_dot(&input, &clen)) {
+ const char *p = input;
+ size_t blen = clen;
+
+ if(!clen)
+ /* . [end] */
+ goto end;
+ else if(ISSLASH(*p)) {
+ /* one dot followed by a slash */
+ input = p + 1;
+ clen--;
+ }
- else if(!strcmp(".", input) || !strcmp("..", input) ||
- !strncmp(".?", input, 2) || !strncmp("..?", input, 3)) {
- *out = 0;
- break;
+ /* D. if the input buffer consists only of "." or "..", then remove
+ that from the input buffer; otherwise, */
+ else if(is_dot(&p, &blen)) {
+ if(!blen)
+ /* .. [end] */
+ goto end;
+ else if(ISSLASH(*p)) {
+ /* ../ */
+ input = p + 1;
+ clen = blen - 1;
}
- else
- dotdot = FALSE;
}
- else if(*input == '/') {
+ }
+
+ while(clen && !result) { /* until end of path content */
+ if(ISSLASH(*input)) {
+ const char *p = &input[1];
+ size_t blen = clen - 1;
/* 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;
- /* remove the last segment from the output buffer */
- while(outptr > out) {
- outptr--;
- if(*outptr == '/')
- break;
+ if(is_dot(&p, &blen)) {
+ if(!blen) { /* /. */
+ result = Curl_dyn_addn(&out, "/", 1);
+ break;
}
- *outptr = 0; /* null-terminate where it stops */
- }
- else if(!strcmp("/..", input) || !strncmp("/..?", input, 4)) {
- /* remove the last segment from the output buffer */
- while(outptr > out) {
- outptr--;
- if(*outptr == '/')
- break;
+ else if(ISSLASH(*p)) { /* /./ */
+ input = p;
+ clen = blen;
+ continue;
+ }
+
+ /* 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(is_dot(&p, &blen) && (ISSLASH(*p) || !blen)) {
+ /* remove the last segment from the output buffer */
+ size_t len = Curl_dyn_len(&out);
+ if(len) {
+ char *ptr = Curl_dyn_ptr(&out);
+ char *last = memrchr(ptr, '/', len);
+ if(last)
+ /* trim the output at the slash */
+ Curl_dyn_setlen(&out, last - ptr);
+ }
+
+ if(blen) { /* /../ */
+ input = p;
+ clen = blen;
+ continue;
+ }
+ result = Curl_dyn_addn(&out, "/", 1);
+ break;
}
- *outptr++ = '/';
- *outptr = 0; /* null-terminate where it stops */
- break;
}
- 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--;
- } while(*input && (*input != '/') && (*input != '?'));
- *outptr = 0;
}
- /* continue until end of path */
- } while(input < endp);
+ /* 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. */
- *outp = out;
- return 0; /* success */
+ result = Curl_dyn_addn(&out, input, 1);
+ input++;
+ clen--;
+ }
+end:
+ if(!result) {
+ if(Curl_dyn_len(&out))
+ *outp = Curl_dyn_ptr(&out);
+ else {
+ *outp = strdup("");
+ if(!*outp)
+ return 1;
+ }
+ }
+ return result ? 1 : 0; /* success */
}
static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
@@ -946,7 +920,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH);
- result = junkscan(url, &urllen, flags);
+ result = junkscan(url, &urllen, !!(flags & CURLU_ALLOW_SPACE));
if(result)
goto fail;
@@ -964,7 +938,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
}
/* path has been allocated large enough to hold this */
- path = (char *)&url[5];
+ path = &url[5];
pathlen = urllen - 5;
u->scheme = strdup("file");
@@ -1010,7 +984,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
ptr += 9; /* now points to the slash after the host */
}
else {
-#if defined(_WIN32)
+#ifdef _WIN32
size_t len;
/* the hostname, NetBIOS computer name, can not contain disallowed
@@ -1262,7 +1236,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
if(!(flags & CURLU_PATH_AS_IS)) {
/* remove ../ and ./ sequences according to RFC3986 */
char *dedot;
- int err = dedotdotify((char *)path, pathlen, &dedot);
+ int err = dedotdotify(path, pathlen, &dedot);
if(err) {
result = CURLUE_OUT_OF_MEMORY;
goto fail;
@@ -1440,7 +1414,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
break;
case CURLUPART_URL: {
char *url;
- char *scheme;
+ const char *scheme;
char *options = u->options;
char *port = u->port;
char *allochost = NULL;
@@ -1452,8 +1426,10 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
punycode = (flags & CURLU_PUNYCODE) ? 1 : 0;
depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0;
if(u->scheme && strcasecompare("file", u->scheme)) {
- url = aprintf("file://%s%s%s",
+ url = aprintf("file://%s%s%s%s%s",
u->path,
+ show_query ? "?": "",
+ u->query ? u->query : "",
show_fragment ? "#": "",
u->fragment ? u->fragment : "");
}
@@ -1465,7 +1441,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
if(u->scheme)
scheme = u->scheme;
else if(flags & CURLU_DEFAULT_SCHEME)
- scheme = (char *) DEFAULT_SCHEME;
+ scheme = DEFAULT_SCHEME;
else
return CURLUE_NO_SCHEME;
@@ -1758,14 +1734,11 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
return CURLUE_BAD_PORT_NUMBER;
else {
char *tmp;
- char *endp;
- unsigned long port;
- errno = 0;
- port = strtoul(part, &endp, 10); /* must be decimal */
- if(errno || (port > 0xffff) || *endp)
+ curl_off_t port;
+ if(Curl_str_number(&part, &port, 0xffff) || *part)
/* weirdly provided number, not good! */
return CURLUE_BAD_PORT_NUMBER;
- tmp = strdup(part);
+ tmp = aprintf("%" CURL_FORMAT_CURL_OFF_T, port);
if(!tmp)
return CURLUE_OUT_OF_MEMORY;
free(u->port);
@@ -1810,7 +1783,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
|| curl_url_get(u, CURLUPART_URL, &oldurl, flags)) {
return parseurl_and_replace(part, u, flags);
}
-
+ DEBUGASSERT(oldurl); /* it is set here */
/* apply the relative part to create a new URL */
uc = redirect_url(oldurl, part, u, flags);
free(oldurl);
@@ -1929,7 +1902,7 @@ nomem:
bad = TRUE;
free(decoded);
}
- else if(hostname_check(u, (char *)newp, n))
+ else if(hostname_check(u, (char *)CURL_UNCONST(newp), n))
bad = TRUE;
if(bad) {
Curl_dyn_free(&enc);
@@ -1939,7 +1912,7 @@ nomem:
}
free(*storep);
- *storep = (char *)newp;
+ *storep = (char *)CURL_UNCONST(newp);
}
return CURLUE_OK;
}
diff --git a/libs/libcurl/src/urldata.h b/libs/libcurl/src/urldata.h
index 08f8254b58..f986d76046 100644
--- a/libs/libcurl/src/urldata.h
+++ b/libs/libcurl/src/urldata.h
@@ -159,6 +159,7 @@ typedef unsigned int curl_prot_t;
#include "http_chunks.h" /* for the structs and enum stuff */
#include "hostip.h"
#include "hash.h"
+#include "hash_offt.h"
#include "splay.h"
#include "dynbuf.h"
#include "dynhds.h"
@@ -513,7 +514,6 @@ struct ConnectBits {
#ifdef USE_UNIX_SOCKETS
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
@@ -566,13 +566,13 @@ struct hostname {
#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
#define USE_CURL_ASYNC
struct Curl_async {
- char *hostname;
struct Curl_dns_entry *dns;
- struct thread_data *tdata;
+#ifdef CURLRES_ASYNCH
+ struct thread_data thdata;
void *resolver; /* resolver state, if it is used in the URL state -
ares_channel e.g. */
+#endif
int port;
- int status; /* if done is TRUE, this is the status from the callback */
BIT(done); /* set TRUE when the lookup is complete */
};
@@ -755,6 +755,7 @@ struct ldapconninfo;
*/
struct connectdata {
struct Curl_llist_node cpool_node; /* conncache lists */
+ struct Curl_llist_node cshutdn_node; /* cshutdn list */
curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
void *closesocket_client;
@@ -769,7 +770,6 @@ struct connectdata {
curl_off_t connection_id; /* Contains a unique number to make it easier to
track the connections in the log output */
char *destination; /* string carrying normalized hostname+port+scope */
- size_t destination_len; /* strlen(destination) + 1 */
/* 'dns_entry' is the particular host we use. This points to an entry in the
DNS cache and it will not get pruned while locked. It gets unlocked in
@@ -803,7 +803,6 @@ struct connectdata {
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 poolas idle */
curl_socket_t sock[2]; /* two sockets, the second is used for the data
@@ -815,9 +814,6 @@ struct connectdata {
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
@@ -1138,6 +1134,7 @@ typedef enum {
EXPIRE_QUIC,
EXPIRE_FTP_ACCEPT,
EXPIRE_ALPN_EYEBALLS,
+ EXPIRE_SHUTDOWN,
EXPIRE_LAST /* not an actual timer, used as a marker only */
} expire_id;
@@ -1312,10 +1309,9 @@ struct UrlState {
char *proxypasswd;
#endif
} aptr;
- unsigned char httpwant; /* when non-zero, a specific HTTP version requested
- to be used in the library's request(s) */
- unsigned char httpversion; /* the lowest HTTP version*10 reported by any
- server involved in this request */
+#ifndef CURL_DISABLE_HTTP
+ struct http_negotiation http_neg;
+#endif
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
@@ -1360,6 +1356,7 @@ struct UrlState {
BIT(internal); /* internal: true if this easy handle was created for
internal use and the user does not have ownership of the
handle. */
+ BIT(http_ignorecustom); /* ignore custom method from now */
};
/*
@@ -1694,6 +1691,9 @@ struct UserDefined {
struct curl_slist *mail_rcpt; /* linked list of mail recipients */
#endif
unsigned int maxconnects; /* Max idle connections in the connection cache */
+#ifdef USE_ECH
+ int tls_ech; /* TLS ECH configuration */
+#endif
unsigned short use_port; /* which port to use (when not using default) */
#ifndef CURL_DISABLE_BINDLOCAL
unsigned short localport; /* local port number to bind to */
@@ -1721,11 +1721,13 @@ struct UserDefined {
to be used in the library's request(s) */
unsigned char ipver; /* the CURL_IPRESOLVE_* defines in the public header
file 0 - whatever, 1 - v2, 2 - v6 */
+ unsigned char upload_flags; /* flags set by CURLOPT_UPLOAD_FLAGS */
#ifdef HAVE_GSSAPI
/* GSS-API credential delegation, see the documentation of
CURLOPT_GSSAPI_DELEGATION */
unsigned char gssapi_delegation;
#endif
+ unsigned char http_follow_mode; /* follow HTTP redirects */
BIT(connect_only); /* make connection/request, then let application use the
socket */
BIT(connect_only_ws); /* special websocket connect-only level */
@@ -1777,7 +1779,6 @@ struct UserDefined {
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 */
@@ -1831,9 +1832,6 @@ struct UserDefined {
#ifndef CURL_DISABLE_WEBSOCKETS
BIT(ws_raw_mode);
#endif
-#ifdef USE_ECH
- int tls_ech; /* TLS ECH configuration */
-#endif
};
#ifndef CURL_DISABLE_MIME
@@ -1886,12 +1884,6 @@ struct Curl_easy {
struct Curl_message msg; /* A single posted message. */
- /* Array with the plain socket numbers this handle takes care of, in no
- particular order. Note that all sockets are added to the sockhash, where
- the state etc are also kept. This array is mostly used to detect when a
- socket is to be removed from the hash. See singlesocket(). */
- struct easy_pollset last_poll;
-
struct Names dns;
struct Curl_multi *multi; /* if non-NULL, points to the multi handle
struct to which this "belongs" when used by
diff --git a/libs/libcurl/src/vauth/cleartext.c b/libs/libcurl/src/vauth/cleartext.c
index 198a452962..93d6340bf2 100644
--- a/libs/libcurl/src/vauth/cleartext.c
+++ b/libs/libcurl/src/vauth/cleartext.c
@@ -36,7 +36,6 @@
#include "vauth/vauth.h"
#include "warnless.h"
-#include "strtok.h"
#include "sendf.h"
#include "curl_printf.h"
diff --git a/libs/libcurl/src/vauth/digest.c b/libs/libcurl/src/vauth/digest.c
index 98e32900db..98d0c04dca 100644
--- a/libs/libcurl/src/vauth/digest.c
+++ b/libs/libcurl/src/vauth/digest.c
@@ -41,7 +41,7 @@
#include "curl_sha512_256.h"
#include "vtls/vtls.h"
#include "warnless.h"
-#include "strtok.h"
+#include "strparse.h"
#include "strcase.h"
#include "curl_printf.h"
#include "rand.h"
@@ -50,6 +50,7 @@
#include "curl_memory.h"
#include "memdebug.h"
+#ifndef USE_WINDOWS_SSPI
#define SESSION_ALGO 1 /* for algos with this bit set */
#define ALGO_MD5 0
@@ -59,7 +60,6 @@
#define ALGO_SHA512_256 4
#define ALGO_SHA512_256SESS (ALGO_SHA512_256 | SESSION_ALGO)
-#if !defined(USE_WINDOWS_SSPI)
#define DIGEST_QOP_VALUE_AUTH (1 << 0)
#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1)
#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2)
@@ -141,8 +141,8 @@ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
return TRUE;
}
-#if !defined(USE_WINDOWS_SSPI)
-/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ASCII string */
+#ifndef USE_WINDOWS_SSPI
+/* Convert MD5 chunk to RFC2617 (section 3.1.3) -suitable ASCII string */
static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
unsigned char *dest) /* 33 bytes */
{
@@ -219,33 +219,21 @@ static bool auth_digest_get_key_value(const char *chlg,
static CURLcode auth_digest_get_qop_values(const char *options, int *value)
{
- char *tmp;
- char *token;
- char *tok_buf = NULL;
-
+ struct Curl_str out;
/* Initialise the output */
*value = 0;
- /* Tokenise the list of qop values. Use a temporary clone of the buffer since
- Curl_strtok_r() ruins it. */
- tmp = strdup(options);
- if(!tmp)
- return CURLE_OUT_OF_MEMORY;
-
- token = Curl_strtok_r(tmp, ",", &tok_buf);
- while(token) {
- if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
+ while(!Curl_str_until(&options, &out, 32, ',')) {
+ if(Curl_str_casecompare(&out, DIGEST_QOP_VALUE_STRING_AUTH))
*value |= DIGEST_QOP_VALUE_AUTH;
- else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
+ else if(Curl_str_casecompare(&out, DIGEST_QOP_VALUE_STRING_AUTH_INT))
*value |= DIGEST_QOP_VALUE_AUTH_INT;
- else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
+ else if(Curl_str_casecompare(&out, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
*value |= DIGEST_QOP_VALUE_AUTH_CONF;
-
- token = Curl_strtok_r(NULL, ",", &tok_buf);
+ if(Curl_str_single(&options, ','))
+ break;
}
- free(tmp);
-
return CURLE_OK;
}
@@ -504,10 +492,6 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
struct digestdata *digest)
{
bool before = FALSE; /* got a nonce before */
- bool foundAuth = FALSE;
- bool foundAuthInt = FALSE;
- char *token = NULL;
- char *tmp = NULL;
/* If we already have received a nonce, keep that in mind */
if(digest->nonce)
@@ -551,29 +535,25 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
return CURLE_OUT_OF_MEMORY;
}
else if(strcasecompare(value, "qop")) {
- char *tok_buf = NULL;
- /* Tokenize the list and choose auth if possible, use a temporary
- clone of the buffer since Curl_strtok_r() ruins it */
- tmp = strdup(content);
- if(!tmp)
- return CURLE_OUT_OF_MEMORY;
-
- token = Curl_strtok_r(tmp, ",", &tok_buf);
- while(token) {
- /* Pass additional spaces here */
- while(*token && ISBLANK(*token))
- token++;
- if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
+ const char *token = content;
+ struct Curl_str out;
+ bool foundAuth = FALSE;
+ bool foundAuthInt = FALSE;
+ /* Pass leading spaces */
+ while(*token && ISBLANK(*token))
+ token++;
+ while(!Curl_str_until(&token, &out, 32, ',')) {
+ if(Curl_str_casecompare(&out, DIGEST_QOP_VALUE_STRING_AUTH))
foundAuth = TRUE;
- }
- else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) {
+ else if(Curl_str_casecompare(&out,
+ DIGEST_QOP_VALUE_STRING_AUTH_INT))
foundAuthInt = TRUE;
- }
- token = Curl_strtok_r(NULL, ",", &tok_buf);
+ if(Curl_str_single(&token, ','))
+ break;
+ while(*token && ISBLANK(*token))
+ token++;
}
- free(tmp);
-
/* Select only auth or auth-int. Otherwise, ignore */
if(foundAuth) {
free(digest->qop);
diff --git a/libs/libcurl/src/vauth/digest_sspi.c b/libs/libcurl/src/vauth/digest_sspi.c
index 01c1a05d2b..3210e8ad0e 100644
--- a/libs/libcurl/src/vauth/digest_sspi.c
+++ b/libs/libcurl/src/vauth/digest_sspi.c
@@ -61,8 +61,9 @@ bool Curl_auth_is_digest_supported(void)
/* Query the security package for Digest */
status =
- Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
- &SecurityPackage);
+ Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)),
+ &SecurityPackage);
/* Release the package buffer as it is not required anymore */
if(status == SEC_E_OK) {
@@ -121,8 +122,9 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
/* Query the security package for DigestSSP */
status =
- Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
- &SecurityPackage);
+ Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)),
+ &SecurityPackage);
if(status != SEC_E_OK) {
failf(data, "SSPI: could not get auth info");
return CURLE_AUTH_ERROR;
@@ -163,10 +165,10 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
/* Acquire our credentials handle */
status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
- (TCHAR *) TEXT(SP_NAME_DIGEST),
- SECPKG_CRED_OUTBOUND, NULL,
- p_identity, NULL, NULL,
- &credentials, &expiry);
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)),
+ SECPKG_CRED_OUTBOUND, NULL,
+ p_identity, NULL, NULL,
+ &credentials, &expiry);
if(status != SEC_E_OK) {
Curl_sspi_free_identity(p_identity);
@@ -180,7 +182,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
chlg_desc.cBuffers = 1;
chlg_desc.pBuffers = &chlg_buf;
chlg_buf.BufferType = SECBUFFER_TOKEN;
- chlg_buf.pvBuffer = (void *) Curl_bufref_ptr(chlg);
+ chlg_buf.pvBuffer = CURL_UNCONST(Curl_bufref_ptr(chlg));
chlg_buf.cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
/* Setup the response "output" security buffer */
@@ -271,7 +273,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg,
if(strcasecompare(value, "realm")) {
/* Setup identity's domain and length */
- domain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *) content);
+ domain.tchar_ptr = curlx_convert_UTF8_to_tchar(content);
if(!domain.tchar_ptr)
return CURLE_OUT_OF_MEMORY;
@@ -413,8 +415,9 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
/* Query the security package for DigestSSP */
status =
- Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
- &SecurityPackage);
+ Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)),
+ &SecurityPackage);
if(status != SEC_E_OK) {
failf(data, "SSPI: could not get auth info");
return CURLE_AUTH_ERROR;
@@ -454,10 +457,10 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
chlg_buf[0].pvBuffer = NULL;
chlg_buf[0].cbBuffer = 0;
chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
- chlg_buf[1].pvBuffer = (void *) request;
+ chlg_buf[1].pvBuffer = CURL_UNCONST(request);
chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request));
chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
- chlg_buf[2].pvBuffer = (void *) uripath;
+ chlg_buf[2].pvBuffer = CURL_UNCONST(uripath);
chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath));
chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS;
chlg_buf[3].pvBuffer = NULL;
@@ -534,10 +537,10 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
/* Acquire our credentials handle */
status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
- (TCHAR *) TEXT(SP_NAME_DIGEST),
- SECPKG_CRED_OUTBOUND, NULL,
- p_identity, NULL, NULL,
- &credentials, &expiry);
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_DIGEST)),
+ SECPKG_CRED_OUTBOUND, NULL,
+ p_identity, NULL, NULL,
+ &credentials, &expiry);
if(status != SEC_E_OK) {
Curl_sspi_free_identity(p_identity);
free(output_token);
@@ -553,7 +556,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
chlg_buf[0].pvBuffer = digest->input_token;
chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len);
chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
- chlg_buf[1].pvBuffer = (void *) request;
+ chlg_buf[1].pvBuffer = CURL_UNCONST(request);
chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request));
chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
chlg_buf[2].pvBuffer = NULL;
@@ -567,7 +570,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
resp_buf.pvBuffer = output_token;
resp_buf.cbBuffer = curlx_uztoul(token_max);
- spn = curlx_convert_UTF8_to_tchar((char *) uripath);
+ spn = curlx_convert_UTF8_to_tchar((const char *) uripath);
if(!spn) {
Curl_pSecFn->FreeCredentialsHandle(&credentials);
@@ -579,8 +582,12 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
/* Allocate our new context handle */
digest->http_context = calloc(1, sizeof(CtxtHandle));
- if(!digest->http_context)
+ if(!digest->http_context) {
+ curlx_unicodefree(spn);
+ Curl_sspi_free_identity(p_identity);
+ free(output_token);
return CURLE_OUT_OF_MEMORY;
+ }
/* Generate our response message */
status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL,
diff --git a/libs/libcurl/src/vauth/krb5_gssapi.c b/libs/libcurl/src/vauth/krb5_gssapi.c
index 2048938483..fde838b3ce 100644
--- a/libs/libcurl/src/vauth/krb5_gssapi.c
+++ b/libs/libcurl/src/vauth/krb5_gssapi.c
@@ -133,7 +133,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
infof(data, "GSSAPI handshake failure (empty challenge message)");
return CURLE_BAD_CONTENT_ENCODING;
}
- input_token.value = (void *) Curl_bufref_ptr(chlg);
+ input_token.value = CURL_UNCONST(Curl_bufref_ptr(chlg));
input_token.length = Curl_bufref_len(chlg);
}
@@ -210,7 +210,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
}
/* Setup the challenge "input" security buffer */
- input_token.value = (void *) Curl_bufref_ptr(chlg);
+ input_token.value = CURL_UNCONST(Curl_bufref_ptr(chlg));
input_token.length = Curl_bufref_len(chlg);
/* Decrypt the inbound challenge and obtain the qop */
diff --git a/libs/libcurl/src/vauth/krb5_sspi.c b/libs/libcurl/src/vauth/krb5_sspi.c
index d7a66aa628..eadeb3d046 100644
--- a/libs/libcurl/src/vauth/krb5_sspi.c
+++ b/libs/libcurl/src/vauth/krb5_sspi.c
@@ -55,9 +55,9 @@ bool Curl_auth_is_gssapi_supported(void)
SECURITY_STATUS status;
/* Query the security package for Kerberos */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
- TEXT(SP_NAME_KERBEROS),
- &SecurityPackage);
+ status = Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_KERBEROS)),
+ &SecurityPackage);
/* Release the package buffer as it is not required anymore */
if(status == SEC_E_OK) {
@@ -118,9 +118,9 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
if(!krb5->output_token) {
/* Query the security package for Kerberos */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
- TEXT(SP_NAME_KERBEROS),
- &SecurityPackage);
+ status = Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_KERBEROS)),
+ &SecurityPackage);
if(status != SEC_E_OK) {
failf(data, "SSPI: could not get auth info");
return CURLE_AUTH_ERROR;
@@ -159,11 +159,10 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
/* Acquire our credentials handle */
status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
- (TCHAR *)
- TEXT(SP_NAME_KERBEROS),
- SECPKG_CRED_OUTBOUND, NULL,
- krb5->p_identity, NULL, NULL,
- krb5->credentials, &expiry);
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_KERBEROS)),
+ SECPKG_CRED_OUTBOUND, NULL,
+ krb5->p_identity, NULL, NULL,
+ krb5->credentials, &expiry);
if(status != SEC_E_OK)
return CURLE_LOGIN_DENIED;
@@ -184,7 +183,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
chlg_desc.cBuffers = 1;
chlg_desc.pBuffers = &chlg_buf;
chlg_buf.BufferType = SECBUFFER_TOKEN;
- chlg_buf.pvBuffer = (void *) Curl_bufref_ptr(chlg);
+ chlg_buf.pvBuffer = CURL_UNCONST(Curl_bufref_ptr(chlg));
chlg_buf.cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
}
@@ -297,7 +296,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
input_desc.cBuffers = 2;
input_desc.pBuffers = input_buf;
input_buf[0].BufferType = SECBUFFER_STREAM;
- input_buf[0].pvBuffer = (void *) Curl_bufref_ptr(chlg);
+ input_buf[0].pvBuffer = CURL_UNCONST(Curl_bufref_ptr(chlg));
input_buf[0].cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
input_buf[1].BufferType = SECBUFFER_DATA;
input_buf[1].pvBuffer = NULL;
diff --git a/libs/libcurl/src/vauth/ntlm.c b/libs/libcurl/src/vauth/ntlm.c
index e835500ebf..e8230e6b83 100644
--- a/libs/libcurl/src/vauth/ntlm.c
+++ b/libs/libcurl/src/vauth/ntlm.c
@@ -46,9 +46,7 @@
#include "vtls/vtls.h"
#include "strdup.h"
-#define BUILDING_CURL_NTLM_MSGS_C
#include "vauth/vauth.h"
-#include "vauth/ntlm.h"
#include "curl_endian.h"
#include "curl_printf.h"
@@ -56,6 +54,112 @@
#include "curl_memory.h"
#include "memdebug.h"
+
+/* NTLM buffer fixed size, large enough for long user + host + domain */
+#define NTLM_BUFSIZE 1024
+
+/* Flag bits definitions based on
+ https://davenport.sourceforge.net/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0)
+/* Indicates that Unicode strings are supported for use in security buffer
+ data. */
+
+#define NTLMFLAG_NEGOTIATE_OEM (1<<1)
+/* Indicates that OEM strings are supported for use in security buffer data. */
+
+#define NTLMFLAG_REQUEST_TARGET (1<<2)
+/* Requests that the server's authentication realm be included in the Type 2
+ message. */
+
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN (1<<4)
+/* Specifies that authenticated communication between the client and server
+ should carry a digital signature (message integrity). */
+
+#define NTLMFLAG_NEGOTIATE_SEAL (1<<5)
+/* Specifies that authenticated communication between the client and server
+ should be encrypted (message confidentiality). */
+
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6)
+/* Indicates that datagram authentication is being used. */
+
+#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7)
+/* Indicates that the LAN Manager session key should be used for signing and
+ sealing authenticated communications. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9)
+/* Indicates that NTLM authentication is being used. */
+
+/* unknown (1<<10) */
+
+#define NTLMFLAG_NEGOTIATE_ANONYMOUS (1<<11)
+/* Sent by the client in the Type 3 message to indicate that an anonymous
+ context has been established. This also affects the response fields. */
+
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12)
+/* Sent by the client in the Type 1 message to indicate that a desired
+ authentication realm is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13)
+/* Sent by the client in the Type 1 message to indicate that the client
+ workstation's name is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14)
+/* Sent by the server to indicate that the server and client are on the same
+ machine. Implies that the client may use a pre-established local security
+ context rather than responding to the challenge. */
+
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15)
+/* Indicates that authenticated communication between the client and server
+ should be signed with a "dummy" signature. */
+
+#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a domain. */
+
+#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a server. */
+
+#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a share. Presumably, this is for share-level
+ authentication. Usage is unclear. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19)
+/* Indicates that the NTLM2 signing and sealing scheme should be used for
+ protecting authenticated communications. */
+
+#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23)
+/* Sent by the server in the Type 2 message to indicate that it is including a
+ Target Information block in the message. */
+
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+
+#define NTLMFLAG_NEGOTIATE_128 (1<<29)
+/* Indicates that 128-bit encryption is supported. */
+
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30)
+/* Indicates that the client will provide an encrypted master key in
+ the "Session Key" field of the Type 3 message. */
+
+#define NTLMFLAG_NEGOTIATE_56 (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+
/* "NTLMSSP" signature is always in ASCII regardless of the platform */
#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
diff --git a/libs/libcurl/src/vauth/ntlm.h b/libs/libcurl/src/vauth/ntlm.h
deleted file mode 100644
index 4c8f5edd36..0000000000
--- a/libs/libcurl/src/vauth/ntlm.h
+++ /dev/null
@@ -1,143 +0,0 @@
-#ifndef HEADER_VAUTH_NTLM_H
-#define HEADER_VAUTH_NTLM_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 "curl_setup.h"
-
-#ifdef USE_NTLM
-
-/* NTLM buffer fixed size, large enough for long user + host + domain */
-#define NTLM_BUFSIZE 1024
-
-/* Stuff only required for curl_ntlm_msgs.c */
-#ifdef BUILDING_CURL_NTLM_MSGS_C
-
-/* Flag bits definitions based on
- https://davenport.sourceforge.net/ntlm.html */
-
-#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0)
-/* Indicates that Unicode strings are supported for use in security buffer
- data. */
-
-#define NTLMFLAG_NEGOTIATE_OEM (1<<1)
-/* Indicates that OEM strings are supported for use in security buffer data. */
-
-#define NTLMFLAG_REQUEST_TARGET (1<<2)
-/* Requests that the server's authentication realm be included in the Type 2
- message. */
-
-/* unknown (1<<3) */
-#define NTLMFLAG_NEGOTIATE_SIGN (1<<4)
-/* Specifies that authenticated communication between the client and server
- should carry a digital signature (message integrity). */
-
-#define NTLMFLAG_NEGOTIATE_SEAL (1<<5)
-/* Specifies that authenticated communication between the client and server
- should be encrypted (message confidentiality). */
-
-#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6)
-/* Indicates that datagram authentication is being used. */
-
-#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7)
-/* Indicates that the LAN Manager session key should be used for signing and
- sealing authenticated communications. */
-
-#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9)
-/* Indicates that NTLM authentication is being used. */
-
-/* unknown (1<<10) */
-
-#define NTLMFLAG_NEGOTIATE_ANONYMOUS (1<<11)
-/* Sent by the client in the Type 3 message to indicate that an anonymous
- context has been established. This also affects the response fields. */
-
-#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12)
-/* Sent by the client in the Type 1 message to indicate that a desired
- authentication realm is included in the message. */
-
-#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13)
-/* Sent by the client in the Type 1 message to indicate that the client
- workstation's name is included in the message. */
-
-#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14)
-/* Sent by the server to indicate that the server and client are on the same
- machine. Implies that the client may use a pre-established local security
- context rather than responding to the challenge. */
-
-#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15)
-/* Indicates that authenticated communication between the client and server
- should be signed with a "dummy" signature. */
-
-#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16)
-/* Sent by the server in the Type 2 message to indicate that the target
- authentication realm is a domain. */
-
-#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17)
-/* Sent by the server in the Type 2 message to indicate that the target
- authentication realm is a server. */
-
-#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18)
-/* Sent by the server in the Type 2 message to indicate that the target
- authentication realm is a share. Presumably, this is for share-level
- authentication. Usage is unclear. */
-
-#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19)
-/* Indicates that the NTLM2 signing and sealing scheme should be used for
- protecting authenticated communications. */
-
-#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20)
-/* unknown purpose */
-
-#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21)
-/* unknown purpose */
-
-#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22)
-/* unknown purpose */
-
-#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23)
-/* Sent by the server in the Type 2 message to indicate that it is including a
- Target Information block in the message. */
-
-/* unknown (1<24) */
-/* unknown (1<25) */
-/* unknown (1<26) */
-/* unknown (1<27) */
-/* unknown (1<28) */
-
-#define NTLMFLAG_NEGOTIATE_128 (1<<29)
-/* Indicates that 128-bit encryption is supported. */
-
-#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30)
-/* Indicates that the client will provide an encrypted master key in
- the "Session Key" field of the Type 3 message. */
-
-#define NTLMFLAG_NEGOTIATE_56 (1<<31)
-/* Indicates that 56-bit encryption is supported. */
-
-#endif /* BUILDING_CURL_NTLM_MSGS_C */
-
-#endif /* USE_NTLM */
-
-#endif /* HEADER_VAUTH_NTLM_H */
diff --git a/libs/libcurl/src/vauth/ntlm_sspi.c b/libs/libcurl/src/vauth/ntlm_sspi.c
index 3bb21cc10b..3d8d1e010e 100644
--- a/libs/libcurl/src/vauth/ntlm_sspi.c
+++ b/libs/libcurl/src/vauth/ntlm_sspi.c
@@ -55,8 +55,9 @@ bool Curl_auth_is_ntlm_supported(void)
SECURITY_STATUS status;
/* Query the security package for NTLM */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
- &SecurityPackage);
+ status = Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NTLM)),
+ &SecurityPackage);
/* Release the package buffer as it is not required anymore */
if(status == SEC_E_OK) {
@@ -103,8 +104,9 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
Curl_auth_cleanup_ntlm(ntlm);
/* Query the security package for NTLM */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
- &SecurityPackage);
+ status = Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NTLM)),
+ &SecurityPackage);
if(status != SEC_E_OK) {
failf(data, "SSPI: could not get auth info");
return CURLE_AUTH_ERROR;
@@ -142,10 +144,10 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
/* Acquire our credentials handle */
status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
- (TCHAR *) TEXT(SP_NAME_NTLM),
- SECPKG_CRED_OUTBOUND, NULL,
- ntlm->p_identity, NULL, NULL,
- ntlm->credentials, &expiry);
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NTLM)),
+ SECPKG_CRED_OUTBOUND, NULL,
+ ntlm->p_identity, NULL, NULL,
+ ntlm->credentials, &expiry);
if(status != SEC_E_OK)
return CURLE_LOGIN_DENIED;
diff --git a/libs/libcurl/src/vauth/spnego_gssapi.c b/libs/libcurl/src/vauth/spnego_gssapi.c
index 850d749c1c..7b7ec3ccfc 100644
--- a/libs/libcurl/src/vauth/spnego_gssapi.c
+++ b/libs/libcurl/src/vauth/spnego_gssapi.c
@@ -156,10 +156,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
}
/* Set channel binding data if available */
- if(nego->channel_binding_data.leng > 0) {
+ if(Curl_dyn_len(&nego->channel_binding_data)) {
memset(&chan, 0, sizeof(struct gss_channel_bindings_struct));
- chan.application_data.length = nego->channel_binding_data.leng;
- chan.application_data.value = nego->channel_binding_data.bufr;
+ chan.application_data.length = Curl_dyn_len(&nego->channel_binding_data);
+ chan.application_data.value = Curl_dyn_ptr(&nego->channel_binding_data);
chan_bindings = &chan;
}
diff --git a/libs/libcurl/src/vauth/spnego_sspi.c b/libs/libcurl/src/vauth/spnego_sspi.c
index b47475dc31..c42c7f8f10 100644
--- a/libs/libcurl/src/vauth/spnego_sspi.c
+++ b/libs/libcurl/src/vauth/spnego_sspi.c
@@ -57,9 +57,9 @@ bool Curl_auth_is_spnego_supported(void)
SECURITY_STATUS status;
/* Query the security package for Negotiate */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
- TEXT(SP_NAME_NEGOTIATE),
- &SecurityPackage);
+ status = Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NEGOTIATE)),
+ &SecurityPackage);
/* Release the package buffer as it is not required anymore */
if(status == SEC_E_OK) {
@@ -128,9 +128,9 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
if(!nego->output_token) {
/* Query the security package for Negotiate */
- nego->status = (DWORD)Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
- TEXT(SP_NAME_NEGOTIATE),
- &SecurityPackage);
+ nego->status = (DWORD)Curl_pSecFn->QuerySecurityPackageInfo(
+ (TCHAR *)CURL_UNCONST(TEXT(SP_NAME_NEGOTIATE)),
+ &SecurityPackage);
if(nego->status != SEC_E_OK) {
failf(data, "SSPI: could not get auth info");
return CURLE_AUTH_ERROR;
@@ -170,10 +170,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
/* Acquire our credentials handle */
nego->status = (DWORD)
Curl_pSecFn->AcquireCredentialsHandle(NULL,
- (TCHAR *)TEXT(SP_NAME_NEGOTIATE),
- SECPKG_CRED_OUTBOUND, NULL,
- nego->p_identity, NULL, NULL,
- nego->credentials, &expiry);
+ (TCHAR *)CURL_UNCONST(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;
diff --git a/libs/libcurl/src/version.c b/libs/libcurl/src/version.c
index 28d1fd0b95..283a9d30b4 100644
--- a/libs/libcurl/src/version.c
+++ b/libs/libcurl/src/version.c
@@ -422,8 +422,6 @@ static int idn_present(curl_version_info_data *info)
return info->libidn != NULL;
#endif
}
-#else
-#define idn_present NULL
#endif
#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
diff --git a/libs/libcurl/src/version_win32.c b/libs/libcurl/src/version_win32.c
index e0e325872d..40eb5dff33 100644
--- a/libs/libcurl/src/version_win32.c
+++ b/libs/libcurl/src/version_win32.c
@@ -24,7 +24,7 @@
#include "curl_setup.h"
-#if defined(_WIN32)
+#ifdef _WIN32
#include <curl/curl.h>
#include "version_win32.h"
@@ -79,7 +79,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
{
bool matched = FALSE;
-#if defined(CURL_WINDOWS_UWP)
+#ifdef CURL_WINDOWS_UWP
/* 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);
@@ -113,88 +113,12 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
/* 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));
- osver.dwOSVersionInfoSize = sizeof(osver);
-
- /* Find out Windows version */
- if(GetVersionEx(&osver)) {
- /* Verify the Operating System version number */
- switch(condition) {
- case VERSION_LESS_THAN:
- if(osver.dwMajorVersion < majorVersion ||
- (osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion < minorVersion) ||
- (buildVersion != 0 &&
- (osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion == minorVersion &&
- osver.dwBuildNumber < buildVersion)))
- matched = TRUE;
- break;
-
- case VERSION_LESS_THAN_EQUAL:
- if(osver.dwMajorVersion < majorVersion ||
- (osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion < minorVersion) ||
- (osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion == minorVersion &&
- (buildVersion == 0 ||
- osver.dwBuildNumber <= buildVersion)))
- matched = TRUE;
- break;
-
- case VERSION_EQUAL:
- if(osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion == minorVersion &&
- (buildVersion == 0 ||
- osver.dwBuildNumber == buildVersion))
- matched = TRUE;
- break;
-
- case VERSION_GREATER_THAN_EQUAL:
- if(osver.dwMajorVersion > majorVersion ||
- (osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion > minorVersion) ||
- (osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion == minorVersion &&
- (buildVersion == 0 ||
- osver.dwBuildNumber >= buildVersion)))
- matched = TRUE;
- break;
-
- case VERSION_GREATER_THAN:
- if(osver.dwMajorVersion > majorVersion ||
- (osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion > minorVersion) ||
- (buildVersion != 0 &&
- (osver.dwMajorVersion == majorVersion &&
- osver.dwMinorVersion == minorVersion &&
- osver.dwBuildNumber > buildVersion)))
- matched = TRUE;
- break;
- }
-
- /* Verify the platform identifier (if necessary) */
- if(matched) {
- switch(platform) {
- case PLATFORM_WINDOWS:
- if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
- matched = FALSE;
- break;
-
- case PLATFORM_WINNT:
- if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
- matched = FALSE;
- break;
-
- default: /* like platform == PLATFORM_DONT_CARE */
- break;
- }
- }
- }
+#elif defined(UNDER_CE)
+ (void)majorVersion;
+ (void)minorVersion;
+ (void)buildVersion;
+ (void)platform;
+ (void)condition;
#else
ULONGLONG cm = 0;
struct OUR_OSVERSIONINFOEXW osver;
diff --git a/libs/libcurl/src/version_win32.h b/libs/libcurl/src/version_win32.h
index e07dfba838..10ebe37783 100644
--- a/libs/libcurl/src/version_win32.h
+++ b/libs/libcurl/src/version_win32.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-#if defined(_WIN32)
+#ifdef _WIN32
/* Version condition */
typedef enum {
diff --git a/libs/libcurl/src/vquic/curl_msh3.c b/libs/libcurl/src/vquic/curl_msh3.c
index ae9e79a662..c3f1375016 100644
--- a/libs/libcurl/src/vquic/curl_msh3.c
+++ b/libs/libcurl/src/vquic/curl_msh3.c
@@ -28,6 +28,7 @@
#include "urldata.h"
#include "hash.h"
+#include "hash_offt.h"
#include "timeval.h"
#include "multiif.h"
#include "sendf.h"
@@ -119,7 +120,7 @@ struct cf_msh3_ctx {
struct cf_call_data call_data;
struct curltime connect_started; /* time the current attempt started */
struct curltime handshake_at; /* time connect handshake finished */
- struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */
+ struct Curl_hash_offt streams; /* hash `data->mid` to `stream_ctx` */
/* Flags written by msh3/msquic thread */
bool handshake_complete;
bool handshake_succeeded;
@@ -130,7 +131,7 @@ struct cf_msh3_ctx {
BIT(active);
};
-static void h3_stream_hash_free(void *stream);
+static void h3_stream_hash_free(curl_off_t id, void *stream);
static CURLcode cf_msh3_ctx_init(struct cf_msh3_ctx *ctx,
const struct Curl_addrinfo *ai)
@@ -154,7 +155,7 @@ static CURLcode cf_msh3_ctx_init(struct cf_msh3_ctx *ctx,
static void cf_msh3_ctx_free(struct cf_msh3_ctx *ctx)
{
if(ctx && ctx->initialized) {
- Curl_hash_destroy(&ctx->streams);
+ Curl_hash_offt_destroy(&ctx->streams);
}
free(ctx);
}
@@ -196,8 +197,9 @@ static void h3_stream_ctx_free(struct stream_ctx *stream)
free(stream);
}
-static void h3_stream_hash_free(void *stream)
+static void h3_stream_hash_free(curl_off_t id, void *stream)
{
+ (void)id;
DEBUGASSERT(stream);
h3_stream_ctx_free((struct stream_ctx *)stream);
}
@@ -398,7 +400,7 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
msh3_lock_acquire(&stream->recv_lock);
if((hd->NameLength == 7) &&
- !strncmp(HTTP_PSEUDO_STATUS, (char *)hd->Name, 7)) {
+ !strncmp(HTTP_PSEUDO_STATUS, (const char *)hd->Name, 7)) {
char line[14]; /* status line is always 13 characters long */
size_t ncopy;
@@ -752,12 +754,13 @@ static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
(void)cf;
if(stream && stream->req) {
msh3_lock_acquire(&stream->recv_lock);
- CURL_TRC_CF((struct Curl_easy *)data, cf, "data pending = %zu",
+ CURL_TRC_CF((struct Curl_easy *)CURL_UNCONST(data), cf,
+ "data pending = %zu",
Curl_bufq_len(&stream->recvbuf));
pending = !Curl_bufq_is_empty(&stream->recvbuf);
msh3_lock_release(&stream->recv_lock);
if(pending)
- h3_drain_stream(cf, (struct Curl_easy *)data);
+ h3_drain_stream(cf, (struct Curl_easy *)CURL_UNCONST(data));
}
CF_DATA_RESTORE(cf, save);
@@ -838,16 +841,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port);
if(verify && (conn_config->CAfile || conn_config->CApath)) {
- /* Need a way to provide trust anchors to MSH3 */
-#ifdef DEBUGBUILD
- /* we need this for our test cases to run */
- CURL_TRC_CF(data, cf, "non-standard CA not supported, "
- "switching off verifypeer in DEBUG mode");
- verify = 0;
-#else
+ /* Note there's currently no way to provide trust anchors to MSH3 and
+ that causes tests to fail. */
CURL_TRC_CF(data, cf, "non-standard CA not supported, "
"attempting with built-in verification");
-#endif
}
CURL_TRC_CF(data, cf, "connecting to %s:%d (verify=%d)",
@@ -883,13 +880,12 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_msh3_ctx *ctx = cf->ctx;
struct cf_call_data save;
CURLcode result = CURLE_OK;
- (void)blocking;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
diff --git a/libs/libcurl/src/vquic/curl_ngtcp2.c b/libs/libcurl/src/vquic/curl_ngtcp2.c
index 8f54f159ee..7b3f0f9b7e 100644
--- a/libs/libcurl/src/vquic/curl_ngtcp2.c
+++ b/libs/libcurl/src/vquic/curl_ngtcp2.c
@@ -45,7 +45,7 @@
#endif
#include "urldata.h"
-#include "hash.h"
+#include "hash_offt.h"
#include "sendf.h"
#include "strdup.h"
#include "rand.h"
@@ -133,7 +133,7 @@ struct cf_ngtcp2_ctx {
struct curltime handshake_at; /* time connect handshake finished */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
struct dynbuf scratch; /* temp buffer for header construction */
- struct Curl_hash streams; /* hash `data->mid` to `h3_stream_ctx` */
+ struct Curl_hash_offt streams; /* hash `data->mid` 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 */
@@ -156,7 +156,7 @@ struct cf_ngtcp2_ctx {
#define CF_CTX_CALL_DATA(cf) \
((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
-static void h3_stream_hash_free(void *stream);
+static void h3_stream_hash_free(curl_off_t id, void *stream);
static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx)
{
@@ -179,8 +179,7 @@ static void cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx *ctx)
vquic_ctx_free(&ctx->q);
Curl_bufcp_free(&ctx->stream_bufcp);
Curl_dyn_free(&ctx->scratch);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
+ Curl_hash_offt_destroy(&ctx->streams);
Curl_ssl_peer_cleanup(&ctx->peer);
}
free(ctx);
@@ -225,8 +224,9 @@ static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
free(stream);
}
-static void h3_stream_hash_free(void *stream)
+static void h3_stream_hash_free(curl_off_t id, void *stream)
{
+ (void)id;
DEBUGASSERT(stream);
h3_stream_ctx_free((struct h3_stream_ctx *)stream);
}
@@ -297,38 +297,6 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
-static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int64_t stream_id,
- struct h3_stream_ctx **pstream)
-{
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream;
-
- (void)cf;
- stream = H3_STREAM_CTX(ctx, data);
- if(stream && stream->id == stream_id) {
- *pstream = stream;
- return data;
- }
- else {
- struct Curl_llist_node *e;
- DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn != data->conn)
- continue;
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->id == stream_id) {
- *pstream = stream;
- return sdata;
- }
- }
- }
- *pstream = NULL;
- return NULL;
-}
-
static void h3_drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -481,17 +449,32 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data)
* the handshake time when we really did connect */
if(ctx->use_earlydata)
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
-#ifdef USE_GNUTLS
if(ctx->use_earlydata) {
+#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA)
+ ctx->earlydata_accepted =
+ (SSL_get_early_data_status(ctx->tls.ossl.ssl) !=
+ SSL_EARLY_DATA_REJECTED);
+#endif
+#ifdef USE_GNUTLS
int flags = gnutls_session_get_flags(ctx->tls.gtls.session);
ctx->earlydata_accepted = !!(flags & GNUTLS_SFLAGS_EARLY_DATA);
+#endif
+#ifdef USE_WOLFSSL
+#ifdef WOLFSSL_EARLY_DATA
+ ctx->earlydata_accepted =
+ (wolfSSL_get_early_data_status(ctx->tls.wssl.ssl) !=
+ WOLFSSL_EARLY_DATA_REJECTED);
+#else
+ DEBUGASSERT(0); /* should not come here if ED is disabled. */
+ ctx->earlydata_accepted = FALSE;
+#endif /* WOLFSSL_EARLY_DATA */
+#endif
CURL_TRC_CF(data, cf, "server did%s accept %zu bytes of early data",
ctx->earlydata_accepted ? "" : " not", ctx->earlydata_skip);
Curl_pgrsEarlyData(data, ctx->earlydata_accepted ?
(curl_off_t)ctx->earlydata_skip :
-(curl_off_t)ctx->earlydata_skip);
}
-#endif
return 0;
}
@@ -695,28 +678,26 @@ static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
return 0;
}
-static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t sid,
+static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
uint64_t max_data, void *user_data,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- curl_int64_t stream_id = (curl_int64_t)sid;
- struct Curl_easy *data = CF_DATA_CURRENT(cf);
- struct Curl_easy *s_data;
+ struct Curl_easy *s_data = stream_user_data;
struct h3_stream_ctx *stream;
int rv;
(void)tconn;
(void)max_data;
- (void)stream_user_data;
rv = nghttp3_conn_unblock_stream(ctx->h3conn, stream_id);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
- s_data = get_stream_easy(cf, data, stream_id, &stream);
- if(s_data && stream && stream->quic_flow_blocked) {
- CURL_TRC_CF(s_data, cf, "[%" FMT_PRId64 "] unblock quic flow", stream_id);
+ stream = H3_STREAM_CTX(ctx, s_data);
+ if(stream && stream->quic_flow_blocked) {
+ CURL_TRC_CF(s_data, cf, "[%" FMT_PRId64 "] unblock quic flow",
+ (curl_int64_t)stream_id);
stream->quic_flow_blocked = FALSE;
h3_drain_stream(cf, s_data);
}
@@ -996,7 +977,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
if(!stream)
return NGHTTP3_ERR_CALLBACK_FAILURE;
- h3_xfer_write_resp(cf, data, stream, (char *)buf, blen, FALSE);
+ h3_xfer_write_resp(cf, data, stream, (const char *)buf, blen, FALSE);
if(blen) {
CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] ACK %zu bytes of DATA",
stream->id, blen);
@@ -1400,7 +1381,7 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
while(nvecs < veccnt &&
Curl_bufq_peek_at(&stream->sendbuf,
stream->sendbuf_len_in_flight,
- (const unsigned char **)&vec[nvecs].base,
+ CURL_UNCONST(&vec[nvecs].base),
&vec[nvecs].len)) {
stream->sendbuf_len_in_flight += vec[nvecs].len;
nwritten += vec[nvecs].len;
@@ -1759,7 +1740,7 @@ static ssize_t read_pkt_to_send(void *userp,
if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) {
veccnt = nghttp3_conn_writev_stream(ctx->h3conn, &stream_id, &fin, vec,
- sizeof(vec) / sizeof(vec[0]));
+ CURL_ARRAYSIZE(vec));
if(veccnt < 0) {
failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
nghttp3_strerror((int)veccnt));
@@ -2173,8 +2154,24 @@ static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
ctx = cf ? cf->ctx : NULL;
data = cf ? CF_DATA_CURRENT(cf) : NULL;
if(cf && data && ctx) {
+ unsigned char *quic_tp = NULL;
+ size_t quic_tp_len = 0;
+#ifdef HAVE_OPENSSL_EARLYDATA
+ ngtcp2_ssize tplen;
+ uint8_t tpbuf[256];
+
+ tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf,
+ sizeof(tpbuf));
+ if(tplen < 0)
+ CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s",
+ ngtcp2_strerror((int)tplen));
+ else {
+ quic_tp = (unsigned char *)tpbuf;
+ quic_tp_len = (size_t)tplen;
+ }
+#endif
Curl_ossl_add_session(cf, data, ctx->peer.scache_key, ssl_sessionid,
- SSL_version(ssl), "h3");
+ SSL_version(ssl), "h3", quic_tp, quic_tp_len);
return 1;
}
return 0;
@@ -2257,8 +2254,23 @@ static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
struct Curl_easy *data = CF_DATA_CURRENT(cf);
DEBUGASSERT(data);
if(data && ctx) {
+ ngtcp2_ssize tplen;
+ uint8_t tpbuf[256];
+ unsigned char *quic_tp = NULL;
+ size_t quic_tp_len = 0;
+
+ tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf,
+ sizeof(tpbuf));
+ if(tplen < 0)
+ CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s",
+ ngtcp2_strerror((int)tplen));
+ else {
+ quic_tp = (unsigned char *)tpbuf;
+ quic_tp_len = (size_t)tplen;
+ }
(void)Curl_wssl_cache_session(cf, data, ctx->peer.scache_key,
- session, wolfSSL_version(ssl), "h3");
+ session, wolfSSL_version(ssl),
+ "h3", quic_tp, quic_tp_len);
}
}
return 0;
@@ -2308,13 +2320,13 @@ static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf,
}
#elif defined(USE_WOLFSSL)
- if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
+ if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ssl_ctx) != 0) {
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
return CURLE_FAILED_INIT;
}
if(ssl_config->primary.cache_session) {
/* Register to get notified when a new session is received */
- wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ctx, wssl_quic_new_session_cb);
+ wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ssl_ctx, wssl_quic_new_session_cb);
}
#endif
return CURLE_OK;
@@ -2322,6 +2334,7 @@ static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf,
static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ struct alpn_spec *alpns,
struct Curl_ssl_session *scs,
bool *do_early_data)
{
@@ -2329,13 +2342,26 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
CURLcode result = CURLE_OK;
*do_early_data = FALSE;
+#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA)
+ ctx->earlydata_max = scs->earlydata_max;
+#endif
#ifdef USE_GNUTLS
ctx->earlydata_max =
gnutls_record_get_max_early_data_size(ctx->tls.gtls.session);
+#endif
+#ifdef USE_WOLFSSL
+#ifdef WOLFSSL_EARLY_DATA
+ ctx->earlydata_max = scs->earlydata_max;
+#else
+ ctx->earlydata_max = 0;
+#endif /* WOLFSSL_EARLY_DATA */
+#endif
+#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
+ (defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA))
if((!ctx->earlydata_max)) {
CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
}
- else if(strcmp("h3", scs->alpn)) {
+ else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
CURL_TRC_CF(data, cf, "SSL session from different ALPN, no early data");
}
else if(!scs->quic_tp || !scs->quic_tp_len) {
@@ -2344,7 +2370,7 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
else {
int rv;
rv = ngtcp2_conn_decode_and_set_0rtt_transport_params(
- ctx->qconn, (uint8_t *)scs->quic_tp, scs->quic_tp_len);
+ ctx->qconn, (const uint8_t *)scs->quic_tp, scs->quic_tp_len);
if(rv)
CURL_TRC_CF(data, cf, "no early data, failed to set 0RTT transport "
"parameters: %s", ngtcp2_strerror(rv));
@@ -2359,10 +2385,11 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
}
}
}
-#else /* USE_GNUTLS */
+#else /* not supported in the TLS backend */
(void)data;
(void)ctx;
(void)scs;
+ (void)alpns;
#endif
return result;
}
@@ -2380,6 +2407,9 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
CURLcode result;
const struct Curl_sockaddr_ex *sockaddr = NULL;
int qfd;
+static const struct alpn_spec ALPN_SPEC_H3 = {
+ { "h3", "h3-29" }, 2
+};
DEBUGASSERT(ctx->initialized);
ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
@@ -2423,9 +2453,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
-#define H3_ALPN "\x2h3\x5h3-29"
- result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
- H3_ALPN, sizeof(H3_ALPN) - 1,
+ result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, &ALPN_SPEC_H3,
cf_ngtcp2_tls_ctx_setup, &ctx->tls,
&ctx->conn_ref,
cf_ngtcp2_on_session_reuse);
@@ -2438,7 +2466,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
#elif defined(USE_GNUTLS)
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
#elif defined(USE_WOLFSSL)
- ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
+ ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.ssl);
#else
#error "ngtcp2 TLS backend not defined"
#endif
@@ -2453,7 +2481,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
@@ -2468,7 +2496,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
/* Connect the UDP filter first */
if(!cf->next->connected) {
- result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+ result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
return result;
}
diff --git a/libs/libcurl/src/vquic/curl_osslq.c b/libs/libcurl/src/vquic/curl_osslq.c
index 47dbd9afa2..7dbd0f13f3 100644
--- a/libs/libcurl/src/vquic/curl_osslq.c
+++ b/libs/libcurl/src/vquic/curl_osslq.c
@@ -171,7 +171,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
switch(addr->family) {
case AF_INET: {
struct sockaddr_in * const sin =
- (struct sockaddr_in * const)(void *)&addr->curl_sa_addr;
+ (struct sockaddr_in * const)CURL_UNCONST(&addr->curl_sa_addr);
if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr,
sizeof(sin->sin_addr), sin->sin_port)) {
goto out;
@@ -182,7 +182,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
#ifdef USE_IPV6
case AF_INET6: {
struct sockaddr_in6 * const sin =
- (struct sockaddr_in6 * const)(void *)&addr->curl_sa_addr;
+ (struct sockaddr_in6 * const)CURL_UNCONST(&addr->curl_sa_addr);
if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr,
sizeof(sin->sin6_addr), sin->sin6_port)) {
}
@@ -285,12 +285,12 @@ struct cf_osslq_ctx {
struct curltime handshake_at; /* time connect handshake finished */
struct curltime first_byte_at; /* when first byte was recvd */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct Curl_hash streams; /* hash `data->mid` to `h3_stream_ctx` */
+ struct Curl_hash_offt streams; /* hash `data->mid` 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 */
SSL_POLL_ITEM *poll_items; /* Array for polling on writable state */
struct Curl_easy **curl_items; /* Array of easy objs */
- size_t item_count; /* count of elements in poll/curl_items */
+ size_t items_max; /* max elements in poll/curl_items */
BIT(initialized);
BIT(got_first_byte); /* if first byte was received */
BIT(x509_store_setup); /* if x509 store has been set up */
@@ -299,7 +299,7 @@ struct cf_osslq_ctx {
BIT(need_send); /* QUIC connection needs to send */
};
-static void h3_stream_hash_free(void *stream);
+static void h3_stream_hash_free(curl_off_t id, void *stream);
static void cf_osslq_ctx_init(struct cf_osslq_ctx *ctx)
{
@@ -309,7 +309,7 @@ static void cf_osslq_ctx_init(struct cf_osslq_ctx *ctx)
Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
ctx->poll_items = NULL;
ctx->curl_items = NULL;
- ctx->item_count = 0;
+ ctx->items_max = 0;
ctx->initialized = TRUE;
}
@@ -317,8 +317,7 @@ static void cf_osslq_ctx_free(struct cf_osslq_ctx *ctx)
{
if(ctx && ctx->initialized) {
Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
+ Curl_hash_offt_destroy(&ctx->streams);
Curl_ssl_peer_cleanup(&ctx->peer);
free(ctx->poll_items);
free(ctx->curl_items);
@@ -603,8 +602,9 @@ static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
free(stream);
}
-static void h3_stream_hash_free(void *stream)
+static void h3_stream_hash_free(curl_off_t id, void *stream)
{
+ (void)id;
DEBUGASSERT(stream);
h3_stream_ctx_free((struct h3_stream_ctx *)stream);
}
@@ -666,6 +666,24 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
+struct cf_ossq_find_ctx {
+ curl_int64_t stream_id;
+ struct h3_stream_ctx *stream;
+};
+
+static bool cf_osslq_find_stream(curl_off_t mid, void *val, void *user_data)
+{
+ struct h3_stream_ctx *stream = val;
+ struct cf_ossq_find_ctx *fctx = user_data;
+
+ (void)mid;
+ if(stream && stream->s.id == fctx->stream_id) {
+ fctx->stream = stream;
+ return FALSE; /* stop iterating */
+ }
+ return TRUE;
+}
+
static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
struct Curl_easy *data,
int64_t stream_id)
@@ -686,17 +704,12 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
return &ctx->h3.s_qpack_dec;
}
else {
- struct Curl_llist_node *e;
- DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn != data->conn)
- continue;
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->s.id == stream_id) {
- return &stream->s;
- }
- }
+ struct cf_ossq_find_ctx fctx;
+ fctx.stream_id = stream_id;
+ fctx.stream = NULL;
+ Curl_hash_offt_visit(&ctx->streams, cf_osslq_find_stream, &fctx);
+ if(fctx.stream)
+ return &fctx.stream->s;
}
return NULL;
}
@@ -1012,7 +1025,7 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
while(nvecs < veccnt &&
Curl_bufq_peek_at(&stream->sendbuf,
stream->sendbuf_len_in_flight,
- (const unsigned char **)&vec[nvecs].base,
+ CURL_UNCONST(&vec[nvecs].base),
&vec[nvecs].len)) {
stream->sendbuf_len_in_flight += vec[nvecs].len;
nwritten += vec[nvecs].len;
@@ -1163,13 +1176,15 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
const struct Curl_sockaddr_ex *peer_addr = NULL;
BIO *bio = NULL;
BIO_ADDR *baddr = NULL;
+static const struct alpn_spec ALPN_SPEC_H3 = {
+ { "h3" }, 1
+};
DEBUGASSERT(ctx->initialized);
#define H3_ALPN "\x2h3"
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
- H3_ALPN, sizeof(H3_ALPN) - 1,
- NULL, NULL, NULL, NULL);
+ &ALPN_SPEC_H3, NULL, NULL, NULL, NULL);
if(result)
goto out;
@@ -1399,6 +1414,29 @@ out:
return result;
}
+struct cf_ossq_recv_ctx {
+ struct Curl_cfilter *cf;
+ struct Curl_multi *multi;
+ CURLcode result;
+};
+
+static bool cf_osslq_iter_recv(curl_off_t mid, void *val, void *user_data)
+{
+ struct h3_stream_ctx *stream = val;
+ struct cf_ossq_recv_ctx *rctx = user_data;
+
+ (void)mid;
+ if(stream && !stream->closed && !Curl_bufq_is_full(&stream->recvbuf)) {
+ struct Curl_easy *sdata = Curl_multi_get_handle(rctx->multi, mid);
+ if(sdata) {
+ rctx->result = cf_osslq_stream_recv(&stream->s, rctx->cf, sdata);
+ if(rctx->result)
+ return FALSE; /* abort iteration */
+ }
+ }
+ return TRUE;
+}
+
static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -1435,22 +1473,14 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
}
if(ctx->h3.conn) {
- struct Curl_llist_node *e;
- struct h3_stream_ctx *stream;
- /* PULL all open streams */
+ struct cf_ossq_recv_ctx rctx;
+
DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) {
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && !stream->closed &&
- !Curl_bufq_is_full(&stream->recvbuf)) {
- result = cf_osslq_stream_recv(&stream->s, cf, sdata);
- if(result)
- goto out;
- }
- }
- }
+ rctx.cf = cf;
+ rctx.multi = data->multi;
+ rctx.result = CURLE_OK;
+ Curl_hash_offt_visit(&ctx->streams, cf_osslq_iter_recv, &rctx);
+ result = rctx.result;
}
out:
@@ -1458,13 +1488,43 @@ out:
return result;
}
+struct cf_ossq_fill_ctx {
+ struct cf_osslq_ctx *ctx;
+ struct Curl_multi *multi;
+ size_t n;
+};
+
+static bool cf_osslq_collect_block_send(curl_off_t mid, void *val,
+ void *user_data)
+{
+ struct h3_stream_ctx *stream = val;
+ struct cf_ossq_fill_ctx *fctx = user_data;
+ struct cf_osslq_ctx *ctx = fctx->ctx;
+
+ if(fctx->n >= ctx->items_max) /* should not happen, prevent mayhem */
+ return FALSE;
+
+ if(stream && stream->s.ssl && stream->s.send_blocked) {
+ struct Curl_easy *sdata = Curl_multi_get_handle(fctx->multi, mid);
+ fprintf(stderr, "[OSSLQ] stream %" FMT_PRId64 " sdata=%p\n",
+ stream->s.id, (void *)sdata);
+ if(sdata) {
+ ctx->poll_items[fctx->n].desc = SSL_as_poll_descriptor(stream->s.ssl);
+ ctx->poll_items[fctx->n].events = SSL_POLL_EVENT_W;
+ ctx->curl_items[fctx->n] = sdata;
+ fctx->n++;
+ }
+ }
+ return TRUE;
+}
+
/* Iterate over all streams and check if blocked can be unblocked */
static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_osslq_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream;
- size_t poll_count = 0;
+ size_t poll_count;
size_t result_count = 0;
size_t idx_count = 0;
CURLcode res = CURLE_OK;
@@ -1472,66 +1532,58 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
void *tmpptr;
if(ctx->h3.conn) {
- struct Curl_llist_node *e;
-
- res = CURLE_OUT_OF_MEMORY;
+ struct cf_ossq_fill_ctx fill_ctx;
- if(ctx->item_count < Curl_llist_count(&data->multi->process)) {
- ctx->item_count = 0;
- tmpptr = realloc(ctx->poll_items,
- Curl_llist_count(&data->multi->process) *
- sizeof(SSL_POLL_ITEM));
+ if(ctx->items_max < Curl_hash_offt_count(&ctx->streams)) {
+ size_t nmax = Curl_hash_offt_count(&ctx->streams);
+ ctx->items_max = 0;
+ tmpptr = realloc(ctx->poll_items, nmax * sizeof(SSL_POLL_ITEM));
if(!tmpptr) {
free(ctx->poll_items);
ctx->poll_items = NULL;
+ res = CURLE_OUT_OF_MEMORY;
goto out;
}
ctx->poll_items = tmpptr;
- tmpptr = realloc(ctx->curl_items,
- Curl_llist_count(&data->multi->process) *
- sizeof(struct Curl_easy *));
+ tmpptr = realloc(ctx->curl_items, nmax * sizeof(struct Curl_easy *));
if(!tmpptr) {
free(ctx->curl_items);
ctx->curl_items = NULL;
+ res = CURLE_OUT_OF_MEMORY;
goto out;
}
ctx->curl_items = tmpptr;
-
- ctx->item_count = Curl_llist_count(&data->multi->process);
- }
-
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn == data->conn) {
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->s.ssl && stream->s.send_blocked) {
- ctx->poll_items[poll_count].desc =
- SSL_as_poll_descriptor(stream->s.ssl);
- ctx->poll_items[poll_count].events = SSL_POLL_EVENT_W;
- ctx->curl_items[poll_count] = sdata;
- poll_count++;
- }
- }
+ ctx->items_max = nmax;
}
- memset(&timeout, 0, sizeof(struct timeval));
- res = CURLE_UNRECOVERABLE_POLL;
- if(!SSL_poll(ctx->poll_items, poll_count, sizeof(SSL_POLL_ITEM), &timeout,
- 0, &result_count))
- goto out;
+ fill_ctx.ctx = ctx;
+ fill_ctx.multi = data->multi;
+ fill_ctx.n = 0;
+ Curl_hash_offt_visit(&ctx->streams, cf_osslq_collect_block_send,
+ &fill_ctx);
+ poll_count = fill_ctx.n;
+ if(poll_count) {
+ CURL_TRC_CF(data, cf, "polling %zu blocked streams", poll_count);
+
+ memset(&timeout, 0, sizeof(struct timeval));
+ res = CURLE_UNRECOVERABLE_POLL;
+ if(!SSL_poll(ctx->poll_items, poll_count, sizeof(SSL_POLL_ITEM),
+ &timeout, 0, &result_count))
+ goto out;
- res = CURLE_OK;
-
- for(idx_count = 0; idx_count < poll_count && result_count > 0;
- idx_count++) {
- if(ctx->poll_items[idx_count].revents & SSL_POLL_EVENT_W) {
- stream = H3_STREAM_CTX(ctx, ctx->curl_items[idx_count]);
- nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
- stream->s.send_blocked = FALSE;
- h3_drain_stream(cf, ctx->curl_items[idx_count]);
- CURL_TRC_CF(ctx->curl_items[idx_count], cf, "unblocked");
- result_count--;
+ res = CURLE_OK;
+
+ for(idx_count = 0; idx_count < poll_count && result_count > 0;
+ idx_count++) {
+ if(ctx->poll_items[idx_count].revents & SSL_POLL_EVENT_W) {
+ stream = H3_STREAM_CTX(ctx, ctx->curl_items[idx_count]);
+ nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
+ stream->s.send_blocked = FALSE;
+ h3_drain_stream(cf, ctx->curl_items[idx_count]);
+ CURL_TRC_CF(ctx->curl_items[idx_count], cf, "unblocked");
+ result_count--;
+ }
}
}
}
@@ -1718,7 +1770,7 @@ out:
static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
@@ -1733,7 +1785,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
/* Connect the UDP filter first */
if(!cf->next->connected) {
- result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+ result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
return result;
}
diff --git a/libs/libcurl/src/vquic/curl_quiche.c b/libs/libcurl/src/vquic/curl_quiche.c
index d4824958de..5d565e31c1 100644
--- a/libs/libcurl/src/vquic/curl_quiche.c
+++ b/libs/libcurl/src/vquic/curl_quiche.c
@@ -29,7 +29,7 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "bufq.h"
-#include "hash.h"
+#include "hash_offt.h"
#include "urldata.h"
#include "cfilters.h"
#include "cf-socket.h"
@@ -97,7 +97,7 @@ struct cf_quiche_ctx {
struct curltime started_at; /* time the current attempt started */
struct curltime handshake_at; /* time connect handshake finished */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */
+ struct Curl_hash_offt streams; /* hash `data->mid` to `stream_ctx` */
curl_off_t data_recvd;
BIT(initialized);
BIT(goaway); /* got GOAWAY from server */
@@ -115,7 +115,7 @@ static void quiche_debug_log(const char *line, void *argp)
}
#endif
-static void h3_stream_hash_free(void *stream);
+static void h3_stream_hash_free(curl_off_t id, void *stream);
static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
{
@@ -142,8 +142,7 @@ static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx)
Curl_ssl_peer_cleanup(&ctx->peer);
vquic_ctx_free(&ctx->q);
Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
+ Curl_hash_offt_destroy(&ctx->streams);
}
free(ctx);
}
@@ -190,30 +189,73 @@ static void h3_stream_ctx_free(struct stream_ctx *stream)
free(stream);
}
-static void h3_stream_hash_free(void *stream)
+static void h3_stream_hash_free(curl_off_t id, void *stream)
{
+ (void)id;
DEBUGASSERT(stream);
h3_stream_ctx_free((struct stream_ctx *)stream);
}
-static void check_resumes(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+typedef bool cf_quiche_svisit(struct Curl_cfilter *cf,
+ struct Curl_easy *sdata,
+ struct stream_ctx *stream,
+ void *user_data);
+
+struct cf_quiche_visit_ctx {
+ struct Curl_cfilter *cf;
+ struct Curl_multi *multi;
+ cf_quiche_svisit *cb;
+ void *user_data;
+};
+
+static bool cf_quiche_stream_do(curl_off_t mid, void *val, void *user_data)
+{
+ struct cf_quiche_visit_ctx *vctx = user_data;
+ struct stream_ctx *stream = val;
+ struct Curl_easy *sdata = Curl_multi_get_handle(vctx->multi, mid);
+ if(sdata)
+ return vctx->cb(vctx->cf, sdata, stream, vctx->user_data);
+ return TRUE;
+}
+
+static void cf_quiche_for_all_streams(struct Curl_cfilter *cf,
+ struct Curl_multi *multi,
+ cf_quiche_svisit *do_cb,
+ void *user_data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct Curl_llist_node *e;
+ struct cf_quiche_visit_ctx vctx;
+ vctx.cf = cf;
+ vctx.multi = multi;
+ vctx.cb = do_cb;
+ vctx.user_data = user_data;
+ Curl_hash_offt_visit(&ctx->streams, cf_quiche_stream_do, &vctx);
+}
- DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn == data->conn) {
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->quic_flow_blocked) {
- stream->quic_flow_blocked = FALSE;
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] unblock", stream->id);
- }
- }
+static bool cf_quiche_do_resume(struct Curl_cfilter *cf,
+ struct Curl_easy *sdata,
+ struct stream_ctx *stream,
+ void *user_data)
+{
+ (void)user_data;
+ if(stream->quic_flow_blocked) {
+ stream->quic_flow_blocked = FALSE;
+ Curl_expire(sdata, 0, EXPIRE_RUN_NOW);
+ CURL_TRC_CF(sdata, cf, "[%"FMT_PRIu64"] unblock", stream->id);
}
+ return TRUE;
+}
+
+static bool cf_quiche_do_expire(struct Curl_cfilter *cf,
+ struct Curl_easy *sdata,
+ struct stream_ctx *stream,
+ void *user_data)
+{
+ (void)stream;
+ (void)user_data;
+ CURL_TRC_CF(sdata, cf, "conn closed, expire transfer");
+ Curl_expire(sdata, 0, EXPIRE_RUN_NOW);
+ return TRUE;
}
static CURLcode h3_data_setup(struct Curl_cfilter *cf,
@@ -285,52 +327,12 @@ static void h3_drain_stream(struct Curl_cfilter *cf,
}
}
-static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- curl_uint64_t stream_id,
- struct stream_ctx **pstream)
-{
- struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream;
-
- (void)cf;
- stream = H3_STREAM_CTX(ctx, data);
- if(stream && stream->id == stream_id) {
- *pstream = stream;
- return data;
- }
- else {
- struct Curl_llist_node *e;
- DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn != data->conn)
- continue;
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->id == stream_id) {
- *pstream = stream;
- return sdata;
- }
- }
- }
- *pstream = NULL;
- return NULL;
-}
-
static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct Curl_llist_node *e;
-
DEBUGASSERT(data->multi);
CURL_TRC_CF(data, cf, "conn closed, expire all transfers");
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata == data || sdata->conn != data->conn)
- continue;
- CURL_TRC_CF(sdata, cf, "conn closed, expire transfer");
- Curl_expire(sdata, 0, EXPIRE_RUN_NOW);
- }
+ cf_quiche_for_all_streams(cf, data->multi, cf_quiche_do_expire, NULL);
}
/*
@@ -557,14 +559,48 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
return result;
}
+static CURLcode cf_quiche_ev_process(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct stream_ctx *stream,
+ quiche_h3_event *ev)
+{
+ CURLcode result = h3_process_event(cf, data, stream, ev);
+ h3_drain_stream(cf, data);
+ if(result)
+ CURL_TRC_CF(data, cf, "error processing event %s "
+ "for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev),
+ stream->id, result);
+ return result;
+}
+
+struct cf_quich_disp_ctx {
+ curl_uint64_t stream_id;
+ struct Curl_cfilter *cf;
+ struct Curl_multi *multi;
+ quiche_h3_event *ev;
+ CURLcode result;
+};
+
+static bool cf_quiche_disp_event(curl_off_t mid, void *val, void *user_data)
+{
+ struct cf_quich_disp_ctx *dctx = user_data;
+ struct stream_ctx *stream = val;
+
+ if(stream->id == dctx->stream_id) {
+ struct Curl_easy *sdata = Curl_multi_get_handle(dctx->multi, mid);
+ if(sdata)
+ dctx->result = cf_quiche_ev_process(dctx->cf, sdata, stream, dctx->ev);
+ return FALSE; /* stop iterating */
+ }
+ return TRUE;
+}
+
static CURLcode cf_poll_events(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
struct stream_ctx *stream = NULL;
- struct Curl_easy *sdata;
quiche_h3_event *ev;
- CURLcode result;
/* Take in the events and distribute them to the transfers. */
while(ctx->h3c) {
@@ -576,28 +612,27 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "error poll: %"FMT_PRId64, stream3_id);
return CURLE_HTTP3;
}
-
- sdata = get_stream_easy(cf, data, stream3_id, &stream);
- if(!sdata || !stream) {
- CURL_TRC_CF(data, cf, "discard event %s for unknown [%"FMT_PRId64"]",
- cf_ev_name(ev), stream3_id);
- }
else {
- result = h3_process_event(cf, sdata, stream, ev);
- h3_drain_stream(cf, sdata);
- if(result) {
- CURL_TRC_CF(data, cf, "error processing event %s "
- "for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev),
- stream3_id, result);
- if(data == sdata) {
- /* Only report this error to the caller if it is about the
- * transfer we were called with. Otherwise we fail a transfer
- * due to a problem in another one. */
- quiche_h3_event_free(ev);
+ struct cf_quich_disp_ctx dctx;
+ dctx.stream_id = (curl_uint64_t)stream3_id;
+ dctx.cf = cf;
+ dctx.multi = data->multi;
+ dctx.ev = ev;
+ dctx.result = CURLE_OK;
+ stream = H3_STREAM_CTX(ctx, data);
+ if(stream && stream->id == dctx.stream_id) {
+ /* event for calling transfer */
+ CURLcode result = cf_quiche_ev_process(cf, data, stream, ev);
+ quiche_h3_event_free(ev);
+ if(result)
return result;
- }
}
- quiche_h3_event_free(ev);
+ else {
+ /* another transfer, do not return errors, as they are not for
+ * the calling transfer */
+ Curl_hash_offt_visit(&ctx->streams, cf_quiche_disp_event, &dctx);
+ quiche_h3_event_free(ev);
+ }
}
}
return CURLE_OK;
@@ -627,7 +662,8 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
recv_info.from = (struct sockaddr *)remote_addr;
recv_info.from_len = remote_addrlen;
- nread = quiche_conn_recv(ctx->qconn, (unsigned char *)pkt, pktlen,
+ nread = quiche_conn_recv(ctx->qconn,
+ (unsigned char *)CURL_UNCONST(pkt), pktlen,
&recv_info);
if(nread < 0) {
if(QUICHE_ERR_DONE == nread) {
@@ -686,7 +722,8 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
if(rctx.pkts > 0) {
/* quiche digested ingress packets. It might have opened flow control
* windows again. */
- check_resumes(cf, data);
+ DEBUGASSERT(data->multi);
+ cf_quiche_for_all_streams(cf, data->multi, cf_quiche_do_resume, NULL);
}
return cf_poll_events(cf, data);
}
@@ -924,7 +961,7 @@ static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf,
ssize_t nwritten;
nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
- (uint8_t *)buf, len, eos);
+ (uint8_t *)CURL_UNCONST(buf), len, eos);
if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
/* Blocked on flow control and should HOLD sending. But when do we open
* again? */
@@ -1267,6 +1304,9 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
int rv;
CURLcode result;
const struct Curl_sockaddr_ex *sockaddr;
+static const struct alpn_spec ALPN_SPEC_H3 = {
+ { "h3" }, 1
+};
DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD);
DEBUGASSERT(ctx->initialized);
@@ -1298,15 +1338,12 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
10 * QUIC_MAX_STREAMS * H3_STREAM_WINDOW_SIZE);
quiche_config_set_max_stream_window(ctx->cfg, 10 * H3_STREAM_WINDOW_SIZE);
quiche_config_set_application_protos(ctx->cfg,
- (uint8_t *)
- QUICHE_H3_APPLICATION_PROTOCOL,
+ (uint8_t *)CURL_UNCONST(QUICHE_H3_APPLICATION_PROTOCOL),
sizeof(QUICHE_H3_APPLICATION_PROTOCOL)
- 1);
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
- QUICHE_H3_APPLICATION_PROTOCOL,
- sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1,
- NULL, NULL, cf, NULL);
+ &ALPN_SPEC_H3, NULL, NULL, cf, NULL);
if(result)
return result;
@@ -1378,7 +1415,7 @@ static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf,
static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct cf_quiche_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
@@ -1390,7 +1427,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
/* Connect the UDP filter first */
if(!cf->next->connected) {
- result = Curl_conn_cf_connect(cf->next, data, blocking, done);
+ result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
return result;
}
diff --git a/libs/libcurl/src/vquic/vquic-tls.c b/libs/libcurl/src/vquic/vquic-tls.c
index d92df69cea..feae0f594a 100644
--- a/libs/libcurl/src/vquic/vquic-tls.c
+++ b/libs/libcurl/src/vquic/vquic-tls.c
@@ -58,178 +58,11 @@
#include "curl_memory.h"
#include "memdebug.h"
-#if defined(USE_WOLFSSL)
-
-#define QUIC_CIPHERS \
- "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
- "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
-#define QUIC_GROUPS "P-256:P-384:P-521"
-
-#if defined(HAVE_SECRET_CALLBACK)
-static void keylog_callback(const WOLFSSL *ssl, const char *line)
-{
- (void)ssl;
- Curl_tls_keylog_write_line(line);
-}
-#endif
-
-static CURLcode 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 wssl_init_ssl(struct curl_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- const char *alpn, size_t alpn_len,
- void *user_data)
-{
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, 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));
- }
-
- if(ssl_config->primary.cache_session) {
- (void)Curl_wssl_setup_session(cf, data, &ctx->wssl, peer->scache_key);
- }
-
- return CURLE_OK;
-}
-#endif /* defined(USE_WOLFSSL) */
-
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
- const char *alpn, size_t alpn_len,
+ const struct alpn_spec *alpns,
Curl_vquic_tls_ctx_setup *cb_setup,
void *cb_user_data, void *ssl_user_data,
Curl_vquic_session_reuse_cb *session_reuse_cb)
@@ -254,21 +87,17 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
#ifdef USE_OPENSSL
(void)result;
- return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer,
- (const unsigned char *)alpn, alpn_len,
- cb_setup, cb_user_data, NULL, ssl_user_data);
+ return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, alpns,
+ cb_setup, cb_user_data, NULL, ssl_user_data,
+ session_reuse_cb);
#elif defined(USE_GNUTLS)
- return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
- (const unsigned char *)alpn, alpn_len,
+ return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer, alpns,
cb_setup, cb_user_data, ssl_user_data,
session_reuse_cb);
#elif defined(USE_WOLFSSL)
- result = wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
- if(result)
- return result;
-
- (void)session_reuse_cb;
- return wssl_init_ssl(ctx, cf, data, peer, alpn, alpn_len, ssl_user_data);
+ return Curl_wssl_ctx_init(&ctx->wssl, cf, data, peer, alpns,
+ cb_setup, cb_user_data,
+ ssl_user_data, session_reuse_cb);
#else
#error "no TLS lib in used, should not happen"
return CURLE_FAILED_INIT;
@@ -287,10 +116,10 @@ void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx)
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);
+ if(ctx->wssl.ssl)
+ wolfSSL_free(ctx->wssl.ssl);
+ if(ctx->wssl.ssl_ctx)
+ wolfSSL_CTX_free(ctx->wssl.ssl_ctx);
#endif
memset(ctx, 0, sizeof(*ctx));
}
@@ -351,7 +180,7 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
(void)data;
if(conn_config->verifyhost) {
if(peer->sni) {
- WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.handle);
+ WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.ssl);
if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
== WOLFSSL_FAILURE) {
result = CURLE_PEER_FAILED_VERIFICATION;
diff --git a/libs/libcurl/src/vquic/vquic-tls.h b/libs/libcurl/src/vquic/vquic-tls.h
index 8b250f2245..7bc24819d8 100644
--- a/libs/libcurl/src/vquic/vquic-tls.h
+++ b/libs/libcurl/src/vquic/vquic-tls.h
@@ -27,6 +27,7 @@
#include "curl_setup.h"
#include "bufq.h"
#include "vtls/vtls.h"
+#include "vtls/vtls_int.h"
#include "vtls/openssl.h"
#if defined(USE_HTTP3) && \
@@ -43,7 +44,7 @@ struct curl_tls_ctx {
#elif defined(USE_GNUTLS)
struct gtls_ctx gtls;
#elif defined(USE_WOLFSSL)
- struct wolfssl_ctx wssl;
+ struct wssl_ctx wssl;
#endif
};
@@ -60,6 +61,7 @@ typedef CURLcode Curl_vquic_tls_ctx_setup(struct Curl_cfilter *cf,
typedef CURLcode Curl_vquic_session_reuse_cb(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ struct alpn_spec *alpns,
struct Curl_ssl_session *scs,
bool *do_early_data);
@@ -70,9 +72,7 @@ typedef CURLcode Curl_vquic_session_reuse_cb(struct Curl_cfilter *cf,
* @param cf the connection filter involved
* @param data the transfer involved
* @param peer the peer that will be connected to
- * @param alpn the ALPN string in protocol format ((len+bytes+)+),
- * may be NULL
- * @param alpn_len the overall number of bytes in `alpn`
+ * @param alpns the ALPN specifications to negotiate, may be NULL
* @param cb_setup optional callback for early TLS config
* @param cb_user_data user_data param for callback
* @param ssl_user_data optional pointer to set in TLS application context
@@ -82,7 +82,7 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
- const char *alpn, size_t alpn_len,
+ const struct alpn_spec *alpns,
Curl_vquic_tls_ctx_setup *cb_setup,
void *cb_user_data,
void *ssl_user_data,
diff --git a/libs/libcurl/src/vquic/vquic.c b/libs/libcurl/src/vquic/vquic.c
index 44f29963d1..f24c9dc799 100644
--- a/libs/libcurl/src/vquic/vquic.c
+++ b/libs/libcurl/src/vquic/vquic.c
@@ -44,6 +44,7 @@
#include "vquic.h"
#include "vquic_int.h"
#include "strerror.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -81,10 +82,10 @@ CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx)
#endif
#ifdef DEBUGBUILD
{
- char *p = getenv("CURL_DBG_QUIC_WBLOCK");
+ const char *p = getenv("CURL_DBG_QUIC_WBLOCK");
if(p) {
- long l = strtol(p, NULL, 10);
- if(l >= 0 && l <= 100)
+ curl_off_t l;
+ if(!Curl_str_number(&p, &l, 100))
qctx->wblock_percent = (int)l;
}
}
@@ -126,7 +127,7 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
#endif
*psent = 0;
- msg_iov.iov_base = (uint8_t *)pkt;
+ msg_iov.iov_base = (uint8_t *)CURL_UNCONST(pkt);
msg_iov.iov_len = pktlen;
msg.msg_iov = &msg_iov;
msg.msg_iovlen = 1;
@@ -147,17 +148,18 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
#endif
- while((sent = sendmsg(qctx->sockfd, &msg, 0)) == -1 && SOCKERRNO == EINTR)
+ while((sent = sendmsg(qctx->sockfd, &msg, 0)) == -1 &&
+ SOCKERRNO == SOCKEINTR)
;
if(sent == -1) {
switch(SOCKERRNO) {
case EAGAIN:
-#if EAGAIN != EWOULDBLOCK
- case EWOULDBLOCK:
+#if EAGAIN != SOCKEWOULDBLOCK
+ case SOCKEWOULDBLOCK:
#endif
return CURLE_AGAIN;
- case EMSGSIZE:
+ case SOCKEMSGSIZE:
/* UDP datagram is too large; caused by PMTUD. Just let it be lost. */
break;
case EIO:
@@ -185,16 +187,16 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
while((sent = send(qctx->sockfd,
(const char *)pkt, (SEND_TYPE_ARG3)pktlen, 0)) == -1 &&
- SOCKERRNO == EINTR)
+ SOCKERRNO == SOCKEINTR)
;
if(sent == -1) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
+ if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) {
return CURLE_AGAIN;
}
else {
failf(data, "send() returned %zd (errno %d)", sent, SOCKERRNO);
- if(SOCKERRNO != EMSGSIZE) {
+ if(SOCKERRNO != SOCKEMSGSIZE) {
return CURLE_SEND_ERROR;
}
/* UDP datagram is too large; caused by PMTUD. Just let it be
@@ -377,7 +379,7 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
total_nread = 0;
while(pkts < max_pkts) {
- n = (int)CURLMIN(MMSG_NUM, max_pkts);
+ n = (int)CURLMIN(CURLMIN(MMSG_NUM, IOV_MAX), max_pkts);
memset(&mmsg, 0, sizeof(mmsg));
for(i = 0; i < n; ++i) {
msg_iov[i].iov_base = bufs[i];
@@ -391,14 +393,14 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
}
while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
- SOCKERRNO == EINTR)
+ SOCKERRNO == SOCKEINTR)
;
if(mcount == -1) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
+ if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) {
CURL_TRC_CF(data, cf, "ingress, recvmmsg -> EAGAIN");
goto out;
}
- if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
+ if(!cf->connected && SOCKERRNO == SOCKECONNREFUSED) {
struct ip_quadruple ip;
Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
failf(data, "QUIC: connection to %s port %u refused",
@@ -483,13 +485,13 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
msg.msg_namelen = sizeof(remote_addr);
msg.msg_controllen = sizeof(msg_ctrl);
while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
- SOCKERRNO == EINTR)
+ SOCKERRNO == SOCKEINTR)
;
if(nread == -1) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
+ if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) {
goto out;
}
- if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
+ if(!cf->connected && SOCKERRNO == SOCKECONNREFUSED) {
struct ip_quadruple ip;
Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
failf(data, "QUIC: connection to %s port %u refused",
@@ -557,14 +559,14 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf,
while((nread = recvfrom(qctx->sockfd, (char *)buf, bufsize, 0,
(struct sockaddr *)&remote_addr,
&remote_addrlen)) == -1 &&
- SOCKERRNO == EINTR)
+ SOCKERRNO == SOCKEINTR)
;
if(nread == -1) {
- if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) {
+ if(SOCKERRNO == EAGAIN || SOCKERRNO == SOCKEWOULDBLOCK) {
CURL_TRC_CF(data, cf, "ingress, recvfrom -> EAGAIN");
goto out;
}
- if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
+ if(!cf->connected && SOCKERRNO == SOCKECONNREFUSED) {
struct ip_quadruple ip;
Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
failf(data, "QUIC: connection to %s port %u refused",
diff --git a/libs/libcurl/src/vssh/libssh.c b/libs/libcurl/src/vssh/libssh.c
index 87ed34ee62..cb98738fc3 100644
--- a/libs/libcurl/src/vssh/libssh.c
+++ b/libs/libcurl/src/vssh/libssh.c
@@ -65,7 +65,7 @@
#include "inet_ntop.h"
#include "parsedate.h" /* for the week day and month names */
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "strtoofft.h"
+#include "strparse.h"
#include "multiif.h"
#include "select.h"
#include "warnless.h"
@@ -138,6 +138,7 @@ static void myssh_block2waitfor(struct connectdata *conn, bool block);
static CURLcode myssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
+static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data);
/*
* SCP protocol handler.
@@ -943,7 +944,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
break;
}
- data->state.most_recent_ftp_entrypath = sshc->homedir;
+ free(data->state.most_recent_ftp_entrypath);
+ data->state.most_recent_ftp_entrypath = strdup(sshc->homedir);
+ if(!data->state.most_recent_ftp_entrypath)
+ return CURLE_OUT_OF_MEMORY;
/* This is the last step in the SFTP connect phase. Do note that while
we get the homedir here, we get the "workingpath" in the DO action
@@ -1602,29 +1606,29 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
if(data->state.use_range) {
curl_off_t from, to;
- char *ptr;
- char *ptr2;
- CURLofft to_t;
- CURLofft from_t;
+ const char *p = data->state.range;
+ int from_t, to_t;
- from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
- if(from_t == CURL_OFFT_FLOW) {
+ from_t = Curl_str_number(&p, &from, CURL_OFF_T_MAX);
+ if(from_t == STRE_OVERFLOW)
return CURLE_RANGE_ERROR;
- }
- while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
- ptr++;
- to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
- if(to_t == CURL_OFFT_FLOW) {
+ Curl_str_passblanks(&p);
+ (void)Curl_str_single(&p, '-');
+
+ to_t = Curl_str_numblanks(&p, &to);
+ if(to_t == STRE_OVERFLOW)
return CURLE_RANGE_ERROR;
- }
- if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
- || (to >= size)) {
+
+ if((to_t == STRE_NO_NUM) || (to >= size)) {
to = size - 1;
+ to_t = STRE_OK;
}
- if(from_t) {
+
+ if(from_t == STRE_NO_NUM) {
/* from is relative to end of file */
from = size - to;
to = size - 1;
+ from_t = STRE_OK;
}
if(from > size) {
failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
@@ -1762,7 +1766,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
SSH_STRING_FREE_CHAR(sshc->homedir);
- data->state.most_recent_ftp_entrypath = NULL;
state(data, SSH_SESSION_DISCONNECT);
break;
@@ -1814,9 +1817,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
- rc = ssh_scp_push_file(sshc->scp_session, protop->path,
- (size_t)data->state.infilesize,
- (int)data->set.new_file_perms);
+ rc = ssh_scp_push_file64(sshc->scp_session, protop->path,
+ (uint64_t)data->state.infilesize,
+ (int)data->set.new_file_perms);
+
if(rc != SSH_OK) {
err_msg = ssh_get_error(sshc->ssh_session);
failf(data, "%s", err_msg);
@@ -1937,53 +1941,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
SSH_STRING_FREE_CHAR(sshc->homedir);
- data->state.most_recent_ftp_entrypath = NULL;
state(data, SSH_SESSION_FREE);
FALLTHROUGH();
case SSH_SESSION_FREE:
- if(sshc->ssh_session) {
- ssh_free(sshc->ssh_session);
- sshc->ssh_session = NULL;
- }
-
- /* worst-case scenario cleanup */
-
- DEBUGASSERT(sshc->ssh_session == NULL);
- DEBUGASSERT(sshc->scp_session == NULL);
-
- if(sshc->readdir_tmp) {
- ssh_string_free_char(sshc->readdir_tmp);
- sshc->readdir_tmp = NULL;
- }
-
- if(sshc->quote_attrs)
- sftp_attributes_free(sshc->quote_attrs);
-
- if(sshc->readdir_attrs)
- sftp_attributes_free(sshc->readdir_attrs);
-
- if(sshc->readdir_link_attrs)
- sftp_attributes_free(sshc->readdir_link_attrs);
-
- if(sshc->privkey)
- ssh_key_free(sshc->privkey);
- if(sshc->pubkey)
- ssh_key_free(sshc->pubkey);
-
- Curl_safefree(sshc->rsa_pub);
- Curl_safefree(sshc->rsa);
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
- Curl_dyn_free(&sshc->readdir_buf);
- Curl_safefree(sshc->readdir_linkPath);
- SSH_STRING_FREE_CHAR(sshc->homedir);
-
+ sshc_cleanup(sshc, data);
/* the code we are about to return */
result = sshc->actualcode;
-
memset(sshc, 0, sizeof(struct ssh_conn));
-
connclose(conn, "SSH session free");
sshc->state = SSH_SESSION_FREE; /* current */
sshc->nextstate = SSH_NO_STATE;
@@ -2121,10 +2086,14 @@ static CURLcode myssh_setup_connection(struct Curl_easy *data,
struct SSHPROTO *ssh;
struct ssh_conn *sshc = &conn->proto.sshc;
+ if(!sshc->initialised) {
+ Curl_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
+ sshc->initialised = TRUE;
+ }
+
data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
if(!ssh)
return CURLE_OUT_OF_MEMORY;
- Curl_dyn_init(&sshc->readdir_buf, CURL_PATH_MAX * 2);
return CURLE_OK;
}
@@ -2327,6 +2296,55 @@ static CURLcode myssh_do_it(struct Curl_easy *data, bool *done)
return result;
}
+static void sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data)
+{
+ (void)data;
+ if(sshc->initialised) {
+ if(sshc->ssh_session) {
+ ssh_free(sshc->ssh_session);
+ sshc->ssh_session = NULL;
+ }
+
+ /* worst-case scenario cleanup */
+ DEBUGASSERT(sshc->ssh_session == NULL);
+ DEBUGASSERT(sshc->scp_session == NULL);
+
+ if(sshc->readdir_tmp) {
+ ssh_string_free_char(sshc->readdir_tmp);
+ sshc->readdir_tmp = NULL;
+ }
+ if(sshc->quote_attrs) {
+ sftp_attributes_free(sshc->quote_attrs);
+ sshc->quote_attrs = NULL;
+ }
+ if(sshc->readdir_attrs) {
+ sftp_attributes_free(sshc->readdir_attrs);
+ sshc->readdir_attrs = NULL;
+ }
+ if(sshc->readdir_link_attrs) {
+ sftp_attributes_free(sshc->readdir_link_attrs);
+ sshc->readdir_link_attrs = NULL;
+ }
+ if(sshc->privkey) {
+ ssh_key_free(sshc->privkey);
+ sshc->privkey = NULL;
+ }
+ if(sshc->pubkey) {
+ ssh_key_free(sshc->pubkey);
+ sshc->pubkey = NULL;
+ }
+
+ Curl_safefree(sshc->rsa_pub);
+ Curl_safefree(sshc->rsa);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ Curl_dyn_free(&sshc->readdir_buf);
+ Curl_safefree(sshc->readdir_linkPath);
+ SSH_STRING_FREE_CHAR(sshc->homedir);
+ sshc->initialised = FALSE;
+ }
+}
+
/* BLOCKING, but the function is using the state machine so the only reason
this is still blocking is that the multi interface code has no support for
disconnecting operations that takes a while */
@@ -2335,10 +2353,10 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
bool dead_connection)
{
CURLcode result = CURLE_OK;
- struct ssh_conn *ssh = &conn->proto.sshc;
+ struct ssh_conn *sshc = &conn->proto.sshc;
(void) dead_connection;
- if(ssh->ssh_session) {
+ if(sshc->ssh_session) {
/* only if there is a session still around to use! */
state(data, SSH_SESSION_DISCONNECT);
@@ -2346,6 +2364,7 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
result = myssh_block_statemach(data, TRUE);
}
+ sshc_cleanup(sshc, data);
return result;
}
@@ -2499,6 +2518,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead_connection)
{
+ struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
(void) dead_connection;
@@ -2511,9 +2531,9 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
}
DEBUGF(infof(data, "SSH DISCONNECT is done"));
+ sshc_cleanup(sshc, data);
return result;
-
}
static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
@@ -2686,7 +2706,7 @@ static void sftp_quote(struct Curl_easy *data)
sshc->nextstate = SSH_NO_STATE;
return;
}
- Curl_debug(data, CURLINFO_HEADER_OUT, (char *) "PWD\n", 4);
+ Curl_debug(data, CURLINFO_HEADER_OUT, "PWD\n", 4);
Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
/* this sends an FTP-like "header" to the header callback so that the
@@ -2739,11 +2759,11 @@ static void sftp_quote(struct Curl_easy *data)
* OpenSSH's sftp program and call the appropriate libssh
* functions.
*/
- if(strncasecompare(cmd, "chgrp ", 6) ||
- strncasecompare(cmd, "chmod ", 6) ||
- strncasecompare(cmd, "chown ", 6) ||
- strncasecompare(cmd, "atime ", 6) ||
- strncasecompare(cmd, "mtime ", 6)) {
+ if(!strncmp(cmd, "chgrp ", 6) ||
+ !strncmp(cmd, "chmod ", 6) ||
+ !strncmp(cmd, "chown ", 6) ||
+ !strncmp(cmd, "atime ", 6) ||
+ !strncmp(cmd, "mtime ", 6)) {
/* attribute change */
/* sshc->quote_path1 contains the mode to set */
@@ -2765,8 +2785,8 @@ static void sftp_quote(struct Curl_easy *data)
state(data, SSH_SFTP_QUOTE_STAT);
return;
}
- if(strncasecompare(cmd, "ln ", 3) ||
- strncasecompare(cmd, "symlink ", 8)) {
+ if(!strncmp(cmd, "ln ", 3) ||
+ !strncmp(cmd, "symlink ", 8)) {
/* symbolic linking */
/* sshc->quote_path1 is the source */
/* get the destination */
@@ -2785,12 +2805,12 @@ static void sftp_quote(struct Curl_easy *data)
state(data, SSH_SFTP_QUOTE_SYMLINK);
return;
}
- else if(strncasecompare(cmd, "mkdir ", 6)) {
+ else if(!strncmp(cmd, "mkdir ", 6)) {
/* create dir */
state(data, SSH_SFTP_QUOTE_MKDIR);
return;
}
- else if(strncasecompare(cmd, "rename ", 7)) {
+ else if(!strncmp(cmd, "rename ", 7)) {
/* rename file */
/* first param is the source path */
/* second param is the dest. path */
@@ -2809,17 +2829,17 @@ static void sftp_quote(struct Curl_easy *data)
state(data, SSH_SFTP_QUOTE_RENAME);
return;
}
- else if(strncasecompare(cmd, "rmdir ", 6)) {
+ else if(!strncmp(cmd, "rmdir ", 6)) {
/* delete dir */
state(data, SSH_SFTP_QUOTE_RMDIR);
return;
}
- else if(strncasecompare(cmd, "rm ", 3)) {
+ else if(!strncmp(cmd, "rm ", 3)) {
state(data, SSH_SFTP_QUOTE_UNLINK);
return;
}
#ifdef HAS_STATVFS_SUPPORT
- else if(strncasecompare(cmd, "statvfs ", 8)) {
+ else if(!strncmp(cmd, "statvfs ", 8)) {
state(data, SSH_SFTP_QUOTE_STATVFS);
return;
}
@@ -2870,10 +2890,13 @@ static void sftp_quote_stat(struct Curl_easy *data)
}
/* Now set the new attributes... */
- if(strncasecompare(cmd, "chgrp", 5)) {
- sshc->quote_attrs->gid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
+ if(!strncmp(cmd, "chgrp", 5)) {
+ const char *p = sshc->quote_path1;
+ curl_off_t gid;
+ (void)Curl_str_number(&p, &gid, UINT_MAX);
+ sshc->quote_attrs->gid = (uint32_t)gid;
if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
- !sshc->acceptfail) {
+ !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chgrp gid not a number");
@@ -2884,11 +2907,10 @@ static void sftp_quote_stat(struct Curl_easy *data)
}
sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
}
- else if(strncasecompare(cmd, "chmod", 5)) {
- mode_t perms;
- perms = (mode_t)strtoul(sshc->quote_path1, NULL, 8);
- /* permissions are octal */
- if(perms == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+ else if(!strncmp(cmd, "chmod", 5)) {
+ curl_off_t perms;
+ const char *p = sshc->quote_path1;
+ if(Curl_str_octal(&p, &perms, 07777)) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chmod permissions not a number");
@@ -2897,13 +2919,15 @@ static void sftp_quote_stat(struct Curl_easy *data)
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
}
- sshc->quote_attrs->permissions = perms;
+ sshc->quote_attrs->permissions = (mode_t)perms;
sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS;
}
- else if(strncasecompare(cmd, "chown", 5)) {
- sshc->quote_attrs->uid = (uint32_t)strtoul(sshc->quote_path1, NULL, 10);
+ else if(!strncmp(cmd, "chown", 5)) {
+ const char *p = sshc->quote_path1;
+ curl_off_t uid;
+ (void)Curl_str_number(&p, &uid, UINT_MAX);
if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
- !sshc->acceptfail) {
+ !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Syntax error: chown uid not a number");
@@ -2914,8 +2938,8 @@ static void sftp_quote_stat(struct Curl_easy *data)
}
sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID;
}
- else if(strncasecompare(cmd, "atime", 5) ||
- strncasecompare(cmd, "mtime", 5)) {
+ else if(!strncmp(cmd, "atime", 5) ||
+ !strncmp(cmd, "mtime", 5)) {
time_t date = Curl_getdate_capped(sshc->quote_path1);
bool fail = FALSE;
if(date == -1) {
@@ -2936,7 +2960,7 @@ static void sftp_quote_stat(struct Curl_easy *data)
sshc->actualcode = CURLE_QUOTE_ERROR;
return;
}
- if(strncasecompare(cmd, "atime", 5))
+ if(!strncmp(cmd, "atime", 5))
sshc->quote_attrs->atime = (uint32_t)date;
else /* mtime */
sshc->quote_attrs->mtime = (uint32_t)date;
diff --git a/libs/libcurl/src/vssh/libssh2.c b/libs/libcurl/src/vssh/libssh2.c
index a75397e95c..4ecf198e17 100644
--- a/libs/libcurl/src/vssh/libssh2.c
+++ b/libs/libcurl/src/vssh/libssh2.c
@@ -68,12 +68,11 @@
#include "inet_ntop.h"
#include "parsedate.h" /* for the week day and month names */
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "strtoofft.h"
#include "multiif.h"
#include "select.h"
#include "warnless.h"
#include "curl_path.h"
-
+#include "strparse.h"
#include <curl_base64.h> /* for base64 encoding/decoding */
#include <curl_sha256.h>
@@ -107,7 +106,8 @@ static int ssh_getsock(struct Curl_easy *data, struct connectdata *conn,
static CURLcode ssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static void ssh_attach(struct Curl_easy *data, struct connectdata *conn);
-
+static int sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data,
+ bool block);
/*
* SCP protocol handler.
*/
@@ -369,7 +369,7 @@ static void state(struct Curl_easy *data, sshstate nowstate)
};
/* a precaution to make sure the lists are in sync */
- DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
+ DEBUGASSERT(CURL_ARRAYSIZE(names) == SSH_LAST);
if(sshc->state != nowstate) {
infof(data, "SFTP %p state change from %s to %s",
@@ -598,9 +598,9 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256];
infof(data, "SSH MD5 public key: %s",
- pubkey_md5 != NULL ? pubkey_md5 : "NULL");
+ pubkey_md5 != NULL ? pubkey_md5 : "NULL");
infof(data, "SSH SHA256 public key: %s",
- pubkey_sha256 != NULL ? pubkey_sha256 : "NULL");
+ pubkey_sha256 != NULL ? pubkey_sha256 : "NULL");
if(pubkey_sha256) {
const char *fingerprint = NULL;
@@ -684,7 +684,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
if(pubkey_md5) {
char md5buffer[33];
- const char *fingerprint = NULL;
+ const char *fingerprint;
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
LIBSSH2_HOSTKEY_HASH_MD5);
@@ -796,7 +796,9 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
int port = 0;
bool found = FALSE;
- if(sshc->kh && !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
+ if(sshc->kh &&
+ !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
+ !data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256]) {
/* lets try to find our host in the known hosts file */
while(!libssh2_knownhost_get(sshc->kh, &store, store)) {
/* For non-standard ports, the name will be enclosed in */
@@ -931,7 +933,7 @@ static CURLcode sftp_quote(struct Curl_easy *data,
char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path);
if(!tmp)
return CURLE_OUT_OF_MEMORY;
- Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4);
+ Curl_debug(data, CURLINFO_HEADER_OUT, "PWD\n", 4);
Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp));
/* this sends an FTP-like "header" to the header callback so that the
@@ -970,11 +972,11 @@ static CURLcode sftp_quote(struct Curl_easy *data,
* 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) ||
- strncasecompare(cmd, "atime ", 6) ||
- strncasecompare(cmd, "mtime ", 6)) {
+ if(!strncmp(cmd, "chgrp ", 6) ||
+ !strncmp(cmd, "chmod ", 6) ||
+ !strncmp(cmd, "chown ", 6) ||
+ !strncmp(cmd, "atime ", 6) ||
+ !strncmp(cmd, "mtime ", 6)) {
/* attribute change */
/* sshc->quote_path1 contains the mode to set */
@@ -990,8 +992,8 @@ static CURLcode sftp_quote(struct Curl_easy *data,
state(data, SSH_SFTP_QUOTE_STAT);
return result;
}
- if(strncasecompare(cmd, "ln ", 3) ||
- strncasecompare(cmd, "symlink ", 8)) {
+ if(!strncmp(cmd, "ln ", 3) ||
+ !strncmp(cmd, "symlink ", 8)) {
/* symbolic linking */
/* sshc->quote_path1 is the source */
/* get the destination */
@@ -1005,12 +1007,12 @@ static CURLcode sftp_quote(struct Curl_easy *data,
state(data, SSH_SFTP_QUOTE_SYMLINK);
return result;
}
- else if(strncasecompare(cmd, "mkdir ", 6)) {
+ else if(!strncmp(cmd, "mkdir ", 6)) {
/* create dir */
state(data, SSH_SFTP_QUOTE_MKDIR);
return result;
}
- else if(strncasecompare(cmd, "rename ", 7)) {
+ else if(!strncmp(cmd, "rename ", 7)) {
/* rename file */
/* first param is the source path */
/* second param is the dest. path */
@@ -1024,16 +1026,16 @@ static CURLcode sftp_quote(struct Curl_easy *data,
state(data, SSH_SFTP_QUOTE_RENAME);
return result;
}
- else if(strncasecompare(cmd, "rmdir ", 6)) {
+ else if(!strncmp(cmd, "rmdir ", 6)) {
/* delete dir */
state(data, SSH_SFTP_QUOTE_RMDIR);
return result;
}
- else if(strncasecompare(cmd, "rm ", 3)) {
+ else if(!strncmp(cmd, "rm ", 3)) {
state(data, SSH_SFTP_QUOTE_UNLINK);
return result;
}
- else if(strncasecompare(cmd, "statvfs ", 8)) {
+ else if(!strncmp(cmd, "statvfs ", 8)) {
state(data, SSH_SFTP_QUOTE_STATVFS);
return result;
}
@@ -1263,7 +1265,7 @@ sftp_pkey_init(struct Curl_easy *data,
if(!sshc->rsa)
out_of_memory = TRUE;
else if(stat(sshc->rsa, &sbuf)) {
- Curl_safefree(sshc->rsa);
+ free(sshc->rsa);
sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
if(!sshc->rsa)
out_of_memory = TRUE;
@@ -1277,10 +1279,10 @@ sftp_pkey_init(struct Curl_easy *data,
/* Nothing found; try the current dir. */
sshc->rsa = strdup("id_rsa");
if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
- Curl_safefree(sshc->rsa);
+ free(sshc->rsa);
sshc->rsa = strdup("id_dsa");
if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
- Curl_safefree(sshc->rsa);
+ free(sshc->rsa);
/* Out of guesses. Set to the empty string to avoid
* surprising info messages. */
sshc->rsa = strdup("");
@@ -1345,7 +1347,7 @@ sftp_quote_stat(struct Curl_easy *data,
sshc->acceptfail = TRUE;
}
- if(!strncasecompare(cmd, "chmod", 5)) {
+ if(!!strncmp(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.
@@ -1367,8 +1369,11 @@ sftp_quote_stat(struct Curl_easy *data,
}
/* Now set the new attributes... */
- if(strncasecompare(cmd, "chgrp", 5)) {
- sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
+ if(!strncmp(cmd, "chgrp", 5)) {
+ const char *p = sshc->quote_path1;
+ curl_off_t gid;
+ (void)Curl_str_number(&p, &gid, ULONG_MAX);
+ sshp->quote_attrs.gid = (unsigned long)gid;
sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) {
@@ -1376,18 +1381,23 @@ sftp_quote_stat(struct Curl_easy *data,
goto fail;
}
}
- else if(strncasecompare(cmd, "chmod", 5)) {
- sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
- sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+ else if(!strncmp(cmd, "chmod", 5)) {
+ curl_off_t perms;
+ const char *p = sshc->quote_path1;
/* permissions are octal */
- if(sshp->quote_attrs.permissions == 0 &&
- !ISDIGIT(sshc->quote_path1[0])) {
+ if(Curl_str_octal(&p, &perms, 07777)) {
failf(data, "Syntax error: chmod permissions not a number");
goto fail;
}
+
+ sshp->quote_attrs.permissions = (unsigned long)perms;
+ sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
}
- else if(strncasecompare(cmd, "chown", 5)) {
- sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
+ else if(!strncmp(cmd, "chown", 5)) {
+ const char *p = sshc->quote_path1;
+ curl_off_t uid;
+ (void)Curl_str_number(&p, &uid, ULONG_MAX);
+ sshp->quote_attrs.uid = (unsigned long)uid;
sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) {
@@ -1395,8 +1405,8 @@ sftp_quote_stat(struct Curl_easy *data,
goto fail;
}
}
- else if(strncasecompare(cmd, "atime", 5) ||
- strncasecompare(cmd, "mtime", 5)) {
+ else if(!strncmp(cmd, "atime", 5) ||
+ !strncmp(cmd, "mtime", 5)) {
time_t date = Curl_getdate_capped(sshc->quote_path1);
bool fail = FALSE;
@@ -1413,7 +1423,7 @@ sftp_quote_stat(struct Curl_easy *data,
#endif
if(fail)
goto fail;
- if(strncasecompare(cmd, "atime", 5))
+ if(!strncmp(cmd, "atime", 5))
sshp->quote_attrs.atime = (unsigned long)date;
else /* mtime */
sshp->quote_attrs.mtime = (unsigned long)date;
@@ -1466,20 +1476,19 @@ sftp_download_stat(struct Curl_easy *data,
}
if(data->state.use_range) {
curl_off_t from, to;
- char *ptr;
- char *ptr2;
- CURLofft to_t;
- CURLofft from_t;
+ const char *p = data->state.range;
+ int to_t, from_t;
- from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
- if(from_t == CURL_OFFT_FLOW)
+ from_t = Curl_str_number(&p, &from, CURL_OFF_T_MAX);
+ if(from_t == STRE_OVERFLOW)
return CURLE_RANGE_ERROR;
- while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
- ptr++;
- to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
- if(to_t == CURL_OFFT_FLOW)
+ Curl_str_passblanks(&p);
+ (void)Curl_str_single(&p, '-');
+
+ to_t = Curl_str_numblanks(&p, &to);
+ if(to_t == STRE_OVERFLOW)
return CURLE_RANGE_ERROR;
- if((to_t == CURL_OFFT_INVAL) /* no "to" value given */
+ if((to_t == STRE_NO_NUM) /* no "to" value given */
|| (to >= size)) {
to = size - 1;
}
@@ -1585,8 +1594,7 @@ static CURLcode sftp_readdir(struct Curl_easy *data,
sshp->readdir_filename,
readdir_len);
if(!result)
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- (char *)"\n", 1);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
if(result)
return result;
}
@@ -1597,7 +1605,6 @@ static CURLcode sftp_readdir(struct Curl_easy *data,
if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
LIBSSH2_SFTP_S_IFLNK)) {
- Curl_dyn_init(&sshp->readdir_link, CURL_PATH_MAX);
result = Curl_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path,
sshp->readdir_filename);
state(data, SSH_SFTP_READDIR_LINK);
@@ -1995,13 +2002,17 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
if(rc > 0) {
/* It seems that this string is not always NULL terminated */
sshp->readdir_filename[rc] = '\0';
+ free(sshc->homedir);
sshc->homedir = strdup(sshp->readdir_filename);
if(!sshc->homedir) {
state(data, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
- data->state.most_recent_ftp_entrypath = sshc->homedir;
+ free(data->state.most_recent_ftp_entrypath);
+ data->state.most_recent_ftp_entrypath = strdup(sshc->homedir);
+ if(!data->state.most_recent_ftp_entrypath)
+ return CURLE_OUT_OF_MEMORY;
}
else {
/* Return the error type */
@@ -2019,13 +2030,13 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
break;
}
- /* This is the last step in the SFTP connect phase. Do note that while
- we get the homedir here, we get the "workingpath" in the DO action
- since the homedir will remain the same between request but the
- working path will not. */
- DEBUGF(infof(data, "SSH CONNECT phase done"));
- state(data, SSH_STOP);
- break;
+ /* This is the last step in the SFTP connect phase. Do note that while
+ we get the homedir here, we get the "workingpath" in the DO action
+ since the homedir will remain the same between request but the
+ working path will not. */
+ DEBUGF(infof(data, "SSH CONNECT phase done"));
+ state(data, SSH_STOP);
+ break;
case SSH_SFTP_QUOTE_INIT:
@@ -2288,7 +2299,6 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
}
case SSH_SFTP_GETINFO:
- {
if(data->set.get_filetime) {
state(data, SSH_SFTP_FILETIME);
}
@@ -2296,7 +2306,6 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
state(data, SSH_SFTP_TRANS_INIT);
}
break;
- }
case SSH_SFTP_FILETIME:
{
@@ -2418,7 +2427,6 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
sshc->actualcode = result ? result : CURLE_SSH;
break;
}
- Curl_dyn_init(&sshp->readdir, CURL_PATH_MAX * 2);
state(data, SSH_SFTP_READDIR);
break;
@@ -2584,7 +2592,6 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
}
Curl_safefree(sshc->homedir);
- data->state.most_recent_ftp_entrypath = NULL;
state(data, SSH_SESSION_DISCONNECT);
break;
@@ -2850,72 +2857,17 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block)
}
Curl_safefree(sshc->homedir);
- data->state.most_recent_ftp_entrypath = NULL;
state(data, SSH_SESSION_FREE);
break;
case SSH_SESSION_FREE:
- if(sshc->kh) {
- libssh2_knownhost_free(sshc->kh);
- sshc->kh = NULL;
- }
-
- if(sshc->ssh_agent) {
- rc = libssh2_agent_disconnect(sshc->ssh_agent);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- if(rc < 0) {
- char *err_msg = NULL;
- (void)libssh2_session_last_error(sshc->ssh_session,
- &err_msg, NULL, 0);
- infof(data, "Failed to disconnect from libssh2 agent: %d %s",
- rc, err_msg);
- }
- libssh2_agent_free(sshc->ssh_agent);
- sshc->ssh_agent = NULL;
-
- /* NB: there is no need to free identities, they are part of internal
- agent stuff */
- sshc->sshagent_identity = NULL;
- sshc->sshagent_prev_identity = NULL;
- }
-
- if(sshc->ssh_session) {
- rc = libssh2_session_free(sshc->ssh_session);
- if(rc == LIBSSH2_ERROR_EAGAIN) {
- break;
- }
- if(rc < 0) {
- char *err_msg = NULL;
- (void)libssh2_session_last_error(sshc->ssh_session,
- &err_msg, NULL, 0);
- infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
- }
- sshc->ssh_session = NULL;
- }
-
- /* worst-case scenario cleanup */
-
- DEBUGASSERT(sshc->ssh_session == NULL);
- DEBUGASSERT(sshc->ssh_channel == NULL);
- DEBUGASSERT(sshc->sftp_session == NULL);
- DEBUGASSERT(sshc->sftp_handle == NULL);
- DEBUGASSERT(sshc->kh == NULL);
- DEBUGASSERT(sshc->ssh_agent == NULL);
-
- Curl_safefree(sshc->rsa_pub);
- Curl_safefree(sshc->rsa);
- Curl_safefree(sshc->quote_path1);
- Curl_safefree(sshc->quote_path2);
- Curl_safefree(sshc->homedir);
-
+ rc = sshc_cleanup(sshc, data, FALSE);
+ if(rc == LIBSSH2_ERROR_EAGAIN)
+ break;
/* the code we are about to return */
result = sshc->actualcode;
-
memset(sshc, 0, sizeof(struct ssh_conn));
-
connclose(conn, "SSH session free");
sshc->state = SSH_SESSION_FREE; /* current */
sshc->nextstate = SSH_NO_STATE;
@@ -3068,13 +3020,23 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data,
static CURLcode ssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
+ struct ssh_conn *sshc = &conn->proto.sshc;
struct SSHPROTO *ssh;
(void)conn;
+ if(!sshc->initialised) {
+ /* other ssh implementations do something here, let's keep
+ * the initialised flag correct even if this implementation does not. */
+ sshc->initialised = TRUE;
+ }
+
data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
if(!ssh)
return CURLE_OUT_OF_MEMORY;
+ Curl_dyn_init(&ssh->readdir, CURL_PATH_MAX * 2);
+ Curl_dyn_init(&ssh->readdir_link, CURL_PATH_MAX);
+
return CURLE_OK;
}
@@ -3103,7 +3065,7 @@ static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer,
return -EAGAIN; /* magic return code for libssh2 */
else if(result)
return -1; /* generic error */
- Curl_debug(data, CURLINFO_DATA_IN, (char *)buffer, (size_t)nread);
+ Curl_debug(data, CURLINFO_DATA_IN, (const char *)buffer, (size_t)nread);
return nread;
}
@@ -3128,7 +3090,7 @@ static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer,
return -EAGAIN; /* magic return code for libssh2 */
else if(result)
return -1; /* error */
- Curl_debug(data, CURLINFO_DATA_OUT, (char *)buffer, nwrite);
+ Curl_debug(data, CURLINFO_DATA_OUT, (const char *)buffer, nwrite);
return (ssize_t)nwrite;
}
#endif
@@ -3146,6 +3108,34 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
CURLcode result;
struct connectdata *conn = data->conn;
+#if LIBSSH2_VERSION_NUM >= 0x010b00
+ {
+ const char *crypto_str;
+ switch(libssh2_crypto_engine()) {
+ case libssh2_gcrypt:
+ crypto_str = "libgcrypt";
+ break;
+ case libssh2_mbedtls:
+ crypto_str = "mbedTLS";
+ break;
+ case libssh2_openssl:
+ crypto_str = "openssl compatible";
+ break;
+ case libssh2_os400qc3:
+ crypto_str = "OS400QC3";
+ break;
+ case libssh2_wincng:
+ crypto_str = "WinCNG";
+ break;
+ default:
+ crypto_str = NULL;
+ break;
+ }
+ if(crypto_str)
+ infof(data, "libssh2 cryptography backend: %s", crypto_str);
+ }
+#endif
+
/* initialize per-handle data if not already */
if(!data->req.p.ssh) {
result = ssh_setup_connection(data, conn);
@@ -3159,10 +3149,11 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
sshc = &conn->proto.sshc;
+ if(conn->user)
+ infof(data, "User: '%s'", conn->user);
+ else
+ infof(data, "User: NULL");
#ifdef CURL_LIBSSH2_DEBUG
- if(conn->user) {
- infof(data, "User: %s", conn->user);
- }
if(conn->passwd) {
infof(data, "Password: %s", conn->passwd);
}
@@ -3369,6 +3360,71 @@ static CURLcode ssh_do(struct Curl_easy *data, bool *done)
return result;
}
+static int sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data,
+ bool block)
+{
+ int rc;
+
+ if(sshc->initialised) {
+ if(sshc->kh) {
+ libssh2_knownhost_free(sshc->kh);
+ sshc->kh = NULL;
+ }
+
+ if(sshc->ssh_agent) {
+ rc = libssh2_agent_disconnect(sshc->ssh_agent);
+ if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) {
+ return rc;
+ }
+ if(rc < 0) {
+ char *err_msg = NULL;
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ infof(data, "Failed to disconnect from libssh2 agent: %d %s",
+ rc, err_msg);
+ }
+ libssh2_agent_free(sshc->ssh_agent);
+ sshc->ssh_agent = NULL;
+
+ /* NB: there is no need to free identities, they are part of internal
+ agent stuff */
+ sshc->sshagent_identity = NULL;
+ sshc->sshagent_prev_identity = NULL;
+ }
+
+ if(sshc->ssh_session) {
+ rc = libssh2_session_free(sshc->ssh_session);
+ if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) {
+ return rc;
+ }
+ if(rc < 0) {
+ char *err_msg = NULL;
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
+ }
+ sshc->ssh_session = NULL;
+ }
+
+ /* worst-case scenario cleanup */
+ DEBUGASSERT(sshc->ssh_session == NULL);
+ DEBUGASSERT(sshc->ssh_channel == NULL);
+ DEBUGASSERT(sshc->sftp_session == NULL);
+ DEBUGASSERT(sshc->sftp_handle == NULL);
+ DEBUGASSERT(sshc->kh == NULL);
+ DEBUGASSERT(sshc->ssh_agent == NULL);
+
+ Curl_safefree(sshc->rsa_pub);
+ Curl_safefree(sshc->rsa);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ Curl_safefree(sshc->homedir);
+ sshc->initialised = FALSE;
+ }
+ return 0;
+}
+
+
/* BLOCKING, but the function is using the state machine so the only reason
this is still blocking is that the multi interface code has no support for
disconnecting operations that takes a while */
@@ -3386,6 +3442,7 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
result = ssh_block_statemach(data, conn, TRUE);
}
+ sshc_cleanup(sshc, data, TRUE);
return result;
}
@@ -3405,6 +3462,7 @@ static CURLcode ssh_done(struct Curl_easy *data, CURLcode status)
Curl_safefree(sshp->path);
Curl_dyn_free(&sshp->readdir);
+ Curl_dyn_free(&sshp->readdir_link);
if(Curl_pgrsDone(data))
return CURLE_ABORTED_BY_CALLBACK;
@@ -3542,6 +3600,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
}
DEBUGF(infof(data, "SSH DISCONNECT is done"));
+ sshc_cleanup(sshc, data, TRUE);
return result;
diff --git a/libs/libcurl/src/vssh/ssh.h b/libs/libcurl/src/vssh/ssh.h
index 4f13ffbb0c..0ed3ffa84e 100644
--- a/libs/libcurl/src/vssh/ssh.h
+++ b/libs/libcurl/src/vssh/ssh.h
@@ -212,6 +212,7 @@ struct ssh_conn {
byte handle[WOLFSSH_MAX_HANDLE];
curl_off_t offset;
#endif /* USE_LIBSSH */
+ BIT(initialised);
};
#ifdef USE_LIBSSH
diff --git a/libs/libcurl/src/vssh/wolfssh.c b/libs/libcurl/src/vssh/wolfssh.c
index 910e5c6d6d..4b278ce62f 100644
--- a/libs/libcurl/src/vssh/wolfssh.c
+++ b/libs/libcurl/src/vssh/wolfssh.c
@@ -34,7 +34,6 @@
#include "sendf.h"
#include "progress.h"
#include "curl_path.h"
-#include "strtoofft.h"
#include "transfer.h"
#include "speedcheck.h"
#include "select.h"
@@ -71,6 +70,7 @@ static int wssh_getsock(struct Curl_easy *data,
curl_socket_t *sock);
static CURLcode wssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
+static void wssh_sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data);
#if 0
/*
@@ -208,7 +208,7 @@ static void state(struct Curl_easy *data, sshstate nowstate)
};
/* a precaution to make sure the lists are in sync */
- DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
+ DEBUGASSERT(CURL_ARRAYSIZE(names) == SSH_LAST);
if(sshc->state != nowstate) {
infof(data, "wolfssh %p state change from %s to %s",
@@ -264,7 +264,7 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle,
sshc->handleSz,
&offset[0],
- (byte *)mem, (word32)len);
+ (byte *)CURL_UNCONST(mem), (word32)len);
if(rc == WS_FATAL_ERROR)
rc = wolfSSH_get_error(sshc->ssh_session);
@@ -368,7 +368,7 @@ static int userauth(byte authtype,
static CURLcode wssh_connect(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
- struct ssh_conn *sshc;
+ struct ssh_conn *sshc = &conn->proto.sshc;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc;
@@ -388,7 +388,6 @@ static CURLcode wssh_connect(struct Curl_easy *data, bool *done)
conn->recv[FIRSTSOCKET] = wsftp_recv;
conn->send[FIRSTSOCKET] = wsftp_send;
}
- sshc = &conn->proto.sshc;
sshc->ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL);
if(!sshc->ctx) {
failf(data, "No wolfSSH context");
@@ -429,8 +428,7 @@ static CURLcode wssh_connect(struct Curl_easy *data, bool *done)
return wssh_multi_statemach(data, done);
error:
- wolfSSH_free(sshc->ssh_session);
- wolfSSH_CTX_free(sshc->ctx);
+ wssh_sshc_cleanup(sshc, data);
return CURLE_FAILED_INIT;
}
@@ -505,7 +503,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
}
break;
case SSH_SFTP_REALPATH:
- name = wolfSSH_SFTP_RealPath(sshc->ssh_session, (char *)".");
+ name = wolfSSH_SFTP_RealPath(sshc->ssh_session,
+ (char *)CURL_UNCONST("."));
rc = wolfSSH_get_error(sshc->ssh_session);
if(rc == WS_WANT_READ) {
*block = TRUE;
@@ -810,11 +809,15 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
case SSH_SFTP_CLOSE:
- if(sshc->handleSz)
+ if(sshc->handleSz) {
rc = wolfSSH_SFTP_Close(sshc->ssh_session, sshc->handle,
sshc->handleSz);
- else
+ if(rc != WS_SUCCESS)
+ rc = wolfSSH_get_error(sshc->ssh_session);
+ }
+ else {
rc = WS_SUCCESS; /* directory listing */
+ }
if(rc == WS_WANT_READ) {
*block = TRUE;
conn->waitfor = KEEP_RECV;
@@ -888,9 +891,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
return CURLE_SSH;
case SSH_SFTP_SHUTDOWN:
- Curl_safefree(sshc->homedir);
- wolfSSH_free(sshc->ssh_session);
- wolfSSH_CTX_free(sshc->ctx);
+ wssh_sshc_cleanup(sshc, data);
state(data, SSH_STOP);
return CURLE_OK;
default:
@@ -1060,6 +1061,20 @@ static CURLcode wssh_done(struct Curl_easy *data, CURLcode status)
return result;
}
+static void wssh_sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data)
+{
+ (void)data;
+ if(sshc->ssh_session) {
+ wolfSSH_free(sshc->ssh_session);
+ sshc->ssh_session = NULL;
+ }
+ if(sshc->ctx) {
+ wolfSSH_CTX_free(sshc->ctx);
+ sshc->ctx = NULL;
+ }
+ Curl_safefree(sshc->homedir);
+}
+
#if 0
static CURLcode wscp_done(struct Curl_easy *data,
CURLcode code, bool premature)
@@ -1085,11 +1100,10 @@ static CURLcode wscp_doing(struct Curl_easy *data,
static CURLcode wscp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead_connection)
{
+ struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
- (void)data;
- (void)conn;
(void)dead_connection;
-
+ wssh_sshc_cleanup(sshc, data);
return result;
}
#endif
@@ -1118,6 +1132,7 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead)
{
+ struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
(void)dead;
@@ -1129,6 +1144,7 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data,
result = wssh_block_statemach(data, TRUE);
}
+ wssh_sshc_cleanup(sshc, data);
DEBUGF(infof(data, "SSH DISCONNECT is done"));
return result;
}
diff --git a/libs/libcurl/src/vtls/bearssl.c b/libs/libcurl/src/vtls/bearssl.c
index 24a0ea0646..bf3f77e8be 100644
--- a/libs/libcurl/src/vtls/bearssl.c
+++ b/libs/libcurl/src/vtls/bearssl.c
@@ -153,7 +153,7 @@ static CURLcode load_cafile(struct cafile_source *source,
}
else if(source->type == CAFILE_SOURCE_BLOB) {
n = source->len;
- p = (unsigned char *) source->data;
+ p = (const unsigned char *) source->data;
}
while(n) {
pushed = br_pem_decoder_push(&pc, p, n);
@@ -338,7 +338,7 @@ static unsigned x509_end_chain(const br_x509_class **ctx)
static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx,
unsigned *usages)
{
- struct x509_context *x509 = (struct x509_context *)ctx;
+ struct x509_context *x509 = (struct x509_context *)CURL_UNCONST(ctx);
if(!x509->verifypeer) {
/* Nothing in the chain is verified, just return the public key of the
@@ -484,7 +484,7 @@ static const uint16_t ciphertable[] = {
BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
};
-#define NUM_OF_CIPHERS (sizeof(ciphertable) / sizeof(ciphertable[0]))
+#define NUM_OF_CIPHERS CURL_ARRAYSIZE(ciphertable)
static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
br_ssl_engine_context *ssl_eng,
@@ -611,12 +611,12 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
if(ssl_config->primary.cache_session) {
struct Curl_ssl_session *sc_session = NULL;
- const br_ssl_session_parameters *session;
ret = Curl_ssl_scache_take(cf, data, connssl->peer.scache_key,
&sc_session);
if(!ret && sc_session && sc_session->sdata && sc_session->sdata_len) {
- session = (br_ssl_session_parameters *)(void *)sc_session->sdata;
+ const br_ssl_session_parameters *session;
+ session = (const br_ssl_session_parameters *)sc_session->sdata;
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
session_set = 1;
infof(data, "BearSSL: reusing session ID");
@@ -729,7 +729,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
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, FALSE,
+ ret = Curl_conn_cf_send(cf->next, data, (const char *)buf, len, FALSE,
&result);
CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
if(ret <= 0) {
@@ -911,18 +911,14 @@ static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return applen;
}
-static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool nonblocking,
- bool *done)
+static CURLcode bearssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
CURLcode ret;
struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- timediff_t timeout_ms;
- int what;
- CURL_TRC_CF(data, cf, "connect_common(blocking=%d)", !nonblocking);
+ CURL_TRC_CF(data, cf, "connect()");
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
CURL_TRC_CF(data, cf, "connect_common, connected");
@@ -930,61 +926,18 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
return CURLE_OK;
}
+ *done = FALSE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+
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 */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* 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;
+ if(ssl_connect_2 == connssl->connecting_state) {
ret = bearssl_connect_step2(cf, data);
- if(ret || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(ret)
return ret;
}
@@ -998,11 +951,6 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
connssl->state = ssl_connection_complete;
*done = TRUE;
}
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
return CURLE_OK;
}
@@ -1044,28 +992,6 @@ static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM,
return CURLE_OK;
}
-static CURLcode bearssl_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode ret;
- bool done = FALSE;
-
- ret = bearssl_connect_common(cf, data, FALSE, &done);
- if(ret)
- return ret;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-static CURLcode bearssl_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return bearssl_connect_common(cf, data, TRUE, done);
-}
-
static void *bearssl_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
{
@@ -1161,7 +1087,6 @@ const struct Curl_ssl Curl_ssl_bearssl = {
bearssl_random, /* random */
NULL, /* cert_status_request */
bearssl_connect, /* connect */
- bearssl_connect_nonblocking, /* connect_nonblocking */
Curl_ssl_adjust_pollset, /* adjust_pollset */
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
diff --git a/libs/libcurl/src/vtls/cipher_suite.c b/libs/libcurl/src/vtls/cipher_suite.c
index ca7c5ba46d..202a1452b0 100644
--- a/libs/libcurl/src/vtls/cipher_suite.c
+++ b/libs/libcurl/src/vtls/cipher_suite.c
@@ -725,7 +725,7 @@ static const struct cs_entry cs_list [] = {
CS_ENTRY(0xCCAE, RSA,PSK,CHACHA20,POLY1305,,,,),
#endif
};
-#define CS_LIST_LEN (sizeof(cs_list) / sizeof(cs_list[0]))
+#define CS_LIST_LEN CURL_ARRAYSIZE(cs_list)
static int cs_str_to_zip(const char *cs_str, size_t cs_len,
uint8_t zip[6])
@@ -786,12 +786,12 @@ static int cs_zip_to_str(const uint8_t zip[6],
/* unzip the 8 indexes */
indexes[0] = zip[0] >> 2;
- indexes[1] = ((zip[0] << 4) & 0x3F) | zip[1] >> 4;
- indexes[2] = ((zip[1] << 2) & 0x3F) | zip[2] >> 6;
+ indexes[1] = (uint8_t)(((zip[0] << 4) & 0x3F) | zip[1] >> 4);
+ indexes[2] = (uint8_t)(((zip[1] << 2) & 0x3F) | zip[2] >> 6);
indexes[3] = ((zip[2] << 0) & 0x3F);
indexes[4] = zip[3] >> 2;
- indexes[5] = ((zip[3] << 4) & 0x3F) | zip[4] >> 4;
- indexes[6] = ((zip[4] << 2) & 0x3F) | zip[5] >> 6;
+ indexes[5] = (uint8_t)(((zip[3] << 4) & 0x3F) | zip[4] >> 4);
+ indexes[6] = (uint8_t)(((zip[4] << 2) & 0x3F) | zip[5] >> 6);
indexes[7] = ((zip[5] << 0) & 0x3F);
if(indexes[0] == CS_TXT_IDX_TLS)
diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c
index 56bae80332..09b4e22352 100644
--- a/libs/libcurl/src/vtls/gtls.c
+++ b/libs/libcurl/src/vtls/gtls.c
@@ -63,12 +63,6 @@
/* The last #include file should be: */
#include "memdebug.h"
-#define QUIC_PRIORITY \
- "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
- "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
- "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
- "%DISABLE_TLS13_COMPAT_MODE"
-
/* Enable GnuTLS debugging by defining GTLSDEBUG */
/*#define GTLSDEBUG */
@@ -106,6 +100,7 @@ static ssize_t gtls_push(void *s, const void *buf, size_t blen)
blen, nwritten, result);
backend->gtls.io_result = result;
if(nwritten < 0) {
+ /* !checksrc! disable ERRNOVAR 1 */
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result) ? EAGAIN : EINVAL);
nwritten = -1;
@@ -127,6 +122,7 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
if(!backend->gtls.shared_creds->trust_setup) {
result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
if(result) {
+ /* !checksrc! disable ERRNOVAR 1 */
gnutls_transport_set_errno(backend->gtls.session, EINVAL);
backend->gtls.io_result = result;
return -1;
@@ -138,6 +134,7 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
blen, nread, result);
backend->gtls.io_result = result;
if(nread < 0) {
+ /* !checksrc! disable ERRNOVAR 1 */
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result) ? EAGAIN : EINVAL);
nread = -1;
@@ -238,115 +235,68 @@ static void unload_file(gnutls_datum_t data)
/* this function does a SSL/TLS (re-)handshake */
static CURLcode handshake(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool duringconnect,
- bool nonblocking)
+ struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
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);
+ int rc;
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);
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(0 == what) {
- if(nonblocking)
- return CURLE_AGAIN;
- else if(timeout_ms) {
- /* timeout */
- 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);
- 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(!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;
+ return CURLE_AGAIN;
+ }
+ else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
+ const char *strerr = NULL;
- 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;
+ if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
+ gnutls_alert_description_t alert = gnutls_alert_get(session);
+ strerr = gnutls_alert_get_name(alert);
}
- 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);
- if(!strerr)
- strerr = gnutls_strerror(rc);
+ infof(data, "gnutls_handshake() warning: %s", strerr);
+ return CURLE_AGAIN;
+ }
+ else if((rc < 0) && backend->gtls.io_result) {
+ return backend->gtls.io_result;
+ }
+ else if(rc < 0) {
+ const char *strerr = NULL;
- infof(data, "gnutls_handshake() warning: %s", strerr);
- continue;
+ if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
+ gnutls_alert_description_t alert = gnutls_alert_get(session);
+ strerr = gnutls_alert_get_name(alert);
}
- 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);
- return CURLE_SSL_CONNECT_ERROR;
- }
+ if(!strerr)
+ strerr = gnutls_strerror(rc);
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
- return CURLE_OK;
+ failf(data, "GnuTLS, handshake failed: %s", strerr);
+ return CURLE_SSL_CONNECT_ERROR;
}
+
+ return CURLE_OK;
}
static gnutls_x509_crt_fmt_t gnutls_do_file_type(const char *type)
@@ -366,12 +316,18 @@ static gnutls_x509_crt_fmt_t gnutls_do_file_type(const char *type)
*/
#define GNUTLS_SRP "+SRP"
+#define QUIC_PRIORITY \
+ "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
+ "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
+ "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
+ "%DISABLE_TLS13_COMPAT_MODE"
+
static CURLcode
gnutls_set_ssl_version_min_max(struct Curl_easy *data,
struct ssl_peer *peer,
struct ssl_primary_config *conn_config,
const char **prioritylist,
- const char *tls13support)
+ bool tls13support)
{
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
@@ -611,7 +567,7 @@ gtls_get_cached_creds(struct Curl_cfilter *cf, struct Curl_easy *data)
if(data->multi) {
shared_creds = Curl_hash_pick(&data->multi->proto_hash,
- (void *)MPROTO_GTLS_X509_KEY,
+ CURL_UNCONST(MPROTO_GTLS_X509_KEY),
sizeof(MPROTO_GTLS_X509_KEY)-1);
if(shared_creds && shared_creds->creds &&
!gtls_shared_creds_expired(data, shared_creds) &&
@@ -655,7 +611,7 @@ static void gtls_set_cached_creds(struct Curl_cfilter *cf,
return;
if(!Curl_hash_add2(&data->multi->proto_hash,
- (void *)MPROTO_GTLS_X509_KEY,
+ CURL_UNCONST(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 */
@@ -827,6 +783,63 @@ static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
return 0;
}
+static CURLcode gtls_set_priority(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct gtls_ctx *gtls,
+ const char *priority)
+{
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct dynbuf buf;
+ const char *err = NULL;
+ CURLcode result = CURLE_OK;
+ int rc;
+
+ Curl_dyn_init(&buf, 4096);
+
+#ifdef USE_GNUTLS_SRP
+ if(conn_config->username) {
+ /* Only add SRP to the cipher list if SRP is requested. Otherwise
+ * GnuTLS will disable TLS 1.3 support. */
+ result = Curl_dyn_add(&buf, priority);
+ if(!result)
+ result = Curl_dyn_add(&buf, ":" GNUTLS_SRP);
+ if(result)
+ goto out;
+ priority = Curl_dyn_ptr(&buf);
+ }
+#endif
+
+ if(conn_config->cipher_list) {
+ if((conn_config->cipher_list[0] == '+') ||
+ (conn_config->cipher_list[0] == '-') ||
+ (conn_config->cipher_list[0] == '!')) {
+ /* add it to out own */
+ if(!Curl_dyn_len(&buf)) { /* not added yet */
+ result = Curl_dyn_add(&buf, priority);
+ if(result)
+ goto out;
+ }
+ result = Curl_dyn_addf(&buf, ":%s", conn_config->cipher_list);
+ if(result)
+ goto out;
+ priority = Curl_dyn_ptr(&buf);
+ }
+ else /* replace our own completely */
+ priority = conn_config->cipher_list;
+ }
+
+ infof(data, "GnuTLS priority: %s", priority);
+ rc = gnutls_priority_set_direct(gtls->session, priority, &err);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "Error %d setting GnuTLS priority: %s", rc, err);
+ result = CURLE_SSL_CONNECT_ERROR;
+ }
+
+out:
+ Curl_dyn_free(&buf);
+ return result;
+}
+
static CURLcode gtls_client_init(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
@@ -839,8 +852,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
int rc;
bool sni = TRUE; /* default is SNI enabled */
const char *prioritylist;
- const char *err = NULL;
- const char *tls13support;
+ bool tls13support;
CURLcode result;
if(!gtls_inited)
@@ -935,7 +947,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
/* "In GnuTLS 3.6.5, TLS 1.3 is enabled by default" */
- tls13support = gnutls_check_version("3.6.5");
+ 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
@@ -960,33 +972,9 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
if(result)
return result;
-#ifdef USE_GNUTLS_SRP
- /* Only add SRP to the cipher list if SRP is requested. Otherwise
- * GnuTLS will disable TLS 1.3 support. */
- if(config->username) {
- char *prioritysrp = aprintf("%s:" GNUTLS_SRP, prioritylist);
- if(!prioritysrp)
- return CURLE_OUT_OF_MEMORY;
- rc = gnutls_priority_set_direct(gtls->session, prioritysrp, &err);
- free(prioritysrp);
-
- if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
- infof(data, "This GnuTLS does not support SRP");
- }
- }
- else {
-#endif
- infof(data, "GnuTLS ciphers: %s", prioritylist);
- rc = gnutls_priority_set_direct(gtls->session, prioritylist, &err);
-#ifdef USE_GNUTLS_SRP
- }
-#endif
-
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "Error %d setting GnuTLS cipher list starting with %s",
- rc, err);
- return CURLE_SSL_CONNECT_ERROR;
- }
+ result = gtls_set_priority(cf, data, gtls, prioritylist);
+ if(result)
+ return result;
if(config->clientcert) {
if(!gtls->shared_creds->trust_setup) {
@@ -1006,7 +994,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
}
- else if(ssl_config->key_passwd) {
+ else {
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 |
@@ -1021,22 +1009,12 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
supported_key_encryption_algorithms);
if(rc != GNUTLS_E_SUCCESS) {
failf(data,
- "error reading X.509 potentially-encrypted key file: %s",
+ "error reading X.509 %skey file: %s",
+ ssl_config->key_passwd ? "potentially-encrypted " : "",
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,
- gnutls_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;
- }
- }
}
#ifdef USE_GNUTLS_SRP
@@ -1089,6 +1067,7 @@ static int keylog_callback(gnutls_session_t session, const char *label,
static CURLcode gtls_on_session_reuse(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ struct alpn_spec *alpns,
struct Curl_ssl_session *scs,
bool *do_early_data)
{
@@ -1104,13 +1083,13 @@ static CURLcode gtls_on_session_reuse(struct Curl_cfilter *cf,
/* Seems to be GnuTLS way to signal no EarlyData in session */
CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
}
- else if(!Curl_alpn_contains_proto(connssl->alpn, scs->alpn)) {
+ else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
CURL_TRC_CF(data, cf, "SSL session has different ALPN, no early data");
}
else {
infof(data, "SSL session allows %zu bytes of early data, "
"reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
- connssl->earlydata_state = ssl_earlydata_use;
+ connssl->earlydata_state = ssl_earlydata_await;
connssl->state = ssl_connection_deferred;
result = Curl_alpn_set_negotiated(cf, data, connssl,
(const unsigned char *)scs->alpn,
@@ -1124,7 +1103,7 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
- const unsigned char *alpn, size_t alpn_len,
+ const struct alpn_spec *alpns_requested,
Curl_gtls_ctx_setup_cb *cb_setup,
void *cb_user_data,
void *ssl_user_data,
@@ -1133,13 +1112,16 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
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 *scs = NULL;
- gnutls_datum_t gtls_alpns[5];
+ gnutls_datum_t gtls_alpns[ALPN_ENTRIES_MAX];
size_t gtls_alpns_count = 0;
bool gtls_session_setup = FALSE;
- CURLcode result;
+ struct alpn_spec alpns;
+ CURLcode result = CURLE_OK;
int rc;
DEBUGASSERT(gctx);
+ Curl_alpn_copy(&alpns, alpns_requested);
+
/* This might be a reconnect, so we check for a session ID in the cache
to speed up things. We need to do this before constructing the gnutls
session since we need to set flags depending on the kind of reuse. */
@@ -1148,7 +1130,8 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
if(result)
goto out;
- if(scs && scs->sdata && scs->sdata_len) {
+ if(scs && scs->sdata && scs->sdata_len &&
+ (!scs->alpn || Curl_alpn_contains_proto(&alpns, scs->alpn))) {
/* we got a cached session, use it! */
result = gtls_client_init(cf, data, peer, scs->earlydata_max, gctx);
@@ -1162,30 +1145,19 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
else {
infof(data, "SSL reusing session with ALPN '%s'",
scs->alpn ? scs->alpn : "-");
- if(ssl_config->earlydata &&
+ if(ssl_config->earlydata && scs->alpn &&
!cf->conn->connect_only &&
(gnutls_protocol_get_version(gctx->session) == GNUTLS_TLS1_3)) {
bool do_early_data = FALSE;
if(sess_reuse_cb) {
- result = sess_reuse_cb(cf, data, scs, &do_early_data);
+ result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data);
if(result)
goto out;
}
if(do_early_data) {
/* We only try the ALPN protocol the session used before,
* otherwise we might send early data for the wrong protocol */
- gtls_alpns[0].data = (unsigned char *)scs->alpn;
- gtls_alpns[0].size = (unsigned)strlen(scs->alpn);
- if(gnutls_alpn_set_protocols(gctx->session,
- gtls_alpns, 1,
- GNUTLS_ALPN_MANDATORY)) {
- failf(data, "failed setting ALPN");
- result = CURLE_SSL_CONNECT_ERROR;
- goto out;
- }
- /* don't set again below */
- gtls_alpns_count = 0;
- alpn = NULL;
+ Curl_alpn_restrict_to(&alpns, scs->alpn);
}
}
}
@@ -1215,24 +1187,14 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
/* convert the ALPN string from our arguments to a list of strings that
* gnutls wants and will convert internally back to this string for sending
* to the server. nice. */
- if(!gtls_alpns_count && alpn && alpn_len) {
- size_t i, alen = alpn_len;
- unsigned char *salpn = (unsigned char *)alpn;
- unsigned char slen;
- for(i = 0; (i < CURL_ARRAYSIZE(gtls_alpns)) && alen; ++i) {
- slen = salpn[0];
- if(slen >= alen)
- return CURLE_FAILED_INIT;
- gtls_alpns[i].data = salpn + 1;
- gtls_alpns[i].size = slen;
- salpn += slen + 1;
- alen -= (size_t)slen + 1;
+ if(!gtls_alpns_count && alpns.count) {
+ size_t i;
+ DEBUGASSERT(CURL_ARRAYSIZE(gtls_alpns) >= alpns.count);
+ for(i = 0; i < alpns.count; ++i) {
+ gtls_alpns[i].data = (unsigned char *)alpns.entries[i];
+ gtls_alpns[i].size = (unsigned int)strlen(alpns.entries[i]);
}
- if(alen) { /* not all alpn chars used, wrong format or too many */
- result = CURLE_FAILED_INIT;
- goto out;
- }
- gtls_alpns_count = i;
+ gtls_alpns_count = alpns.count;
}
if(gtls_alpns_count &&
@@ -1254,33 +1216,24 @@ gtls_connect_step1(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;
- struct alpn_proto_buf proto;
CURLcode result;
DEBUGASSERT(backend);
- DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
same connection */
return CURLE_OK;
- memset(&proto, 0, sizeof(proto));
- if(connssl->alpn) {
- result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
- if(result) {
- failf(data, "Error determining ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
- proto.data, proto.len,
- NULL, NULL, cf, gtls_on_session_reuse);
+ connssl->alpn, NULL, NULL, cf,
+ gtls_on_session_reuse);
if(result)
return result;
if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
+ struct alpn_proto_buf proto;
+ memset(&proto, 0, sizeof(proto));
Curl_alpn_to_proto_str(&proto, connssl->alpn);
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
@@ -1639,10 +1592,10 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
unsigned char addrbuf[sizeof(struct use_addr)];
size_t addrlen = 0;
- if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
+ if(curlx_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
addrlen = 4;
#ifdef USE_IPV6
- else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
+ else if(curlx_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
addrlen = 16;
#endif
@@ -1828,30 +1781,6 @@ out:
return result;
}
-static CURLcode gtls_set_earlydata(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const void *buf, size_t blen)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- ssize_t nwritten = 0;
- CURLcode result = CURLE_OK;
-
- DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_use);
- DEBUGASSERT(Curl_bufq_is_empty(&connssl->earlydata));
- if(blen) {
- if(blen > connssl->earlydata_max)
- blen = connssl->earlydata_max;
- nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
- CURL_TRC_CF(data, cf, "gtls_set_earlydata(len=%zu) -> %zd",
- blen, nwritten);
- if(nwritten < 0)
- return result;
- }
- connssl->earlydata_state = ssl_earlydata_sending;
- connssl->earlydata_skip = Curl_bufq_len(&connssl->earlydata);
- return CURLE_OK;
-}
-
static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -1886,8 +1815,7 @@ static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf,
Curl_bufq_skip(&connssl->earlydata, (size_t)n);
}
/* sent everything there was */
- infof(data, "SSL sending %" FMT_OFF_T " bytes of early data",
- connssl->earlydata_skip);
+ infof(data, "SSL sending %zu bytes of early data", connssl->earlydata_skip);
out:
return result;
}
@@ -1901,17 +1829,22 @@ out:
'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) {
+static CURLcode gtls_connect_common(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done) {
struct ssl_connect_data *connssl = cf->ctx;
struct gtls_ssl_backend_data *backend =
(struct gtls_ssl_backend_data *)connssl->backend;
CURLcode result = CURLE_OK;
DEBUGASSERT(backend);
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ *done = FALSE;
/* Initiate the connection, if not already done */
if(connssl->connecting_state == ssl_connect_1) {
@@ -1922,7 +1855,7 @@ gtls_connect_common(struct Curl_cfilter *cf,
}
if(connssl->connecting_state == ssl_connect_2) {
- if(connssl->earlydata_state == ssl_earlydata_use) {
+ if(connssl->earlydata_state == ssl_earlydata_await) {
goto out;
}
else if(connssl->earlydata_state == ssl_earlydata_sending) {
@@ -1930,13 +1863,11 @@ gtls_connect_common(struct Curl_cfilter *cf,
if(result)
goto out;
connssl->earlydata_state = ssl_earlydata_sent;
- if(!Curl_ssl_cf_is_proxy(cf))
- Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
}
DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
(connssl->earlydata_state == ssl_earlydata_sent));
- result = handshake(cf, data, TRUE, nonblocking);
+ result = handshake(cf, data);
if(result)
goto out;
connssl->connecting_state = ssl_connect_3;
@@ -1951,7 +1882,6 @@ gtls_connect_common(struct Curl_cfilter *cf,
goto out;
connssl->state = ssl_connection_complete;
- connssl->connecting_state = ssl_connect_1;
rc = gnutls_alpn_get_selected_protocol(backend->gtls.session, &proto);
if(rc) { /* No ALPN from server */
@@ -1964,82 +1894,43 @@ gtls_connect_common(struct Curl_cfilter *cf,
if(result)
goto out;
- if(connssl->earlydata_state == ssl_earlydata_sent) {
- /* report the true time the handshake was done */
- connssl->handshake_done = Curl_now();
- Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done);
- if(gnutls_session_get_flags(backend->gtls.session) &
- GNUTLS_SFLAGS_EARLY_DATA) {
- connssl->earlydata_state = ssl_earlydata_accepted;
- infof(data, "Server accepted %zu bytes of TLS early data.",
- connssl->earlydata_skip);
- }
- else {
- connssl->earlydata_state = ssl_earlydata_rejected;
- if(!Curl_ssl_cf_is_proxy(cf))
- Curl_pgrsEarlyData(data, -(curl_off_t)connssl->earlydata_skip);
- infof(data, "Server rejected TLS early data.");
- connssl->earlydata_skip = 0;
- }
+ if(connssl->earlydata_state > ssl_earlydata_none) {
+ /* We should be in this state by now */
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent);
+ connssl->earlydata_state =
+ (gnutls_session_get_flags(backend->gtls.session) &
+ GNUTLS_SFLAGS_EARLY_DATA) ?
+ ssl_earlydata_accepted : ssl_earlydata_rejected;
}
+ connssl->connecting_state = ssl_connect_done;
}
+ if(connssl->connecting_state == ssl_connect_done)
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+
out:
if(result == CURLE_AGAIN) {
*done = FALSE;
return CURLE_OK;
}
- *done = ((connssl->connecting_state == ssl_connect_1) ||
+ *done = ((connssl->state == ssl_connection_complete) ||
(connssl->state == ssl_connection_deferred));
+ CURL_TRC_CF(data, cf, "gtls_connect_common() -> %d, done=%d", result, *done);
return result;
}
-static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
+static CURLcode gtls_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
- if(connssl->state == ssl_connection_deferred) {
+ if((connssl->state == ssl_connection_deferred) &&
+ (connssl->earlydata_state == ssl_earlydata_await)) {
/* We refuse to be pushed, we are waiting for someone to send/recv. */
*done = TRUE;
return CURLE_OK;
}
- return gtls_connect_common(cf, data, TRUE, done);
-}
-
-static CURLcode gtls_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = gtls_connect_common(cf, data, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
-static CURLcode gtls_connect_deferred(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const void *buf,
- size_t blen,
- bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- CURLcode result = CURLE_OK;
-
- DEBUGASSERT(connssl->state == ssl_connection_deferred);
- *done = FALSE;
- if(connssl->earlydata_state == ssl_earlydata_use) {
- result = gtls_set_earlydata(cf, data, buf, blen);
- if(result)
- return result;
- }
-
- return gtls_connect_common(cf, data, TRUE, done);
+ return gtls_connect_common(cf, data, done);
}
static bool gtls_data_pending(struct Curl_cfilter *cf,
@@ -2069,38 +1960,9 @@ static ssize_t gtls_send(struct Curl_cfilter *cf,
ssize_t rc;
size_t nwritten, total_written = 0;
+ (void)data;
DEBUGASSERT(backend);
- if(connssl->state == ssl_connection_deferred) {
- bool done = FALSE;
- *curlcode = gtls_connect_deferred(cf, data, buf, blen, &done);
- if(*curlcode) {
- rc = -1;
- goto out;
- }
- else if(!done) {
- *curlcode = CURLE_AGAIN;
- rc = -1;
- goto out;
- }
- DEBUGASSERT(connssl->state == ssl_connection_complete);
- }
-
- if(connssl->earlydata_skip) {
- if(connssl->earlydata_skip >= blen) {
- connssl->earlydata_skip -= blen;
- *curlcode = CURLE_OK;
- rc = (ssize_t)blen;
- goto out;
- }
- else {
- total_written += connssl->earlydata_skip;
- buf = ((const char *)buf) + connssl->earlydata_skip;
- blen -= connssl->earlydata_skip;
- connssl->earlydata_skip = 0;
- }
- }
-
while(blen) {
backend->gtls.io_result = CURLE_OK;
rc = gnutls_record_send(backend->gtls.session, buf, blen);
@@ -2121,7 +1983,7 @@ static ssize_t gtls_send(struct Curl_cfilter *cf,
nwritten = (size_t)rc;
total_written += nwritten;
DEBUGASSERT(nwritten <= blen);
- buf = (char *)buf + nwritten;
+ buf = (char *)CURL_UNCONST(buf) + nwritten;
blen -= nwritten;
}
rc = total_written;
@@ -2247,21 +2109,6 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
(void)data;
DEBUGASSERT(backend);
- if(connssl->state == ssl_connection_deferred) {
- bool done = FALSE;
- *curlcode = gtls_connect_deferred(cf, data, NULL, 0, &done);
- if(*curlcode) {
- ret = -1;
- goto out;
- }
- else if(!done) {
- *curlcode = CURLE_AGAIN;
- ret = -1;
- goto out;
- }
- DEBUGASSERT(connssl->state == ssl_connection_complete);
- }
-
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
@@ -2272,9 +2119,8 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
if(ret == GNUTLS_E_REHANDSHAKE) {
/* BLOCKING call, this is bad but a work-around for now. Fixing this "the
proper way" takes a whole lot of work. */
- CURLcode result = handshake(cf, data, FALSE, FALSE);
+ CURLcode result = handshake(cf, data);
if(result)
- /* handshake() writes error message on its own */
*curlcode = result;
else
*curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
@@ -2344,6 +2190,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
SSLSUPP_CERTINFO |
SSLSUPP_PINNEDPUBKEY |
SSLSUPP_HTTPS_PROXY |
+ SSLSUPP_CIPHER_LIST |
SSLSUPP_CA_CACHE,
sizeof(struct gtls_ssl_backend_data),
@@ -2356,7 +2203,6 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_random, /* random */
gtls_cert_status_request, /* cert_status_request */
gtls_connect, /* connect */
- gtls_connect_nonblocking, /* connect_nonblocking */
Curl_ssl_adjust_pollset, /* adjust_pollset */
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
diff --git a/libs/libcurl/src/vtls/gtls.h b/libs/libcurl/src/vtls/gtls.h
index 7a45758a32..da1f57f8c8 100644
--- a/libs/libcurl/src/vtls/gtls.h
+++ b/libs/libcurl/src/vtls/gtls.h
@@ -42,6 +42,7 @@
struct Curl_easy;
struct Curl_cfilter;
+struct alpn_spec;
struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;
@@ -81,6 +82,7 @@ typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
typedef CURLcode Curl_gtls_init_session_reuse_cb(struct Curl_cfilter *cf,
struct Curl_easy *data,
+ struct alpn_spec *alpns,
struct Curl_ssl_session *scs,
bool *do_early_data);
@@ -88,7 +90,7 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
- const unsigned char *alpn, size_t alpn_len,
+ const struct alpn_spec *alpns,
Curl_gtls_ctx_setup_cb *cb_setup,
void *cb_user_data,
void *ssl_user_data,
diff --git a/libs/libcurl/src/vtls/keylog.c b/libs/libcurl/src/vtls/keylog.c
index e403114934..c922879d05 100644
--- a/libs/libcurl/src/vtls/keylog.c
+++ b/libs/libcurl/src/vtls/keylog.c
@@ -27,7 +27,8 @@
defined(USE_GNUTLS) || \
defined(USE_WOLFSSL) || \
(defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
- defined(USE_QUICHE)
+ defined(USE_QUICHE) || \
+ defined(USE_RUSTLS)
#include "keylog.h"
#include <curl/curl.h>
@@ -36,18 +37,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1)
-
-#define CLIENT_RANDOM_SIZE 32
-
-/*
- * The master secret in TLS 1.2 and before is always 48 bytes. In TLS 1.3, the
- * secret size depends on the cipher suite's hash function which is 32 bytes
- * for SHA-256 and 48 bytes for SHA-384.
- */
-#define SECRET_MAXLEN 48
-
-
/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
static FILE *keylog_file_fp;
diff --git a/libs/libcurl/src/vtls/keylog.h b/libs/libcurl/src/vtls/keylog.h
index 3a48017f81..41e901db73 100644
--- a/libs/libcurl/src/vtls/keylog.h
+++ b/libs/libcurl/src/vtls/keylog.h
@@ -25,6 +25,17 @@
***************************************************************************/
#include "curl_setup.h"
+#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1)
+
+#define CLIENT_RANDOM_SIZE 32
+
+/*
+ * The master secret in TLS 1.2 and before is always 48 bytes. In TLS 1.3, the
+ * secret size depends on the cipher suite's hash function which is 32 bytes
+ * for SHA-256 and 48 bytes for SHA-384.
+ */
+#define SECRET_MAXLEN 48
+
/*
* Opens the TLS key log file if requested by the user. The SSLKEYLOGFILE
* environment variable specifies the output file.
diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c
index c0e98e12c5..851802f147 100644
--- a/libs/libcurl/src/vtls/mbedtls.c
+++ b/libs/libcurl/src/vtls/mbedtls.c
@@ -198,7 +198,7 @@ static int mbedtls_bio_cf_write(void *bio,
if(!data)
return 0;
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, FALSE,
+ nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, blen, FALSE,
&result);
CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d",
blen, nwritten, result);
@@ -726,6 +726,9 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key,
ssl_config->key_passwd);
#endif
+ if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
+ mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
+ ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
@@ -754,6 +757,9 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
(const unsigned char *)passwd,
passwd ? strlen(passwd) : 0);
#endif
+ if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
+ mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
+ ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
@@ -762,10 +768,6 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CERTPROBLEM;
}
}
-
- if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
- mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
- ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
}
/* Load the CRL */
@@ -1211,7 +1213,7 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
len = backend->send_blocked_len;
}
- ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
+ ret = mbedtls_ssl_write(&backend->ssl, (const unsigned char *)mem, len);
if(ret < 0) {
CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X",
@@ -1440,16 +1442,12 @@ static CURLcode mbedtls_random(struct Curl_easy *data,
#endif
}
-static CURLcode
-mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
- bool nonblocking,
- bool *done)
+static CURLcode mbedtls_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
CURLcode retcode;
struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- timediff_t timeout_ms;
- int what;
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
@@ -1457,73 +1455,20 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
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);
+ *done = FALSE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
+ if(ssl_connect_1 == connssl->connecting_state) {
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;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* 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;
+ if(ssl_connect_2 == connssl->connecting_state) {
retcode = mbed_connect_step2(cf, data);
- if(retcode ||
- (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(retcode)
return retcode;
-
- } /* repeat step2 until all transactions are done. */
+ }
if(ssl_connect_3 == connssl->connecting_state) {
/* For tls1.3 we get notified about new sessions */
@@ -1548,34 +1493,6 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
connssl->state = ssl_connection_complete;
*done = TRUE;
}
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-static CURLcode mbedtls_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return mbed_connect_common(cf, data, TRUE, done);
-}
-
-
-static CURLcode mbedtls_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode retcode;
- bool done = FALSE;
-
- retcode = mbed_connect_common(cf, data, FALSE, &done);
- if(retcode)
- return retcode;
-
- DEBUGASSERT(done);
return CURLE_OK;
}
@@ -1682,7 +1599,6 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_random, /* random */
NULL, /* 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 */
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c
index 97c25ef655..6044d4d073 100644
--- a/libs/libcurl/src/vtls/openssl.c
+++ b/libs/libcurl/src/vtls/openssl.c
@@ -34,7 +34,7 @@
#include <limits.h>
/* Wincrypt must be included before anything that could include OpenSSL. */
-#if defined(USE_WIN32_CRYPTO)
+#ifdef USE_WIN32_CRYPTO
#include <wincrypt.h>
/* Undefine wincrypt conflicting symbols for BoringSSL. */
#undef X509_NAME
@@ -62,6 +62,7 @@
#include "strcase.h"
#include "hostcheck.h"
#include "multiif.h"
+#include "strdup.h"
#include "strerror.h"
#include "curl_printf.h"
@@ -83,7 +84,7 @@
#include <openssl/tls1.h>
#include <openssl/evp.h>
-#if defined(HAVE_SSL_SET1_ECH_CONFIG_LIST)
+#ifdef HAVE_SSL_SET1_ECH_CONFIG_LIST
#define USE_ECH_OPENSSL
#endif
@@ -93,17 +94,25 @@
# endif
#endif /* USE_ECH_OPENSSL */
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
+#ifndef OPENSSL_NO_OCSP
#include <openssl/ocsp.h>
#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL) && /* 0.9.7 or later */ \
- !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_UI_CONSOLE)
+#if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_UI_CONSOLE)
#define USE_OPENSSL_ENGINE
#include <openssl/engine.h>
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x03000000fL && !defined(OPENSSL_NO_UI_CONSOLE)
+#ifdef LIBRESSL_VERSION_NUMBER
+# /* As of LibreSSL 2.0.0-4.0.0: OPENSSL_VERSION_NUMBER == 0x20000000L */
+# if LIBRESSL_VERSION_NUMBER < 0x2090100fL /* 2019-04-13 */
+# error "LibreSSL 2.9.1 or later required"
+# endif
+#elif OPENSSL_VERSION_NUMBER < 0x1000201fL /* 2015-03-19 */
+# error "OpenSSL 1.0.2a or later required"
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x3000000fL && !defined(OPENSSL_NO_UI_CONSOLE)
#include <openssl/provider.h>
#include <openssl/store.h>
/* this is used in the following conditions to make them easier to read */
@@ -131,49 +140,24 @@
#include <openssl/ui.h>
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
-#define SSL_METHOD_QUAL const
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#define OSSL_UI_METHOD_CAST(x) (x)
#else
-#define SSL_METHOD_QUAL
+#define OSSL_UI_METHOD_CAST(x) CURL_UNCONST(x)
#endif
-#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
-#define HAVE_ERR_REMOVE_THREAD_STATE 1
-#endif
-
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL 1.1.0+ and LibreSSL */
#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */
#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */
#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */
-#define CONST_EXTS const
#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1
-
-/* funny typecast define due to difference in API */
-#ifdef LIBRESSL_VERSION_NUMBER
-#define ARG2_X509_signature_print (X509_ALGOR *)
-#else
-#define ARG2_X509_signature_print
-#endif
-
#else
/* For OpenSSL before 1.1.0 */
#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x)
#define X509_get0_notBefore(x) X509_get_notBefore(x)
#define X509_get0_notAfter(x) X509_get_notAfter(x)
-#define CONST_EXTS /* nope */
-#ifndef LIBRESSL_VERSION_NUMBER
#define OpenSSL_version_num() SSLeay()
#endif
-#endif
-
-#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
-#define HAVE_X509_GET0_SIGNATURE 1
-#endif
#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \
OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \
@@ -181,11 +165,6 @@
#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1
#endif
-#if (OPENSSL_VERSION_NUMBER < 0x0090808fL)
-/* not present in older OpenSSL */
-#define OPENSSL_load_builtin_modules(x)
-#endif
-
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
#define HAVE_EVP_PKEY_GET_PARAMS 1
#endif
@@ -210,35 +189,21 @@
LIBRESSL_VERSION_NUMBER >= 0x3040100fL)) && \
!defined(OPENSSL_IS_BORINGSSL)
#define HAVE_SSL_CTX_SET_CIPHERSUITES
- #if !defined(OPENSSL_IS_AWSLC)
+ #ifndef OPENSSL_IS_AWSLC
#define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
#endif
#endif
-/*
- * Whether SSL_CTX_set1_curves_list is available.
- * OpenSSL: supported since 1.0.2, see
- * https://docs.openssl.org/master/man3/SSL_CTX_set1_curves/
- * BoringSSL: supported since 5fd1807d95f7 (committed 2016-09-30)
- * LibreSSL: since 2.5.3 (April 12, 2017)
- */
-#if (OPENSSL_VERSION_NUMBER >= 0x10002000L) || \
- defined(OPENSSL_IS_BORINGSSL)
-#define HAVE_SSL_CTX_SET_EC_CURVES
-#endif
-
-#if defined(LIBRESSL_VERSION_NUMBER)
+#ifdef LIBRESSL_VERSION_NUMBER
#define OSSL_PACKAGE "LibreSSL"
#elif defined(OPENSSL_IS_BORINGSSL)
#define OSSL_PACKAGE "BoringSSL"
#elif defined(OPENSSL_IS_AWSLC)
#define OSSL_PACKAGE "AWS-LC"
+#elif (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_MSH3)
+#define OSSL_PACKAGE "quictls"
#else
-# if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_MSH3)
-# define OSSL_PACKAGE "quictls"
-# else
-# define OSSL_PACKAGE "OpenSSL"
-#endif
+#define OSSL_PACKAGE "OpenSSL"
#endif
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
@@ -272,8 +237,6 @@ typedef int numcert_t;
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x2070100fL) && \
!defined(OPENSSL_IS_BORINGSSL) && \
!defined(OPENSSL_IS_AWSLC)
#define HAVE_OPENSSL_VERSION
@@ -294,13 +257,6 @@ typedef unsigned long sslerr_t;
#define HAVE_SSL_X509_STORE_SHARE
#endif
-/* 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 */
-
static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl);
static CURLcode push_certinfo(struct Curl_easy *data,
@@ -364,10 +320,16 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
static CURLcode X509V3_ext(struct Curl_easy *data,
int certnum,
- CONST_EXTS STACK_OF(X509_EXTENSION) *exts)
+ const STACK_OF(X509_EXTENSION) *extsarg)
{
int i;
CURLcode result = CURLE_OK;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+ const STACK_OF(X509_EXTENSION) *exts = extsarg;
+#else
+ STACK_OF(X509_EXTENSION) *exts = CURL_UNCONST(extsarg);
+#endif
if((int)sk_X509_EXTENSION_num(exts) <= 0)
/* no extensions, bail out */
@@ -456,7 +418,7 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
if(result)
break;
-#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS)
+#ifdef HAVE_X509_GET0_EXTENSIONS
{
const X509_ALGOR *sigalg = NULL;
X509_PUBKEY *xpubkey = NULL;
@@ -673,21 +635,19 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
#ifdef USE_OPENSSL
-#if USE_PRE_1_1_API
-#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define BIO_set_init(x,v) ((x)->init=(v))
#define BIO_get_data(x) ((x)->ptr)
#define BIO_set_data(x,v) ((x)->ptr=(v))
-#endif
#define BIO_get_shutdown(x) ((x)->shutdown)
#define BIO_set_shutdown(x,v) ((x)->shutdown=(v))
-#endif /* USE_PRE_1_1_API */
+#endif /* HAVE_PRE_1_1_API */
static int ossl_bio_cf_create(BIO *bio)
{
BIO_set_shutdown(bio, 1);
BIO_set_init(bio, 1);
-#if USE_PRE_1_1_API
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
bio->num = -1;
#endif
BIO_set_data(bio, NULL);
@@ -804,7 +764,7 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
return (int)nread;
}
-#if USE_PRE_1_1_API
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
static BIO_METHOD ossl_bio_cf_meth_1_0 = {
BIO_TYPE_MEM,
@@ -850,14 +810,6 @@ static void ossl_bio_cf_method_free(BIO_METHOD *m)
#endif
-/*
- * Number of bytes to read from the random number seed file. This must be
- * a finite value (because some entropy "files" like /dev/urandom have
- * an infinite length), but must be large enough to provide enough
- * entropy to properly seed OpenSSL's PRNG.
- */
-#define RAND_LOAD_LENGTH 1024
-
#ifdef HAVE_KEYLOG_CALLBACK
static void ossl_keylog_callback(const SSL *ssl, const char *line)
{
@@ -881,9 +833,7 @@ ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
if(!session || *keylog_done)
return;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- LIBRESSL_VERSION_NUMBER < 0x20700000L)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
/* 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);
@@ -930,15 +880,15 @@ static const char *SSL_ERROR_to_str(int err)
return "SSL_ERROR_WANT_CONNECT";
case SSL_ERROR_WANT_ACCEPT:
return "SSL_ERROR_WANT_ACCEPT";
-#if defined(SSL_ERROR_WANT_ASYNC)
+#ifdef SSL_ERROR_WANT_ASYNC
case SSL_ERROR_WANT_ASYNC:
return "SSL_ERROR_WANT_ASYNC";
#endif
-#if defined(SSL_ERROR_WANT_ASYNC_JOB)
+#ifdef SSL_ERROR_WANT_ASYNC_JOB
case SSL_ERROR_WANT_ASYNC_JOB:
return "SSL_ERROR_WANT_ASYNC_JOB";
#endif
-#if defined(SSL_ERROR_WANT_EARLY)
+#ifdef SSL_ERROR_WANT_EARLY
case SSL_ERROR_WANT_EARLY:
return "SSL_ERROR_WANT_EARLY";
#endif
@@ -981,14 +931,14 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size)
}
static int passwd_callback(char *buf, int num, int encrypting,
- void *global_passwd)
+ void *password)
{
DEBUGASSERT(0 == encrypting);
- if(!encrypting && num >= 0) {
- int klen = curlx_uztosi(strlen((char *)global_passwd));
+ if(!encrypting && num >= 0 && password) {
+ int klen = curlx_uztosi(strlen((char *)password));
if(num > klen) {
- memcpy(buf, global_passwd, klen + 1);
+ memcpy(buf, password, klen + 1);
return klen;
}
}
@@ -1042,6 +992,14 @@ static CURLcode ossl_seed(struct Curl_easy *data)
RAND_add(randb, (int)len, (double)len/2);
} while(!rand_enough());
+ /*
+ * Number of bytes to read from the random number seed file. This must be
+ * a finite value (because some entropy "files" like /dev/urandom have
+ * an infinite length), but must be large enough to provide enough
+ * entropy to properly seed OpenSSL's PRNG.
+ */
+# define RAND_LOAD_LENGTH 1024
+
{
/* generates a default path for the random seed file */
char fname[256];
@@ -1164,7 +1122,7 @@ static int use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob,
else if(type == SSL_FILETYPE_PEM) {
/* ERR_R_PEM_LIB; */
x = PEM_read_bio_X509(in, NULL,
- passwd_callback, (void *)key_passwd);
+ passwd_callback, CURL_UNCONST(key_passwd));
}
else {
ret = 0;
@@ -1194,7 +1152,7 @@ static int use_privatekey_blob(SSL_CTX *ctx, const struct curl_blob *blob,
if(type == SSL_FILETYPE_PEM)
pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback,
- (void *)key_passwd);
+ CURL_UNCONST(key_passwd));
else if(type == SSL_FILETYPE_ASN1)
pkey = d2i_PrivateKey_bio(in, NULL);
else
@@ -1214,13 +1172,8 @@ static int
use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
const char *key_passwd)
{
-/* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
-#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* OpenSSL 1.0.2 or later */ \
- !(defined(LIBRESSL_VERSION_NUMBER) && \
- (LIBRESSL_VERSION_NUMBER < 0x2090100fL)) /* LibreSSL 2.9.1 or later */
int ret = 0;
X509 *x = NULL;
- void *passwd_callback_userdata = (void *)key_passwd;
BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len));
if(!in)
return CURLE_OUT_OF_MEMORY;
@@ -1228,7 +1181,7 @@ use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
ERR_clear_error();
x = PEM_read_bio_X509_AUX(in, NULL,
- passwd_callback, (void *)key_passwd);
+ passwd_callback, CURL_UNCONST(key_passwd));
if(!x)
goto end;
@@ -1247,7 +1200,7 @@ use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
}
while((ca = PEM_read_bio_X509(in, NULL, passwd_callback,
- passwd_callback_userdata))
+ CURL_UNCONST(key_passwd)))
!= NULL) {
if(!SSL_CTX_add0_chain_cert(ctx, ca)) {
@@ -1269,12 +1222,6 @@ end:
X509_free(x);
BIO_free(in);
return ret;
-#else
- (void)ctx; /* unused */
- (void)blob; /* unused */
- (void)key_passwd; /* unused */
- return 0;
-#endif
}
static
@@ -1296,9 +1243,7 @@ int cert_stuff(struct Curl_easy *data,
if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE) ||
(file_type == SSL_FILETYPE_PROVIDER)) {
SSL *ssl;
- X509 *x509 = NULL;
- EVP_PKEY *pri = NULL;
- STACK_OF(X509) *ca = NULL;
+ X509 *x509;
int cert_done = 0;
int cert_use_result;
@@ -1372,7 +1317,7 @@ int cert_stuff(struct Curl_easy *data,
/* Does the engine supports LOAD_CERT_CTRL ? */
if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
- 0, (void *)cmd_name, NULL)) {
+ 0, CURL_UNCONST(cmd_name), NULL)) {
failf(data, "ssl engine does not support loading certificates");
return 0;
}
@@ -1461,7 +1406,7 @@ int cert_stuff(struct Curl_easy *data,
failf(data, "No cert found in the openssl store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
- goto fail;
+ return 0;
}
if(SSL_CTX_use_certificate(ctx, cert) != 1) {
@@ -1487,6 +1432,8 @@ int cert_stuff(struct Curl_easy *data,
{
BIO *cert_bio = NULL;
PKCS12 *p12 = NULL;
+ EVP_PKEY *pri;
+ STACK_OF(X509) *ca = NULL;
if(cert_blob) {
cert_bio = BIO_new_mem_buf(cert_blob->data, (int)(cert_blob->len));
if(!cert_bio) {
@@ -1637,7 +1584,7 @@ fail:
if(data->state.engine) {
UI_METHOD *ui_method =
- UI_create_method((char *)"curl user interface");
+ UI_create_method(OSSL_UI_METHOD_CAST("curl user interface"));
if(!ui_method) {
failf(data, "unable do create " OSSL_PACKAGE
" user-interface method");
@@ -1673,9 +1620,9 @@ fail:
case SSL_FILETYPE_PROVIDER:
{
/* Implicitly use pkcs11 provider if none was provided and the
- * cert_file is a PKCS#11 URI */
+ * key_file is a PKCS#11 URI */
if(!data->state.provider) {
- if(is_pkcs11_uri(cert_file)) {
+ if(is_pkcs11_uri(key_file)) {
if(ossl_set_provider(data, "pkcs11") != CURLE_OK) {
return 0;
}
@@ -1688,7 +1635,7 @@ fail:
OSSL_STORE_CTX *store = NULL;
OSSL_STORE_INFO *info = NULL;
UI_METHOD *ui_method =
- UI_create_method((char *)"curl user interface");
+ UI_create_method(OSSL_UI_METHOD_CAST("curl user interface"));
if(!ui_method) {
failf(data, "unable do create " OSSL_PACKAGE
" user-interface method");
@@ -1735,7 +1682,7 @@ fail:
failf(data, "No private key found in the openssl store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
- goto fail;
+ return 0;
}
if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
@@ -1851,8 +1798,7 @@ static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d)
*/
static int ossl_init(void)
{
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
const uint64_t flags =
#ifdef OPENSSL_INIT_ENGINE_ALL_BUILTIN
/* not present in BoringSSL */
@@ -1902,8 +1848,7 @@ static int ossl_init(void)
/* Global cleanup */
static void ossl_cleanup(void)
{
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
/* OpenSSL 1.1 deprecates all these cleanup functions and
turns them into no-ops in OpenSSL 1.0 compatibility mode */
#else
@@ -1919,11 +1864,7 @@ static void ossl_cleanup(void)
ERR_free_strings();
/* Free thread local error state, destroying hash upon zero refcount */
-#ifdef HAVE_ERR_REMOVE_THREAD_STATE
ERR_remove_thread_state(NULL);
-#else
- ERR_remove_state(0);
-#endif
/* Free all memory allocated by all configuration modules */
CONF_modules_free();
@@ -1941,18 +1882,7 @@ static void ossl_cleanup(void)
static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine)
{
#ifdef USE_OPENSSL_ENGINE
- ENGINE *e;
-
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
- e = ENGINE_by_id(engine);
-#else
- /* avoid memory leak */
- for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
- const char *e_id = ENGINE_get_id(e);
- if(!strcmp(engine, e_id))
- break;
- }
-#endif
+ ENGINE *e = ENGINE_by_id(engine);
if(!e) {
failf(data, "SSL Engine '%s' not found", engine);
@@ -2211,8 +2141,7 @@ static void ossl_close_all(struct Curl_easy *data)
#else
(void)data;
#endif
-#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \
- defined(HAVE_ERR_REMOVE_THREAD_STATE)
+#ifndef HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED
/* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread
so we need to clean it here in case the thread will be killed. All OpenSSL
code should extract the error in association with the error so clearing
@@ -2289,14 +2218,14 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
hostlen = strlen(peer->hostname);
switch(peer->type) {
case CURL_SSL_PEER_IPV4:
- if(!Curl_inet_pton(AF_INET, peer->hostname, &addr))
+ if(!curlx_inet_pton(AF_INET, peer->hostname, &addr))
return CURLE_PEER_FAILED_VERIFICATION;
target = GEN_IPADD;
addrlen = sizeof(struct in_addr);
break;
#ifdef USE_IPV6
case CURL_SSL_PEER_IPV6:
- if(!Curl_inet_pton(AF_INET6, peer->hostname, &addr))
+ if(!curlx_inet_pton(AF_INET6, peer->hostname, &addr))
return CURLE_PEER_FAILED_VERIFICATION;
target = GEN_IPADD;
addrlen = sizeof(struct in6_addr);
@@ -2342,7 +2271,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
/* 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);
+ const char *altptr = (const char *)ASN1_STRING_get0_data(check->d.ia5);
size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
switch(target) {
@@ -2428,7 +2357,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
if(tmp) {
if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
cnlen = ASN1_STRING_length(tmp);
- cn = (unsigned char *) ASN1_STRING_get0_data(tmp);
+ cn = (unsigned char *)CURL_UNCONST(ASN1_STRING_get0_data(tmp));
}
else { /* not a UTF8 name */
cnlen = ASN1_STRING_to_UTF8(&cn, tmp);
@@ -2470,14 +2399,13 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
return result;
}
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
+#if !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)
+#ifdef OPENSSL_IS_AWSLC
const uint8_t *status;
#else
unsigned char *status;
@@ -2536,34 +2464,6 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
}
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);
-
- /* Find issuer of responder cert and add it to the OCSP response chain */
- for(i = 0; i < sk_X509_num(ch); i++) {
- X509 *issuer = sk_X509_value(ch, i);
- if(X509_check_issued(issuer, responder) == X509_V_OK) {
- if(!OCSP_basic_add1_cert(br, issuer)) {
- failf(data, "Could not add issuer cert to OCSP response");
- result = CURLE_SSL_INVALIDCERTSTATUS;
- goto end;
- }
- }
- }
- }
-#endif
-
if(OCSP_basic_verify(br, ch, st, 0) <= 0) {
failf(data, "OCSP response verification failed");
result = CURLE_SSL_INVALIDCERTSTATUS;
@@ -2835,15 +2735,15 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
tls_rt_name = "";
if(content_type == SSL3_RT_CHANGE_CIPHER_SPEC) {
- msg_type = *(char *)buf;
+ msg_type = *(const char *)buf;
msg_name = "Change cipher spec";
}
else if(content_type == SSL3_RT_ALERT) {
- msg_type = (((char *)buf)[0] << 8) + ((char *)buf)[1];
+ msg_type = (((const char *)buf)[0] << 8) + ((const char *)buf)[1];
msg_name = SSL_alert_desc_string_long(msg_type);
}
else {
- msg_type = *(char *)buf;
+ msg_type = *(const char *)buf;
msg_name = ssl_msg_type(ssl_ver, msg_type);
}
@@ -2855,7 +2755,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
}
Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
- CURLINFO_SSL_DATA_IN, (char *)buf, len);
+ CURLINFO_SSL_DATA_IN, (const char *)buf, len);
(void) ssl;
}
#endif
@@ -2863,9 +2763,8 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
#ifdef USE_OPENSSL
/* ====================================================== */
-/* Check for OpenSSL 1.0.2 which has ALPN support. */
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L \
- && !defined(OPENSSL_NO_TLSEXT)
+/* Check for ALPN support. */
+#ifndef OPENSSL_NO_TLSEXT
# define HAS_ALPN_OPENSSL
#endif
@@ -2998,20 +2897,10 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
#endif
FALLTHROUGH();
case CURL_SSLVERSION_TLSv1_2:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_1;
-#else
- failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
- return CURLE_NOT_BUILT_IN;
-#endif
FALLTHROUGH();
case CURL_SSLVERSION_TLSv1_1:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1;
-#else
- failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
- return CURLE_NOT_BUILT_IN;
-#endif
FALLTHROUGH();
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1:
@@ -3020,14 +2909,10 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
switch(ssl_version_max) {
case CURL_SSLVERSION_MAX_TLSv1_0:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_1;
-#endif
FALLTHROUGH();
case CURL_SSLVERSION_MAX_TLSv1_1:
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_2;
-#endif
FALLTHROUGH();
case CURL_SSLVERSION_MAX_TLSv1_2:
#ifdef TLS1_3_VERSION
@@ -3051,10 +2936,13 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
const char *ssl_peer_key,
SSL_SESSION *session,
int ietf_tls_id,
- const char *alpn)
+ const char *alpn,
+ unsigned char *quic_tp,
+ size_t quic_tp_len)
{
const struct ssl_config_data *config;
unsigned char *der_session_buf = NULL;
+ unsigned char *qtp_clone = NULL;
CURLcode result = CURLE_OK;
if(!cf || !data)
@@ -3065,6 +2953,7 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
struct Curl_ssl_session *sc_session = NULL;
size_t der_session_size;
unsigned char *der_session_ptr;
+ size_t earlydata_max = 0;
der_session_size = i2d_SSL_SESSION(session, NULL);
if(der_session_size == 0) {
@@ -3084,11 +2973,23 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
goto out;
}
- result = Curl_ssl_session_create(der_session_buf, der_session_size,
- ietf_tls_id, alpn,
- (curl_off_t)time(NULL) +
- SSL_SESSION_get_timeout(session), 0,
- &sc_session);
+#ifdef HAVE_OPENSSL_EARLYDATA
+ earlydata_max = SSL_SESSION_get_max_early_data(session);
+#endif
+ if(quic_tp && quic_tp_len) {
+ qtp_clone = Curl_memdup0((char *)quic_tp, quic_tp_len);
+ if(!qtp_clone) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ }
+
+ result = Curl_ssl_session_create2(der_session_buf, der_session_size,
+ ietf_tls_id, alpn,
+ (curl_off_t)time(NULL) +
+ SSL_SESSION_get_timeout(session),
+ earlydata_max, qtp_clone, quic_tp_len,
+ &sc_session);
der_session_buf = NULL; /* took ownership of sdata */
if(!result) {
result = Curl_ssl_scache_put(cf, data, ssl_peer_key, sc_session);
@@ -3111,7 +3012,8 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
struct Curl_easy *data = CF_DATA_CURRENT(cf);
struct ssl_connect_data *connssl = cf->ctx;
Curl_ossl_add_session(cf, data, connssl->peer.scache_key, ssl_sessionid,
- SSL_version(ssl), connssl->negotiated.alpn);
+ SSL_version(ssl), connssl->negotiated.alpn,
+ NULL, 0);
}
return 0;
}
@@ -3172,7 +3074,7 @@ static CURLcode load_cacert_from_memory(X509_STORE *store,
return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE;
}
-#if defined(USE_WIN32_CRYPTO)
+#ifdef USE_WIN32_CRYPTO
static CURLcode import_windows_cert_store(struct Curl_easy *data,
const char *name,
X509_STORE *store,
@@ -3340,7 +3242,7 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf,
return CURLE_OUT_OF_MEMORY;
if(verifypeer) {
-#if defined(USE_WIN32_CRYPTO)
+#ifdef USE_WIN32_CRYPTO
/* Import certificates from the Windows root certificate store if
requested.
https://stackoverflow.com/questions/9507184/
@@ -3458,7 +3360,7 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf,
https://web.archive.org/web/20190422050538/
rt.openssl.org/Ticket/Display.html?id=3621
*/
-#if defined(X509_V_FLAG_TRUSTED_FIRST)
+#ifdef X509_V_FLAG_TRUSTED_FIRST
X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
#endif
#ifdef X509_V_FLAG_PARTIAL_CHAIN
@@ -3479,7 +3381,7 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf,
return result;
}
-#if defined(HAVE_SSL_X509_STORE_SHARE)
+#ifdef HAVE_SSL_X509_STORE_SHARE
/* key to use at `multi->proto_hash` */
#define MPROTO_OSSL_X509_KEY "tls:ossl:x509:share"
@@ -3540,7 +3442,7 @@ static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf,
DEBUGASSERT(multi);
share = multi ? Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_OSSL_X509_KEY),
sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
if(share && share->store &&
!ossl_cached_x509_store_expired(data, share) &&
@@ -3563,7 +3465,7 @@ static void ossl_set_cached_x509_store(struct Curl_cfilter *cf,
if(!multi)
return;
share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_OSSL_X509_KEY),
sizeof(MPROTO_OSSL_X509_KEY)-1);
if(!share) {
@@ -3571,7 +3473,7 @@ static void ossl_set_cached_x509_store(struct Curl_cfilter *cf,
if(!share)
return;
if(!Curl_hash_add2(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_OSSL_X509_KEY),
sizeof(MPROTO_OSSL_X509_KEY)-1,
share, oss_x509_share_free)) {
free(share);
@@ -3651,15 +3553,16 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
- const unsigned char *alpn, size_t alpn_len,
+ const struct alpn_spec *alpns_requested,
Curl_ossl_ctx_setup_cb *cb_setup,
void *cb_user_data,
Curl_ossl_new_session_cb *cb_new_session,
- void *ssl_user_data)
+ void *ssl_user_data,
+ Curl_ossl_init_session_reuse_cb *sess_reuse_cb)
{
CURLcode result = CURLE_OK;
const char *ciphers;
- SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
+ const SSL_METHOD *req_method = NULL;
ctx_option_t ctx_options = 0;
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);
@@ -3669,12 +3572,14 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
const char * const ssl_cert_type = ssl_config->cert_type;
const bool verifypeer = conn_config->verifypeer;
char error_buffer[256];
+ struct alpn_spec alpns;
/* Make funny stuff to get random input */
result = ossl_seed(data);
if(result)
return result;
+ Curl_alpn_copy(&alpns, alpns_requested);
ssl_config->certverifyresult = !X509_V_OK;
switch(peer->transport) {
@@ -3846,15 +3751,6 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
SSL_CTX_set_mode(octx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#endif
- if(alpn && alpn_len) {
-#ifdef HAS_ALPN_OPENSSL
- if(SSL_CTX_set_alpn_protos(octx->ssl_ctx, alpn, (int)alpn_len)) {
- failf(data, "Error setting ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
-#endif
- }
-
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
if(!result &&
!cert_stuff(data, octx->ssl_ctx,
@@ -3898,17 +3794,20 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
SSL_CTX_set_post_handshake_auth(octx->ssl_ctx, 1);
#endif
-#ifdef HAVE_SSL_CTX_SET_EC_CURVES
{
const char *curves = conn_config->curves;
if(curves) {
- if(!SSL_CTX_set1_curves_list(octx->ssl_ctx, curves)) {
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+#define OSSL_CURVE_CAST(x) (x)
+#else
+#define OSSL_CURVE_CAST(x) (char *)CURL_UNCONST(x)
+#endif
+ if(!SSL_CTX_set1_curves_list(octx->ssl_ctx, OSSL_CURVE_CAST(curves))) {
failf(data, "failed setting curves list: '%s'", curves);
return CURLE_SSL_CIPHER;
}
}
}
-#endif
#ifdef USE_OPENSSL_SRP
if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) {
@@ -3992,8 +3891,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
SSL_set_app_data(octx->ssl, ssl_user_data);
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
if(conn_config->verifystatus)
SSL_set_tlsext_status_type(octx->ssl, TLSEXT_STATUSTYPE_ocsp);
#endif
@@ -4140,12 +4038,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
octx->reused_session = FALSE;
if(ssl_config->primary.cache_session) {
- struct Curl_ssl_session *sc_session = NULL;
+ struct Curl_ssl_session *scs = NULL;
- result = Curl_ssl_scache_take(cf, data, peer->scache_key, &sc_session);
- if(!result && sc_session && sc_session->sdata && sc_session->sdata_len) {
- const unsigned char *der_sessionid = sc_session->sdata;
- size_t der_sessionid_size = sc_session->sdata_len;
+ result = Curl_ssl_scache_take(cf, data, peer->scache_key, &scs);
+ if(!result && scs && scs->sdata && scs->sdata_len) {
+ const unsigned char *der_sessionid = scs->sdata;
+ size_t der_sessionid_size = scs->sdata_len;
SSL_SESSION *ssl_session = NULL;
/* If OpenSSL does not accept the session from the cache, this
@@ -4160,8 +4058,29 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
sizeof(error_buffer)));
}
else {
- infof(data, "SSL reusing session");
+ infof(data, "SSL reusing session with ALPN '%s'",
+ scs->alpn ? scs->alpn : "-");
octx->reused_session = TRUE;
+#ifdef HAVE_OPENSSL_EARLYDATA
+ if(ssl_config->earlydata && scs->alpn &&
+ SSL_SESSION_get_max_early_data(ssl_session) &&
+ !cf->conn->connect_only &&
+ (SSL_version(octx->ssl) == TLS1_3_VERSION)) {
+ bool do_early_data = FALSE;
+ if(sess_reuse_cb) {
+ result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data);
+ if(result)
+ return result;
+ }
+ if(do_early_data) {
+ /* We only try the ALPN protocol the session used before,
+ * otherwise we might send early data for the wrong protocol */
+ Curl_alpn_restrict_to(&alpns, scs->alpn);
+ }
+ }
+#else
+ (void)sess_reuse_cb;
+#endif
}
SSL_SESSION_free(ssl_session);
}
@@ -4169,37 +4088,73 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
infof(data, "SSL session not accepted by OpenSSL, continuing without");
}
}
- Curl_ssl_scache_return(cf, data, peer->scache_key, sc_session);
+ Curl_ssl_scache_return(cf, data, peer->scache_key, scs);
+ }
+
+#ifdef HAS_ALPN_OPENSSL
+ if(alpns.count) {
+ struct alpn_proto_buf proto;
+ memset(&proto, 0, sizeof(proto));
+ result = Curl_alpn_to_proto_buf(&proto, &alpns);
+ if(result) {
+ failf(data, "Error determining ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(SSL_set_alpn_protos(octx->ssl, proto.data, (int)proto.len)) {
+ failf(data, "Error setting ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
+#endif
return CURLE_OK;
}
+static CURLcode ossl_on_session_reuse(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct alpn_spec *alpns,
+ struct Curl_ssl_session *scs,
+ bool *do_early_data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result = CURLE_OK;
+
+ *do_early_data = FALSE;
+ connssl->earlydata_max = scs->earlydata_max;
+ if(!connssl->earlydata_max) {
+ CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
+ }
+ else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
+ CURL_TRC_CF(data, cf, "SSL session has different ALPN, no early data");
+ }
+ else {
+ infof(data, "SSL session allows %zu bytes of early data, "
+ "reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
+ connssl->earlydata_state = ssl_earlydata_await;
+ connssl->state = ssl_connection_deferred;
+ result = Curl_alpn_set_negotiated(cf, data, connssl,
+ (const unsigned char *)scs->alpn,
+ scs->alpn ? strlen(scs->alpn) : 0);
+ *do_early_data = !result;
+ }
+ return result;
+}
+
static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
- struct alpn_proto_buf proto;
BIO *bio;
CURLcode result;
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
DEBUGASSERT(octx);
- memset(&proto, 0, sizeof(proto));
-#ifdef HAS_ALPN_OPENSSL
- if(connssl->alpn) {
- result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
- if(result) {
- failf(data, "Error determining ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-#endif
result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer,
- proto.data, proto.len, NULL, NULL,
- ossl_new_session_cb, cf);
+ connssl->alpn, NULL, NULL,
+ ossl_new_session_cb, cf,
+ ossl_on_session_reuse);
if(result)
return result;
@@ -4225,7 +4180,9 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
#endif
#ifdef HAS_ALPN_OPENSSL
- if(connssl->alpn) {
+ if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
+ struct alpn_proto_buf proto;
+ memset(&proto, 0, sizeof(proto));
Curl_alpn_to_proto_str(&proto, connssl->alpn);
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
@@ -4338,27 +4295,25 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
if(SSL_ERROR_WANT_READ == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want recv");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
if(SSL_ERROR_WANT_WRITE == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want send");
connssl->io_need = CURL_SSL_IO_NEED_SEND;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
#ifdef SSL_ERROR_WANT_ASYNC
if(SSL_ERROR_WANT_ASYNC == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want async");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
- connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
#endif
#ifdef SSL_ERROR_WANT_RETRY_VERIFY
if(SSL_ERROR_WANT_RETRY_VERIFY == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want retry_verify");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
- connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
#endif
else {
@@ -4395,7 +4350,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
else
failf(data, "%s", "SSL certificate verification failed");
}
-#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
+#ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED
/* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */
else if((lib == ERR_LIB_SSL) &&
@@ -4661,7 +4616,7 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl)
sizeof(group_name), NULL);
msnprintf(group_name_final, sizeof(group_name_final), "/%s", group_name);
}
- type_name = EVP_PKEY_get0_type_name(current_pkey);
+ type_name = current_pkey ? EVP_PKEY_get0_type_name(current_pkey) : NULL;
#else
get_group_name = 0;
type_name = NULL;
@@ -4735,15 +4690,16 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
+ char *buf;
long len;
ASN1_TIME_print(mem, X509_get0_notBefore(octx->server_cert));
- len = BIO_get_mem_data(mem, (char **) &ptr);
- infof(data, " start date: %.*s", (int)len, ptr);
+ len = BIO_get_mem_data(mem, (char **) &buf);
+ infof(data, " start date: %.*s", (int)len, buf);
(void)BIO_reset(mem);
ASN1_TIME_print(mem, X509_get0_notAfter(octx->server_cert));
- len = BIO_get_mem_data(mem, (char **) &ptr);
- infof(data, " expire date: %.*s", (int)len, ptr);
+ len = BIO_get_mem_data(mem, (char **) &buf);
+ infof(data, " expire date: %.*s", (int)len, buf);
(void)BIO_reset(mem);
}
#endif
@@ -4864,8 +4820,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
}
infof_certstack(data, octx->ssl);
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
+#if !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);
@@ -4917,137 +4872,169 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
*/
result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer);
- if(!result)
- connssl->connecting_state = ssl_connect_done;
- else
+ if(result)
/* on error, remove sessions we might have in the pool */
Curl_ssl_scache_remove_all(cf, data, connssl->peer.scache_key);
return result;
}
-static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool nonblocking,
- bool *done)
+#ifdef HAVE_OPENSSL_EARLYDATA
+static CURLcode ossl_send_earlydata(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
+ const unsigned char *buf;
+ size_t blen, nwritten;
+ int rc;
+
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sending);
+ octx->io_result = CURLE_OK;
+ while(Curl_bufq_peek(&connssl->earlydata, &buf, &blen)) {
+ nwritten = 0;
+ rc = SSL_write_early_data(octx->ssl, buf, blen, &nwritten);
+ CURL_TRC_CF(data, cf, "SSL_write_early_data(len=%zu) -> %d, %zu",
+ blen, rc, nwritten);
+ if(rc <= 0) {
+ long sslerror;
+ char error_buffer[256];
+ int err = SSL_get_error(octx->ssl, rc);
+
+ switch(err) {
+ case SSL_ERROR_WANT_READ:
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ result = CURLE_AGAIN;
+ goto out;
+ case SSL_ERROR_WANT_WRITE:
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ result = CURLE_AGAIN;
+ goto out;
+ case SSL_ERROR_SYSCALL: {
+ int sockerr = SOCKERRNO;
+
+ if(octx->io_result == CURLE_AGAIN) {
+ result = CURLE_AGAIN;
+ goto out;
+ }
+ sslerror = ERR_get_error();
+ if(sslerror)
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
+ else if(sockerr)
+ Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
+ else
+ msnprintf(error_buffer, sizeof(error_buffer), "%s",
+ SSL_ERROR_to_str(err));
+
+ failf(data, OSSL_PACKAGE " SSL_write:early_data: %s, errno %d",
+ error_buffer, sockerr);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ case SSL_ERROR_SSL: {
+ /* A failure in the SSL library occurred, usually a protocol error.
+ The OpenSSL error queue contains more information on the error. */
+ sslerror = ERR_get_error();
+ failf(data, "SSL_write_early_data() error: %s",
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ default:
+ /* a true error */
+ failf(data, OSSL_PACKAGE " SSL_write_early_data: %s, errno %d",
+ SSL_ERROR_to_str(err), SOCKERRNO);
+ result = CURLE_SEND_ERROR;
+ goto out;
+ }
+ }
+ Curl_bufq_skip(&connssl->earlydata, nwritten);
+ }
+ /* sent everything there was */
+ infof(data, "SSL sending %zu bytes of early data", connssl->earlydata_skip);
+out:
+ return result;
+}
+#endif /* HAVE_OPENSSL_EARLYDATA */
+
+static CURLcode ossl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
CURLcode result = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- int what;
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
/* 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;
- }
+ *done = FALSE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ if(ssl_connect_1 == connssl->connecting_state) {
+ CURL_TRC_CF(data, cf, "ossl_connect, step1");
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;
+ if(ssl_connect_2 == connssl->connecting_state) {
+ CURL_TRC_CF(data, cf, "ossl_connect, step2");
+#ifdef HAVE_OPENSSL_EARLYDATA
+ if(connssl->earlydata_state == ssl_earlydata_await) {
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;
- goto out;
- }
- if(0 == what) {
- /* timeout */
- failf(data, "SSL connection timeout");
- result = CURLE_OPERATION_TIMEDOUT;
+ else if(connssl->earlydata_state == ssl_earlydata_sending) {
+ result = ossl_send_earlydata(cf, data);
+ if(result)
goto out;
- }
- /* socket is readable or writable */
+ connssl->earlydata_state = ssl_earlydata_sent;
}
+#endif
+ DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
+ (connssl->earlydata_state == ssl_earlydata_sent));
- /* 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)))
+ if(result)
goto out;
-
- } /* repeat step2 until all transactions are done. */
+ }
if(ssl_connect_3 == connssl->connecting_state) {
+ CURL_TRC_CF(data, cf, "ossl_connect, step3");
result = ossl_connect_step3(cf, data);
if(result)
goto out;
+ connssl->connecting_state = ssl_connect_done;
+#ifdef HAVE_OPENSSL_EARLYDATA
+ if(connssl->earlydata_state > ssl_earlydata_none) {
+ struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ /* We should be in this state by now */
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent);
+ connssl->earlydata_state =
+ (SSL_get_early_data_status(octx->ssl) == SSL_EARLY_DATA_ACCEPTED) ?
+ ssl_earlydata_accepted : ssl_earlydata_rejected;
+ }
+#endif
}
if(ssl_connect_done == connssl->connecting_state) {
+ CURL_TRC_CF(data, cf, "ossl_connect, done");
connssl->state = ssl_connection_complete;
- *done = TRUE;
}
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
out:
+ if(result == CURLE_AGAIN) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ *done = ((connssl->state == ssl_connection_complete) ||
+ (connssl->state == ssl_connection_deferred));
return result;
}
-static CURLcode ossl_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return ossl_connect_common(cf, data, TRUE, done);
-}
-
-static CURLcode ossl_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = ossl_connect_common(cf, data, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
static bool ossl_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
@@ -5340,7 +5327,6 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex,
size_t Curl_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);
@@ -5354,13 +5340,6 @@ size_t Curl_ossl_version(char *buffer, size_t size)
*p = '_';
}
return count;
-#else
- return msnprintf(buffer, size, "%s/%lx.%lx.%lx",
- OSSL_PACKAGE,
- (LIBRESSL_VERSION_NUMBER >> 28) & 0xf,
- (LIBRESSL_VERSION_NUMBER >> 20) & 0xff,
- (LIBRESSL_VERSION_NUMBER >> 12) & 0xff);
-#endif
#elif defined(OPENSSL_IS_BORINGSSL)
#ifdef CURL_BORINGSSL_VERSION
return msnprintf(buffer, size, "%s/%s",
@@ -5384,25 +5363,19 @@ size_t Curl_ossl_version(char *buffer, size_t size)
sub[2]='\0';
sub[1]='\0';
ssleay_value = OpenSSL_version_num();
- if(ssleay_value < 0x906000) {
- ssleay_value = SSLEAY_VERSION_NUMBER;
- sub[0]='\0';
- }
- else {
- if(ssleay_value&0xff0) {
- int minor_ver = (ssleay_value >> 4) & 0xff;
- if(minor_ver > 26) {
- /* handle extended version introduced for 0.9.8za */
- sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
- sub[0] = 'z';
- }
- else {
- sub[0] = (char) (minor_ver + 'a' - 1);
- }
+ if(ssleay_value&0xff0) {
+ int minor_ver = (ssleay_value >> 4) & 0xff;
+ if(minor_ver > 26) {
+ /* handle extended version introduced for 0.9.8za */
+ sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
+ sub[0] = 'z';
+ }
+ else {
+ sub[0] = (char) (minor_ver + 'a' - 1);
}
- else
- sub[0]='\0';
}
+ else
+ sub[0]='\0';
return msnprintf(buffer, size, "%s/%lx.%lx.%lx%s"
#ifdef OPENSSL_FIPS
@@ -5435,7 +5408,7 @@ static CURLcode ossl_random(struct Curl_easy *data,
return rc == 1 ? CURLE_OK : CURLE_FAILED_INIT;
}
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+#ifndef OPENSSL_NO_SHA256
static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */
size_t tmplen,
unsigned char *sha256sum /* output */,
@@ -5461,8 +5434,7 @@ static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */
static bool ossl_cert_status_request(void)
{
-#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
- !defined(OPENSSL_NO_OCSP)
+#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_OCSP)
return TRUE;
#else
return FALSE;
@@ -5507,7 +5479,6 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_random, /* random */
ossl_cert_status_request, /* cert_status_request */
ossl_connect, /* connect */
- ossl_connect_nonblocking, /* connect_nonblocking */
Curl_ssl_adjust_pollset, /* adjust_pollset */
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
@@ -5516,7 +5487,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_set_engine_default, /* set_engine_default */
ossl_engines_list, /* engines_list */
NULL, /* false_start */
-#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+#ifndef OPENSSL_NO_SHA256
ossl_sha256sum, /* sha256sum */
#else
NULL, /* sha256sum */
diff --git a/libs/libcurl/src/vtls/openssl.h b/libs/libcurl/src/vtls/openssl.h
index bd5aafba96..f72f6dea35 100644
--- a/libs/libcurl/src/vtls/openssl.h
+++ b/libs/libcurl/src/vtls/openssl.h
@@ -49,7 +49,16 @@
#define HAVE_KEYLOG_CALLBACK
#endif
+/* Check for OpenSSL 1.1.1 which has early data support. */
+#undef HAVE_OPENSSL_EARLYDATA
+#if OPENSSL_VERSION_NUMBER >= 0x10100010L && defined(TLS1_3_VERSION) && \
+ !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
+#define HAVE_OPENSSL_EARLYDATA
+#endif
+
+struct alpn_spec;
struct ssl_peer;
+struct Curl_ssl_session;
/* Struct to hold a curl OpenSSL instance */
struct ossl_ctx {
@@ -75,16 +84,22 @@ typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf,
void *user_data);
typedef int Curl_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid);
+typedef CURLcode Curl_ossl_init_session_reuse_cb(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct alpn_spec *alpns,
+ struct Curl_ssl_session *scs,
+ bool *do_early_data);
CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
- const unsigned char *alpn, size_t alpn_len,
+ const struct alpn_spec *alpns,
Curl_ossl_ctx_setup_cb *cb_setup,
void *cb_user_data,
Curl_ossl_new_session_cb *cb_new_session,
- void *ssl_user_data);
+ void *ssl_user_data,
+ Curl_ossl_init_session_reuse_cb *sess_reuse_cb);
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
#define SSL_get1_peer_certificate SSL_get_peer_certificate
@@ -113,7 +128,9 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
const char *ssl_peer_key,
SSL_SESSION *ssl_sessionid,
int ietf_tls_id,
- const char *alpn);
+ const char *alpn,
+ unsigned char *quic_tp,
+ size_t quic_tp_len);
/*
* Get the server cert, verify it and show it, etc., only call failf() if
diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c
index ca987d7eed..f8e668e17a 100644
--- a/libs/libcurl/src/vtls/rustls.c
+++ b/libs/libcurl/src/vtls/rustls.c
@@ -8,6 +8,7 @@
* Copyright (C) Jacob Hoffman-Andrews,
* <github@hoffman-andrews.com>
* Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
+ * Copyright (C) Daniel McCarney, <daniel@binaryparadox.net>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -29,7 +30,6 @@
#include "curl_printf.h"
-#include <errno.h>
#include <rustls.h>
#include "inet_pton.h"
@@ -38,12 +38,10 @@
#include "vtls.h"
#include "vtls_int.h"
#include "rustls.h"
-#include "select.h"
+#include "keylog.h"
#include "strerror.h"
-#include "multiif.h"
-#include "connect.h" /* for the connect timeout */
#include "cipher_suite.h"
-#include "rand.h"
+#include "x509asn1.h"
struct rustls_ssl_backend_data
{
@@ -55,7 +53,7 @@ struct rustls_ssl_backend_data
};
/* For a given rustls_result error code, return the best-matching CURLcode. */
-static CURLcode map_error(rustls_result r)
+static CURLcode map_error(const rustls_result r)
{
if(rustls_result_is_cert_error(r)) {
return CURLE_PEER_FAILED_VERIFICATION;
@@ -70,10 +68,19 @@ static CURLcode map_error(rustls_result r)
}
}
+static void
+rustls_failf(struct Curl_easy *data, const rustls_result rr, const char *msg)
+{
+ char errorbuf[STRERROR_LEN];
+ size_t errorlen;
+ rustls_error(rr, errorbuf, sizeof(errorbuf), &errorlen);
+ failf(data, "%s: %.*s", msg, (int)errorlen, errorbuf);
+}
+
static bool
cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
{
- struct ssl_connect_data *ctx = cf->ctx;
+ const struct ssl_connect_data *ctx = cf->ctx;
struct rustls_ssl_backend_data *backend;
(void)data;
@@ -90,7 +97,7 @@ struct io_ctx {
static int
read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
- struct io_ctx *io_ctx = userdata;
+ const struct io_ctx *io_ctx = userdata;
struct ssl_connect_data *const connssl = io_ctx->cf->ctx;
CURLcode result;
int ret = 0;
@@ -98,6 +105,7 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
(char *)buf, len, &result);
if(nread < 0) {
nread = 0;
+ /* !checksrc! disable ERRNOVAR 4 */
if(CURLE_AGAIN == result)
ret = EAGAIN;
else
@@ -114,7 +122,7 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
static int
write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
- struct io_ctx *io_ctx = userdata;
+ const 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,
@@ -136,7 +144,7 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
static ssize_t tls_recv_more(struct Curl_cfilter *cf,
struct Curl_easy *data, CURLcode *err)
{
- struct ssl_connect_data *const connssl = cf->ctx;
+ const struct ssl_connect_data *const connssl = cf->ctx;
struct rustls_ssl_backend_data *const backend =
(struct rustls_ssl_backend_data *)connssl->backend;
struct io_ctx io_ctx;
@@ -162,11 +170,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
rresult = rustls_connection_process_new_packets(backend->conn);
if(rresult != RUSTLS_RESULT_OK) {
- char errorbuf[255];
- size_t errorlen;
- rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
- failf(data, "rustls_connection_process_new_packets: %.*s",
- (int)errorlen, errorbuf);
+ rustls_failf(data, rresult, "rustls_connection_process_new_packets");
*err = map_error(rresult);
return -1;
}
@@ -192,7 +196,7 @@ 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;
+ const struct ssl_connect_data *const connssl = cf->ctx;
struct rustls_ssl_backend_data *const backend =
(struct rustls_ssl_backend_data *)connssl->backend;
struct rustls_connection *rconn = NULL;
@@ -232,10 +236,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
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);
+ rustls_failf(data, rresult, "rustls_connection_read");
*err = CURLE_RECV_ERROR;
nread = -1;
goto out;
@@ -278,7 +279,6 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
rustls_io_result io_error;
size_t tlswritten = 0;
size_t tlswritten_total = 0;
- CURLcode result = CURLE_OK;
io_ctx.cf = cf;
io_ctx.data = data;
@@ -304,7 +304,7 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
tlswritten_total += tlswritten;
}
- return result;
+ return CURLE_OK;
}
/*
@@ -321,14 +321,11 @@ 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;
+ const struct ssl_connect_data *const connssl = cf->ctx;
struct rustls_ssl_backend_data *const backend =
(struct rustls_ssl_backend_data *)connssl->backend;
struct rustls_connection *rconn = NULL;
size_t plainwritten = 0;
- rustls_result rresult;
- char errorbuf[256];
- size_t errorlen;
const unsigned char *buf = plainbuf;
size_t blen = plainlen;
ssize_t nwritten = 0;
@@ -360,11 +357,11 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(blen > 0) {
+ rustls_result rresult;
CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to Rustls", blen);
rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
if(rresult != RUSTLS_RESULT_OK) {
- rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
- failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf);
+ rustls_failf(data, rresult, "rustls_connection_write");
*err = CURLE_WRITE_ERROR;
return -1;
}
@@ -418,7 +415,7 @@ read_file_into(const char *filename,
while(!feof(f)) {
uint8_t buf[256];
- size_t rr = fread(buf, 1, sizeof(buf), f);
+ const size_t rr = fread(buf, 1, sizeof(buf), f);
if(rr == 0 ||
CURLE_OK != Curl_dyn_addn(out, buf, rr)) {
fclose(f);
@@ -436,8 +433,8 @@ cr_get_selected_ciphers(struct Curl_easy *data,
const struct rustls_supported_ciphersuite **selected,
size_t *selected_size)
{
- size_t supported_len = *selected_size;
- size_t default_len = rustls_default_crypto_provider_ciphersuites_len();
+ const size_t supported_len = *selected_size;
+ const size_t default_len = rustls_default_crypto_provider_ciphersuites_len();
const struct rustls_supported_ciphersuite *entry;
const char *ciphers = ciphers12;
size_t count = 0, default13_count = 0, i, j;
@@ -522,247 +519,607 @@ add_ciphers:
*selected_size = count;
}
+static void
+cr_keylog_log_cb(struct rustls_str label,
+ const uint8_t *client_random, size_t client_random_len,
+ const uint8_t *secret, size_t secret_len)
+{
+ char clabel[KEYLOG_LABEL_MAXLEN];
+ (void)client_random_len;
+ DEBUGASSERT(client_random_len == CLIENT_RANDOM_SIZE);
+ /* Turning a "rustls_str" into a null delimited "c" string */
+ msnprintf(clabel, label.len + 1, "%.*s", (int)label.len, label.data);
+ Curl_tls_keylog_write(clabel, client_random, secret, secret_len);
+}
+
static CURLcode
-cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
- struct rustls_ssl_backend_data *const backend)
+init_config_builder(struct Curl_easy *data,
+ const struct ssl_primary_config *conn_config,
+ struct rustls_client_config_builder **config_builder)
{
- struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const struct rustls_supported_ciphersuite **cipher_suites = NULL;
struct rustls_crypto_provider_builder *custom_provider_builder = NULL;
const struct rustls_crypto_provider *custom_provider = NULL;
- struct rustls_connection *rconn = NULL;
- struct rustls_client_config_builder *config_builder = NULL;
- const struct rustls_root_cert_store *roots = NULL;
- struct rustls_root_cert_store_builder *roots_builder = NULL;
- struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
- struct rustls_server_cert_verifier *server_cert_verifier = NULL;
- 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 bool verifypeer = conn_config->verifypeer;
- char errorbuf[256];
- size_t errorlen;
- rustls_result result;
- DEBUGASSERT(backend);
- rconn = backend->conn;
+ uint16_t tls_versions[2] = {
+ RUSTLS_TLS_VERSION_TLSV1_2,
+ RUSTLS_TLS_VERSION_TLSV1_3,
+ };
+ size_t tls_versions_len = 2;
+ size_t cipher_suites_len =
+ rustls_default_crypto_provider_ciphersuites_len();
- {
- uint16_t tls_versions[2] = {
- RUSTLS_TLS_VERSION_TLSV1_2,
- RUSTLS_TLS_VERSION_TLSV1_3,
- };
- size_t tls_versions_len = 2;
- const struct rustls_supported_ciphersuite **cipher_suites;
- size_t cipher_suites_len =
- rustls_default_crypto_provider_ciphersuites_len();
-
- switch(conn_config->version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- break;
- case CURL_SSLVERSION_TLSv1_3:
- tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
+ CURLcode result = CURLE_OK;
+ rustls_result rr;
+
+ switch(conn_config->version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
+ tls_versions_len = 1;
+ break;
+ default:
+ failf(data, "rustls: unsupported minimum TLS version value");
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto cleanup;
+ }
+
+ switch(conn_config->version_max) {
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ case CURL_SSLVERSION_MAX_NONE:
+ case CURL_SSLVERSION_MAX_TLSv1_3:
+ break;
+ case CURL_SSLVERSION_MAX_TLSv1_2:
+ if(tls_versions[0] == RUSTLS_TLS_VERSION_TLSV1_2) {
tls_versions_len = 1;
break;
- default:
- failf(data, "rustls: unsupported minimum TLS version value");
- return CURLE_BAD_FUNCTION_ARGUMENT;
}
+ FALLTHROUGH();
+ case CURL_SSLVERSION_MAX_TLSv1_1:
+ case CURL_SSLVERSION_MAX_TLSv1_0:
+ default:
+ failf(data, "rustls: unsupported maximum TLS version value");
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto cleanup;
+ }
- switch(conn_config->version_max) {
- case CURL_SSLVERSION_MAX_DEFAULT:
- case CURL_SSLVERSION_MAX_NONE:
- case CURL_SSLVERSION_MAX_TLSv1_3:
- break;
- case CURL_SSLVERSION_MAX_TLSv1_2:
- if(tls_versions[0] == RUSTLS_TLS_VERSION_TLSV1_2) {
- tls_versions_len = 1;
- break;
- }
- FALLTHROUGH();
- case CURL_SSLVERSION_MAX_TLSv1_1:
- case CURL_SSLVERSION_MAX_TLSv1_0:
- default:
- failf(data, "rustls: unsupported maximum TLS version value");
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
+#if defined(USE_ECH)
+ if(ECH_ENABLED(data)) {
+ tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
+ tls_versions_len = 1;
+ infof(data, "rustls: ECH enabled, forcing TLSv1.3");
+ }
+#endif /* USE_ECH */
- cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len));
- if(!cipher_suites)
- return CURLE_OUT_OF_MEMORY;
-
- cr_get_selected_ciphers(data,
- conn_config->cipher_list,
- conn_config->cipher_list13,
- cipher_suites, &cipher_suites_len);
- if(cipher_suites_len == 0) {
- failf(data, "rustls: no supported cipher in list");
- free(cipher_suites);
- return CURLE_SSL_CIPHER;
- }
+ cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len));
+ if(!cipher_suites) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto cleanup;
+ }
- result = rustls_crypto_provider_builder_new_from_default(
- &custom_provider_builder);
- if(result != RUSTLS_RESULT_OK) {
- failf(data,
- "rustls: failed to create crypto provider builder from default");
- return CURLE_SSL_CIPHER;
- }
+ cr_get_selected_ciphers(data,
+ conn_config->cipher_list,
+ conn_config->cipher_list13,
+ cipher_suites, &cipher_suites_len);
+ if(cipher_suites_len == 0) {
+ failf(data, "rustls: no supported cipher in list");
+ result = CURLE_SSL_CIPHER;
+ goto cleanup;
+ }
- result =
- rustls_crypto_provider_builder_set_cipher_suites(
- custom_provider_builder,
- cipher_suites,
- cipher_suites_len);
- if(result != RUSTLS_RESULT_OK) {
- failf(data,
- "rustls: failed to set ciphersuites for crypto provider builder");
- rustls_crypto_provider_builder_free(custom_provider_builder);
- return CURLE_SSL_CIPHER;
- }
+ rr = rustls_crypto_provider_builder_new_from_default(
+ &custom_provider_builder);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr,
+ "failed to create crypto provider builder from default");
+ result = CURLE_SSL_CIPHER;
+ goto cleanup;
+ }
- result = rustls_crypto_provider_builder_build(
- custom_provider_builder, &custom_provider);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to build custom crypto provider");
- rustls_crypto_provider_builder_free(custom_provider_builder);
- return CURLE_SSL_CIPHER;
- }
+ rr =
+ rustls_crypto_provider_builder_set_cipher_suites(
+ custom_provider_builder,
+ cipher_suites,
+ cipher_suites_len);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr,
+ "failed to set ciphersuites for crypto provider builder");
+ result = CURLE_SSL_CIPHER;
+ goto cleanup;
+ }
+
+ rr = rustls_crypto_provider_builder_build(
+ custom_provider_builder, &custom_provider);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to build custom crypto provider");
+ result = CURLE_SSL_CIPHER;
+ goto cleanup;
+ }
- result = rustls_client_config_builder_new_custom(custom_provider,
+ rr = rustls_client_config_builder_new_custom(custom_provider,
tls_versions,
tls_versions_len,
- &config_builder);
+ config_builder);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to create client config builder");
+ result = CURLE_SSL_CIPHER;
+ goto cleanup;
+ }
+
+cleanup:
+ if(cipher_suites) {
free(cipher_suites);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to create client config");
- return CURLE_SSL_CIPHER;
- }
}
+ if(custom_provider_builder) {
+ rustls_crypto_provider_builder_free(custom_provider_builder);
+ }
+ if(custom_provider) {
+ rustls_crypto_provider_free(custom_provider);
+ }
+ return result;
+}
- rustls_crypto_provider_builder_free(custom_provider_builder);
- rustls_crypto_provider_free(custom_provider);
+static void
+init_config_builder_alpn(struct Curl_easy *data,
+ const struct ssl_connect_data *connssl,
+ struct rustls_client_config_builder *config_builder) {
+ struct alpn_proto_buf proto;
+ rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
+ size_t i;
- if(connssl->alpn) {
- struct alpn_proto_buf proto;
- rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
- size_t i;
+ for(i = 0; i < connssl->alpn->count; ++i) {
+ alpn[i].data = (const uint8_t *)connssl->alpn->entries[i];
+ alpn[i].len = strlen(connssl->alpn->entries[i]);
+ }
+ rustls_client_config_builder_set_alpn_protocols(config_builder, alpn,
+ connssl->alpn->count);
+ Curl_alpn_to_proto_str(&proto, connssl->alpn);
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+}
- for(i = 0; i < connssl->alpn->count; ++i) {
- alpn[i].data = (const uint8_t *)connssl->alpn->entries[i];
- alpn[i].len = strlen(connssl->alpn->entries[i]);
- }
- rustls_client_config_builder_set_alpn_protocols(config_builder, alpn,
- connssl->alpn->count);
- Curl_alpn_to_proto_str(&proto, connssl->alpn);
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+static CURLcode
+init_config_builder_verifier_crl(
+ struct Curl_easy *data,
+ const struct ssl_primary_config *conn_config,
+ struct rustls_web_pki_server_cert_verifier_builder *builder)
+{
+ CURLcode result = CURLE_OK;
+ struct dynbuf crl_contents;
+ rustls_result rr;
+
+ Curl_dyn_init(&crl_contents, DYN_CRLFILE_SIZE);
+ if(!read_file_into(conn_config->CRLfile, &crl_contents)) {
+ failf(data, "rustls: failed to read revocation list file");
+ result = CURLE_SSL_CRL_BADFILE;
+ goto cleanup;
}
- if(!verifypeer) {
- rustls_client_config_builder_dangerous_set_certificate_verifier(
- config_builder, cr_verify_none);
+
+ rr = rustls_web_pki_server_cert_verifier_builder_add_crl(
+ builder,
+ Curl_dyn_uptr(&crl_contents),
+ Curl_dyn_len(&crl_contents));
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to parse revocation list");
+ result = CURLE_SSL_CRL_BADFILE;
+ goto cleanup;
}
- 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_builder_free(config_builder);
- return CURLE_SSL_CACERT_BADFILE;
- }
+
+cleanup:
+ Curl_dyn_free(&crl_contents);
+ return result;
+}
+
+static CURLcode
+init_config_builder_verifier(struct Curl_easy *data,
+ struct rustls_client_config_builder *builder,
+ const struct ssl_primary_config *conn_config,
+ const struct curl_blob *ca_info_blob,
+ const char * const ssl_cafile) {
+ const struct rustls_root_cert_store *roots = NULL;
+ struct rustls_root_cert_store_builder *roots_builder = NULL;
+ struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
+ struct rustls_server_cert_verifier *server_cert_verifier = NULL;
+ rustls_result rr = RUSTLS_RESULT_OK;
+ CURLcode result = CURLE_OK;
+
+ roots_builder = rustls_root_cert_store_builder_new();
+ if(ca_info_blob) {
+ rr = rustls_root_cert_store_builder_add_pem(roots_builder,
+ ca_info_blob->data,
+ ca_info_blob->len,
+ 1);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to parse trusted certificates from blob");
+
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto cleanup;
}
- 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_builder_free(config_builder);
- return CURLE_SSL_CACERT_BADFILE;
- }
+ }
+ else if(ssl_cafile) {
+ rr = rustls_root_cert_store_builder_load_roots_from_file(roots_builder,
+ ssl_cafile,
+ 1);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to load trusted certificates");
+
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto cleanup;
}
+ }
- result = rustls_root_cert_store_builder_build(roots_builder, &roots);
- rustls_root_cert_store_builder_free(roots_builder);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to build trusted root certificate store");
- rustls_client_config_builder_free(config_builder);
- return CURLE_SSL_CACERT_BADFILE;
+ rr = rustls_root_cert_store_builder_build(roots_builder, &roots);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to build trusted root certificate store");
+ result = CURLE_SSL_CACERT_BADFILE;
+ }
+
+ verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
+
+ if(conn_config->CRLfile) {
+ result = init_config_builder_verifier_crl(data,
+ conn_config,
+ verifier_builder);
+ if(result != CURLE_OK) {
+ goto cleanup;
}
+ }
- verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
+ rr = rustls_web_pki_server_cert_verifier_builder_build(
+ verifier_builder, &server_cert_verifier);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to build certificate verifier");
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto cleanup;
+ }
+
+ rustls_client_config_builder_set_server_verifier(builder,
+ server_cert_verifier);
+cleanup:
+ if(roots_builder) {
+ rustls_root_cert_store_builder_free(roots_builder);
+ }
+ if(roots) {
rustls_root_cert_store_free(roots);
+ }
+ if(verifier_builder) {
+ rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
+ }
+ if(server_cert_verifier) {
+ rustls_server_cert_verifier_free(server_cert_verifier);
+ }
- if(conn_config->CRLfile) {
- struct dynbuf crl_contents;
- Curl_dyn_init(&crl_contents, SIZE_MAX);
- if(!read_file_into(conn_config->CRLfile, &crl_contents)) {
- failf(data, "rustls: failed to read revocation list file");
- Curl_dyn_free(&crl_contents);
- rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
- return CURLE_SSL_CRL_BADFILE;
- }
+ return result;
+}
- result = rustls_web_pki_server_cert_verifier_builder_add_crl(
- verifier_builder,
- Curl_dyn_uptr(&crl_contents),
- Curl_dyn_len(&crl_contents));
- Curl_dyn_free(&crl_contents);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to parse revocation list");
- rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
- return CURLE_SSL_CRL_BADFILE;
- }
+static CURLcode
+init_config_builder_platform_verifier(
+ struct Curl_easy *data,
+ struct rustls_client_config_builder *builder)
+{
+ struct rustls_server_cert_verifier *server_cert_verifier = NULL;
+ CURLcode result = CURLE_OK;
+ rustls_result rr;
+
+ rr = rustls_platform_server_cert_verifier(&server_cert_verifier);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to create platform certificate verifier");
+ result = CURLE_SSL_CACERT_BADFILE;
+ goto cleanup;
+ }
+
+ rustls_client_config_builder_set_server_verifier(builder,
+ server_cert_verifier);
+
+cleanup:
+ if(server_cert_verifier) {
+ rustls_server_cert_verifier_free(server_cert_verifier);
+ }
+ return result;
+}
+
+static CURLcode
+init_config_builder_keylog(struct Curl_easy *data,
+ struct rustls_client_config_builder *builder)
+{
+ rustls_result rr;
+
+ Curl_tls_keylog_open();
+ if(!Curl_tls_keylog_enabled()) {
+ return CURLE_OK;
+ }
+
+ rr = rustls_client_config_builder_set_key_log(builder,
+ cr_keylog_log_cb,
+ NULL);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "rustls_client_config_builder_set_key_log");
+ Curl_tls_keylog_close();
+ return map_error(rr);
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode
+init_config_builder_client_auth(struct Curl_easy *data,
+ const struct ssl_primary_config *conn_config,
+ const struct ssl_config_data *ssl_config,
+ struct rustls_client_config_builder *builder)
+{
+ struct dynbuf cert_contents;
+ struct dynbuf key_contents;
+ rustls_result rr;
+ const struct rustls_certified_key *certified_key = NULL;
+ CURLcode result = CURLE_OK;
+
+ if(conn_config->clientcert && !ssl_config->key) {
+ failf(data, "rustls: must provide key with certificate '%s'",
+ conn_config->clientcert);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ else if(!conn_config->clientcert && ssl_config->key) {
+ failf(data, "rustls: must provide certificate with key '%s'",
+ conn_config->clientcert);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+
+ Curl_dyn_init(&cert_contents, SIZE_MAX);
+ Curl_dyn_init(&key_contents, SIZE_MAX);
+
+ if(!read_file_into(conn_config->clientcert, &cert_contents)) {
+ failf(data, "rustls: failed to read client certificate file: '%s'",
+ conn_config->clientcert);
+ result = CURLE_SSL_CERTPROBLEM;
+ goto cleanup;
+ }
+
+ if(!read_file_into(ssl_config->key, &key_contents)) {
+ failf(data, "rustls: failed to read key file: '%s'", ssl_config->key);
+ result = CURLE_SSL_CERTPROBLEM;
+ goto cleanup;
+ }
+
+ rr = rustls_certified_key_build(Curl_dyn_uptr(&cert_contents),
+ Curl_dyn_len(&cert_contents),
+ Curl_dyn_uptr(&key_contents),
+ Curl_dyn_len(&key_contents),
+ &certified_key);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "rustls: failed to build certified key");
+ result = CURLE_SSL_CERTPROBLEM;
+ goto cleanup;
+ }
+
+ rr = rustls_certified_key_keys_match(certified_key);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data,
+ rr,
+ "rustls: client certificate and keypair files do not match:");
+
+ result = CURLE_SSL_CERTPROBLEM;
+ goto cleanup;
+ }
+
+ rr = rustls_client_config_builder_set_certified_key(builder,
+ &certified_key,
+ 1);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "rustls: failed to set certified key");
+ result = CURLE_SSL_CERTPROBLEM;
+ goto cleanup;
+ }
+
+cleanup:
+ Curl_dyn_free(&cert_contents);
+ Curl_dyn_free(&key_contents);
+ if(certified_key) {
+ rustls_certified_key_free(certified_key);
+ }
+ return result;
+}
+
+#if defined(USE_ECH)
+static CURLcode
+init_config_builder_ech(struct Curl_easy *data,
+ const struct ssl_connect_data *connssl,
+ struct rustls_client_config_builder *builder)
+{
+ const rustls_hpke *hpke = rustls_supported_hpke();
+ unsigned char *ech_config = NULL;
+ size_t ech_config_len = 0;
+ struct Curl_dns_entry *dns = NULL;
+ struct Curl_https_rrinfo *rinfo = NULL;
+ CURLcode result = CURLE_OK;
+ rustls_result rr;
+
+ if(!hpke) {
+ failf(data,
+ "rustls: ECH unavailable, rustls-ffi built without "
+ "HPKE compatible crypto provider");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+
+ if(data->set.str[STRING_ECH_PUBLIC]) {
+ failf(data, "rustls: ECH outername not supported");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+
+ if(data->set.tls_ech == CURLECH_GREASE) {
+ rr = rustls_client_config_builder_enable_ech_grease(builder, hpke);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "rustls: failed to configure ECH GREASE");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
}
+ return CURLE_OK;
+ }
- result = rustls_web_pki_server_cert_verifier_builder_build(
- verifier_builder, &server_cert_verifier);
- rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to build certificate verifier");
- rustls_server_cert_verifier_free(server_cert_verifier);
+ if(data->set.tls_ech & CURLECH_CLA_CFG
+ && data->set.str[STRING_ECH_CONFIG]) {
+ const char *b64 = data->set.str[STRING_ECH_CONFIG];
+ size_t decode_result;
+ if(!b64) {
+ infof(data, "rustls: ECHConfig from command line empty");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+ /* rustls-ffi expects the raw TLS encoded ECHConfigList bytes */
+ decode_result = Curl_base64_decode(b64, &ech_config, &ech_config_len);
+ if(decode_result || !ech_config) {
+ infof(data, "rustls: cannot base64 decode ECHConfig from command line");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+ }
+ else {
+ if(connssl->peer.hostname) {
+ dns = Curl_fetch_addr(
+ data,
+ connssl->peer.hostname,
+ connssl->peer.port);
+ }
+ if(!dns) {
+ failf(data, "rustls: ECH requested but no DNS info available");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+ rinfo = dns->hinfo;
+ if(!rinfo || !rinfo->echconfiglist) {
+ failf(data, "rustls: ECH requested but no ECHConfig available");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+ ech_config = rinfo->echconfiglist;
+ ech_config_len = rinfo->echconfiglist_len;
+ }
+
+ rr = rustls_client_config_builder_enable_ech(builder,
+ ech_config,
+ ech_config_len,
+ hpke);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "rustls: failed to configure ECH");
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto cleanup;
+ }
+cleanup:
+ if(dns) {
+ Curl_resolv_unlink(data, &dns);
+ }
+ return result;
+}
+#endif /* USE_ECH */
+
+static CURLcode
+cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
+ struct rustls_ssl_backend_data *const backend)
+{
+ const struct ssl_connect_data *connssl = cf->ctx;
+ const 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 rustls_connection *rconn = NULL;
+ struct rustls_client_config_builder *config_builder = NULL;
+
+ 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);
+ CURLcode result = CURLE_OK;
+ rustls_result rr;
+
+ DEBUGASSERT(backend);
+ rconn = backend->conn;
+
+ result = init_config_builder(data, conn_config, &config_builder);
+ if(result != CURLE_OK) {
+ return result;
+ }
+
+ if(connssl->alpn) {
+ init_config_builder_alpn(data, connssl, config_builder);
+ }
+
+ if(!conn_config->verifypeer) {
+ rustls_client_config_builder_dangerous_set_certificate_verifier(
+ config_builder, cr_verify_none);
+ }
+ else if(ssl_config->native_ca_store) {
+ result = init_config_builder_platform_verifier(data, config_builder);
+ if(result != CURLE_OK) {
+ rustls_client_config_builder_free(config_builder);
+ return result;
+ }
+ }
+ else if(ca_info_blob || ssl_cafile) {
+ result = init_config_builder_verifier(data,
+ config_builder,
+ conn_config,
+ ca_info_blob,
+ ssl_cafile);
+ if(result != CURLE_OK) {
rustls_client_config_builder_free(config_builder);
- return CURLE_SSL_CACERT_BADFILE;
+ return result;
}
+ }
- rustls_client_config_builder_set_server_verifier(config_builder,
- server_cert_verifier);
- rustls_server_cert_verifier_free(server_cert_verifier);
+ if(conn_config->clientcert || ssl_config->key) {
+ result = init_config_builder_client_auth(data,
+ conn_config,
+ ssl_config,
+ config_builder);
+ if(result != CURLE_OK) {
+ rustls_client_config_builder_free(config_builder);
+ return result;
+ }
+ }
+
+#if defined(USE_ECH)
+ if(ECH_ENABLED(data)) {
+ result = init_config_builder_ech(data, connssl, config_builder);
+ if(result != CURLE_OK && data->set.tls_ech & CURLECH_HARD) {
+ rustls_client_config_builder_free(config_builder);
+ return result;
+ }
+ }
+#endif /* USE_ECH */
+
+ result = init_config_builder_keylog(data, config_builder);
+ if(result != CURLE_OK) {
+ rustls_client_config_builder_free(config_builder);
+ return result;
}
- result = rustls_client_config_builder_build(
+ rr = rustls_client_config_builder_build(
config_builder,
&backend->config);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to build client config");
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, rr, "failed to build client config");
+ rustls_client_config_builder_free(config_builder);
rustls_client_config_free(backend->config);
return CURLE_SSL_CONNECT_ERROR;
}
DEBUGASSERT(rconn == NULL);
- result = rustls_client_connection_new(backend->config,
- connssl->peer.hostname, &rconn);
- if(result != RUSTLS_RESULT_OK) {
- rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
- failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf);
+ rr = rustls_client_connection_new(backend->config,
+ connssl->peer.hostname,
+ &rconn);
+ if(rr != RUSTLS_RESULT_OK) {
+ rustls_failf(data, result, "rustls_client_connection_new");
return CURLE_COULDNT_CONNECT;
}
DEBUGASSERT(rconn);
rustls_connection_set_userdata(rconn, backend);
backend->conn = rconn;
- return CURLE_OK;
+
+ return result;
}
static void
@@ -779,48 +1136,36 @@ cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data,
/* Given an established network connection, do a TLS handshake.
*
- * If `blocking` is true, this function will block until the handshake is
- * complete. Otherwise it will return as soon as I/O would block.
- *
- * For the non-blocking I/O case, this function will set `*done` to true
- * once the handshake is complete. This function never reads the value of
- * `*done*`.
+ * This function will set `*done` to true once the handshake is complete.
+ * This function never reads the value of `*done*`.
*/
static CURLcode
-cr_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool blocking,
- bool *done)
+cr_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data, bool *done)
{
struct ssl_connect_data *const connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- struct rustls_ssl_backend_data *const backend =
+ const struct rustls_ssl_backend_data *const backend =
(struct rustls_ssl_backend_data *)connssl->backend;
- struct rustls_connection *rconn = NULL;
+ const struct rustls_connection *rconn = NULL;
CURLcode tmperr = CURLE_OK;
int result;
- int what;
bool wants_read;
bool wants_write;
- curl_socket_t writefd;
- curl_socket_t readfd;
- timediff_t timeout_ms;
- timediff_t socket_check_timeout;
DEBUGASSERT(backend);
- CURL_TRC_CF(data, cf, "cr_connect_common, state=%d", connssl->state);
+ CURL_TRC_CF(data, cf, "cr_connect, state=%d", connssl->state);
*done = FALSE;
+
if(!backend->conn) {
result = cr_init_backend(cf, data,
(struct rustls_ssl_backend_data *)connssl->backend);
- CURL_TRC_CF(data, cf, "cr_connect_common, init backend -> %d", result);
+ CURL_TRC_CF(data, cf, "cr_connect, init backend -> %d", result);
if(result != CURLE_OK) {
return result;
}
connssl->state = ssl_connection_negotiating;
}
-
rconn = backend->conn;
/* Read/write data until the handshake is done or the socket would block. */
@@ -846,8 +1191,10 @@ cr_connect_common(struct Curl_cfilter *cf,
}
/* REALLY Done with the handshake. */
{
- uint16_t proto = rustls_connection_get_protocol_version(rconn);
- uint16_t cipher = rustls_connection_get_negotiated_ciphersuite(rconn);
+ const uint16_t proto =
+ rustls_connection_get_protocol_version(rconn);
+ const uint16_t cipher =
+ rustls_connection_get_negotiated_ciphersuite(rconn);
char buf[64] = "";
const char *ver = "TLS version unknown";
if(proto == RUSTLS_TLS_VERSION_TLSV1_3)
@@ -858,6 +1205,43 @@ cr_connect_common(struct Curl_cfilter *cf,
infof(data, "rustls: handshake complete, %s, cipher: %s",
ver, buf);
}
+ if(data->set.ssl.certinfo) {
+ size_t num_certs = 0;
+ while(rustls_connection_get_peer_certificate(rconn, (int)num_certs)) {
+ num_certs++;
+ }
+ result = Curl_ssl_init_certinfo(data, (int)num_certs);
+ if(result)
+ return result;
+ for(size_t i = 0; i < num_certs; i++) {
+ const rustls_certificate *cert;
+ const unsigned char *der_data;
+ size_t der_len;
+ rustls_result rresult = RUSTLS_RESULT_OK;
+ cert = rustls_connection_get_peer_certificate(rconn, i);
+ DEBUGASSERT(cert); /* Should exist since we counted already */
+ rresult = rustls_certificate_get_der(cert, &der_data, &der_len);
+ if(rresult != RUSTLS_RESULT_OK) {
+ char errorbuf[255];
+ size_t errorlen;
+ rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
+ failf(data,
+ "Failed getting DER of server certificate #%ld: %.*s", i,
+ (int)errorlen, errorbuf);
+ return map_error(rresult);
+ }
+ {
+ const char *beg;
+ const char *end;
+ beg = (const char *)der_data;
+ end = (const char *)(der_data + der_len);
+ result = Curl_extract_certinfo(data, (int)i, beg, end);
+ if(result)
+ return result;
+ }
+ }
+ }
+
connssl->state = ssl_connection_complete;
*done = TRUE;
return CURLE_OK;
@@ -868,50 +1252,14 @@ cr_connect_common(struct Curl_cfilter *cf,
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;
- }
-
- socket_check_timeout = blocking ? timeout_ms : 0;
-
- what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- socket_check_timeout);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
- }
- if(blocking && 0 == what) {
- failf(data, "rustls: connection timeout after %" FMT_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);
if(tmperr == CURLE_AGAIN) {
CURL_TRC_CF(data, cf, "writing would block");
- /* fall through */
+ connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ return CURLE_OK;
}
else if(tmperr != CURLE_OK) {
return tmperr;
@@ -923,7 +1271,8 @@ cr_connect_common(struct Curl_cfilter *cf,
if(tls_recv_more(cf, data, &tmperr) < 0) {
if(tmperr == CURLE_AGAIN) {
CURL_TRC_CF(data, cf, "reading would block");
- /* fall through */
+ connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ return CURLE_OK;
}
else if(tmperr == CURLE_RECV_ERROR) {
return CURLE_SSL_CONNECT_ERROR;
@@ -940,20 +1289,6 @@ cr_connect_common(struct Curl_cfilter *cf,
DEBUGASSERT(FALSE);
}
-static CURLcode
-cr_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
-{
- return cr_connect_common(cf, data, false, done);
-}
-
-static CURLcode
-cr_connect_blocking(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- bool done; /* unused */
- return cr_connect_common(cf, data, true, &done);
-}
-
static void *
cr_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
@@ -967,14 +1302,13 @@ cr_get_internals(struct ssl_connect_data *connssl,
static CURLcode
cr_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool send_shutdown, bool *done)
+ const 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);
@@ -1007,6 +1341,7 @@ cr_shutdown(struct Curl_cfilter *cf,
}
for(i = 0; i < 10; ++i) {
+ char buf[1024];
nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result);
if(nread <= 0)
break;
@@ -1036,7 +1371,7 @@ out:
static void
cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = cf->ctx;
+ const struct ssl_connect_data *connssl = cf->ctx;
struct rustls_ssl_backend_data *backend =
(struct rustls_ssl_backend_data *)connssl->backend;
@@ -1054,7 +1389,7 @@ cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
static size_t cr_version(char *buffer, size_t size)
{
- struct rustls_str ver = rustls_version();
+ const struct rustls_str ver = rustls_version();
return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
}
@@ -1068,23 +1403,29 @@ cr_random(struct Curl_easy *data, unsigned char *entropy, size_t length)
return map_error(rresult);
}
+static void cr_cleanup(void)
+{
+ Curl_tls_keylog_close();
+}
+
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */
SSLSUPP_HTTPS_PROXY |
SSLSUPP_CIPHER_LIST |
- SSLSUPP_TLS13_CIPHERSUITES,
+ SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_CERTINFO |
+ SSLSUPP_ECH,
sizeof(struct rustls_ssl_backend_data),
NULL, /* init */
- NULL, /* cleanup */
+ cr_cleanup, /* cleanup */
cr_version, /* version */
cr_shutdown, /* shutdown */
cr_data_pending, /* data_pending */
cr_random, /* random */
NULL, /* cert_status_request */
- cr_connect_blocking, /* connect */
- cr_connect_nonblocking, /* connect_nonblocking */
+ cr_connect, /* connect */
Curl_ssl_adjust_pollset, /* adjust_pollset */
cr_get_internals, /* get_internals */
cr_close, /* close_one */
diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c
index e0a978f1db..f685011aca 100644
--- a/libs/libcurl/src/vtls/schannel.c
+++ b/libs/libcurl/src/vtls/schannel.c
@@ -53,8 +53,10 @@
#include "x509asn1.h"
#include "curl_printf.h"
#include "multiif.h"
+#include "system_win32.h"
#include "version_win32.h"
#include "rand.h"
+#include "strparse.h"
/* The last #include file should be: */
#include "curl_memory.h"
@@ -71,19 +73,6 @@
#define SCH_DEV(x) do { } while(0)
#endif
-/* ALPN requires version 8.1 of the Windows SDK, which was
- shipped with Visual Studio 2013, aka _MSC_VER 1800:
-
- https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
-*/
-#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
-# define HAS_ALPN_SCHANNEL
-#endif
-
-#ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM
-#define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305"
-#endif
-
#ifndef BCRYPT_CHAIN_MODE_CCM
#define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM"
#endif
@@ -152,10 +141,27 @@
#define CALG_SHA_256 0x0000800c
#endif
+/* Work around typo in CeGCC (as of 0.59.1) w32api headers */
+#if defined(__MINGW32CE__) && \
+ !defined(ALG_CLASS_DHASH) && defined(ALG_CLASS_HASH)
+#define ALG_CLASS_DHASH ALG_CLASS_HASH
+#endif
+
#ifndef PKCS12_NO_PERSIST_KEY
#define PKCS12_NO_PERSIST_KEY 0x00008000
#endif
+/* ALPN requires version 8.1 of the Windows SDK, which was
+ shipped with Visual Studio 2013, aka _MSC_VER 1800:
+ https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
+ Or mingw-w64 9.0 or upper.
+*/
+#if (defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 9) || \
+ (defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_))
+#define HAS_ALPN_SCHANNEL
+static bool s_win_has_alpn;
+#endif
+
static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char *pinnedpubkey);
@@ -232,8 +238,6 @@ schannel_set_ssl_version_min_max(DWORD *enabled_protocols,
return CURLE_OK;
}
-/* longest is 26, buffer is slightly bigger */
-#define LONGEST_ALG_ID 32
#define CIPHEROPTION(x) {#x, x}
struct algo {
@@ -350,9 +354,9 @@ static const struct algo algs[]= {
};
static int
-get_alg_id_by_name(char *name)
+get_alg_id_by_name(const char *name)
{
- char *nameEnd = strchr(name, ':');
+ const char *nameEnd = strchr(name, ':');
size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
int i;
@@ -369,12 +373,13 @@ static CURLcode
set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
ALG_ID *algIds)
{
- char *startCur = ciphers;
+ const char *startCur = ciphers;
int algCount = 0;
while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) {
- long alg = strtol(startCur, 0, 0);
- if(!alg)
+ curl_off_t alg;
+ if(Curl_str_number(&startCur, &alg, INT_MAX) || !alg)
alg = get_alg_id_by_name(startCur);
+
if(alg)
algIds[algCount++] = (ALG_ID)alg;
else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
@@ -654,8 +659,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
else
pszPassword[0] = 0;
- if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
- VERSION_GREATER_THAN_EQUAL))
+ if(Curl_isVistaOrGreater)
cert_store = PFXImportCertStore(&datablob, pszPassword,
PKCS12_NO_PERSIST_KEY);
else
@@ -802,11 +806,12 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
#endif
sspi_status =
- Curl_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
- SECPKG_CRED_OUTBOUND, NULL,
- &credentials, NULL, NULL,
- &backend->cred->cred_handle,
- &backend->cred->time_stamp);
+ Curl_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *)CURL_UNCONST(UNISP_NAME),
+ 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.
@@ -842,11 +847,12 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
#endif
sspi_status =
- Curl_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
- SECPKG_CRED_OUTBOUND, NULL,
- &schannel_cred, NULL, NULL,
- &backend->cred->cred_handle,
- &backend->cred->time_stamp);
+ Curl_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *)CURL_UNCONST(UNISP_NAME),
+ SECPKG_CRED_OUTBOUND, NULL,
+ &schannel_cred, NULL, NULL,
+ &backend->cred->cred_handle,
+ &backend->cred->time_stamp);
}
#ifdef HAS_CLIENT_CERT_PATH
@@ -882,7 +888,9 @@ schannel_connect_step1(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;
+#ifndef UNDER_CE
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+#endif
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
@@ -892,7 +900,6 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
unsigned char alpn_buffer[128];
#endif
SECURITY_STATUS sspi_status = SEC_E_OK;
- struct Curl_schannel_cred *old_cred = NULL;
CURLcode result;
DEBUGASSERT(backend);
@@ -909,20 +916,14 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#ifdef HAS_ALPN_SCHANNEL
- /* 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);
+ backend->use_alpn = connssl->alpn && s_win_has_alpn;
#else
backend->use_alpn = FALSE;
#endif
-#ifdef _WIN32_WCE
+#ifdef UNDER_CE
#ifdef HAS_MANUAL_VERIFY_API
- /* certificate validation on CE does not seem to work right; we will
+ /* certificate validation on Windows CE does not seem to work right; we will
* do it following a more manual process. */
backend->use_manual_cred_validation = TRUE;
#else
@@ -955,9 +956,10 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check for an existing reusable credential handle */
if(ssl_config->primary.cache_session) {
+ struct Curl_schannel_cred *old_cred;
Curl_ssl_scache_lock(data);
- if(Curl_ssl_scache_get_obj(cf, data, connssl->peer.scache_key,
- (void **)&old_cred)) {
+ old_cred = Curl_ssl_scache_get_obj(cf, data, connssl->peer.scache_key);
+ if(old_cred) {
backend->cred = old_cred;
DEBUGF(infof(data, "schannel: reusing existing credential handle"));
@@ -973,7 +975,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
if(!backend->cred) {
char *snihost;
result = schannel_acquire_credential_handle(cf, data);
- if(result)
+ if(result || !backend->cred)
return result;
/* schannel_acquire_credential_handle() sets backend->cred accordingly or
it returns error otherwise. */
@@ -1629,6 +1631,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
args.data = data;
args.idx = 0;
args.certs_count = certs_count;
+ args.result = CURLE_OK;
traverse_cert_store(ccert_context, add_cert_to_certinfo, &args);
result = args.result;
}
@@ -1642,16 +1645,12 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_OK;
}
-static CURLcode
-schannel_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool nonblocking, bool *done)
+static CURLcode schannel_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- CURLcode result;
struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
- timediff_t timeout_ms;
- int what;
+ CURLcode result;
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
@@ -1659,73 +1658,19 @@ schannel_connect_common(struct Curl_cfilter *cf,
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;
- }
+ *done = FALSE;
+ if(ssl_connect_1 == connssl->connecting_state) {
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;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL/TLS connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* 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.
- */
+ if(ssl_connect_2 == connssl->connecting_state) {
result = schannel_connect_step2(cf, data);
- if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(result)
return result;
-
- } /* repeat step2 until all transactions are done. */
+ }
if(ssl_connect_3 == connssl->connecting_state) {
result = schannel_connect_step3(cf, data);
@@ -1752,11 +1697,6 @@ schannel_connect_common(struct Curl_cfilter *cf,
*done = TRUE;
}
- else
- *done = FALSE;
-
- /* reset our connection state machine */
- connssl->connecting_state = ssl_connect_1;
return CURLE_OK;
}
@@ -2002,7 +1942,6 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
backend->encdata_offset),
size, err);
if(*err) {
- nread = -1;
if(*err == CURLE_AGAIN)
SCH_DEV(infof(data, "schannel: recv returned CURLE_AGAIN"));
else if(*err == CURLE_RECV_ERROR)
@@ -2129,7 +2068,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
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);
+ *err = schannel_connect(cf, data, &done);
backend->recv_renegotiating = FALSE;
if(*err) {
infof(data, "schannel: renegotiation failed");
@@ -2240,28 +2179,6 @@ cleanup:
return *err ? -1 : 0;
}
-static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return schannel_connect_common(cf, data, TRUE, done);
-}
-
-static CURLcode schannel_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = schannel_connect_common(cf, data, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
-}
-
static bool schannel_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
@@ -2466,6 +2383,34 @@ static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
static int schannel_init(void)
{
+#if defined(HAS_ALPN_SCHANNEL) && !defined(UNDER_CE)
+ bool wine = FALSE;
+ bool wine_has_alpn = FALSE;
+
+#ifndef CURL_WINDOWS_UWP
+ typedef const char *(APIENTRY *WINE_GET_VERSION_FN)(void);
+ /* GetModuleHandle() not available for UWP.
+ Assume no WINE because WINE has no UWP support. */
+ WINE_GET_VERSION_FN p_wine_get_version =
+ CURLX_FUNCTION_CAST(WINE_GET_VERSION_FN,
+ (GetProcAddress(GetModuleHandleA("ntdll"),
+ "wine_get_version")));
+ wine = !!p_wine_get_version;
+ if(wine) {
+ const char *wine_version = p_wine_get_version(); /* e.g. "6.0.2" */
+ /* Assume ALPN support with WINE 6.0 or upper */
+ wine_has_alpn = wine_version && atoi(wine_version) >= 6;
+ }
+#endif
+ if(wine)
+ s_win_has_alpn = wine_has_alpn;
+ else {
+ /* ALPN is supported on Windows 8.1 / Server 2012 R2 and above. */
+ s_win_has_alpn = curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL);
+ }
+#endif /* HAS_ALPN_SCHANNEL && !UNDER_CE */
+
return Curl_sspi_global_init() == CURLE_OK ? 1 : 0;
}
@@ -2589,7 +2534,12 @@ static void schannel_checksum(const unsigned char *input,
if(!CryptCreateHash(hProv, algId, 0, 0, &hHash))
break; /* failed */
+#ifdef __MINGW32CE__
+ /* workaround for CeGCC, should be (const BYTE*) */
+ if(!CryptHashData(hHash, (BYTE*)CURL_UNCONST(input), (DWORD)inputlen, 0))
+#else
if(!CryptHashData(hHash, input, (DWORD)inputlen, 0))
+#endif
break; /* failed */
/* get hash size */
@@ -2653,7 +2603,7 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
}
share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ CURL_UNCONST(MPROTO_SCHANNEL_CERT_SHARE_KEY),
sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
if(!share || !share->cert_store) {
return NULL;
@@ -2731,7 +2681,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
}
share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ CURL_UNCONST(MPROTO_SCHANNEL_CERT_SHARE_KEY),
sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
if(!share) {
share = calloc(1, sizeof(*share));
@@ -2739,7 +2689,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
return FALSE;
}
if(!Curl_hash_add2(&multi->proto_hash,
- (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
+ CURL_UNCONST(MPROTO_SCHANNEL_CERT_SHARE_KEY),
sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
share, schannel_cert_share_free)) {
free(share);
@@ -2800,7 +2750,6 @@ const struct Curl_ssl Curl_ssl_schannel = {
schannel_random, /* random */
NULL, /* cert_status_request */
schannel_connect, /* connect */
- schannel_connect_nonblocking, /* connect_nonblocking */
Curl_ssl_adjust_pollset, /* adjust_pollset */
schannel_get_internals, /* get_internals */
schannel_close, /* close_one */
diff --git a/libs/libcurl/src/vtls/schannel_verify.c b/libs/libcurl/src/vtls/schannel_verify.c
index 42f7f517e4..26b3805cc6 100644
--- a/libs/libcurl/src/vtls/schannel_verify.c
+++ b/libs/libcurl/src/vtls/schannel_verify.c
@@ -57,6 +57,22 @@
#ifdef HAS_MANUAL_VERIFY_API
+#ifdef __MINGW32CE__
+#define CERT_QUERY_OBJECT_BLOB 0x00000002
+#define CERT_QUERY_CONTENT_CERT 1
+#define CERT_QUERY_CONTENT_FLAG_CERT (1 << CERT_QUERY_CONTENT_CERT)
+#define CERT_QUERY_FORMAT_BINARY 1
+#define CERT_QUERY_FORMAT_BASE64_ENCODED 2
+#define CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED 3
+#define CERT_QUERY_FORMAT_FLAG_ALL \
+ (1 << CERT_QUERY_FORMAT_BINARY) | \
+ (1 << CERT_QUERY_FORMAT_BASE64_ENCODED) | \
+ (1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED)
+#define CERT_CHAIN_REVOCATION_CHECK_CHAIN 0x20000000
+#define CERT_NAME_DISABLE_IE4_UTF8_FLAG 0x00010000
+#define CERT_TRUST_IS_OFFLINE_REVOCATION 0x01000000
+#endif /* __MINGW32CE__ */
+
#define MAX_CAFILE_SIZE 1048576 /* 1 MiB */
#define BEGIN_CERT "-----BEGIN CERTIFICATE-----"
#define END_CERT "\n-----END CERTIFICATE-----"
@@ -76,6 +92,7 @@ struct cert_chain_engine_config_win7 {
HCERTSTORE hExclusiveTrustedPeople;
};
+#ifndef UNDER_CE
static int is_cr_or_lf(char c)
{
return c == '\r' || c == '\n';
@@ -138,13 +155,13 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
}
else {
CERT_BLOB cert_blob;
- CERT_CONTEXT *cert_context = NULL;
+ const CERT_CONTEXT *cert_context = NULL;
BOOL add_cert_result = FALSE;
DWORD actual_content_type = 0;
DWORD cert_size = (DWORD)
((end_cert_ptr + end_cert_len) - begin_cert_ptr);
- cert_blob.pbData = (BYTE *)begin_cert_ptr;
+ cert_blob.pbData = (BYTE *)CURL_UNCONST(begin_cert_ptr);
cert_blob.cbData = cert_size;
if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
&cert_blob,
@@ -162,7 +179,7 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
"schannel: failed to extract certificate from CA file "
"'%s': %s",
ca_file_text,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
more_certs = 0;
}
@@ -191,8 +208,8 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
"schannel: failed to add certificate from CA file '%s' "
"to certificate store: %s",
ca_file_text,
- Curl_winapi_strerror(GetLastError(), buffer,
- sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer,
+ sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
more_certs = 0;
}
@@ -232,13 +249,13 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
size_t ca_file_bufsize = 0;
DWORD total_bytes_read = 0;
- ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
+ ca_file_tstr = curlx_convert_UTF8_to_tchar(ca_file);
if(!ca_file_tstr) {
char buffer[STRERROR_LEN];
failf(data,
"schannel: invalid path name for CA file '%s': %s",
ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -260,7 +277,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
failf(data,
"schannel: failed to open CA file '%s': %s",
ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -270,7 +287,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
failf(data,
"schannel: failed to determine size of CA file '%s': %s",
ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -300,7 +317,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
failf(data,
"schannel: failed to read from CA file '%s': %s",
ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
goto cleanup;
}
@@ -330,9 +347,11 @@ cleanup:
return result;
}
+#endif
#endif /* HAS_MANUAL_VERIFY_API */
+#ifndef UNDER_CE
/*
* 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
@@ -380,6 +399,9 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
(void)Win8_compat;
#endif
+ if(!alt_name_info)
+ return 0;
+
compute_content = host_names != NULL && length != 0;
/* Initialize default return values. */
@@ -442,14 +464,14 @@ static bool get_num_host_info(struct num_ip_data *ip_blob,
struct in6_addr ia6;
bool result = FALSE;
- int res = Curl_inet_pton(AF_INET, hostname, &ia);
+ int res = curlx_inet_pton(AF_INET, hostname, &ia);
if(res) {
ip_blob->size = sizeof(struct in_addr);
memcpy(&ip_blob->bData.ia, &ia, sizeof(struct in_addr));
result = TRUE;
}
else {
- res = Curl_inet_pton(AF_INET6, hostname, &ia6);
+ res = curlx_inet_pton(AF_INET6, hostname, &ia6);
if(res) {
ip_blob->size = sizeof(struct in6_addr);
memcpy(&ip_blob->bData.ia6, &ia6, sizeof(struct in6_addr));
@@ -511,15 +533,68 @@ static bool get_alt_name_info(struct Curl_easy *data,
#endif
return result;
}
+#endif /* !UNDER_CE */
/* Verify the server's hostname */
CURLcode Curl_verify_host(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct ssl_connect_data *connssl = cf->ctx;
- SECURITY_STATUS sspi_status;
CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
+ struct ssl_connect_data *connssl = cf->ctx;
CERT_CONTEXT *pCertContextServer = NULL;
+#ifdef UNDER_CE
+ TCHAR cert_hostname_buff[256];
+ DWORD len;
+
+ /* This code does not support certificates with multiple alternative names.
+ * Right now we are only asking for the first preferred alternative name.
+ * Instead we would need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
+ * (If Windows CE supports that?) and run this section in a loop for each.
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
+ * curl: (51) schannel: CertGetNameString() certificate hostname
+ * (.google.com) did not match connection (google.com)
+ */
+ len = CertGetNameString(pCertContextServer,
+ CERT_NAME_DNS_TYPE,
+ CERT_NAME_DISABLE_IE4_UTF8_FLAG,
+ NULL,
+ cert_hostname_buff,
+ 256);
+ if(len > 0) {
+ /* Comparing the cert name and the connection hostname encoded as UTF-8
+ * is acceptable since both values are assumed to use ASCII
+ * (or some equivalent) encoding
+ */
+ char *cert_hostname = curlx_convert_tchar_to_UTF8(cert_hostname_buff);
+ if(!cert_hostname) {
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else{
+ const char *conn_hostname = connssl->peer.hostname;
+ if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname),
+ conn_hostname, strlen(conn_hostname))) {
+ infof(data,
+ "schannel: connection hostname (%s) validated "
+ "against certificate name (%s)\n",
+ conn_hostname, cert_hostname);
+ result = CURLE_OK;
+ }
+ else{
+ failf(data,
+ "schannel: connection hostname (%s) "
+ "does not match certificate name (%s)",
+ conn_hostname, cert_hostname);
+ }
+ Curl_safefree(cert_hostname);
+ }
+ }
+ else {
+ failf(data,
+ "schannel: CertGetNameString did not provide any "
+ "certificate name information");
+ }
+#else
+ SECURITY_STATUS sspi_status;
TCHAR *cert_hostname_buff = NULL;
size_t cert_hostname_buff_index = 0;
const char *conn_hostname = connssl->peer.hostname;
@@ -664,6 +739,7 @@ cleanup:
if(pCertContextServer)
CertFreeCertificateContext(pCertContextServer);
+#endif /* !UNDER_CE */
return result;
}
@@ -681,15 +757,17 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
CERT_CONTEXT *pCertContextServer = NULL;
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
HCERTCHAINENGINE cert_chain_engine = NULL;
+#ifndef UNDER_CE
HCERTSTORE trust_store = NULL;
HCERTSTORE own_trust_store = NULL;
+#endif /* !UNDER_CE */
DEBUGASSERT(BACKEND);
sspi_status =
Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT,
- &pCertContextServer);
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
if((sspi_status != SEC_E_OK) || !pCertContextServer) {
char buffer[STRERROR_LEN];
@@ -698,6 +776,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
result = CURLE_PEER_FAILED_VERIFICATION;
}
+#ifndef UNDER_CE
if(result == CURLE_OK &&
(conn_config->CAfile || conn_config->ca_info_blob) &&
BACKEND->use_manual_cred_validation) {
@@ -729,7 +808,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
if(!trust_store) {
char buffer[STRERROR_LEN];
failf(data, "schannel: failed to create certificate store: %s",
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
}
else {
@@ -777,11 +856,12 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
char buffer[STRERROR_LEN];
failf(data,
"schannel: failed to create certificate chain engine: %s",
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
result = CURLE_SSL_CACERT_BADFILE;
}
}
}
+#endif /* !UNDER_CE */
if(result == CURLE_OK) {
CERT_CHAIN_PARA ChainPara;
@@ -800,7 +880,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
&pChainContext)) {
char buffer[STRERROR_LEN];
failf(data, "schannel: CertGetCertificateChain failed: %s",
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ curlx_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
pChainContext = NULL;
result = CURLE_PEER_FAILED_VERIFICATION;
}
@@ -848,6 +928,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
}
}
+#ifndef UNDER_CE
if(cert_chain_engine) {
CertFreeCertificateChainEngine(cert_chain_engine);
}
@@ -855,6 +936,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
if(own_trust_store) {
CertCloseStore(own_trust_store, 0);
}
+#endif /* !UNDER_CE */
if(pChainContext)
CertFreeCertificateChain(pChainContext);
diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c
index 10dfe1e92e..9cb51f2c53 100644
--- a/libs/libcurl/src/vtls/sectransp.c
+++ b/libs/libcurl/src/vtls/sectransp.c
@@ -34,7 +34,7 @@
#include "urldata.h" /* for the Curl_easy definition */
#include "curl_base64.h"
-#include "strtok.h"
+#include "strparse.h"
#include "multiif.h"
#include "strcase.h"
#include "x509asn1.h"
@@ -211,9 +211,6 @@ static const uint16_t default_ciphers[] = {
#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+ */
@@ -266,7 +263,7 @@ static OSStatus sectransp_bio_cf_in_read(SSLConnectionRef connection,
void *buf,
size_t *dataLength) /* IN/OUT */
{
- struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
+ const struct Curl_cfilter *cf = (const struct Curl_cfilter *)connection;
struct ssl_connect_data *connssl = cf->ctx;
struct st_ssl_backend_data *backend =
(struct st_ssl_backend_data *)connssl->backend;
@@ -306,7 +303,7 @@ static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection,
const void *buf,
size_t *dataLength) /* IN/OUT */
{
- struct Curl_cfilter *cf = (struct Curl_cfilter *)connection;
+ const struct Curl_cfilter *cf = (const struct Curl_cfilter *)connection;
struct ssl_connect_data *connssl = cf->ctx;
struct st_ssl_backend_data *backend =
(struct st_ssl_backend_data *)connssl->backend;
@@ -341,30 +338,28 @@ static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection,
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;
- char *tok_buf;
+ char buf[256];
/* Get the Darwin kernel version from the kernel using sysctl(): */
mib[0] = CTL_KERN;
mib[1] = KERN_OSRELEASE;
if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1)
return;
- os_version = malloc(os_version_len*sizeof(char));
- if(!os_version)
- return;
- if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) {
- free(os_version);
- return;
+ if(os_version_len < sizeof(buf)) {
+ if(sysctl(mib, 2, buf, &os_version_len, NULL, 0) != -1) {
+ const char *os = buf;
+ curl_off_t fnum;
+ curl_off_t snum;
+ /* Parse the version: */
+ if(!Curl_str_number(&os, &fnum, INT_MAX) &&
+ !Curl_str_single(&os, '.') &&
+ !Curl_str_number(&os, &snum, INT_MAX)) {
+ *major = (int)fnum;
+ *minor = (int)snum;
+ }
+ }
}
-
- /* Parse the version: */
- os_version_major = Curl_strtok_r(os_version, ".", &tok_buf);
- os_version_minor = Curl_strtok_r(NULL, ".", &tok_buf);
- *major = atoi(os_version_major);
- *minor = atoi(os_version_minor);
- free(os_version);
}
#endif /* CURL_BUILD_MAC */
@@ -541,8 +536,8 @@ static OSStatus CopyIdentityWithLabel(char *label,
for(i = 0; i < keys_list_count; i++) {
OSStatus err = noErr;
SecCertificateRef cert = NULL;
- SecIdentityRef identity =
- (SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
+ const void *item = CFArrayGetValueAtIndex(keys_list, i);
+ SecIdentityRef identity = (SecIdentityRef)CURL_UNCONST(item);
err = SecIdentityCopyCertificate(identity, &cert);
if(err == noErr) {
CFStringRef common_name = NULL;
@@ -671,22 +666,22 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
count = CFArrayGetCount(items);
for(i = 0; i < count; i++) {
- CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i);
- CFTypeID itemID = CFGetTypeID(item);
+ const CFTypeRef item = CFArrayGetValueAtIndex(items, i);
+ CFTypeID itemID = CFGetTypeID(item);
if(itemID == CFDictionaryGetTypeID()) {
- CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue(
- (CFDictionaryRef) item,
- kSecImportItemIdentity);
+ const CFTypeRef identity = CFDictionaryGetValue(
+ (CFDictionaryRef)item,
+ kSecImportItemIdentity);
CFRetain(identity);
- *out_cert_and_key = (SecIdentityRef) identity;
+ *out_cert_and_key = (SecIdentityRef)CURL_UNCONST(identity);
break;
}
#if CURL_BUILD_MAC_10_7
else if(itemID == SecCertificateGetTypeID()) {
status = SecIdentityCreateWithCertificate(NULL,
- (SecCertificateRef) item,
- out_cert_and_key);
+ (SecCertificateRef)CURL_UNCONST(item),
+ out_cert_and_key);
break;
}
#endif
@@ -927,7 +922,7 @@ static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
/* 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++) {
+ for(j = 0; j < CURL_ARRAYSIZE(default_ciphers); j++) {
if(default_ciphers[j] == ciphers[i]) {
ciphers[count++] = ciphers[i];
break;
@@ -1096,10 +1091,13 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
if(result != CURLE_OK)
return result;
+ if(connssl->alpn) {
#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, *)) {
+#else
+ if(&SSLSetALPNProtocols && &SSLCopyALPNProtocols) {
+#endif
struct alpn_proto_buf proto;
size_t i;
CFStringRef cstr;
@@ -1122,7 +1120,6 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
}
-#endif
if(ssl_config->key) {
infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
@@ -1338,8 +1335,9 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
size_t ssl_sessionid_len;
Curl_ssl_scache_lock(data);
- if(Curl_ssl_scache_get_obj(cf, data, connssl->peer.scache_key,
- (void **)&ssl_sessionid)) {
+ ssl_sessionid = Curl_ssl_scache_get_obj(cf, data,
+ connssl->peer.scache_key);
+ if(ssl_sessionid) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid,
strlen(ssl_sessionid));
@@ -1696,7 +1694,8 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
const char *pinnedpubkey)
{ /* Scratch */
size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24;
- unsigned char *pubkey = NULL, *realpubkey = NULL;
+ const unsigned char *pubkey = NULL;
+ unsigned char *realpubkey = NULL;
const unsigned char *spkiHeader = NULL;
CFDataRef publicKeyBits = NULL;
@@ -1746,7 +1745,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
pubkeylen = (size_t)CFDataGetLength(publicKeyBits);
- pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits);
+ pubkey = (const unsigned char *)CFDataGetBytePtr(publicKeyBits);
switch(pubkeylen) {
case 526:
@@ -2092,10 +2091,13 @@ check_handshake:
break;
}
+ if(connssl->alpn) {
#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, *)) {
+#else
+ if(&SSLSetALPNProtocols && &SSLCopyALPNProtocols) {
+#endif
CFArrayRef alpnArr = NULL;
CFStringRef chosenProtocol = NULL;
err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr);
@@ -2123,7 +2125,6 @@ check_handshake:
CFRelease(alpnArr);
}
}
-#endif
return CURLE_OK;
}
@@ -2131,7 +2132,7 @@ check_handshake:
static CURLcode
add_cert_to_certinfo(struct Curl_easy *data,
- SecCertificateRef server_cert,
+ const SecCertificateRef server_cert,
int idx)
{
CURLcode result = CURLE_OK;
@@ -2151,7 +2152,7 @@ add_cert_to_certinfo(struct Curl_easy *data,
static CURLcode
collect_server_cert_single(struct Curl_cfilter *cf, struct Curl_easy *data,
- SecCertificateRef server_cert,
+ const SecCertificateRef server_cert,
CFIndex idx)
{
CURLcode result = CURLE_OK;
@@ -2248,8 +2249,8 @@ static CURLcode collect_server_cert(struct Curl_cfilter *cf,
if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
- server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
- i);
+ const void *item = CFArrayGetValueAtIndex(server_certs, i);
+ server_cert = (SecCertificateRef)CURL_UNCONST(item);
result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(server_certs);
@@ -2265,7 +2266,8 @@ static CURLcode collect_server_cert(struct Curl_cfilter *cf,
if(ssl_config->certinfo)
result = Curl_ssl_init_certinfo(data, (int)count);
for(i = 0L ; !result && (i < count) ; i++) {
- server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
+ const void *item = CFArrayGetValueAtIndex(server_certs, i);
+ server_cert = (SecCertificateRef)CURL_UNCONST(item);
result = collect_server_cert_single(cf, data, server_cert, i);
}
CFRelease(server_certs);
@@ -2292,15 +2294,12 @@ static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
return CURLE_OK;
}
-static CURLcode
-sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
- bool nonblocking,
- bool *done)
+static CURLcode sectransp_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ 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) {
@@ -2308,73 +2307,20 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
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;
- }
+ *done = FALSE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ if(ssl_connect_1 == connssl->connecting_state) {
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;
- }
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- /* socket is readable or writable */
- }
-
- /* 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.
- */
+ if(ssl_connect_2 == connssl->connecting_state) {
result = sectransp_connect_step2(cf, data);
- if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(result)
return result;
-
- } /* repeat step2 until all transactions are done. */
-
+ }
if(ssl_connect_3 == connssl->connecting_state) {
result = sectransp_connect_step3(cf, data);
@@ -2387,34 +2333,6 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
connssl->state = ssl_connection_complete;
*done = TRUE;
}
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-static CURLcode sectransp_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return sectransp_connect_common(cf, data, TRUE, done);
-}
-
-static CURLcode sectransp_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = sectransp_connect_common(cf, data, FALSE, &done);
-
- if(result)
- return result;
-
- DEBUGASSERT(done);
return CURLE_OK;
}
@@ -2549,7 +2467,7 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
if(backend->ssl_ctx) { /* SSL is in use */
- CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
+ CURL_TRC_CF((struct Curl_easy *)CURL_UNCONST(data), cf, "data_pending");
err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
if(err == noErr)
return buffer > 0UL;
@@ -2759,7 +2677,6 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_random, /* random */
NULL, /* cert_status_request */
sectransp_connect, /* connect */
- sectransp_connect_nonblocking, /* connect_nonblocking */
Curl_ssl_adjust_pollset, /* adjust_pollset */
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c
index 182744bb6e..0247d77577 100644
--- a/libs/libcurl/src/vtls/vtls.c
+++ b/libs/libcurl/src/vtls/vtls.c
@@ -154,17 +154,19 @@ static const struct alpn_spec ALPN_SPEC_H2_H11 = {
};
#endif
-static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn)
+static const struct alpn_spec *
+alpn_get_spec(http_majors allowed, bool use_alpn)
{
if(!use_alpn)
return NULL;
#ifdef USE_HTTP2
- if(httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
+ if(allowed & CURL_HTTP_V2x) {
+ if(allowed & CURL_HTTP_V1x)
+ return &ALPN_SPEC_H2_H11;
return &ALPN_SPEC_H2;
- if(httpwant >= CURL_HTTP_VERSION_2)
- return &ALPN_SPEC_H2_H11;
+ }
#else
- (void)httpwant;
+ (void)allowed;
#endif
/* Use the ALPN protocol "http/1.1" for HTTP/1.x.
Avoid "http/1.0" because some servers do not support it. */
@@ -483,39 +485,6 @@ static void cf_ctx_free(struct ssl_connect_data *ctx)
}
}
-static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- CURLcode result;
-
- if(!ssl_prefs_check(data))
- return CURLE_SSL_CONNECT_ERROR;
-
- /* mark this is being ssl-enabled from here on. */
- connssl->state = ssl_connection_negotiating;
-
- result = connssl->ssl_impl->connect_blocking(cf, data);
-
- if(!result) {
- DEBUGASSERT(connssl->state == ssl_connection_complete);
- }
-
- return result;
-}
-
-static CURLcode
-ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data,
- bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
-
- if(!ssl_prefs_check(data))
- return CURLE_SSL_CONNECT_ERROR;
-
- /* mark this is being ssl requested from here on. */
- return connssl->ssl_impl->connect_nonblocking(cf, data, done);
-}
-
CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
struct dynbuf *binding)
{
@@ -921,20 +890,11 @@ static int multissl_init(void)
}
static CURLcode multissl_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- if(multissl_setup(NULL))
- return CURLE_FAILED_INIT;
- return Curl_ssl->connect_blocking(cf, data);
-}
-
-static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
+ struct Curl_easy *data, bool *done)
{
if(multissl_setup(NULL))
return CURLE_FAILED_INIT;
- return Curl_ssl->connect_nonblocking(cf, data, done);
+ return Curl_ssl->do_connect(cf, data, done);
}
static void multissl_adjust_pollset(struct Curl_cfilter *cf,
@@ -993,7 +953,6 @@ static const struct Curl_ssl Curl_ssl_multi = {
NULL, /* random */
NULL, /* cert_status_request */
multissl_connect, /* connect */
- multissl_connect_nonblocking, /* connect_nonblocking */
multissl_adjust_pollset, /* adjust_pollset */
multissl_get_internals, /* get_internals */
multissl_close, /* close_one */
@@ -1232,10 +1191,10 @@ static ssl_peer_type get_peer_type(const char *hostname)
#else
struct in_addr addr;
#endif
- if(Curl_inet_pton(AF_INET, hostname, &addr))
+ if(curlx_inet_pton(AF_INET, hostname, &addr))
return CURL_SSL_PEER_IPV4;
#ifdef USE_IPV6
- else if(Curl_inet_pton(AF_INET6, hostname, &addr)) {
+ else if(curlx_inet_pton(AF_INET6, hostname, &addr)) {
return CURL_SSL_PEER_IPV6;
}
#endif
@@ -1341,13 +1300,13 @@ static void ssl_cf_close(struct Curl_cfilter *cf,
static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
- bool blocking, bool *done)
+ bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
struct cf_call_data save;
CURLcode result;
- if(cf->connected) {
+ if(cf->connected && (connssl->state != ssl_connection_deferred)) {
*done = TRUE;
return CURLE_OK;
}
@@ -1358,15 +1317,13 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
}
if(!cf->next->connected) {
- result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+ result = cf->next->cft->do_connect(cf->next, data, done);
if(result || !*done)
return result;
}
CF_DATA_SAVE(save, cf, data);
CURL_TRC_CF(data, cf, "cf_connect()");
- DEBUGASSERT(data->conn);
- DEBUGASSERT(data->conn == cf->conn);
DEBUGASSERT(connssl);
*done = FALSE;
@@ -1378,14 +1335,14 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
goto out;
}
- if(blocking) {
- result = ssl_connect(cf, data);
- *done = (result == CURLE_OK);
- }
- else {
- result = ssl_connect_nonblocking(cf, data, done);
+ if(!connssl->prefs_checked) {
+ if(!ssl_prefs_check(data))
+ return CURLE_SSL_CONNECT_ERROR;
+ connssl->prefs_checked = TRUE;
}
+ result = connssl->ssl_impl->do_connect(cf, data, done);
+
if(!result && *done) {
cf->connected = TRUE;
if(connssl->state == ssl_connection_complete)
@@ -1393,6 +1350,8 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
/* Connection can be deferred when sending early data */
DEBUGASSERT(connssl->state == ssl_connection_complete ||
connssl->state == ssl_connection_deferred);
+ DEBUGASSERT(connssl->state != ssl_connection_deferred ||
+ connssl->earlydata_state > ssl_earlydata_none);
}
out:
CURL_TRC_CF(data, cf, "cf_connect() -> %d, done=%d", result, *done);
@@ -1400,6 +1359,77 @@ out:
return result;
}
+static CURLcode ssl_cf_set_earlydata(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *buf, size_t blen)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ ssize_t nwritten = 0;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_await);
+ DEBUGASSERT(Curl_bufq_is_empty(&connssl->earlydata));
+ if(blen) {
+ if(blen > connssl->earlydata_max)
+ blen = connssl->earlydata_max;
+ nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result);
+ CURL_TRC_CF(data, cf, "ssl_cf_set_earlydata(len=%zu) -> %zd",
+ blen, nwritten);
+ if(nwritten < 0)
+ return result;
+ }
+ return CURLE_OK;
+}
+
+static CURLcode ssl_cf_connect_deferred(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *buf, size_t blen,
+ bool *done)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(connssl->state == ssl_connection_deferred);
+ *done = FALSE;
+ if(connssl->earlydata_state == ssl_earlydata_await) {
+ result = ssl_cf_set_earlydata(cf, data, buf, blen);
+ if(result)
+ return result;
+ /* we buffered any early data we'd like to send. Actually
+ * do the connect now which sends it and performs the handshake. */
+ connssl->earlydata_state = ssl_earlydata_sending;
+ connssl->earlydata_skip = Curl_bufq_len(&connssl->earlydata);
+ }
+
+ result = ssl_cf_connect(cf, data, done);
+
+ if(!result && *done) {
+ Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done);
+ switch(connssl->earlydata_state) {
+ case ssl_earlydata_none:
+ break;
+ case ssl_earlydata_accepted:
+ if(!Curl_ssl_cf_is_proxy(cf))
+ Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
+ infof(data, "Server accepted %zu bytes of TLS early data.",
+ connssl->earlydata_skip);
+ break;
+ case ssl_earlydata_rejected:
+ if(!Curl_ssl_cf_is_proxy(cf))
+ Curl_pgrsEarlyData(data, -(curl_off_t)connssl->earlydata_skip);
+ infof(data, "Server rejected TLS early data.");
+ connssl->earlydata_skip = 0;
+ break;
+ default:
+ /* This should not happen. Either we do not use early data or we
+ * should know if it was accepted or not. */
+ DEBUGASSERT(NULL);
+ break;
+ }
+ }
+ return result;
+}
+
static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
@@ -1418,21 +1448,57 @@ static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
}
static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
- struct Curl_easy *data, const void *buf, size_t len,
+ struct Curl_easy *data,
+ const void *buf, size_t blen,
bool eos, CURLcode *err)
{
struct ssl_connect_data *connssl = cf->ctx;
struct cf_call_data save;
- ssize_t nwritten = 0;
+ ssize_t nwritten = 0, early_written = 0;
(void)eos;
- /* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
*err = CURLE_OK;
- if(len > 0) {
- CF_DATA_SAVE(save, cf, data);
- nwritten = connssl->ssl_impl->send_plain(cf, data, buf, len, err);
- CF_DATA_RESTORE(cf, save);
+ CF_DATA_SAVE(save, cf, data);
+
+ if(connssl->state == ssl_connection_deferred) {
+ bool done = FALSE;
+ *err = ssl_cf_connect_deferred(cf, data, buf, blen, &done);
+ if(*err) {
+ nwritten = -1;
+ goto out;
+ }
+ else if(!done) {
+ *err = CURLE_AGAIN;
+ nwritten = -1;
+ goto out;
+ }
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+ }
+
+ if(connssl->earlydata_skip) {
+ if(connssl->earlydata_skip >= blen) {
+ connssl->earlydata_skip -= blen;
+ *err = CURLE_OK;
+ nwritten = (ssize_t)blen;
+ goto out;
+ }
+ else {
+ early_written = connssl->earlydata_skip;
+ buf = ((const char *)buf) + connssl->earlydata_skip;
+ blen -= connssl->earlydata_skip;
+ connssl->earlydata_skip = 0;
+ }
}
+
+ /* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */
+ if(blen > 0)
+ nwritten = connssl->ssl_impl->send_plain(cf, data, buf, blen, err);
+
+ if(nwritten >= 0)
+ nwritten += early_written;
+
+out:
+ CF_DATA_RESTORE(cf, save);
return nwritten;
}
@@ -1446,6 +1512,21 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
CF_DATA_SAVE(save, cf, data);
*err = CURLE_OK;
+ if(connssl->state == ssl_connection_deferred) {
+ bool done = FALSE;
+ *err = ssl_cf_connect_deferred(cf, data, NULL, 0, &done);
+ if(*err) {
+ nread = -1;
+ goto out;
+ }
+ else if(!done) {
+ *err = CURLE_AGAIN;
+ nread = -1;
+ goto out;
+ }
+ DEBUGASSERT(connssl->state == ssl_connection_complete);
+ }
+
nread = connssl->ssl_impl->recv_plain(cf, data, buf, len, err);
if(nread > 0) {
DEBUGASSERT((size_t)nread <= len);
@@ -1454,6 +1535,8 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
/* eof */
*err = CURLE_OK;
}
+
+out:
CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
nread, *err);
CF_DATA_RESTORE(cf, save);
@@ -1468,7 +1551,9 @@ static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
CURLcode result = CURLE_OK;
*done = TRUE;
- if(!cf->shutdown && Curl_ssl->shut_down) {
+ /* If we have done the SSL handshake, shut down the connection cleanly */
+ if(cf->connected && (connssl->state == ssl_connection_complete) &&
+ !cf->shutdown && Curl_ssl->shut_down) {
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
@@ -1576,7 +1661,7 @@ static CURLcode cf_ssl_create(struct Curl_cfilter **pcf,
DEBUGASSERT(data->conn);
- ctx = cf_ctx_new(data, alpn_get_spec(data->state.httpwant,
+ ctx = cf_ctx_new(data, alpn_get_spec(data->state.http_neg.wanted,
conn->bits.tls_enable_alpn));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
@@ -1627,16 +1712,16 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf,
struct ssl_connect_data *ctx;
CURLcode result;
bool use_alpn = conn->bits.tls_enable_alpn;
- int httpwant = CURL_HTTP_VERSION_1_1;
+ http_majors allowed = CURL_HTTP_V1x;
#ifdef USE_HTTP2
if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) {
use_alpn = TRUE;
- httpwant = CURL_HTTP_VERSION_2;
+ allowed = (CURL_HTTP_V1x|CURL_HTTP_V2x);
}
#endif
- ctx = cf_ctx_new(data, alpn_get_spec(httpwant, use_alpn));
+ ctx = cf_ctx_new(data, alpn_get_spec(allowed, use_alpn));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -1768,7 +1853,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
if(cf->cft == &Curl_cft_ssl) {
bool done;
CURL_TRC_CF(data, cf, "shutdown and remove SSL, start");
- Curl_shutdown_start(data, sockindex, NULL);
+ Curl_shutdown_start(data, sockindex, 0, NULL);
result = vtls_shutdown_blocking(cf, data, send_shutdown, &done);
Curl_shutdown_clear(data, sockindex);
if(!result && !done) /* blocking failed? */
@@ -1866,6 +1951,24 @@ bool Curl_alpn_contains_proto(const struct alpn_spec *spec,
return FALSE;
}
+void Curl_alpn_restrict_to(struct alpn_spec *spec, const char *proto)
+{
+ size_t plen = strlen(proto);
+ DEBUGASSERT(plen < sizeof(spec->entries[0]));
+ if(plen < sizeof(spec->entries[0])) {
+ memcpy(spec->entries[0], proto, plen + 1);
+ spec->count = 1;
+ }
+}
+
+void Curl_alpn_copy(struct alpn_spec *dest, const struct alpn_spec *src)
+{
+ if(src)
+ memcpy(dest, src, sizeof(*dest));
+ else
+ memset(dest, 0, sizeof(*dest));
+}
+
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_connect_data *connssl,
diff --git a/libs/libcurl/src/vtls/vtls_int.h b/libs/libcurl/src/vtls/vtls_int.h
index bb37346396..59657883df 100644
--- a/libs/libcurl/src/vtls/vtls_int.h
+++ b/libs/libcurl/src/vtls/vtls_int.h
@@ -49,7 +49,7 @@ struct ssl_connect_data;
#define ALPN_PROTO_BUF_MAX (ALPN_ENTRIES_MAX * (ALPN_NAME_MAX + 1))
struct alpn_spec {
- const char entries[ALPN_ENTRIES_MAX][ALPN_NAME_MAX];
+ char entries[ALPN_ENTRIES_MAX][ALPN_NAME_MAX];
size_t count; /* number of entries */
};
@@ -62,6 +62,8 @@ CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf,
const struct alpn_spec *spec);
CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
const struct alpn_spec *spec);
+void Curl_alpn_restrict_to(struct alpn_spec *spec, const char *proto);
+void Curl_alpn_copy(struct alpn_spec *dest, const struct alpn_spec *src);
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -89,7 +91,7 @@ typedef enum {
typedef enum {
ssl_earlydata_none,
- ssl_earlydata_use,
+ ssl_earlydata_await,
ssl_earlydata_sending,
ssl_earlydata_sent,
ssl_earlydata_accepted,
@@ -124,6 +126,7 @@ struct ssl_connect_data {
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 */
+ BIT(prefs_checked); /* SSL preferences have been checked */
};
@@ -157,11 +160,8 @@ struct Curl_ssl {
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);
+ CURLcode (*do_connect)(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. */
diff --git a/libs/libcurl/src/vtls/vtls_scache.c b/libs/libcurl/src/vtls/vtls_scache.c
index c78ef7e9a8..d06c6cf9f9 100644
--- a/libs/libcurl/src/vtls/vtls_scache.c
+++ b/libs/libcurl/src/vtls/vtls_scache.c
@@ -59,6 +59,9 @@
#include "curl_memory.h"
#include "memdebug.h"
+
+static bool cf_ssl_peer_key_is_global(const char *peer_key);
+
/* a peer+tls-config we cache sessions for */
struct Curl_ssl_scache_peer {
char *ssl_peer_key; /* id for peer + relevant TLS configuration */
@@ -73,6 +76,7 @@ struct Curl_ssl_scache_peer {
size_t max_sessions;
long age; /* just a number, the higher the more recent */
BIT(hmac_set); /* if key_salt and key_hmac are present */
+ BIT(exportable); /* sessions for this peer can be exported */
};
#define CURL_SCACHE_MAGIC 0x000e1551
@@ -104,32 +108,18 @@ static struct Curl_ssl_scache *cf_ssl_scache_get(struct Curl_easy *data)
return scache;
}
-static void cf_ssl_scache_clear_session(struct Curl_ssl_session *s)
-{
- if(s->sdata) {
- free((void *)s->sdata);
- s->sdata = NULL;
- }
- s->sdata_len = 0;
- if(s->quic_tp) {
- free((void *)s->quic_tp);
- s->quic_tp = NULL;
- }
- s->quic_tp_len = 0;
- s->ietf_tls_id = 0;
- s->valid_until = 0;
- Curl_safefree(s->alpn);
-}
-
-static void cf_ssl_scache_sesssion_ldestroy(void *udata, void *s)
+static void cf_ssl_scache_sesssion_ldestroy(void *udata, void *obj)
{
+ struct Curl_ssl_session *s = obj;
(void)udata;
- cf_ssl_scache_clear_session(s);
+ free(CURL_UNCONST(s->sdata));
+ free(CURL_UNCONST(s->quic_tp));
+ free((void *)s->alpn);
free(s);
}
CURLcode
-Curl_ssl_session_create(unsigned char *sdata, size_t sdata_len,
+Curl_ssl_session_create(void *sdata, size_t sdata_len,
int ietf_tls_id, const char *alpn,
curl_off_t valid_until, size_t earlydata_max,
struct Curl_ssl_session **psession)
@@ -140,7 +130,7 @@ Curl_ssl_session_create(unsigned char *sdata, size_t sdata_len,
}
CURLcode
-Curl_ssl_session_create2(unsigned char *sdata, size_t sdata_len,
+Curl_ssl_session_create2(void *sdata, size_t sdata_len,
int ietf_tls_id, const char *alpn,
curl_off_t valid_until, size_t earlydata_max,
unsigned char *quic_tp, size_t quic_tp_len,
@@ -223,6 +213,19 @@ static void cf_ssl_scache_peer_set_obj(struct Curl_ssl_scache_peer *peer,
peer->sobj_free = sobj_free;
}
+static void cf_ssl_cache_peer_update(struct Curl_ssl_scache_peer *peer)
+{
+ /* The sessions of this peer are exportable if
+ * - it has no confidential information
+ * - its peer key is not yet known, because sessions were
+ * imported using only the salt+hmac
+ * - the peer key is global, e.g. carrying no relative paths */
+ peer->exportable = (!peer->clientcert && !peer->srp_username &&
+ !peer->srp_password &&
+ (!peer->ssl_peer_key ||
+ cf_ssl_peer_key_is_global(peer->ssl_peer_key)));
+}
+
static CURLcode
cf_ssl_scache_peer_init(struct Curl_ssl_scache_peer *peer,
const char *ssl_peer_key,
@@ -265,6 +268,8 @@ cf_ssl_scache_peer_init(struct Curl_ssl_scache_peer *peer,
if(!peer->srp_password)
goto out;
}
+
+ cf_ssl_cache_peer_update(peer);
result = CURLE_OK;
out:
if(result)
@@ -372,17 +377,22 @@ void Curl_ssl_scache_unlock(struct Curl_easy *data)
static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf,
const char *name,
- char *path)
+ char *path,
+ bool *is_local)
{
if(path && path[0]) {
/* We try to add absolute paths, so that the session key can stay
* valid when used in another process with different CWD. However,
* when a path does not exist, this does not work. Then, we add
* the path as is. */
-#ifdef _WIN32
+#ifdef UNDER_CE
+ (void)is_local;
+ return Curl_dyn_addf(buf, ":%s-%s", name, path);
+#elif defined(_WIN32)
char abspath[_MAX_PATH];
if(_fullpath(abspath, path, _MAX_PATH))
return Curl_dyn_addf(buf, ":%s-%s", name, abspath);
+ *is_local = TRUE;
#elif defined(HAVE_REALPATH)
if(path[0] != '/') {
char *abspath = realpath(path, NULL);
@@ -391,6 +401,7 @@ static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf,
(free)(abspath); /* allocated by libc, free without memdebug */
return r;
}
+ *is_local = TRUE;
}
#endif
return Curl_dyn_addf(buf, ":%s-%s", name, path);
@@ -423,6 +434,17 @@ out:
return r;
}
+#define CURL_SSLS_LOCAL_SUFFIX ":L"
+#define CURL_SSLS_GLOBAL_SUFFIX ":G"
+
+static bool cf_ssl_peer_key_is_global(const char *peer_key)
+{
+ size_t len = peer_key ? strlen(peer_key) : 0;
+ return (len > 2) &&
+ (peer_key[len - 1] == 'G') &&
+ (peer_key[len - 2] == ':');
+}
+
CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
const struct ssl_peer *peer,
const char *tls_id,
@@ -431,6 +453,7 @@ CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
struct ssl_primary_config *ssl = Curl_ssl_cf_get_primary_config(cf);
struct dynbuf buf;
size_t key_len;
+ bool is_local = FALSE;
CURLcode r;
*ppeer_key = NULL;
@@ -514,16 +537,16 @@ CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
goto out;
}
if(ssl->verifypeer) {
- r = cf_ssl_peer_key_add_path(&buf, "CA", ssl->CAfile);
+ r = cf_ssl_peer_key_add_path(&buf, "CA", ssl->CAfile, &is_local);
if(r)
goto out;
- r = cf_ssl_peer_key_add_path(&buf, "CApath", ssl->CApath);
+ r = cf_ssl_peer_key_add_path(&buf, "CApath", ssl->CApath, &is_local);
if(r)
goto out;
- r = cf_ssl_peer_key_add_path(&buf, "CRL", ssl->CRLfile);
+ r = cf_ssl_peer_key_add_path(&buf, "CRL", ssl->CRLfile, &is_local);
if(r)
goto out;
- r = cf_ssl_peer_key_add_path(&buf, "Issuer", ssl->issuercert);
+ r = cf_ssl_peer_key_add_path(&buf, "Issuer", ssl->issuercert, &is_local);
if(r)
goto out;
if(ssl->cert_blob) {
@@ -569,6 +592,11 @@ CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
if(r)
goto out;
+ r = Curl_dyn_addf(&buf, is_local ?
+ CURL_SSLS_LOCAL_SUFFIX : CURL_SSLS_GLOBAL_SUFFIX);
+ if(r)
+ goto out;
+
*ppeer_key = Curl_dyn_take(&buf, &key_len);
/* we just added printable char, and dynbuf always 0 terminates,
* no need to track length */
@@ -655,6 +683,7 @@ cf_ssl_find_peer_by_key(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+ cf_ssl_cache_peer_update(&scache->peers[i]);
*ppeer = &scache->peers[i];
goto out;
}
@@ -832,10 +861,6 @@ CURLcode Curl_ssl_scache_put(struct Curl_cfilter *cf,
Curl_ssl_session_destroy(s);
return CURLE_OK;
}
- if(!GOOD_SCACHE(scache)) {
- Curl_ssl_session_destroy(s);
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
Curl_ssl_scache_lock(data);
result = cf_scache_add_session(cf, data, scache, ssl_peer_key, s);
@@ -933,31 +958,29 @@ out:
return result;
}
-bool Curl_ssl_scache_get_obj(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const char *ssl_peer_key,
- void **sobj)
+void *Curl_ssl_scache_get_obj(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const char *ssl_peer_key)
{
struct Curl_ssl_scache *scache = cf_ssl_scache_get(data);
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_ssl_scache_peer *peer = NULL;
CURLcode result;
+ void *sobj;
- *sobj = NULL;
if(!scache)
- return FALSE;
+ return NULL;
result = cf_ssl_find_peer_by_key(data, scache, ssl_peer_key, conn_config,
&peer);
if(result)
- return FALSE;
+ return NULL;
- if(peer)
- *sobj = peer->sobj;
+ sobj = peer ? peer->sobj : NULL;
CURL_TRC_SSLS(data, "%s cached session for '%s'",
- *sobj ? "Found" : "No", ssl_peer_key);
- return !!*sobj;
+ sobj ? "Found" : "No", ssl_peer_key);
+ return sobj;
}
void Curl_ssl_scache_remove_all(struct Curl_cfilter *cf,
@@ -1062,7 +1085,7 @@ out:
CURLcode Curl_ssl_session_import(struct Curl_easy *data,
const char *ssl_peer_key,
const unsigned char *shmac, size_t shmac_len,
- const unsigned char *sdata, size_t sdata_len)
+ const void *sdata, size_t sdata_len)
{
struct Curl_ssl_scache *scache = cf_ssl_scache_get(data);
struct Curl_ssl_scache_peer *peer = NULL;
@@ -1157,8 +1180,8 @@ CURLcode Curl_ssl_session_export(struct Curl_easy *data,
peer = &scache->peers[i];
if(!peer->ssl_peer_key && !peer->hmac_set)
continue; /* skip free entry */
- if(peer->clientcert || peer->srp_username || peer->srp_password)
- continue; /* not exporting those */
+ if(!peer->exportable)
+ continue;
Curl_dyn_reset(&hbuf);
cf_scache_peer_remove_expired(peer, now);
diff --git a/libs/libcurl/src/vtls/vtls_scache.h b/libs/libcurl/src/vtls/vtls_scache.h
index e9b5b76e36..3dea24024d 100644
--- a/libs/libcurl/src/vtls/vtls_scache.h
+++ b/libs/libcurl/src/vtls/vtls_scache.h
@@ -85,12 +85,11 @@ void Curl_ssl_scache_unlock(struct Curl_easy *data);
* @param cf the connection filter wanting to use it
* @param data the transfer involved
* @param ssl_peer_key the key for lookup
- * @param sobj on return, the object for the peer key or NULL
+ * @retval sobj the object for the peer key or NULL
*/
-bool Curl_ssl_scache_get_obj(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const char *ssl_peer_key,
- void **sobj);
+void *Curl_ssl_scache_get_obj(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const char *ssl_peer_key);
typedef void Curl_ssl_scache_obj_dtor(void *sobj);
@@ -116,7 +115,7 @@ CURLcode Curl_ssl_scache_add_obj(struct Curl_cfilter *cf,
/* All about a SSL session ticket */
struct Curl_ssl_session {
- const unsigned char *sdata; /* session ticket data, plain bytes */
+ const void *sdata; /* session ticket data, plain bytes */
size_t sdata_len; /* number of bytes in sdata */
curl_off_t valid_until; /* seconds since EPOCH until ticket expires */
int ietf_tls_id; /* TLS protocol identifier negotiated */
@@ -138,7 +137,7 @@ struct Curl_ssl_session {
* @param psession on return the scached session instance created
*/
CURLcode
-Curl_ssl_session_create(unsigned char *sdata, size_t sdata_len,
+Curl_ssl_session_create(void *sdata, size_t sdata_len,
int ietf_tls_id, const char *alpn,
curl_off_t valid_until,
size_t earlydata_max,
@@ -147,7 +146,7 @@ Curl_ssl_session_create(unsigned char *sdata, size_t sdata_len,
/* Variation of session creation with quic transport parameter bytes,
* Takes ownership of `quic_tp` regardless of return code. */
CURLcode
-Curl_ssl_session_create2(unsigned char *sdata, size_t sdata_len,
+Curl_ssl_session_create2(void *sdata, size_t sdata_len,
int ietf_tls_id, const char *alpn,
curl_off_t valid_until,
size_t earlydata_max,
@@ -200,7 +199,7 @@ void Curl_ssl_scache_remove_all(struct Curl_cfilter *cf,
CURLcode Curl_ssl_session_import(struct Curl_easy *data,
const char *ssl_peer_key,
const unsigned char *shmac, size_t shmac_len,
- const unsigned char *sdata, size_t sdata_len);
+ const void *sdata, size_t sdata_len);
CURLcode Curl_ssl_session_export(struct Curl_easy *data,
curl_ssls_export_cb *export_fn,
diff --git a/libs/libcurl/src/vtls/vtls_spack.c b/libs/libcurl/src/vtls/vtls_spack.c
index 22c84e8a38..b1bca85dbc 100644
--- a/libs/libcurl/src/vtls/vtls_spack.c
+++ b/libs/libcurl/src/vtls/vtls_spack.c
@@ -254,10 +254,11 @@ CURLcode Curl_ssl_session_pack(struct Curl_easy *data,
}
CURLcode Curl_ssl_session_unpack(struct Curl_easy *data,
- const unsigned char *buf, size_t buflen,
+ const void *bufv, size_t buflen,
struct Curl_ssl_session **ps)
{
struct Curl_ssl_session *s = NULL;
+ const unsigned char *buf = (const unsigned char *)bufv;
const unsigned char *end = buf + buflen;
uint8_t val8, *pval8;
uint16_t val16;
diff --git a/libs/libcurl/src/vtls/vtls_spack.h b/libs/libcurl/src/vtls/vtls_spack.h
index ec48853e4c..62f9da6944 100644
--- a/libs/libcurl/src/vtls/vtls_spack.h
+++ b/libs/libcurl/src/vtls/vtls_spack.h
@@ -35,7 +35,7 @@ CURLcode Curl_ssl_session_pack(struct Curl_easy *data,
struct dynbuf *buf);
CURLcode Curl_ssl_session_unpack(struct Curl_easy *data,
- const unsigned char *buf, size_t buflen,
+ const void *bufv, size_t buflen,
struct Curl_ssl_session **ps);
#endif /* USE_SSLS_EXPORT */
diff --git a/libs/libcurl/src/vtls/wolfssl.c b/libs/libcurl/src/vtls/wolfssl.c
index edd60e3e1a..3cd67a2fe5 100644
--- a/libs/libcurl/src/vtls/wolfssl.c
+++ b/libs/libcurl/src/vtls/wolfssl.c
@@ -36,6 +36,7 @@
#include <wolfssl/options.h>
#include <wolfssl/version.h>
+
#if LIBWOLFSSL_VERSION_HEX < 0x03004006 /* wolfSSL 3.4.6 (2015) */
#error "wolfSSL version should be at least 3.4.6"
#endif
@@ -64,8 +65,10 @@
#include "keylog.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
+#include "progress.h"
#include "select.h"
#include "strcase.h"
+#include "strdup.h"
#include "x509asn1.h"
#include "curl_printf.h"
#include "multiif.h"
@@ -115,6 +118,10 @@
#undef USE_BIO_CHAIN
#endif
+static CURLcode wssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done);
+
#ifdef OPENSSL_EXTRA
/*
* Availability note:
@@ -122,13 +129,13 @@
* 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
+ * wolfSSL_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
-wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
- int secretSz, void *ctx)
+wssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
+ int secretSz, void *ctx)
{
const char *label;
unsigned char client_random[SSL3_RANDOM_SIZE];
@@ -164,7 +171,7 @@ wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
return 0;
}
- if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
+ if(wolfSSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
/* Should never happen as wolfSSL_KeepArrays() was called before. */
return 0;
}
@@ -174,8 +181,7 @@ wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
}
#endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
-static void
-wolfssl_log_tls12_secret(WOLFSSL *ssl)
+static void wssl_log_tls12_secret(WOLFSSL *ssl)
{
unsigned char *ms, *sr, *cr;
unsigned int msLen, srLen, crLen, i, x = 0;
@@ -217,7 +223,7 @@ wolfssl_log_tls12_secret(WOLFSSL *ssl)
}
#endif /* OPENSSL_EXTRA */
-static int wolfssl_do_file_type(const char *type)
+static int wssl_do_file_type(const char *type)
{
if(!type || !type[0])
return WOLFSSL_FILETYPE_PEM;
@@ -235,19 +241,19 @@ struct group_name_map {
};
static const struct group_name_map gnm[] = {
- { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" },
- { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" },
- { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" },
- { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" },
- { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" },
- { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" },
+ { WOLFSSL_ML_KEM_512, "ML_KEM_512" },
+ { WOLFSSL_ML_KEM_768, "ML_KEM_768" },
+ { WOLFSSL_ML_KEM_1024, "ML_KEM_1024" },
+ { WOLFSSL_P256_ML_KEM_512, "P256_ML_KEM_512" },
+ { WOLFSSL_P384_ML_KEM_768, "P384_ML_KEM_768" },
+ { WOLFSSL_P521_ML_KEM_1024, "P521_ML_KEM_1024" },
{ 0, NULL }
};
#endif
#ifdef USE_BIO_CHAIN
-static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
+static int wssl_bio_cf_create(WOLFSSL_BIO *bio)
{
#ifdef USE_FULL_BIO
wolfSSL_BIO_set_shutdown(bio, 1);
@@ -256,14 +262,14 @@ static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
return 1;
}
-static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio)
+static int wssl_bio_cf_destroy(WOLFSSL_BIO *bio)
{
if(!bio)
return 0;
return 1;
}
-static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
+static long wssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
long ret = 1;
@@ -304,30 +310,29 @@ static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
return ret;
}
-static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
- const char *buf, int blen)
+static int wssl_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 wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten, skiplen = 0;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- if(backend->shutting_down && backend->io_send_blocked_len &&
- (backend->io_send_blocked_len < blen)) {
+ if(wssl->shutting_down && wssl->io_send_blocked_len &&
+ (wssl->io_send_blocked_len < blen)) {
/* bug in wolfSSL: <https://github.com/wolfSSL/wolfssl/issues/7784>
* It adds the close notify message again every time we retry
* sending during shutdown. */
CURL_TRC_CF(data, cf, "bio_write, shutdown restrict send of %d"
- " to %d bytes", blen, backend->io_send_blocked_len);
- skiplen = (ssize_t)(blen - backend->io_send_blocked_len);
- blen = backend->io_send_blocked_len;
+ " to %d bytes", blen, wssl->io_send_blocked_len);
+ skiplen = (ssize_t)(blen - wssl->io_send_blocked_len);
+ blen = wssl->io_send_blocked_len;
}
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
- backend->io_result = result;
+ wssl->io_result = result;
CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
blen, nwritten, result);
#ifdef USE_FULL_BIO
@@ -335,20 +340,19 @@ static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
#endif
if(nwritten < 0 && CURLE_AGAIN == result) {
wolfSSL_BIO_set_retry_write(bio);
- if(backend->shutting_down && !backend->io_send_blocked_len)
- backend->io_send_blocked_len = blen;
+ if(wssl->shutting_down && !wssl->io_send_blocked_len)
+ wssl->io_send_blocked_len = blen;
}
else if(!result && skiplen)
nwritten += skiplen;
return (int)nwritten;
}
-static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
+static int wssl_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 wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result = CURLE_OK;
@@ -358,8 +362,20 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
if(!buf)
return 0;
+ if((connssl->connecting_state == ssl_connect_2) &&
+ !wssl->x509_store_setup) {
+ /* During handshake, init the x509 store before receiving the
+ * server response. This allows sending of ClientHello without delay. */
+ result = Curl_wssl_setup_x509_store(cf, data, wssl);
+ if(result) {
+ CURL_TRC_CF(data, cf, "Curl_wssl_setup_x509_store() -> %d", result);
+ wssl->io_result = result;
+ return -1;
+ }
+ }
+
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
- backend->io_result = result;
+ wssl->io_result = result;
CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result);
#ifdef USE_FULL_BIO
wolfSSL_BIO_clear_retry_flags(bio);
@@ -371,28 +387,28 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
return (int)nread;
}
-static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL;
+static WOLFSSL_BIO_METHOD *wssl_bio_cf_method = NULL;
-static void wolfssl_bio_cf_init_methods(void)
+static void wssl_bio_cf_init_methods(void)
{
- wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(WOLFSSL_BIO_MEMORY,
+ wssl_bio_cf_method = wolfSSL_BIO_meth_new(WOLFSSL_BIO_MEMORY,
"wolfSSL CF BIO");
- wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write);
- wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read);
- wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl);
- wolfSSL_BIO_meth_set_create(wolfssl_bio_cf_method, &wolfssl_bio_cf_create);
- wolfSSL_BIO_meth_set_destroy(wolfssl_bio_cf_method, &wolfssl_bio_cf_destroy);
+ wolfSSL_BIO_meth_set_write(wssl_bio_cf_method, &wssl_bio_cf_out_write);
+ wolfSSL_BIO_meth_set_read(wssl_bio_cf_method, &wssl_bio_cf_in_read);
+ wolfSSL_BIO_meth_set_ctrl(wssl_bio_cf_method, &wssl_bio_cf_ctrl);
+ wolfSSL_BIO_meth_set_create(wssl_bio_cf_method, &wssl_bio_cf_create);
+ wolfSSL_BIO_meth_set_destroy(wssl_bio_cf_method, &wssl_bio_cf_destroy);
}
-static void wolfssl_bio_cf_free_methods(void)
+static void wssl_bio_cf_free_methods(void)
{
- wolfSSL_BIO_meth_free(wolfssl_bio_cf_method);
+ wolfSSL_BIO_meth_free(wssl_bio_cf_method);
}
#else /* USE_BIO_CHAIN */
-#define wolfssl_bio_cf_init_methods() Curl_nop_stmt
-#define wolfssl_bio_cf_free_methods() Curl_nop_stmt
+#define wssl_bio_cf_init_methods() Curl_nop_stmt
+#define wssl_bio_cf_free_methods() Curl_nop_stmt
#endif /* !USE_BIO_CHAIN */
@@ -401,12 +417,15 @@ CURLcode Curl_wssl_cache_session(struct Curl_cfilter *cf,
const char *ssl_peer_key,
WOLFSSL_SESSION *session,
int ietf_tls_id,
- const char *alpn)
+ const char *alpn,
+ unsigned char *quic_tp,
+ size_t quic_tp_len)
{
CURLcode result = CURLE_OK;
struct Curl_ssl_session *sc_session = NULL;
- unsigned char *sdata = NULL;
+ unsigned char *sdata = NULL, *qtp_clone = NULL;
unsigned int sdata_len;
+ unsigned int earlydata_max = 0;
if(!session)
goto out;
@@ -429,12 +448,23 @@ CURLcode Curl_wssl_cache_session(struct Curl_cfilter *cf,
result = CURLE_FAILED_INIT;
goto out;
}
+ if(quic_tp && quic_tp_len) {
+ qtp_clone = Curl_memdup0((char *)quic_tp, quic_tp_len);
+ if(!qtp_clone) {
+ free(sdata);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+#ifdef WOLFSSL_EARLY_DATA
+ earlydata_max = wolfSSL_SESSION_get_max_early_data(session);
+#endif
- result = Curl_ssl_session_create(sdata, sdata_len,
- ietf_tls_id, alpn,
- (curl_off_t)time(NULL) +
- wolfSSL_SESSION_get_timeout(session), 0,
- &sc_session);
+ result = Curl_ssl_session_create2(sdata, sdata_len,
+ ietf_tls_id, alpn,
+ (curl_off_t)time(NULL) +
+ wolfSSL_SESSION_get_timeout(session),
+ earlydata_max, qtp_clone, quic_tp_len,
+ &sc_session);
sdata = NULL; /* took ownership of sdata */
if(!result) {
result = Curl_ssl_scache_put(cf, data, ssl_peer_key, sc_session);
@@ -460,51 +490,112 @@ static int wssl_vtls_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
if(connssl && data) {
(void)Curl_wssl_cache_session(cf, data, connssl->peer.scache_key,
session, wolfSSL_version(ssl),
- connssl->negotiated.alpn);
+ connssl->negotiated.alpn, NULL, 0);
}
}
return 0;
}
-CURLcode Curl_wssl_setup_session(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct wolfssl_ctx *wss,
- const char *ssl_peer_key)
+static CURLcode wssl_on_session_reuse(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct alpn_spec *alpns,
+ struct Curl_ssl_session *scs,
+ bool *do_early_data)
{
- struct Curl_ssl_session *sc_session = NULL;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
+
+ *do_early_data = FALSE;
+#ifdef WOLFSSL_EARLY_DATA
+ connssl->earlydata_max = wolfSSL_SESSION_get_max_early_data(
+ wolfSSL_get_session(wssl->ssl));
+#else
+ (void)wssl;
+ connssl->earlydata_max = 0;
+#endif
+
+ if(!connssl->earlydata_max) {
+ /* Seems to be GnuTLS way to signal no EarlyData in session */
+ CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
+ }
+ else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
+ CURL_TRC_CF(data, cf, "SSL session has different ALPN, no early data");
+ }
+ else {
+ infof(data, "SSL session allows %zu bytes of early data, "
+ "reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
+ connssl->earlydata_state = ssl_earlydata_await;
+ connssl->state = ssl_connection_deferred;
+ result = Curl_alpn_set_negotiated(cf, data, connssl,
+ (const unsigned char *)scs->alpn,
+ scs->alpn ? strlen(scs->alpn) : 0);
+ *do_early_data = !result;
+ }
+ return result;
+}
+
+static CURLcode
+wssl_setup_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct wssl_ctx *wss,
+ struct alpn_spec *alpns,
+ const char *ssl_peer_key,
+ Curl_wssl_init_session_reuse_cb *sess_reuse_cb)
+{
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct Curl_ssl_session *scs = NULL;
CURLcode result;
- result = Curl_ssl_scache_take(cf, data, ssl_peer_key, &sc_session);
- if(!result && sc_session && sc_session->sdata && sc_session->sdata_len) {
+ result = Curl_ssl_scache_take(cf, data, ssl_peer_key, &scs);
+ if(!result && scs && scs->sdata && scs->sdata_len &&
+ (!scs->alpn || Curl_alpn_contains_proto(alpns, scs->alpn))) {
WOLFSSL_SESSION *session;
/* wolfSSL changes the passed pointer for whatever reasons, yikes */
- const unsigned char *sdata = sc_session->sdata;
- session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata,
- (long)sc_session->sdata_len);
+ const unsigned char *sdata = scs->sdata;
+ session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata, (long)scs->sdata_len);
if(session) {
- int ret = wolfSSL_set_session(wss->handle, session);
+ int ret = wolfSSL_set_session(wss->ssl, session);
if(ret != WOLFSSL_SUCCESS) {
- Curl_ssl_session_destroy(sc_session);
- sc_session = NULL;
+ Curl_ssl_session_destroy(scs);
+ scs = NULL;
infof(data, "cached session not accepted (%d), "
"removing from cache", ret);
}
- else
- infof(data, "SSL reusing session ID");
+ else {
+ infof(data, "SSL reusing session with ALPN '%s'",
+ scs->alpn ? scs->alpn : "-");
+ if(ssl_config->earlydata &&
+ !cf->conn->connect_only &&
+ !strcmp("TLSv1.3", wolfSSL_get_version(wss->ssl))) {
+ bool do_early_data = FALSE;
+ if(sess_reuse_cb) {
+ result = sess_reuse_cb(cf, data, alpns, scs, &do_early_data);
+ if(result)
+ goto out;
+ }
+ if(do_early_data) {
+ /* We only try the ALPN protocol the session used before,
+ * otherwise we might send early data for the wrong protocol */
+ Curl_alpn_restrict_to(alpns, scs->alpn);
+ }
+ }
+ }
wolfSSL_SESSION_free(session);
}
else {
failf(data, "could not decode previous session");
}
}
- Curl_ssl_scache_return(cf, data, ssl_peer_key, sc_session);
+out:
+ Curl_ssl_scache_return(cf, data, ssl_peer_key, scs);
return result;
}
static CURLcode wssl_populate_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
WOLFSSL_X509_STORE *store,
- struct wolfssl_ctx *wssl)
+ struct wssl_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;
@@ -514,38 +605,41 @@ static CURLcode wssl_populate_x509_store(struct Curl_cfilter *cf,
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;
+ bool imported_ca_info_blob = FALSE;
-#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
+ /* We do not want to do this again, no matter the outcome */
+ wssl->x509_store_setup = TRUE;
+
+#ifndef NO_FILESYSTEM
/* load native CA certificates */
if(ssl_config->native_ca_store) {
- if(wolfSSL_CTX_load_system_CA_certs(wssl->ctx) != WOLFSSL_SUCCESS) {
+#ifdef WOLFSSL_SYS_CA_CERTS
+ if(wolfSSL_CTX_load_system_CA_certs(wssl->ssl_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;
}
+#else
+ infof(data, "ignoring native CA option because wolfSSL was built without "
+ "native CA support");
+#endif
}
#endif /* !NO_FILESYSTEM */
/* load certificate blob */
if(ca_info_blob) {
- if(wolfSSL_CTX_load_verify_buffer(wssl->ctx, ca_info_blob->data,
+ if(wolfSSL_CTX_load_verify_buffer(wssl->ssl_ctx, ca_info_blob->data,
(long)ca_info_blob->len,
WOLFSSL_FILETYPE_PEM) !=
WOLFSSL_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;
- }
+ 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");
- wssl->x509_store_setup = TRUE;
}
}
@@ -557,14 +651,15 @@ static CURLcode wssl_populate_x509_store(struct Curl_cfilter *cf,
if(!store)
return CURLE_OUT_OF_MEMORY;
- if((ssl_cafile || ssl_capath) && (!wssl->x509_store_setup)) {
+ if(ssl_cafile || ssl_capath) {
int rc =
- wolfSSL_CTX_load_verify_locations_ex(wssl->ctx,
+ wolfSSL_CTX_load_verify_locations_ex(wssl->ssl_ctx,
ssl_cafile,
ssl_capath,
WOLFSSL_LOAD_FLAG_IGNORE_ERR);
if(WOLFSSL_SUCCESS != rc) {
- if(conn_config->verifypeer) {
+ if(conn_config->verifypeer &&
+ !imported_native_ca && !imported_ca_info_blob) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:"
" CAfile: %s CApath: %s",
@@ -588,7 +683,6 @@ static CURLcode wssl_populate_x509_store(struct Curl_cfilter *cf,
}
#endif
(void)store;
- wssl->x509_store_setup = TRUE;
return CURLE_OK;
}
@@ -650,7 +744,7 @@ static WOLFSSL_X509_STORE *wssl_get_cached_x509_store(struct Curl_cfilter *cf,
DEBUGASSERT(multi);
share = multi ? Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_WSSL_X509_KEY),
sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
if(share && share->store &&
!wssl_cached_x509_store_expired(data, share) &&
@@ -673,7 +767,7 @@ static void wssl_set_cached_x509_store(struct Curl_cfilter *cf,
if(!multi)
return;
share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_WSSL_X509_KEY),
sizeof(MPROTO_WSSL_X509_KEY)-1);
if(!share) {
@@ -681,7 +775,7 @@ static void wssl_set_cached_x509_store(struct Curl_cfilter *cf,
if(!share)
return;
if(!Curl_hash_add2(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_WSSL_X509_KEY),
sizeof(MPROTO_WSSL_X509_KEY)-1,
share, wssl_x509_share_free)) {
free(share);
@@ -713,7 +807,7 @@ static void wssl_set_cached_x509_store(struct Curl_cfilter *cf,
CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct wolfssl_ctx *wssl)
+ struct wssl_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);
@@ -733,11 +827,12 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
cached_store = cache_criteria_met ? wssl_get_cached_x509_store(cf, data)
: NULL;
- if(cached_store && wolfSSL_CTX_get_cert_store(wssl->ctx) == cached_store) {
+ if(cached_store &&
+ wolfSSL_CTX_get_cert_store(wssl->ssl_ctx) == cached_store) {
/* The cached store is already in use, do nothing. */
}
else if(cached_store && wolfSSL_X509_STORE_up_ref(cached_store)) {
- wolfSSL_CTX_set_cert_store(wssl->ctx, cached_store);
+ wolfSSL_CTX_set_cert_store(wssl->ssl_ctx, cached_store);
}
else if(cache_criteria_met) {
/* wolfSSL's initial store in CTX is not shareable by default.
@@ -747,7 +842,7 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
failf(data, "SSL: could not create a X509 store");
return CURLE_OUT_OF_MEMORY;
}
- wolfSSL_CTX_set_cert_store(wssl->ctx, store);
+ wolfSSL_CTX_set_cert_store(wssl->ssl_ctx, store);
result = wssl_populate_x509_store(cf, data, store, wssl);
if(!result) {
@@ -756,7 +851,7 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
}
else {
/* We never share the CTX's store, use it. */
- WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
+ WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ssl_ctx);
result = wssl_populate_x509_store(cf, data, store, wssl);
}
@@ -831,30 +926,49 @@ wssl_legacy_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version)
#define wolfSSL_CTX_set_max_proto_version wssl_legacy_CTX_set_max_proto_version
#endif
-/*
- * 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)
+#define QUIC_CIPHERS \
+ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
+ "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
+#define QUIC_GROUPS "P-256:P-384:P-521"
+
+#if defined(HAVE_SECRET_CALLBACK)
+static void keylog_callback(const WOLFSSL *ssl, const char *line)
{
+ (void)ssl;
+ Curl_tls_keylog_write_line(line);
+}
+#endif
+
+CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const struct alpn_spec *alpns_requested,
+ Curl_wssl_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ void *ssl_user_data,
+ Curl_wssl_init_session_reuse_cb *sess_reuse_cb)
+{
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_primary_config *conn_config;
+ WOLFSSL_METHOD* req_method = NULL;
+ struct alpn_spec alpns;
int res;
char *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 WOLFSSL_HAVE_KYBER
word16 pqkem = 0;
size_t idx = 0;
#endif
+ CURLcode result = CURLE_FAILED_INIT;
- DEBUGASSERT(backend);
-
- if(connssl->state == ssl_connection_complete)
- return CURLE_OK;
+ DEBUGASSERT(!wctx->ssl_ctx);
+ DEBUGASSERT(!wctx->ssl);
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config) {
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+ Curl_alpn_copy(&alpns, alpns_requested);
#if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */
req_method = wolfSSLv23_client_method();
@@ -863,58 +977,62 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
if(!req_method) {
failf(data, "wolfSSL: could not create a client method");
- return CURLE_OUT_OF_MEMORY;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
- if(backend->ctx)
- wolfSSL_CTX_free(backend->ctx);
+ if(wctx->ssl_ctx)
+ wolfSSL_CTX_free(wctx->ssl_ctx);
- backend->ctx = wolfSSL_CTX_new(req_method);
- if(!backend->ctx) {
+ wctx->ssl_ctx = wolfSSL_CTX_new(req_method);
+ if(!wctx->ssl_ctx) {
failf(data, "wolfSSL: could not create a context");
- return CURLE_OUT_OF_MEMORY;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_VERSION);
+ res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_VERSION);
break;
case CURL_SSLVERSION_TLSv1_1:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_1_VERSION);
+ res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_1_VERSION);
break;
case CURL_SSLVERSION_TLSv1_2:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_2_VERSION);
+ res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_2_VERSION);
break;
#ifdef WOLFSSL_TLS13
case CURL_SSLVERSION_TLSv1_3:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_3_VERSION);
+ res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_3_VERSION);
break;
#endif
default:
failf(data, "wolfSSL: unsupported minimum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(res != WOLFSSL_SUCCESS) {
failf(data, "wolfSSL: failed set the minimum TLS version");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
switch(conn_config->version_max) {
#ifdef WOLFSSL_TLS13
case CURL_SSLVERSION_MAX_TLSv1_3:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
+ res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_3_VERSION);
break;
#endif
case CURL_SSLVERSION_MAX_TLSv1_2:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_2_VERSION);
+ res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_2_VERSION);
break;
case CURL_SSLVERSION_MAX_TLSv1_1:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_1_VERSION);
+ res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_1_VERSION);
break;
case CURL_SSLVERSION_MAX_TLSv1_0:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_VERSION);
+ res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_VERSION);
break;
case CURL_SSLVERSION_MAX_DEFAULT:
case CURL_SSLVERSION_MAX_NONE:
@@ -922,20 +1040,23 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
break;
default:
failf(data, "wolfSSL: unsupported maximum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(res != WOLFSSL_SUCCESS) {
failf(data, "wolfSSL: failed set the maximum TLS version");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
#ifndef WOLFSSL_TLS13
{
char *ciphers = conn_config->cipher_list;
if(ciphers) {
- if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
+ if(!SSL_CTX_set_cipher_list(wctx->ssl_ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
- return CURLE_SSL_CIPHER;
+ result = CURLE_SSL_CIPHER;
+ goto out;
}
infof(data, "Cipher selection: %s", ciphers);
}
@@ -946,7 +1067,6 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
const char *ciphers12 = conn_config->cipher_list;
const char *ciphers13 = conn_config->cipher_list13;
struct dynbuf c;
- CURLcode result;
Curl_dyn_init(&c, MAX_CIPHER_LEN);
if(ciphers13)
@@ -965,12 +1085,13 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
result = wssl_add_default_ciphers(FALSE, &c);
}
if(result)
- return result;
+ goto out;
- if(!wolfSSL_CTX_set_cipher_list(backend->ctx, Curl_dyn_ptr(&c))) {
+ if(!wolfSSL_CTX_set_cipher_list(wctx->ssl_ctx, Curl_dyn_ptr(&c))) {
failf(data, "failed setting cipher list: %s", Curl_dyn_ptr(&c));
Curl_dyn_free(&c);
- return CURLE_SSL_CIPHER;
+ result = CURLE_SSL_CIPHER;
+ goto out;
}
infof(data, "Cipher selection: %s", Curl_dyn_ptr(&c));
Curl_dyn_free(&c);
@@ -978,8 +1099,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
curves = conn_config->curves;
- if(curves) {
+ if(!curves && cf->conn->transport == TRNSPRT_QUIC)
+ curves = (char *)CURL_UNCONST(QUIC_GROUPS);
+ if(curves) {
#ifdef WOLFSSL_HAVE_KYBER
for(idx = 0; gnm[idx].name != NULL; idx++) {
if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
@@ -991,9 +1114,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
if(pqkem == 0)
#endif
{
- if(!wolfSSL_CTX_set1_curves_list(backend->ctx, curves)) {
+ if(!wolfSSL_CTX_set1_curves_list(wctx->ssl_ctx, curves)) {
failf(data, "failed setting curves list: '%s'", curves);
- return CURLE_SSL_CIPHER;
+ result = CURLE_SSL_CIPHER;
+ goto out;
}
}
}
@@ -1005,30 +1129,32 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
const char *key_file = ssl_config->key;
const struct curl_blob *cert_blob = ssl_config->primary.cert_blob;
const struct curl_blob *key_blob = ssl_config->key_blob;
- int file_type = wolfssl_do_file_type(ssl_config->cert_type);
+ int file_type = wssl_do_file_type(ssl_config->cert_type);
int rc;
switch(file_type) {
case WOLFSSL_FILETYPE_PEM:
rc = cert_blob ?
- wolfSSL_CTX_use_certificate_chain_buffer(backend->ctx,
+ wolfSSL_CTX_use_certificate_chain_buffer(wctx->ssl_ctx,
cert_blob->data,
(long)cert_blob->len) :
- wolfSSL_CTX_use_certificate_chain_file(backend->ctx, cert_file);
+ wolfSSL_CTX_use_certificate_chain_file(wctx->ssl_ctx, cert_file);
break;
case WOLFSSL_FILETYPE_ASN1:
rc = cert_blob ?
- wolfSSL_CTX_use_certificate_buffer(backend->ctx, cert_blob->data,
+ wolfSSL_CTX_use_certificate_buffer(wctx->ssl_ctx, cert_blob->data,
(long)cert_blob->len, file_type) :
- wolfSSL_CTX_use_certificate_file(backend->ctx, cert_file, file_type);
+ wolfSSL_CTX_use_certificate_file(wctx->ssl_ctx, cert_file, file_type);
break;
default:
failf(data, "unknown cert type");
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto out;
}
if(rc != 1) {
failf(data, "unable to use client certificate");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(!key_blob && !key_file) {
@@ -1036,53 +1162,57 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
key_file = cert_file;
}
else
- file_type = wolfssl_do_file_type(ssl_config->key_type);
+ file_type = wssl_do_file_type(ssl_config->key_type);
rc = key_blob ?
- wolfSSL_CTX_use_PrivateKey_buffer(backend->ctx, key_blob->data,
+ wolfSSL_CTX_use_PrivateKey_buffer(wctx->ssl_ctx, key_blob->data,
(long)key_blob->len, file_type) :
- wolfSSL_CTX_use_PrivateKey_file(backend->ctx, key_file, file_type);
+ wolfSSL_CTX_use_PrivateKey_file(wctx->ssl_ctx, key_file, file_type);
if(rc != 1) {
failf(data, "unable to set private key");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
}
#else /* NO_FILESYSTEM */
if(ssl_config->primary.cert_blob) {
const struct curl_blob *cert_blob = ssl_config->primary.cert_blob;
const struct curl_blob *key_blob = ssl_config->key_blob;
- int file_type = wolfssl_do_file_type(ssl_config->cert_type);
+ int file_type = wssl_do_file_type(ssl_config->cert_type);
int rc;
switch(file_type) {
case WOLFSSL_FILETYPE_PEM:
- rc = wolfSSL_CTX_use_certificate_chain_buffer(backend->ctx,
+ rc = wolfSSL_CTX_use_certificate_chain_buffer(wctx->ssl_ctx,
cert_blob->data,
(long)cert_blob->len);
break;
case WOLFSSL_FILETYPE_ASN1:
- rc = wolfSSL_CTX_use_certificate_buffer(backend->ctx, cert_blob->data,
+ rc = wolfSSL_CTX_use_certificate_buffer(wctx->ssl_ctx, cert_blob->data,
(long)cert_blob->len, file_type);
break;
default:
failf(data, "unknown cert type");
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto out;
}
if(rc != 1) {
failf(data, "unable to use client certificate");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(!key_blob)
key_blob = cert_blob;
else
- file_type = wolfssl_do_file_type(ssl_config->key_type);
+ file_type = wssl_do_file_type(ssl_config->key_type);
- if(wolfSSL_CTX_use_PrivateKey_buffer(backend->ctx, key_blob->data,
+ if(wolfSSL_CTX_use_PrivateKey_buffer(wctx->ssl_ctx, key_blob->data,
(long)key_blob->len,
file_type) != 1) {
failf(data, "unable to set private key");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
}
#endif /* !NO_FILESYSTEM */
@@ -1091,37 +1221,49 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
* 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. */
- wolfSSL_CTX_set_verify(backend->ctx,
+ wolfSSL_CTX_set_verify(wctx->ssl_ctx,
conn_config->verifypeer ? WOLFSSL_VERIFY_PEER :
WOLFSSL_VERIFY_NONE, NULL);
#ifdef HAVE_SNI
- if(connssl->peer.sni) {
- size_t sni_len = strlen(connssl->peer.sni);
+ if(peer->sni) {
+ size_t sni_len = strlen(peer->sni);
if((sni_len < USHRT_MAX)) {
- if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME,
- connssl->peer.sni,
- (unsigned short)sni_len) != 1) {
+ if(wolfSSL_CTX_UseSNI(wctx->ssl_ctx, WOLFSSL_SNI_HOST_NAME,
+ peer->sni, (unsigned short)sni_len) != 1) {
failf(data, "Failed to set SNI");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
+ CURL_TRC_CF(data, cf, "set SNI '%s'", peer->sni);
}
}
#endif
+ if(ssl_config->primary.cache_session &&
+ cf->conn->transport != TRNSPRT_QUIC) {
+ /* Register to get notified when a new session is received */
+ wolfSSL_CTX_sess_set_new_cb(wctx->ssl_ctx, wssl_vtls_new_session_cb);
+ }
+
+ if(cb_setup) {
+ result = cb_setup(cf, data, cb_user_data);
+ if(result)
+ goto out;
+ }
+
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- CURLcode result;
- if(!backend->x509_store_setup) {
- result = Curl_wssl_setup_x509_store(cf, data, backend);
+ if(!wctx->x509_store_setup) {
+ result = Curl_wssl_setup_x509_store(cf, data, wctx);
if(result)
- return result;
+ goto out;
}
- result = (*data->set.ssl.fsslctx)(data, backend->ctx,
+ result = (*data->set.ssl.fsslctx)(data, wctx->ssl_ctx,
data->set.ssl.fsslctxp);
if(result) {
failf(data, "error signaled by ssl ctx callback");
- return result;
+ goto out;
}
}
#ifdef NO_FILESYSTEM
@@ -1130,82 +1272,89 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
" 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;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
#endif
/* Let's make an SSL structure */
- if(backend->handle)
- wolfSSL_free(backend->handle);
- backend->handle = wolfSSL_new(backend->ctx);
- if(!backend->handle) {
+ wctx->ssl = wolfSSL_new(wctx->ssl_ctx);
+ if(!wctx->ssl) {
failf(data, "SSL: could not create a handle");
- return CURLE_OUT_OF_MEMORY;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
+ wolfSSL_set_app_data(wctx->ssl, ssl_user_data);
+#ifdef WOLFSSL_QUIC
+ if(cf->conn->transport == TRNSPRT_QUIC)
+ wolfSSL_set_quic_use_legacy_codepoint(wctx->ssl, 0);
+#endif
+
#ifdef WOLFSSL_HAVE_KYBER
if(pqkem) {
- if(wolfSSL_UseKeyShare(backend->handle, pqkem) != WOLFSSL_SUCCESS) {
+ if(wolfSSL_UseKeyShare(wctx->ssl, pqkem) != WOLFSSL_SUCCESS) {
failf(data, "unable to use PQ KEM");
}
}
#endif
+ /* Check if there is a cached ID we can/should use here! */
+ if(ssl_config->primary.cache_session) {
+ /* Set session from cache if there is one */
+ (void)wssl_setup_session(cf, data, wctx, &alpns,
+ peer->scache_key, sess_reuse_cb);
+ }
+
#ifdef HAVE_ALPN
- if(connssl->alpn) {
+ if(alpns.count) {
struct alpn_proto_buf proto;
- CURLcode result;
+ memset(&proto, 0, sizeof(proto));
+ Curl_alpn_to_proto_str(&proto, &alpns);
- result = Curl_alpn_to_proto_str(&proto, connssl->alpn);
- if(result ||
- wolfSSL_UseALPN(backend->handle,
- (char *)proto.data, (unsigned int)proto.len,
+ if(wolfSSL_UseALPN(wctx->ssl, (char *)proto.data,
+ (unsigned int)proto.len,
WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != WOLFSSL_SUCCESS) {
failf(data, "SSL: failed setting ALPN protocols");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+ CURL_TRC_CF(data, cf, "set ALPN: %s", proto.data);
}
#endif /* HAVE_ALPN */
#ifdef OPENSSL_EXTRA
if(Curl_tls_keylog_enabled()) {
/* Ensure the Client Random is preserved. */
- wolfSSL_KeepArrays(backend->handle);
+ wolfSSL_KeepArrays(wctx->ssl);
#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
- wolfSSL_set_tls13_secret_cb(backend->handle,
- wolfssl_tls13_secret_callback, NULL);
+ wolfSSL_set_tls13_secret_cb(wctx->ssl,
+ wssl_tls13_secret_callback, NULL);
#endif
}
#endif /* OPENSSL_EXTRA */
#ifdef HAVE_SECURE_RENEGOTIATION
- if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
+ if(wolfSSL_UseSecureRenegotiation(wctx->ssl) != SSL_SUCCESS) {
failf(data, "SSL: failed setting secure renegotiation");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
#endif /* HAVE_SECURE_RENEGOTIATION */
- /* Check if there is a cached ID we can/should use here! */
- if(ssl_config->primary.cache_session) {
- /* Set session from cache if there is one */
- (void)Curl_wssl_setup_session(cf, data, backend, connssl->peer.scache_key);
- /* Register to get notified when a new session is received */
- wolfSSL_set_app_data(backend->handle, cf);
- wolfSSL_CTX_sess_set_new_cb(backend->ctx, wssl_vtls_new_session_cb);
- }
-
#ifdef USE_ECH_WOLFSSL
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;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(data->set.tls_ech == CURLECH_GREASE) {
infof(data, "ECH: GREASE'd ECH not yet supported for wolfSSL");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(data->set.tls_ech & CURLECH_CLA_CFG
&& data->set.str[STRING_ECH_CONFIG]) {
@@ -1214,10 +1363,12 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
b64len = (word32) strlen(b64val);
if(b64len
- && wolfSSL_SetEchConfigsBase64(backend->handle, b64val, b64len)
+ && wolfSSL_SetEchConfigsBase64(wctx->ssl, b64val, b64len)
!= WOLFSSL_SUCCESS) {
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
+ if(data->set.tls_ech & CURLECH_HARD) {
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
}
else {
trying_ech_now = 1;
@@ -1225,13 +1376,16 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
else {
+ struct ssl_connect_data *connssl = cf->ctx;
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;
+ if(data->set.tls_ech & CURLECH_HARD) {
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
}
else {
struct Curl_https_rrinfo *rinfo = NULL;
@@ -1242,11 +1396,13 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
size_t elen = rinfo->echconfiglist_len;
infof(data, "ECH: ECHConfig from DoH HTTPS RR");
- if(wolfSSL_SetEchConfigs(backend->handle, ecl, (word32) elen) !=
+ if(wolfSSL_SetEchConfigs(wctx->ssl, ecl, (word32) elen) !=
WOLFSSL_SUCCESS) {
infof(data, "ECH: wolfSSL_SetEchConfigs failed");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
+ if(data->set.tls_ech & CURLECH_HARD) {
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
}
else {
trying_ech_now = 1;
@@ -1255,49 +1411,107 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
else {
infof(data, "ECH: requested but no ECHConfig available");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
+ if(data->set.tls_ech & CURLECH_HARD) {
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
}
Curl_resolv_unlink(data, &dns);
}
}
- if(trying_ech_now && wolfSSL_set_min_proto_version(backend->handle,
+ if(trying_ech_now && wolfSSL_set_min_proto_version(wctx->ssl,
TLS1_3_VERSION) != 1) {
infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
}
#endif /* USE_ECH_WOLFSSL */
+ result = CURLE_OK;
+
+out:
+ if(result && wctx->ssl) {
+ wolfSSL_free(wctx->ssl);
+ wctx->ssl = NULL;
+ }
+ if(result && wctx->ssl_ctx) {
+ wolfSSL_CTX_free(wctx->ssl_ctx);
+ wctx->ssl_ctx = NULL;
+ }
+ return result;
+}
+
+/*
+ * This function loads all the client/CA certificates and CRLs. Setup the TLS
+ * layer and do all necessary magic.
+ */
+static CURLcode
+wssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ CURLcode result;
+
+ DEBUGASSERT(wssl);
+
+ if(connssl->state == ssl_connection_complete)
+ return CURLE_OK;
+
+ result = Curl_wssl_ctx_init(wssl, cf, data, &connssl->peer,
+ connssl->alpn, NULL, NULL, cf,
+ wssl_on_session_reuse);
+ if(result)
+ return result;
+
+#ifdef HAS_ALPN
+ if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
+ struct alpn_proto_buf proto;
+ memset(&proto, 0, sizeof(proto));
+ Curl_alpn_to_proto_str(&proto, connssl->alpn);
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+ }
+#endif
+
+ /* Enable RFC2818 checks */
+ if(conn_config->verifyhost) {
+ char *snihost = connssl->peer.sni ?
+ connssl->peer.sni : connssl->peer.hostname;
+ if(wolfSSL_check_domain_name(wssl->ssl, snihost) !=
+ WOLFSSL_SUCCESS) {
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
#ifdef USE_BIO_CHAIN
{
WOLFSSL_BIO *bio;
- bio = wolfSSL_BIO_new(wolfssl_bio_cf_method);
+ bio = wolfSSL_BIO_new(wssl_bio_cf_method);
if(!bio)
return CURLE_OUT_OF_MEMORY;
wolfSSL_BIO_set_data(bio, cf);
- wolfSSL_set_bio(backend->handle, bio, bio);
+ wolfSSL_set_bio(wssl->ssl, bio, bio);
}
#else /* USE_BIO_CHAIN */
/* pass the raw socket into the SSL layer */
- if(!wolfSSL_set_fd(backend->handle,
+ if(!wolfSSL_set_fd(wssl->ssl,
(int)Curl_conn_cf_get_socket(cf, data))) {
- failf(data, "SSL: SSL_set_fd failed");
+ failf(data, "SSL: wolfSSL_set_fd failed");
return CURLE_SSL_CONNECT_ERROR;
}
#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)
+static char *wssl_strerror(unsigned long error, char *buf,
+ unsigned long size)
{
DEBUGASSERT(size > 40);
*buf = '\0';
@@ -1313,15 +1527,10 @@ static char *wolfssl_strerror(unsigned long error, char *buf,
return buf;
}
-
-static CURLcode
-wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
+static CURLcode wssl_verify_pinned(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] :
@@ -1330,29 +1539,144 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#endif
- DEBUGASSERT(backend);
+ if(pinnedpubkey) {
+#ifdef KEEP_PEER_CERT
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ WOLFSSL_X509 *x509;
+ const char *x509_der;
+ int x509_der_len;
+ struct Curl_X509certificate x509_parsed;
+ struct Curl_asn1Element *pubkey;
+ CURLcode result;
- wolfSSL_ERR_clear_error();
+ x509 = wolfSSL_get_peer_certificate(wssl->ssl);
+ if(!x509) {
+ failf(data, "SSL: failed retrieving server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
- /* Enable RFC2818 checks */
- if(conn_config->verifyhost) {
- char *snihost = connssl->peer.sni ?
- connssl->peer.sni : connssl->peer.hostname;
- if(wolfSSL_check_domain_name(backend->handle, snihost) == WOLFSSL_FAILURE)
- return CURLE_SSL_CONNECT_ERROR;
+ x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
+ if(!x509_der) {
+ failf(data, "SSL: failed retrieving ASN.1 server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ memset(&x509_parsed, 0, sizeof(x509_parsed));
+ if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+ pubkey = &x509_parsed.subjectPublicKeyInfo;
+ if(!pubkey->header || pubkey->end <= pubkey->header) {
+ failf(data, "SSL: failed retrieving public key from server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ result = Curl_pin_peer_pubkey(data,
+ pinnedpubkey,
+ (const unsigned char *)pubkey->header,
+ (size_t)(pubkey->end - pubkey->header));
+ wolfSSL_FreeX509(x509);
+ if(result) {
+ failf(data, "SSL: public key does not match pinned public key");
+ return result;
+ }
+#else
+ failf(data, "Library lacks pinning support built-in");
+ return CURLE_NOT_BUILT_IN;
+#endif
}
+ return CURLE_OK;
+}
- 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;
- result = Curl_wssl_setup_x509_store(cf, data, backend);
+#ifdef WOLFSSL_EARLY_DATA
+static CURLcode wssl_send_earlydata(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
+ const unsigned char *buf;
+ size_t blen;
+
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sending);
+ wssl->io_result = CURLE_OK;
+ while(Curl_bufq_peek(&connssl->earlydata, &buf, &blen)) {
+ int nwritten = 0, rc;
+
+ wolfSSL_ERR_clear_error();
+ rc = wolfSSL_write_early_data(wssl->ssl, buf, (int)blen, &nwritten);
+ CURL_TRC_CF(data, cf, "wolfSSL_write_early_data(len=%zu) -> %d, %d",
+ blen, rc, nwritten);
+ if(rc < 0) {
+ int err = wolfSSL_get_error(wssl->ssl, rc);
+ switch(err) {
+ case WOLFSSL_ERROR_NONE: /* just did not get anything */
+ case WOLFSSL_ERROR_WANT_READ:
+ case WOLFSSL_ERROR_WANT_WRITE:
+ result = CURLE_AGAIN;
+ break;
+ default: {
+ char error_buffer[256];
+ int detail = wolfSSL_get_error(wssl->ssl, err);
+ CURL_TRC_CF(data, cf, "SSL send early data, error: '%s'(%d)",
+ wssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
+ detail);
+ result = CURLE_SEND_ERROR;
+ break;
+ }
+ }
+ goto out;
+ }
+
+ Curl_bufq_skip(&connssl->earlydata, (size_t)nwritten);
+ }
+ /* sent everything there was */
+ connssl->earlydata_state = ssl_earlydata_sent;
+ if(!Curl_ssl_cf_is_proxy(cf))
+ Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
+ infof(data, "SSL sending %zu bytes of early data", connssl->earlydata_skip);
+out:
+ return result;
+}
+#endif /* WOLFSSL_EARLY_DATA */
+
+static CURLcode wssl_handshake(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ int ret = -1, detail;
+ CURLcode result;
+
+ DEBUGASSERT(wssl);
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+
+#ifdef WOLFSSL_EARLY_DATA
+ if(connssl->earlydata_state == ssl_earlydata_sending) {
+ result = wssl_send_earlydata(cf, data);
if(result)
return result;
}
+ DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
+ (connssl->earlydata_state == ssl_earlydata_sent));
+#else
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_none);
+#endif /* WOLFSSL_EARLY_DATA */
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- ret = wolfSSL_connect(backend->handle);
+ wolfSSL_ERR_clear_error();
+ ret = wolfSSL_connect(wssl->ssl);
+
+ if(!wssl->x509_store_setup) {
+ /* After having send off the ClientHello, we prepare the x509
+ * store to verify the coming certificate from the server */
+ result = Curl_wssl_setup_x509_store(cf, data, wssl);
+ if(result) {
+ CURL_TRC_CF(data, cf, "Curl_wssl_setup_x509_store() -> %d", result);
+ return result;
+ }
+ }
#ifdef OPENSSL_EXTRA
if(Curl_tls_keylog_enabled()) {
@@ -1368,67 +1692,49 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
* changes, the worst case is that no key is logged on error.
*/
if(ret == WOLFSSL_SUCCESS ||
- (!wolfSSL_want_read(backend->handle) &&
- !wolfSSL_want_write(backend->handle))) {
- wolfssl_log_tls12_secret(backend->handle);
+ (!wolfSSL_want_read(wssl->ssl) &&
+ !wolfSSL_want_write(wssl->ssl))) {
+ wssl_log_tls12_secret(wssl->ssl);
/* Client Random and master secrets are no longer needed, erase these.
* Ignored while the handshake is still in progress. */
- wolfSSL_FreeArrays(backend->handle);
+ wolfSSL_FreeArrays(wssl->ssl);
}
}
#endif /* OPENSSL_EXTRA */
- if(ret != 1) {
- int detail = wolfSSL_get_error(backend->handle, ret);
+ detail = wolfSSL_get_error(wssl->ssl, ret);
+ CURL_TRC_CF(data, cf, "wolfSSL_connect() -> %d, detail=%d", ret, detail);
+ if(ret == WOLFSSL_SUCCESS) {
+ return CURLE_OK;
+ }
+ else {
if(WOLFSSL_ERROR_WANT_READ == detail) {
connssl->io_need = CURL_SSL_IO_NEED_RECV;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
else if(WOLFSSL_ERROR_WANT_WRITE == detail) {
connssl->io_need = CURL_SSL_IO_NEED_SEND;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
- /* 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
+ /* 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 */
failf(data, " subject alt name(s) or common name do not match \"%s\"",
connssl->peer.dispname);
return CURLE_PEER_FAILED_VERIFICATION;
-#else
- /* When the wolfssl_check_domain_name() is used and you desire to
- * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost
- * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
- * error. The only way to do this is currently to switch the
- * Wolfssl_check_domain_name() in and out based on the
- * 'ssl_config.verifyhost' value. */
- if(conn_config->verifyhost) {
- failf(data,
- " subject alt name(s) or common name do not match \"%s\"\n",
- connssl->dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else {
- infof(data,
- " subject alt name(s) and/or common name do not match \"%s\"",
- connssl->dispname);
- return CURLE_OK;
- }
-#endif
}
else if(ASN_NO_SIGNER_E == detail) {
if(conn_config->verifypeer) {
failf(data, " CA signer not available for verification");
return CURLE_SSL_CACERT_BADFILE;
}
- else {
- /* Just continue with a warning if no strict certificate
- verification is required. */
- infof(data, "CA signer not available for verification, "
- "continuing anyway");
- }
+ /* Just continue with a warning if no strict certificate
+ verification is required. */
+ infof(data, "CA signer not available for verification, "
+ "continuing anyway");
+ return CURLE_OK;
}
else if(ASN_AFTER_DATE_E == detail) {
failf(data, "server verification failed: certificate has expired.");
@@ -1438,6 +1744,15 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
failf(data, "server verification failed: certificate not valid yet.");
return CURLE_PEER_FAILED_VERIFICATION;
}
+ else if(wssl->io_result) {
+ switch(wssl->io_result) {
+ case CURLE_SEND_ERROR:
+ case CURLE_RECV_ERROR:
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ return wssl->io_result;
+ }
+ }
#ifdef USE_ECH_WOLFSSL
else if(-1 == detail) {
/* try access a retry_config ECHConfigList for tracing */
@@ -1446,7 +1761,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
int rv = 0;
/* this currently does not produce the retry_configs */
- rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
+ rv = wolfSSL_GetEchConfigs(wssl->ssl, echConfigs,
&echConfigsLen);
if(rv != WOLFSSL_SUCCESS) {
infof(data, "Failed to get ECHConfigs");
@@ -1455,160 +1770,100 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
char *b64str = NULL;
size_t blen = 0;
- rv = Curl_base64_encode((const char *)echConfigs, echConfigsLen,
- &b64str, &blen);
- if(!rv && b64str)
+ result = Curl_base64_encode((const char *)echConfigs, echConfigsLen,
+ &b64str, &blen);
+ if(!result && b64str)
infof(data, "ECH: (not yet) retry_configs %s", b64str);
free(b64str);
}
+ return CURLE_SSL_CONNECT_ERROR;
}
#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)));
+ wssl_strerror((unsigned long)detail, error_buffer,
+ sizeof(error_buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
}
-
- if(pinnedpubkey) {
-#ifdef KEEP_PEER_CERT
- WOLFSSL_X509 *x509;
- const char *x509_der;
- int x509_der_len;
- struct Curl_X509certificate x509_parsed;
- struct Curl_asn1Element *pubkey;
- CURLcode result;
-
- x509 = wolfSSL_get_peer_certificate(backend->handle);
- if(!x509) {
- failf(data, "SSL: failed retrieving server certificate");
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- }
-
- x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
- if(!x509_der) {
- failf(data, "SSL: failed retrieving ASN.1 server certificate");
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- }
-
- memset(&x509_parsed, 0, sizeof(x509_parsed));
- if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-
- pubkey = &x509_parsed.subjectPublicKeyInfo;
- if(!pubkey->header || pubkey->end <= pubkey->header) {
- failf(data, "SSL: failed retrieving public key from server certificate");
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- }
-
- result = Curl_pin_peer_pubkey(data,
- pinnedpubkey,
- (const unsigned char *)pubkey->header,
- (size_t)(pubkey->end - pubkey->header));
- wolfSSL_FreeX509(x509);
- if(result) {
- failf(data, "SSL: public key does not match pinned public key");
- return result;
- }
-#else
- failf(data, "Library lacks pinning support built-in");
- return CURLE_NOT_BUILT_IN;
-#endif
- }
-
-#ifdef HAVE_ALPN
- if(connssl->alpn) {
- int rc;
- char *protocol = NULL;
- unsigned short protocol_len = 0;
-
- rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
-
- if(rc == WOLFSSL_SUCCESS) {
- Curl_alpn_set_negotiated(cf, data, connssl,
- (const unsigned char *)protocol, protocol_len);
- }
- else if(rc == WOLFSSL_ALPN_NOT_FOUND)
- Curl_alpn_set_negotiated(cf, data, connssl, NULL, 0);
- else {
- failf(data, "ALPN, failure getting protocol, error %d", rc);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-#endif /* HAVE_ALPN */
-
- connssl->connecting_state = ssl_connect_3;
-#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
- infof(data, "SSL connection using %s / %s",
- wolfSSL_get_version(backend->handle),
- wolfSSL_get_cipher_name(backend->handle));
-#else
- infof(data, "SSL connected");
-#endif
-
- return CURLE_OK;
}
-static ssize_t wolfssl_send(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const void *mem,
- size_t len,
- CURLcode *curlcode)
+static ssize_t wssl_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *buf, size_t blen,
+ 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);
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ size_t total_written = 0;
+ ssize_t nwritten = -1;
+ DEBUGASSERT(wssl);
wolfSSL_ERR_clear_error();
- rc = wolfSSL_write(backend->handle, mem, memlen);
- if(rc <= 0) {
- int err = wolfSSL_get_error(backend->handle, rc);
+ if(blen) {
+ int memlen = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
+ int rc;
- switch(err) {
- case WOLFSSL_ERROR_WANT_READ:
- case WOLFSSL_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);
+ rc = wolfSSL_write(wssl->ssl, buf, memlen);
+ if(rc <= 0) {
+ int err = wolfSSL_get_error(wssl->ssl, rc);
+
+ switch(err) {
+ case WOLFSSL_ERROR_WANT_READ:
+ case WOLFSSL_ERROR_WANT_WRITE:
+ /* there is data pending, re-invoke wolfSSL_write() */
+ if(total_written) {
+ *curlcode = CURLE_OK;
+ nwritten = total_written;
+ goto out;
+ }
*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);
+ nwritten = -1;
+ goto out;
+
+ default:
+ if(wssl->io_result == CURLE_AGAIN) {
+ if(total_written) {
+ *curlcode = CURLE_OK;
+ nwritten = total_written;
+ goto out;
+ }
+ *curlcode = CURLE_AGAIN;
+ nwritten = -1;
+ goto out;
+ }
+ {
+ char error_buffer[256];
+ failf(data, "SSL write: %s, errno %d",
+ wssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
+ SOCKERRNO);
+ }
+ *curlcode = CURLE_SEND_ERROR;
+ nwritten = -1;
+ goto out;
}
- *curlcode = CURLE_SEND_ERROR;
- return -1;
}
+ else
+ total_written += rc;
}
- CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc);
- return rc;
+
+ *curlcode = CURLE_OK;
+ nwritten = total_written;
+out:
+ CURL_TRC_CF(data, cf, "wssl_send(len=%zu) -> %" FMT_OFF_T ", %d",
+ blen, nwritten, *curlcode);
+ return nwritten;
}
-static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
+static CURLcode wssl_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;
+ struct wssl_ctx *wctx = (struct wssl_ctx *)connssl->backend;
CURLcode result = CURLE_OK;
char buf[1024];
char error_buffer[256];
@@ -1617,7 +1872,7 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
int detail;
DEBUGASSERT(wctx);
- if(!wctx->handle || cf->shutdown) {
+ if(!wctx->ssl || cf->shutdown) {
*done = TRUE;
goto out;
}
@@ -1625,12 +1880,12 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
wctx->shutting_down = TRUE;
connssl->io_need = CURL_SSL_IO_NEED_NONE;
*done = FALSE;
- if(!(wolfSSL_get_shutdown(wctx->handle) & WOLFSSL_SENT_SHUTDOWN)) {
+ if(!(wolfSSL_get_shutdown(wctx->ssl) & WOLFSSL_SENT_SHUTDOWN)) {
/* We have not started the shutdown from our side yet. Check
* if the server already sent us one. */
wolfSSL_ERR_clear_error();
- nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
- err = wolfSSL_get_error(wctx->handle, nread);
+ nread = wolfSSL_read(wctx->ssl, buf, (int)sizeof(buf));
+ err = wolfSSL_get_error(wctx->ssl, nread);
CURL_TRC_CF(data, cf, "wolfSSL_read, nread=%d, err=%d", nread, err);
if(!nread && err == WOLFSSL_ERROR_ZERO_RETURN) {
bool input_pending;
@@ -1652,16 +1907,16 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
}
}
- /* SSL should now have started the shutdown from our side. Since it
+ /* wolfSSL should now have started the shutdown from our side. Since it
* was not complete, we are lacking the close notify from the server. */
if(send_shutdown) {
wolfSSL_ERR_clear_error();
- if(wolfSSL_shutdown(wctx->handle) == 1) {
+ if(wolfSSL_shutdown(wctx->ssl) == 1) {
CURL_TRC_CF(data, cf, "SSL shutdown finished");
*done = TRUE;
goto out;
}
- if(WOLFSSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->handle, nread)) {
+ if(WOLFSSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->ssl, nread)) {
CURL_TRC_CF(data, cf, "SSL shutdown still wants to send");
connssl->io_need = CURL_SSL_IO_NEED_SEND;
goto out;
@@ -1672,11 +1927,11 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
for(i = 0; i < 10; ++i) {
wolfSSL_ERR_clear_error();
- nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
+ nread = wolfSSL_read(wctx->ssl, buf, (int)sizeof(buf));
if(nread <= 0)
break;
}
- err = wolfSSL_get_error(wctx->handle, nread);
+ err = wolfSSL_get_error(wctx->ssl, nread);
switch(err) {
case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
CURL_TRC_CF(data, cf, "SSL shutdown received");
@@ -1684,7 +1939,7 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
break;
case WOLFSSL_ERROR_NONE: /* just did not get anything */
case WOLFSSL_ERROR_WANT_READ:
- /* SSL has send its notify and now wants to read the reply
+ /* wolfSSL 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;
@@ -1694,10 +1949,10 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
connssl->io_need = CURL_SSL_IO_NEED_SEND;
break;
default:
- detail = wolfSSL_get_error(wctx->handle, err);
+ detail = wolfSSL_get_error(wctx->ssl, err);
CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)",
- wolfssl_strerror((unsigned long)err, error_buffer,
- sizeof(error_buffer)),
+ wssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
detail);
result = CURLE_RECV_ERROR;
break;
@@ -1708,91 +1963,89 @@ out:
return result;
}
-static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static void wssl_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;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
(void) data;
- DEBUGASSERT(backend);
+ DEBUGASSERT(wssl);
- if(backend->handle) {
- wolfSSL_free(backend->handle);
- backend->handle = NULL;
+ if(wssl->ssl) {
+ wolfSSL_free(wssl->ssl);
+ wssl->ssl = NULL;
}
- if(backend->ctx) {
- wolfSSL_CTX_free(backend->ctx);
- backend->ctx = NULL;
+ if(wssl->ssl_ctx) {
+ wolfSSL_CTX_free(wssl->ssl_ctx);
+ wssl->ssl_ctx = NULL;
}
}
-static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- char *buf, size_t blen,
- CURLcode *curlcode)
+static ssize_t wssl_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;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
int nread;
- DEBUGASSERT(backend);
+ DEBUGASSERT(wssl);
wolfSSL_ERR_clear_error();
*curlcode = CURLE_OK;
- nread = wolfSSL_read(backend->handle, buf, buffsize);
+ nread = wolfSSL_read(wssl->ssl, buf, buffsize);
if(nread <= 0) {
- int err = wolfSSL_get_error(backend->handle, nread);
+ int err = wolfSSL_get_error(wssl->ssl, nread);
switch(err) {
case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
*curlcode = CURLE_OK;
return 0;
case WOLFSSL_ERROR_NONE:
case WOLFSSL_ERROR_WANT_READ:
case WOLFSSL_ERROR_WANT_WRITE:
- if(!backend->io_result && connssl->peer_closed) {
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+ if(!wssl->io_result && connssl->peer_closed) {
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
*curlcode = CURLE_OK;
return 0;
}
/* there is data pending, re-invoke wolfSSL_read() */
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
+ CURL_TRC_CF(data, cf, "wssl_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);
+ if(wssl->io_result == CURLE_AGAIN) {
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen);
*curlcode = CURLE_AGAIN;
return -1;
}
- else if(!backend->io_result && connssl->peer_closed) {
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+ else if(!wssl->io_result && connssl->peer_closed) {
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
*curlcode = CURLE_OK;
return 0;
}
else {
char error_buffer[256];
failf(data, "SSL read: %s, errno %d",
- wolfssl_strerror((unsigned long)err, error_buffer,
- sizeof(error_buffer)),
+ wssl_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);
+
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> %d", blen, nread);
return nread;
}
-
size_t Curl_wssl_version(char *buffer, size_t size)
{
#if LIBWOLFSSL_VERSION_HEX >= 0x03006000
@@ -1803,7 +2056,7 @@ size_t Curl_wssl_version(char *buffer, size_t size)
}
-static int wolfssl_init(void)
+static int wssl_init(void)
{
int ret;
@@ -1811,14 +2064,14 @@ static int wolfssl_init(void)
Curl_tls_keylog_open();
#endif
ret = (wolfSSL_Init() == WOLFSSL_SUCCESS);
- wolfssl_bio_cf_init_methods();
+ wssl_bio_cf_init_methods();
return ret;
}
-static void wolfssl_cleanup(void)
+static void wssl_cleanup(void)
{
- wolfssl_bio_cf_free_methods();
+ wssl_bio_cf_free_methods();
wolfSSL_Cleanup();
#ifdef OPENSSL_EXTRA
Curl_tls_keylog_close();
@@ -1826,31 +2079,29 @@ static void wolfssl_cleanup(void)
}
-static bool wolfssl_data_pending(struct Curl_cfilter *cf,
- const struct Curl_easy *data)
+static bool wssl_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
struct ssl_connect_data *ctx = cf->ctx;
- struct wolfssl_ctx *backend;
+ struct wssl_ctx *wssl;
(void)data;
DEBUGASSERT(ctx && ctx->backend);
- backend = (struct wolfssl_ctx *)ctx->backend;
- if(backend->handle) /* SSL is in use */
- return wolfSSL_pending(backend->handle);
+ wssl = (struct wssl_ctx *)ctx->backend;
+ if(wssl->ssl) /* wolfSSL is in use */
+ return wolfSSL_pending(wssl->ssl);
else
return FALSE;
}
-static CURLcode
-wolfssl_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool nonblocking,
- bool *done)
+static CURLcode wssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- CURLcode result;
struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
@@ -1858,116 +2109,108 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
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;
- }
+ *done = FALSE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
- result = wolfssl_connect_step1(cf, data);
+ if(ssl_connect_1 == connssl->connecting_state) {
+ result = wssl_connect_step1(cf, data);
if(result)
return result;
+ connssl->connecting_state = ssl_connect_2;
}
- while(ssl_connect_2 == connssl->connecting_state) {
-
- /* check allowed time left */
- const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ if(ssl_connect_2 == connssl->connecting_state) {
+ if(connssl->earlydata_state == ssl_earlydata_await) {
+ /* We defer the handshake until request data arrives. */
+ DEBUGASSERT(connssl->state == ssl_connection_deferred);
+ goto out;
+ }
+ result = wssl_handshake(cf, data);
+ if(result == CURLE_AGAIN)
+ goto out;
+ wssl->hs_result = result;
+ connssl->connecting_state = ssl_connect_3;
+ }
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
+ if(ssl_connect_3 == connssl->connecting_state) {
+ /* Once the handshake has errored, it stays in that state and will
+ * error again on every call. */
+ if(wssl->hs_result) {
+ result = wssl->hs_result;
+ goto out;
}
+ result = wssl_verify_pinned(cf, data);
+ if(result) {
+ wssl->hs_result = result;
+ goto out;
+ }
+ /* handhshake was done without errors */
+#ifdef HAVE_ALPN
+ if(connssl->alpn) {
+ int rc;
+ char *protocol = NULL;
+ unsigned short protocol_len = 0;
+
+ rc = wolfSSL_ALPN_GetProtocol(wssl->ssl, &protocol, &protocol_len);
- /* 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;
- int 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;
+ if(rc == WOLFSSL_SUCCESS) {
+ Curl_alpn_set_negotiated(cf, data, connssl,
+ (const unsigned char *)protocol,
+ protocol_len);
}
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
+ else if(rc == WOLFSSL_ALPN_NOT_FOUND)
+ Curl_alpn_set_negotiated(cf, data, connssl, NULL, 0);
+ else {
+ failf(data, "ALPN, failure getting protocol, error %d", rc);
+ wssl->hs_result = result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
- /* socket is readable or writable */
}
+#endif /* HAVE_ALPN */
- /* 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.
- */
- 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 (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
+ infof(data, "SSL connection using %s / %s",
+ wolfSSL_get_version(wssl->ssl),
+ wolfSSL_get_cipher_name(wssl->ssl));
+#else
+ infof(data, "SSL connected");
+#endif
- if(ssl_connect_3 == connssl->connecting_state) {
- /* In other backends, this is where we verify the certificate, but
- * wolfSSL already does that as part of the handshake. */
connssl->connecting_state = ssl_connect_done;
+ connssl->state = ssl_connection_complete;
+
+#ifdef WOLFSSL_EARLY_DATA
+ if(connssl->earlydata_state > ssl_earlydata_none) {
+ /* We should be in this state by now */
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent);
+ connssl->earlydata_state =
+ (wolfSSL_get_early_data_status(wssl->ssl) ==
+ WOLFSSL_EARLY_DATA_REJECTED) ?
+ ssl_earlydata_rejected : ssl_earlydata_accepted;
+ }
+#endif /* WOLFSSL_EARLY_DATA */
}
- if(ssl_connect_done == connssl->connecting_state) {
- connssl->state = ssl_connection_complete;
+ if((connssl->connecting_state == ssl_connect_done) ||
+ (connssl->state == ssl_connection_deferred)) {
*done = TRUE;
}
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-
-static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return wolfssl_connect_common(cf, data, TRUE, done);
-}
-
-
-static CURLcode wolfssl_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode result;
- bool done = FALSE;
- result = wolfssl_connect_common(cf, data, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
+out:
+ if(result) {
+ *done = FALSE;
+ if(result == CURLE_AGAIN)
+ return CURLE_OK;
+ }
+ else if((connssl->connecting_state == ssl_connect_done) ||
+ (connssl->state == ssl_connection_deferred)) {
+ *done = TRUE;
+ }
+ return result;
}
-static CURLcode wolfssl_random(struct Curl_easy *data,
- unsigned char *entropy, size_t length)
+static CURLcode wssl_random(struct Curl_easy *data,
+ unsigned char *entropy, size_t length)
{
WC_RNG rng;
(void)data;
@@ -1982,10 +2225,10 @@ static CURLcode wolfssl_random(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum /* output */,
- size_t unused)
+static CURLcode wssl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused)
{
wc_Sha256 SHA256pw;
(void)unused;
@@ -1996,14 +2239,13 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
return CURLE_OK;
}
-static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
+static void *wssl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
{
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
(void)info;
- DEBUGASSERT(backend);
- return backend->handle;
+ DEBUGASSERT(wssl);
+ return wssl->ssl;
}
const struct Curl_ssl Curl_ssl_wolfssl = {
@@ -2027,28 +2269,27 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
SSLSUPP_CA_CACHE |
SSLSUPP_CIPHER_LIST,
- sizeof(struct wolfssl_ctx),
+ sizeof(struct wssl_ctx),
- wolfssl_init, /* init */
- wolfssl_cleanup, /* cleanup */
+ wssl_init, /* init */
+ wssl_cleanup, /* cleanup */
Curl_wssl_version, /* version */
- wolfssl_shutdown, /* shutdown */
- wolfssl_data_pending, /* data_pending */
- wolfssl_random, /* random */
+ wssl_shutdown, /* shutdown */
+ wssl_data_pending, /* data_pending */
+ wssl_random, /* random */
NULL, /* cert_status_request */
- wolfssl_connect, /* connect */
- wolfssl_connect_nonblocking, /* connect_nonblocking */
+ wssl_connect, /* connect */
Curl_ssl_adjust_pollset, /* adjust_pollset */
- wolfssl_get_internals, /* get_internals */
- wolfssl_close, /* close_one */
+ wssl_get_internals, /* get_internals */
+ wssl_close, /* close_one */
NULL, /* close_all */
NULL, /* set_engine */
NULL, /* set_engine_default */
NULL, /* engines_list */
NULL, /* false_start */
- wolfssl_sha256sum, /* sha256sum */
- wolfssl_recv, /* recv decrypted data */
- wolfssl_send, /* send data to encrypt */
+ wssl_sha256sum, /* sha256sum */
+ wssl_recv, /* recv decrypted data */
+ wssl_send, /* send data to encrypt */
NULL, /* get_channel_binding */
};
diff --git a/libs/libcurl/src/vtls/wolfssl.h b/libs/libcurl/src/vtls/wolfssl.h
index 24f676366c..cf4bff8e2c 100644
--- a/libs/libcurl/src/vtls/wolfssl.h
+++ b/libs/libcurl/src/vtls/wolfssl.h
@@ -29,19 +29,21 @@
#include "urldata.h"
+struct alpn_spec;
+struct ssl_peer;
+struct Curl_ssl_session;
+
struct WOLFSSL;
-typedef struct WOLFSSL WOLFSSL;
struct WOLFSSL_CTX;
-typedef struct WOLFSSL_CTX WOLFSSL_CTX;
struct WOLFSSL_SESSION;
-typedef struct WOLFSSL_SESSION WOLFSSL_SESSION;
extern const struct Curl_ssl Curl_ssl_wolfssl;
-struct wolfssl_ctx {
- WOLFSSL_CTX *ctx;
- WOLFSSL *handle;
+struct wssl_ctx {
+ struct WOLFSSL_CTX *ssl_ctx;
+ struct WOLFSSL *ssl;
CURLcode io_result; /* result of last BIO cfilter operation */
+ CURLcode hs_result; /* result of handshake */
int io_send_blocked_len; /* length of last BIO write that EAGAINed */
BIT(x509_store_setup); /* x509 store has been set up */
BIT(shutting_down); /* TLS is being shut down */
@@ -49,21 +51,43 @@ struct wolfssl_ctx {
size_t Curl_wssl_version(char *buffer, size_t size);
+typedef CURLcode Curl_wssl_ctx_setup_cb(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *user_data);
+
+typedef CURLcode Curl_wssl_init_session_reuse_cb(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct alpn_spec *alpns,
+ struct Curl_ssl_session *scs,
+ bool *do_early_data);
+
+CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const struct alpn_spec *alpns,
+ Curl_wssl_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ void *ssl_user_data,
+ Curl_wssl_init_session_reuse_cb *sess_reuse_cb);
+
CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct wolfssl_ctx *wssl);
+ struct wssl_ctx *wssl);
CURLcode Curl_wssl_setup_session(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct wolfssl_ctx *wss,
+ struct wssl_ctx *wss,
const char *ssl_peer_key);
CURLcode Curl_wssl_cache_session(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char *ssl_peer_key,
- WOLFSSL_SESSION *session,
+ struct WOLFSSL_SESSION *session,
int ietf_tls_id,
- const char *alpn);
+ const char *alpn,
+ unsigned char *quic_tp,
+ size_t quic_tp_len);
#endif /* USE_WOLFSSL */
diff --git a/libs/libcurl/src/vtls/x509asn1.c b/libs/libcurl/src/vtls/x509asn1.c
index f38137e0f2..082b5191d9 100644
--- a/libs/libcurl/src/vtls/x509asn1.c
+++ b/libs/libcurl/src/vtls/x509asn1.c
@@ -26,16 +26,16 @@
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_RUSTLS)
-#if defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
+ defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_RUSTLS)
#define WANT_PARSEX509 /* uses Curl_parseX509() */
#endif
#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_RUSTLS)
#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
-#define WANT_PARSEX509 /* ... uses Curl_parseX509() */
#endif
#include <curl/curl.h>
@@ -64,10 +64,10 @@
#define CURL_ASN1_MAX ((size_t) 0x40000) /* 256K */
/* ASN.1 classes. */
-#define CURL_ASN1_UNIVERSAL 0
-#define CURL_ASN1_APPLICATION 1
-#define CURL_ASN1_CONTEXT_SPECIFIC 2
-#define CURL_ASN1_PRIVATE 3
+/* #define CURL_ASN1_UNIVERSAL 0 */
+/* #define CURL_ASN1_APPLICATION 1 */
+/* #define CURL_ASN1_CONTEXT_SPECIFIC 2 */
+/* #define CURL_ASN1_PRIVATE 3 */
/* ASN.1 types. */
#define CURL_ASN1_BOOLEAN 1
@@ -76,27 +76,27 @@
#define CURL_ASN1_OCTET_STRING 4
#define CURL_ASN1_NULL 5
#define CURL_ASN1_OBJECT_IDENTIFIER 6
-#define CURL_ASN1_OBJECT_DESCRIPTOR 7
-#define CURL_ASN1_INSTANCE_OF 8
-#define CURL_ASN1_REAL 9
+/* #define CURL_ASN1_OBJECT_DESCRIPTOR 7 */
+/* #define CURL_ASN1_INSTANCE_OF 8 */
+/* #define CURL_ASN1_REAL 9 */
#define CURL_ASN1_ENUMERATED 10
-#define CURL_ASN1_EMBEDDED 11
+/* #define CURL_ASN1_EMBEDDED 11 */
#define CURL_ASN1_UTF8_STRING 12
-#define CURL_ASN1_RELATIVE_OID 13
-#define CURL_ASN1_SEQUENCE 16
-#define CURL_ASN1_SET 17
+/* #define CURL_ASN1_RELATIVE_OID 13 */
+/* #define CURL_ASN1_SEQUENCE 16 */
+/* #define CURL_ASN1_SET 17 */
#define CURL_ASN1_NUMERIC_STRING 18
#define CURL_ASN1_PRINTABLE_STRING 19
#define CURL_ASN1_TELETEX_STRING 20
-#define CURL_ASN1_VIDEOTEX_STRING 21
+/* #define CURL_ASN1_VIDEOTEX_STRING 21 */
#define CURL_ASN1_IA5_STRING 22
#define CURL_ASN1_UTC_TIME 23
#define CURL_ASN1_GENERALIZED_TIME 24
-#define CURL_ASN1_GRAPHIC_STRING 25
+/* #define CURL_ASN1_GRAPHIC_STRING 25 */
#define CURL_ASN1_VISIBLE_STRING 26
-#define CURL_ASN1_GENERAL_STRING 27
+/* #define CURL_ASN1_GENERAL_STRING 27 */
#define CURL_ASN1_UNIVERSAL_STRING 28
-#define CURL_ASN1_CHARACTER_STRING 29
+/* #define CURL_ASN1_CHARACTER_STRING 29 */
#define CURL_ASN1_BMP_STRING 30
@@ -1026,7 +1026,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
len = ((elem.end - q) * 8);
if(len) {
unsigned int i;
- for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
+ for(i = *(const unsigned char *) q; !(i & 0x80); i <<= 1)
len--;
}
if(len > 32)
@@ -1277,4 +1277,5 @@ done:
#endif /* WANT_EXTRACT_CERTINFO */
-#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP
+ or USE_MBEDTLS or USE_RUSTLS */
diff --git a/libs/libcurl/src/vtls/x509asn1.h b/libs/libcurl/src/vtls/x509asn1.h
index 670a565302..34ba802d0f 100644
--- a/libs/libcurl/src/vtls/x509asn1.h
+++ b/libs/libcurl/src/vtls/x509asn1.h
@@ -29,7 +29,7 @@
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_RUSTLS)
#include "cfilters.h"
#include "urldata.h"
@@ -80,7 +80,7 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
#ifdef UNITTESTS
#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_MBEDTLS) || defined(USE_RUSTLS)
/* used by unit1656.c */
CURLcode Curl_x509_GTime2str(struct dynbuf *store,
@@ -91,5 +91,6 @@ CURLcode Curl_x509_getASN1Element(struct Curl_asn1Element *elem,
#endif
#endif
-#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP
+ or USE_MBEDTLS or USE_RUSTLS */
#endif /* HEADER_CURL_X509ASN1_H */
diff --git a/libs/libcurl/src/warnless.c b/libs/libcurl/src/warnless.c
index ecfbfb8c9e..32cca52de7 100644
--- a/libs/libcurl/src/warnless.c
+++ b/libs/libcurl/src/warnless.c
@@ -45,43 +45,18 @@
#include <limits.h>
#define CURL_MASK_UCHAR ((unsigned char)~0)
-#define CURL_MASK_SCHAR (CURL_MASK_UCHAR >> 1)
#define CURL_MASK_USHORT ((unsigned short)~0)
-#define CURL_MASK_SSHORT (CURL_MASK_USHORT >> 1)
#define CURL_MASK_UINT ((unsigned int)~0)
#define CURL_MASK_SINT (CURL_MASK_UINT >> 1)
#define CURL_MASK_ULONG ((unsigned long)~0)
-#define CURL_MASK_SLONG (CURL_MASK_ULONG >> 1)
-
-#define CURL_MASK_UCOFFT ((unsigned CURL_TYPEOF_CURL_OFF_T)~0)
-#define CURL_MASK_SCOFFT (CURL_MASK_UCOFFT >> 1)
#define CURL_MASK_USIZE_T ((size_t)~0)
#define CURL_MASK_SSIZE_T (CURL_MASK_USIZE_T >> 1)
/*
-** unsigned long to unsigned short
-*/
-
-unsigned short curlx_ultous(unsigned long ulnum)
-{
-#ifdef __INTEL_COMPILER
-# pragma warning(push)
-# pragma warning(disable:810) /* conversion may lose significant bits */
-#endif
-
- DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT);
- return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT);
-
-#ifdef __INTEL_COMPILER
-# pragma warning(pop)
-#endif
-}
-
-/*
** unsigned long to unsigned char
*/
@@ -323,7 +298,7 @@ size_t curlx_sitouz(int sinum)
#endif
}
-#if defined(_WIN32)
+#ifdef _WIN32
ssize_t curlx_read(int fd, void *buf, size_t count)
{
diff --git a/libs/libcurl/src/warnless.h b/libs/libcurl/src/warnless.h
index 549ed461a1..630d6ccb1b 100644
--- a/libs/libcurl/src/warnless.h
+++ b/libs/libcurl/src/warnless.h
@@ -33,8 +33,6 @@
#define CURLX_FUNCTION_CAST(target_type, func) \
(target_type)(void (*) (void))(func)
-unsigned short curlx_ultous(unsigned long ulnum);
-
unsigned char curlx_ultouc(unsigned long ulnum);
int curlx_uztosi(size_t uznum);
@@ -59,7 +57,7 @@ unsigned short curlx_uitous(unsigned int uinum);
size_t curlx_sitouz(int sinum);
-#if defined(_WIN32)
+#ifdef _WIN32
ssize_t curlx_read(int fd, void *buf, size_t count);
@@ -72,7 +70,7 @@ ssize_t curlx_write(int fd, const void *buf, size_t count);
#ifndef HEADER_CURL_WARNLESS_H_REDEFS
#define HEADER_CURL_WARNLESS_H_REDEFS
-#if defined(_WIN32)
+#ifdef _WIN32
#undef read
#define read(fd, buf, count) curlx_read(fd, buf, count)
#undef write
diff --git a/libs/libcurl/src/ws.c b/libs/libcurl/src/ws.c
index 92e9eb5635..1d641dfdb0 100644
--- a/libs/libcurl/src/ws.c
+++ b/libs/libcurl/src/ws.c
@@ -39,6 +39,7 @@
#include "transfer.h"
#include "select.h"
#include "nonblock.h"
+#include "strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -46,16 +47,26 @@
#include "memdebug.h"
-#define WSBIT_FIN 0x80
-#define WSBIT_RSV1 0x40
-#define WSBIT_RSV2 0x20
-#define WSBIT_RSV3 0x10
+/***
+ RFC 6455 Section 5.2
+
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-------+
+ |F|R|R|R| opcode|
+ |I|S|S|S| (4) |
+ |N|V|V|V| |
+ | |1|2|3| |
+*/
+#define WSBIT_FIN (0x80)
+#define WSBIT_RSV1 (0x40)
+#define WSBIT_RSV2 (0x20)
+#define WSBIT_RSV3 (0x10)
#define WSBIT_RSV_MASK (WSBIT_RSV1 | WSBIT_RSV2 | WSBIT_RSV3)
-#define WSBIT_OPCODE_CONT 0
-#define WSBIT_OPCODE_TEXT (1)
-#define WSBIT_OPCODE_BIN (2)
-#define WSBIT_OPCODE_CLOSE (8)
-#define WSBIT_OPCODE_PING (9)
+#define WSBIT_OPCODE_CONT (0x0)
+#define WSBIT_OPCODE_TEXT (0x1)
+#define WSBIT_OPCODE_BIN (0x2)
+#define WSBIT_OPCODE_CLOSE (0x8)
+#define WSBIT_OPCODE_PING (0x9)
#define WSBIT_OPCODE_PONG (0xa)
#define WSBIT_OPCODE_MASK (0xf)
@@ -65,58 +76,120 @@
#define WS_CHUNK_SIZE 65535
#define WS_CHUNK_COUNT 2
-struct ws_frame_meta {
- char proto_opcode;
- int flags;
- const char *name;
-};
-
-static struct ws_frame_meta WS_FRAMES[] = {
- { WSBIT_OPCODE_CONT, CURLWS_CONT, "CONT" },
- { WSBIT_OPCODE_TEXT, CURLWS_TEXT, "TEXT" },
- { WSBIT_OPCODE_BIN, CURLWS_BINARY, "BIN" },
- { WSBIT_OPCODE_CLOSE, CURLWS_CLOSE, "CLOSE" },
- { WSBIT_OPCODE_PING, CURLWS_PING, "PING" },
- { WSBIT_OPCODE_PONG, CURLWS_PONG, "PONG" },
-};
-
-static const char *ws_frame_name_of_op(unsigned char proto_opcode)
+static const char *ws_frame_name_of_op(unsigned char firstbyte)
{
- unsigned char opcode = proto_opcode & WSBIT_OPCODE_MASK;
- size_t i;
- for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) {
- if(WS_FRAMES[i].proto_opcode == opcode)
- return WS_FRAMES[i].name;
+ switch(firstbyte & WSBIT_OPCODE_MASK) {
+ case WSBIT_OPCODE_CONT:
+ return "CONT";
+ case WSBIT_OPCODE_TEXT:
+ return "TEXT";
+ case WSBIT_OPCODE_BIN:
+ return "BIN";
+ case WSBIT_OPCODE_CLOSE:
+ return "CLOSE";
+ case WSBIT_OPCODE_PING:
+ return "PING";
+ case WSBIT_OPCODE_PONG:
+ return "PONG";
+ default:
+ return "???";
}
- return "???";
}
-static int ws_frame_op2flags(unsigned char proto_opcode)
+static int ws_frame_firstbyte2flags(struct Curl_easy *data,
+ unsigned char firstbyte, int cont_flags)
{
- unsigned char opcode = proto_opcode & WSBIT_OPCODE_MASK;
- size_t i;
- for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) {
- if(WS_FRAMES[i].proto_opcode == opcode)
- return WS_FRAMES[i].flags;
+ switch(firstbyte) {
+ case WSBIT_OPCODE_CONT:
+ /* continuation of a previous fragment: restore stored flags */
+ return cont_flags | CURLWS_CONT;
+ case (WSBIT_OPCODE_CONT | WSBIT_FIN):
+ /* continuation of a previous fragment: restore stored flags */
+ return cont_flags & ~CURLWS_CONT;
+ case WSBIT_OPCODE_TEXT:
+ return CURLWS_TEXT | CURLWS_CONT;
+ case (WSBIT_OPCODE_TEXT | WSBIT_FIN):
+ return CURLWS_TEXT;
+ case WSBIT_OPCODE_BIN:
+ return CURLWS_BINARY | CURLWS_CONT;
+ case (WSBIT_OPCODE_BIN | WSBIT_FIN):
+ return CURLWS_BINARY;
+ case (WSBIT_OPCODE_CLOSE | WSBIT_FIN):
+ return CURLWS_CLOSE;
+ case (WSBIT_OPCODE_PING | WSBIT_FIN):
+ return CURLWS_PING;
+ case (WSBIT_OPCODE_PONG | WSBIT_FIN):
+ return CURLWS_PONG;
+ default:
+ if(firstbyte & WSBIT_RSV_MASK) {
+ failf(data, "WS: unknown reserved bit: %x",
+ firstbyte & WSBIT_RSV_MASK);
+ }
+ else {
+ failf(data, "WS: unknown opcode: %x",
+ firstbyte & WSBIT_OPCODE_MASK);
+ }
+ return 0;
}
- return 0;
}
-static unsigned char ws_frame_flags2op(int flags)
+static unsigned char ws_frame_flags2firstbyte(struct Curl_easy *data,
+ unsigned int flags,
+ bool contfragment,
+ CURLcode *err)
{
- 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;
+ switch(flags & ~CURLWS_OFFSET) {
+ case 0:
+ if(contfragment) {
+ infof(data, "WS: no flags given; interpreting as continuation "
+ "fragment for compatibility");
+ return (WSBIT_OPCODE_CONT | WSBIT_FIN);
+ }
+ failf(data, "WS: no flags given");
+ *err = CURLE_BAD_FUNCTION_ARGUMENT;
+ return 0xff;
+ case CURLWS_CONT:
+ if(contfragment) {
+ infof(data, "WS: setting CURLWS_CONT flag without message type is "
+ "supported for compatibility but highly discouraged");
+ return WSBIT_OPCODE_CONT;
+ }
+ failf(data, "WS: No ongoing fragmented message to continue");
+ *err = CURLE_BAD_FUNCTION_ARGUMENT;
+ return 0xff;
+ case CURLWS_TEXT:
+ return contfragment ? (WSBIT_OPCODE_CONT | WSBIT_FIN)
+ : (WSBIT_OPCODE_TEXT | WSBIT_FIN);
+ case (CURLWS_TEXT | CURLWS_CONT):
+ return contfragment ? WSBIT_OPCODE_CONT : WSBIT_OPCODE_TEXT;
+ case CURLWS_BINARY:
+ return contfragment ? (WSBIT_OPCODE_CONT | WSBIT_FIN)
+ : (WSBIT_OPCODE_BIN | WSBIT_FIN);
+ case (CURLWS_BINARY | CURLWS_CONT):
+ return contfragment ? WSBIT_OPCODE_CONT : WSBIT_OPCODE_BIN;
+ case CURLWS_CLOSE:
+ return WSBIT_OPCODE_CLOSE | WSBIT_FIN;
+ case (CURLWS_CLOSE | CURLWS_CONT):
+ failf(data, "WS: CLOSE frame must not be fragmented");
+ *err = CURLE_BAD_FUNCTION_ARGUMENT;
+ return 0xff;
+ case CURLWS_PING:
+ return WSBIT_OPCODE_PING | WSBIT_FIN;
+ case (CURLWS_PING | CURLWS_CONT):
+ failf(data, "WS: PING frame must not be fragmented");
+ *err = CURLE_BAD_FUNCTION_ARGUMENT;
+ return 0xff;
+ case CURLWS_PONG:
+ return WSBIT_OPCODE_PONG | WSBIT_FIN;
+ case (CURLWS_PONG | CURLWS_CONT):
+ failf(data, "WS: PONG frame must not be fragmented");
+ *err = CURLE_BAD_FUNCTION_ARGUMENT;
+ return 0xff;
+ default:
+ failf(data, "WS: unknown flags: %x", flags);
+ *err = CURLE_SEND_ERROR;
+ return 0xff;
}
- return 0;
-}
-
-/* No extensions are supported. If any of the RSV bits are set, we must fail */
-static bool ws_frame_rsv_supported(int flags)
-{
- unsigned char reserved_bits = flags & WSBIT_RSV_MASK;
- return reserved_bits == 0;
}
static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data,
@@ -158,6 +231,16 @@ typedef ssize_t ws_write_payload(const unsigned char *buf, size_t buflen,
void *userp,
CURLcode *err);
+static void ws_dec_next_frame(struct ws_decoder *dec)
+{
+ dec->frame_age = 0;
+ dec->frame_flags = 0;
+ dec->payload_offset = 0;
+ dec->payload_len = 0;
+ dec->head_len = dec->head_total = 0;
+ dec->state = WS_DEC_INIT;
+ /* dec->cont_flags must be carried over to next frame */
+}
static void ws_dec_reset(struct ws_decoder *dec)
{
@@ -167,6 +250,7 @@ static void ws_dec_reset(struct ws_decoder *dec)
dec->payload_len = 0;
dec->head_len = dec->head_total = 0;
dec->state = WS_DEC_INIT;
+ dec->cont_flags = 0;
}
static void ws_dec_init(struct ws_decoder *dec)
@@ -186,20 +270,21 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec,
dec->head[0] = *inbuf;
Curl_bufq_skip(inraw, 1);
- if(!ws_frame_rsv_supported(dec->head[0])) {
- failf(data, "WS: unknown reserved bit in frame header: %x",
- dec->head[0] & WSBIT_RSV_MASK);
+ dec->frame_flags = ws_frame_firstbyte2flags(data, dec->head[0],
+ dec->cont_flags);
+ if(!dec->frame_flags) {
+ failf(data, "WS: invalid first byte: %x", dec->head[0]);
ws_dec_reset(dec);
return CURLE_RECV_ERROR;
}
- dec->frame_flags = ws_frame_op2flags(dec->head[0]);
- if(!dec->frame_flags) {
- failf(data, "WS: unknown opcode: %x",
- dec->head[0] & WSBIT_OPCODE_MASK);
- ws_dec_reset(dec);
- return CURLE_RECV_ERROR;
+ if(dec->frame_flags & CURLWS_CONT) {
+ dec->cont_flags = dec->frame_flags;
}
+ else {
+ dec->cont_flags = 0;
+ }
+
dec->head_len = 1;
/* ws_dec_info(dec, data, "seeing opcode"); */
continue;
@@ -320,7 +405,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec,
switch(dec->state) {
case WS_DEC_INIT:
- ws_dec_reset(dec);
+ ws_dec_next_frame(dec);
dec->state = WS_DEC_HEAD;
FALLTHROUGH();
case WS_DEC_HEAD:
@@ -369,11 +454,13 @@ static void update_meta(struct websocket *ws,
curl_off_t payload_len,
size_t cur_len)
{
+ curl_off_t bytesleft = (payload_len - payload_offset - cur_len);
+
ws->frame.age = frame_age;
ws->frame.flags = frame_flags;
ws->frame.offset = payload_offset;
ws->frame.len = cur_len;
- ws->frame.bytesleft = (payload_len - payload_offset - cur_len);
+ ws->frame.bytesleft = bytesleft;
}
/* WebSockets decoding client writer */
@@ -511,10 +598,8 @@ static const struct Curl_cwtype ws_cw_decode = {
static void ws_enc_info(struct ws_encoder *enc, struct Curl_easy *data,
const char *msg)
{
- infof(data, "WS-ENC: %s [%s%s%s payload=%" FMT_OFF_T "/%" FMT_OFF_T "]",
+ infof(data, "WS-ENC: %s [%s%s payload=%" FMT_OFF_T "/%" FMT_OFF_T "]",
msg, ws_frame_name_of_op(enc->firstbyte),
- (enc->firstbyte & WSBIT_OPCODE_MASK) == WSBIT_OPCODE_CONT ?
- " CONT" : "",
(enc->firstbyte & WSBIT_FIN) ? "" : " NON-FIN",
enc->payload_len - enc->payload_remain, enc->payload_len);
}
@@ -562,7 +647,6 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data,
CURLcode *err)
{
unsigned char firstbyte = 0;
- unsigned char opcode;
unsigned char head[14];
size_t hlen;
ssize_t n;
@@ -582,32 +666,16 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data,
return -1;
}
- opcode = ws_frame_flags2op((int)flags & ~CURLWS_CONT);
- if(!opcode) {
- failf(data, "WS: provided flags not recognized '%x'", flags);
- *err = CURLE_SEND_ERROR;
+ firstbyte = ws_frame_flags2firstbyte(data, flags, enc->contfragment, err);
+ if(*err) {
+ failf(data, "WS: provided flags not valid: %x", flags);
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;
+ /* fragmentation only applies to data frames (text/binary);
+ * control frames (close/ping/pong) do not affect the CONT status */
+ if(flags & (CURLWS_TEXT | CURLWS_BINARY)) {
+ enc->contfragment = (flags & CURLWS_CONT) ? (bit)TRUE : (bit)FALSE;
}
head[0] = enc->firstbyte = firstbyte;
@@ -746,7 +814,7 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req)
}
strcpy(keyval, randstr);
free(randstr);
- for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) {
+ for(i = 0; !result && (i < CURL_ARRAYSIZE(heads)); i++) {
if(!Curl_checkheaders(data, STRCONST(heads[i].name))) {
result = Curl_dyn_addf(req, "%s %s\r\n", heads[i].name,
heads[i].val);
@@ -778,12 +846,11 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
data->conn->proto.ws = ws;
#ifdef DEBUGBUILD
{
- char *p = getenv("CURL_WS_CHUNK_SIZE");
+ const char *p = getenv("CURL_WS_CHUNK_SIZE");
if(p) {
- long l = strtol(p, NULL, 10);
- if(l > 0 && l <= (1*1024*1024)) {
+ curl_off_t l;
+ if(!Curl_str_number(&p, &l, 1*1024*1024))
chunk_size = (size_t)l;
- }
}
}
#endif
@@ -854,7 +921,7 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
else { /* !connect_only */
/* And pass any additional data to the writers */
if(nread) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)mem, nread);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, mem, nread);
}
}
k->upgr101 = UPGR101_RECEIVED;
@@ -1032,12 +1099,11 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws,
/* Simulate a blocking send after this chunk has been sent */
bool eagain_next = FALSE;
size_t chunk_egain = 0;
- char *p = getenv("CURL_WS_CHUNK_EAGAIN");
+ const char *p = getenv("CURL_WS_CHUNK_EAGAIN");
if(p) {
- long l = strtol(p, NULL, 10);
- if(l > 0 && l <= (1*1024*1024)) {
+ curl_off_t l;
+ if(!Curl_str_number(&p, &l, 1*1024*1024))
chunk_egain = (size_t)l;
- }
}
#endif
@@ -1051,7 +1117,7 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws,
}
#endif
if(blocking) {
- result = ws_send_raw_blocking(data, ws, (char *)out, outlen);
+ result = ws_send_raw_blocking(data, ws, (const char *)out, outlen);
n = result ? 0 : outlen;
}
else if(data->set.connect_only || Curl_is_in_callback(data))
@@ -1309,7 +1375,10 @@ static CURLcode ws_setup_conn(struct Curl_easy *data,
struct connectdata *conn)
{
/* WebSockets is 1.1 only (for now) */
- data->state.httpwant = CURL_HTTP_VERSION_1_1;
+ data->state.http_neg.accept_09 = FALSE;
+ data->state.http_neg.only_10 = FALSE;
+ data->state.http_neg.wanted = CURL_HTTP_V1x;
+ data->state.http_neg.allowed = CURL_HTTP_V1x;
return Curl_http_setup_conn(data, conn);
}
diff --git a/libs/libcurl/src/ws.h b/libs/libcurl/src/ws.h
index 7a8c17895a..f6aaa7936f 100644
--- a/libs/libcurl/src/ws.h
+++ b/libs/libcurl/src/ws.h
@@ -43,6 +43,7 @@ struct ws_decoder {
unsigned char head[10];
int head_len, head_total;
enum ws_dec_state state;
+ int cont_flags;
};
/* a client-side WS frame encoder, generating frame headers and