summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Utilities/cmcurl/CMake/FindNGTCP2.cmake2
-rw-r--r--Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake2
-rw-r--r--Utilities/cmcurl/CMakeLists.txt150
-rw-r--r--Utilities/cmcurl/include/curl/curl.h7
-rw-r--r--Utilities/cmcurl/include/curl/curlver.h8
-rw-r--r--Utilities/cmcurl/include/curl/urlapi.h4
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt23
-rw-r--r--Utilities/cmcurl/lib/Makefile.inc6
-rw-r--r--Utilities/cmcurl/lib/cf-https-connect.c (renamed from Utilities/cmcurl/lib/cf-http.c)59
-rw-r--r--Utilities/cmcurl/lib/cf-https-connect.h (renamed from Utilities/cmcurl/lib/cf-http.h)0
-rw-r--r--Utilities/cmcurl/lib/cf-socket.c147
-rw-r--r--Utilities/cmcurl/lib/cf-socket.h7
-rw-r--r--Utilities/cmcurl/lib/cfilters.c36
-rw-r--r--Utilities/cmcurl/lib/cfilters.h19
-rw-r--r--Utilities/cmcurl/lib/conncache.c14
-rw-r--r--Utilities/cmcurl/lib/connect.c35
-rw-r--r--Utilities/cmcurl/lib/content_encoding.c8
-rw-r--r--Utilities/cmcurl/lib/cookie.c246
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.c10
-rw-r--r--Utilities/cmcurl/lib/curl_log.c2
-rw-r--r--Utilities/cmcurl/lib/curl_path.c75
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h4
-rw-r--r--Utilities/cmcurl/lib/curl_setup_once.h8
-rw-r--r--Utilities/cmcurl/lib/doh.c2
-rw-r--r--Utilities/cmcurl/lib/dynbuf.c3
-rw-r--r--Utilities/cmcurl/lib/easy.c1
-rw-r--r--Utilities/cmcurl/lib/ftp.c154
-rw-r--r--Utilities/cmcurl/lib/ftp.h5
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.c43
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.h34
-rw-r--r--Utilities/cmcurl/lib/headers.c17
-rw-r--r--Utilities/cmcurl/lib/hostasyn.c2
-rw-r--r--Utilities/cmcurl/lib/hostip.c91
-rw-r--r--Utilities/cmcurl/lib/hostip.h2
-rw-r--r--Utilities/cmcurl/lib/http.c175
-rw-r--r--Utilities/cmcurl/lib/http2.c351
-rw-r--r--Utilities/cmcurl/lib/http_aws_sigv4.c190
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c12
-rw-r--r--Utilities/cmcurl/lib/idn.c5
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.c13
-rw-r--r--Utilities/cmcurl/lib/inet_pton.c15
-rw-r--r--Utilities/cmcurl/lib/krb5.c8
-rw-r--r--Utilities/cmcurl/lib/ldap.c8
-rw-r--r--Utilities/cmcurl/lib/mqtt.c5
-rw-r--r--Utilities/cmcurl/lib/multi.c103
-rw-r--r--Utilities/cmcurl/lib/parsedate.c159
-rw-r--r--Utilities/cmcurl/lib/progress.c13
-rw-r--r--Utilities/cmcurl/lib/rand.c9
-rw-r--r--Utilities/cmcurl/lib/rtsp.c15
-rw-r--r--Utilities/cmcurl/lib/select.c4
-rw-r--r--Utilities/cmcurl/lib/setopt.c6
-rw-r--r--Utilities/cmcurl/lib/sigpipe.h1
-rw-r--r--Utilities/cmcurl/lib/smb.c3
-rw-r--r--Utilities/cmcurl/lib/telnet.c179
-rw-r--r--Utilities/cmcurl/lib/transfer.c21
-rw-r--r--Utilities/cmcurl/lib/url.c96
-rw-r--r--Utilities/cmcurl/lib/urlapi.c31
-rw-r--r--Utilities/cmcurl/lib/urldata.h16
-rw-r--r--Utilities/cmcurl/lib/version.c11
-rw-r--r--Utilities/cmcurl/lib/vquic/curl_msh3.c23
-rw-r--r--Utilities/cmcurl/lib/vquic/curl_ngtcp2.c61
-rw-r--r--Utilities/cmcurl/lib/vquic/curl_quiche.c51
-rw-r--r--Utilities/cmcurl/lib/vquic/vquic.c7
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh.c54
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh2.c15
-rw-r--r--Utilities/cmcurl/lib/vssh/ssh.h4
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c32
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c59
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c141
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c107
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c48
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.c39
-rw-r--r--Utilities/cmcurl/lib/vtls/x509asn1.c4
-rw-r--r--Utilities/cmcurl/lib/wildcard.c75
-rw-r--r--Utilities/cmcurl/lib/wildcard.h70
-rw-r--r--Utilities/cmcurl/lib/ws.c7
76 files changed, 1934 insertions, 1538 deletions
diff --git a/Utilities/cmcurl/CMake/FindNGTCP2.cmake b/Utilities/cmcurl/CMake/FindNGTCP2.cmake
index 9f4e9f2..ff0d49e 100644
--- a/Utilities/cmcurl/CMake/FindNGTCP2.cmake
+++ b/Utilities/cmcurl/CMake/FindNGTCP2.cmake
@@ -71,7 +71,7 @@ endif()
if(NGTCP2_FIND_COMPONENTS)
set(NGTCP2_CRYPTO_BACKEND "")
foreach(component IN LISTS NGTCP2_FIND_COMPONENTS)
- if(component MATCHES "^(BoringSSL|OpenSSL|GnuTLS)")
+ if(component MATCHES "^(BoringSSL|OpenSSL|wolfSSL|GnuTLS)")
if(NGTCP2_CRYPTO_BACKEND)
message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
endif()
diff --git a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
index cef31b5..3771237 100644
--- a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
+++ b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
@@ -29,7 +29,6 @@ if(NOT UNIX)
set(HAVE_ARPA_INET_H 0)
set(HAVE_FCNTL_H 1)
- set(HAVE_INTTYPES_H 0)
set(HAVE_IO_H 1)
set(HAVE_NETDB_H 0)
set(HAVE_NETINET_IN_H 0)
@@ -37,7 +36,6 @@ if(NOT UNIX)
set(HAVE_PWD_H 0)
set(HAVE_SETJMP_H 1)
set(HAVE_SIGNAL_H 1)
- set(HAVE_STDINT_H 0)
set(HAVE_STDLIB_H 1)
set(HAVE_STRINGS_H 0)
set(HAVE_STRING_H 1)
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index 6fc316d..f10a47d 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -197,7 +197,7 @@ endif()
# HAVE_RAND_EGD: `RAND_egd` present in OpenSSL
# HAVE_BORINGSSL: OpenSSL is BoringSSL
# HAVE_PK11_CREATEMANAGEDGENERICOBJECTL: `PK11_CreateManagedGenericObject` present in NSS
-# HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL
+# HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL/wolfSSL
# HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in QUICHE
# HAVE_ZSTD_CREATEDSTREAM: `ZSTD_createDStream` present in Zstd
#
@@ -523,7 +523,7 @@ if(APPLE)
endif()
if(WIN32)
cmake_dependent_option(CURL_USE_SCHANNEL "enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
- cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON
+ cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without OpenSSL" ON
CURL_USE_SCHANNEL OFF)
endif()
cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
@@ -583,6 +583,58 @@ if(use_core_foundation)
list(APPEND CURL_LIBS "-framework CoreFoundation")
endif()
+# Keep compression lib detection before TLS detection, which
+# might depend on it.
+
+set(HAVE_LIBZ OFF)
+set(USE_ZLIB OFF)
+optional_dependency(ZLIB)
+if(ZLIB_FOUND)
+ set(HAVE_LIBZ ON)
+ set(USE_ZLIB ON)
+
+ # Depend on ZLIB via imported targets if supported by the running
+ # version of CMake. This allows our dependents to get our dependencies
+ # transitively.
+ if(NOT CMAKE_VERSION VERSION_LESS 3.4)
+ list(APPEND CURL_LIBS ZLIB::ZLIB)
+ else()
+ list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
+ include_directories(${ZLIB_INCLUDE_DIRS})
+ endif()
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
+endif()
+
+option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
+set(HAVE_BROTLI OFF)
+if(CURL_BROTLI)
+ find_package(Brotli QUIET)
+ if(BROTLI_FOUND)
+ set(HAVE_BROTLI ON)
+ list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
+ include_directories(${BROTLI_INCLUDE_DIRS})
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
+ endif()
+endif()
+
+option(CURL_ZSTD "Set to ON to enable building curl with zstd support." OFF)
+set(HAVE_ZSTD OFF)
+if(CURL_ZSTD)
+ find_package(Zstd REQUIRED)
+ if (NOT DEFINED HAVE_ZSTD_CREATEDSTREAM)
+ cmake_push_check_state()
+ set(CMAKE_REQUIRED_INCLUDES ${Zstd_INCLUDE_DIRS})
+ set(CMAKE_REQUIRED_LIBRARIES ${Zstd_LIBRARIES})
+ check_symbol_exists(ZSTD_createDStream "zstd.h" HAVE_ZSTD_CREATEDSTREAM)
+ cmake_pop_check_state()
+ endif()
+ if(Zstd_FOUND AND HAVE_ZSTD_CREATEDSTREAM)
+ set(HAVE_ZSTD ON)
+ list(APPEND CURL_LIBS ${Zstd_LIBRARIES})
+ include_directories(${Zstd_INCLUDE_DIRS})
+ endif()
+endif()
+
if(CURL_USE_OPENSSL)
find_package(OpenSSL)
if(NOT OpenSSL_FOUND)
@@ -660,23 +712,39 @@ if(USE_NGHTTP2)
endif()
function(CheckQuicSupportInOpenSSL)
- # Be sure that the OpenSSL library actually supports QUIC.
+ # Be sure that the OpenSSL/wolfSSL library actually supports QUIC.
if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD)
cmake_push_check_state()
- set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
- set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}")
- check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
+ if(USE_WOLFSSL)
+ set(CMAKE_REQUIRED_INCLUDES "${WolfSSL_INCLUDE_DIRS}")
+ set(CMAKE_REQUIRED_LIBRARIES "${WolfSSL_LIBRARIES}")
+ if(HAVE_LIBZ)
+ list(APPEND CMAKE_REQUIRED_INCLUDES "${ZLIB_INCLUDE_DIRS}")
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "${ZLIB_LIBRARIES}")
+ endif()
+ if(WIN32)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES "crypt32")
+ endif()
+ list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_UINTPTR_T) # to pull in stdint.h (as of wolfSSL v5.5.4)
+ check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
+ else()
+ set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
+ set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}")
+ check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
+ endif()
cmake_pop_check_state()
endif()
if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD)
- message(FATAL_ERROR "QUIC support is missing in OpenSSL/BoringSSL. Try setting -DOPENSSL_ROOT_DIR")
+ message(FATAL_ERROR "QUIC support is missing in OpenSSL/BoringSSL/wolfSSL. Try setting -DOPENSSL_ROOT_DIR")
endif()
endfunction()
option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF)
if(USE_NGTCP2)
- if(USE_OPENSSL)
- if(HAVE_BORINGSSL)
+ if(USE_OPENSSL OR USE_WOLFSSL)
+ if(USE_WOLFSSL)
+ find_package(NGTCP2 REQUIRED wolfSSL)
+ elseif(HAVE_BORINGSSL)
find_package(NGTCP2 REQUIRED BoringSSL)
else()
find_package(NGTCP2 REQUIRED OpenSSL)
@@ -686,7 +754,7 @@ if(USE_NGTCP2)
# TODO add GnuTLS support as vtls library.
find_package(NGTCP2 REQUIRED GnuTLS)
else()
- message(FATAL_ERROR "ngtcp2 requires OpenSSL or GnuTLS")
+ message(FATAL_ERROR "ngtcp2 requires OpenSSL, wolfSSL or GnuTLS")
endif()
set(USE_NGTCP2 ON)
include_directories(${NGTCP2_INCLUDE_DIRS})
@@ -734,6 +802,8 @@ if(NOT CURL_DISABLE_LDAP)
check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32)
if(NOT HAVE_WLDAP32)
set(USE_WIN32_LDAP OFF)
+ elseif(NOT CURL_DISABLE_LDAPS)
+ set(HAVE_LDAP_SSL ON)
endif()
endif()
endif()
@@ -849,56 +919,6 @@ if(WIN32)
endif()
endif()
-set(HAVE_LIBZ OFF)
-set(USE_ZLIB OFF)
-#optional_dependency(ZLIB)
-find_package(ZLIB)
-if(ZLIB_FOUND)
- set(HAVE_LIBZ ON)
- set(USE_ZLIB ON)
-
- # Depend on ZLIB via imported targets if supported by the running
- # version of CMake. This allows our dependents to get our dependencies
- # transitively.
- if(NOT CMAKE_VERSION VERSION_LESS 3.4)
- list(APPEND CURL_LIBS ZLIB::ZLIB)
- else()
- list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
- include_directories(${ZLIB_INCLUDE_DIRS})
- list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
- endif()
-endif()
-
-option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
-set(HAVE_BROTLI OFF)
-if(CURL_BROTLI)
- find_package(Brotli QUIET)
- if(BROTLI_FOUND)
- set(HAVE_BROTLI ON)
- list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
- include_directories(${BROTLI_INCLUDE_DIRS})
- list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
- endif()
-endif()
-
-option(CURL_ZSTD "Set to ON to enable building curl with zstd support." OFF)
-set(HAVE_ZSTD OFF)
-if(CURL_ZSTD)
- find_package(Zstd REQUIRED)
- if (NOT DEFINED HAVE_ZSTD_CREATEDSTREAM)
- cmake_push_check_state()
- set(CMAKE_REQUIRED_INCLUDES ${Zstd_INCLUDE_DIRS})
- set(CMAKE_REQUIRED_LIBRARIES ${Zstd_LIBRARIES})
- check_symbol_exists(ZSTD_createDStream "zstd.h" HAVE_ZSTD_CREATEDSTREAM)
- cmake_pop_check_state()
- endif()
- if(Zstd_FOUND AND HAVE_ZSTD_CREATEDSTREAM)
- set(HAVE_ZSTD ON)
- list(APPEND CURL_LIBS ${Zstd_LIBRARIES})
- include_directories(${Zstd_INCLUDE_DIRS})
- endif()
-endif()
-
#libpsl
option(CURL_USE_LIBPSL "Use libPSL" ON)
mark_as_advanced(CURL_USE_LIBPSL)
@@ -1035,7 +1055,9 @@ elseif("${CURL_CA_BUNDLE}" STREQUAL "none")
unset(CURL_CA_BUNDLE CACHE)
elseif("${CURL_CA_BUNDLE}" STREQUAL "auto")
unset(CURL_CA_BUNDLE CACHE)
- set(CURL_CA_BUNDLE_AUTODETECT TRUE)
+ if(NOT CMAKE_CROSSCOMPILING)
+ set(CURL_CA_BUNDLE_AUTODETECT TRUE)
+ endif()
else()
set(CURL_CA_BUNDLE_SET TRUE)
endif()
@@ -1046,7 +1068,7 @@ elseif("${CURL_CA_PATH}" STREQUAL "none")
unset(CURL_CA_PATH CACHE)
elseif("${CURL_CA_PATH}" STREQUAL "auto")
unset(CURL_CA_PATH CACHE)
- if(NOT USE_NSS)
+ if(NOT CMAKE_CROSSCOMPILING AND NOT USE_NSS)
set(CURL_CA_PATH_AUTODETECT TRUE)
endif()
else()
@@ -1156,7 +1178,6 @@ check_include_file_concat("unistd.h" HAVE_UNISTD_H)
check_include_file_concat("utime.h" HAVE_UTIME_H)
check_include_file_concat("stddef.h" HAVE_STDDEF_H)
-check_include_file_concat("stdint.h" HAVE_STDINT_H)
check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H)
check_type_size(size_t SIZEOF_SIZE_T)
@@ -1208,7 +1229,6 @@ check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
check_symbol_exists(signal "${CURL_INCLUDES}" HAVE_SIGNAL)
check_symbol_exists(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL)
-check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64)
check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R)
check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO)
@@ -1415,8 +1435,6 @@ else()
set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H})
set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H})
endif()
-set(CURL_PULL_STDINT_H ${HAVE_STDINT_H})
-set(CURL_PULL_INTTYPES_H ${HAVE_INTTYPES_H})
include(CMake/OtherTests.cmake)
diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h
index c5ce0a5..4c6288d 100644
--- a/Utilities/cmcurl/include/curl/curl.h
+++ b/Utilities/cmcurl/include/curl/curl.h
@@ -34,11 +34,12 @@
#endif
/* Compile-time deprecation macros. */
-#if defined(__GNUC__) && (__GNUC__ >= 6) && \
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) && \
!defined(__INTEL_COMPILER) && \
!defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
-#define CURL_DEPRECATED(version, message) \
- __attribute__((deprecated("since " # version ". " message)))
+#define CURL_DEPRECATED(version, message) \
+ __attribute__((deprecated("since " # version ". " message)))
#define CURL_IGNORE_DEPRECATION(statements) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h
index ce39cdc..6f2affa 100644
--- a/Utilities/cmcurl/include/curl/curlver.h
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@ -32,12 +32,12 @@
/* This is the version number of the libcurl package from which this header
file origins: */
-#define LIBCURL_VERSION "7.88.1"
+#define LIBCURL_VERSION "8.0.1"
/* The numeric version number is also available "in parts" by using these
defines: */
-#define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 88
+#define LIBCURL_VERSION_MAJOR 8
+#define LIBCURL_VERSION_MINOR 0
#define LIBCURL_VERSION_PATCH 1
/* This is the numeric version of the libcurl version number, meant for easier
@@ -59,7 +59,7 @@
CURL_VERSION_BITS() macro since curl's own configure script greps for it
and needs it to contain the full number.
*/
-#define LIBCURL_VERSION_NUM 0x075801
+#define LIBCURL_VERSION_NUM 0x080001
/*
* This is the date and time when the full source package was created. The
diff --git a/Utilities/cmcurl/include/curl/urlapi.h b/Utilities/cmcurl/include/curl/urlapi.h
index b97b534..b3504b6 100644
--- a/Utilities/cmcurl/include/curl/urlapi.h
+++ b/Utilities/cmcurl/include/curl/urlapi.h
@@ -117,14 +117,14 @@ CURL_EXTERN void curl_url_cleanup(CURLU *handle);
* curl_url_dup() duplicates a CURLU handle and returns a new copy. The new
* handle must also be freed with curl_url_cleanup().
*/
-CURL_EXTERN CURLU *curl_url_dup(CURLU *in);
+CURL_EXTERN CURLU *curl_url_dup(const CURLU *in);
/*
* curl_url_get() extracts a specific part of the URL from a CURLU
* handle. Returns error code. The returned pointer MUST be freed with
* curl_free() afterwards.
*/
-CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
+CURL_EXTERN CURLUcode curl_url_get(const CURLU *handle, CURLUPart what,
char **part, unsigned int flags);
/*
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index 15853ff..c3eb842 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -47,29 +47,6 @@ if(WIN32 AND NOT CURL_STATICLIB)
list(APPEND CSOURCES libcurl.rc)
endif()
-# SET(CSOURCES
-# # memdebug.c -not used
-# # nwlib.c - Not used
-# # strtok.c - specify later
-# # strtoofft.c - specify later
-# )
-
-# #OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF)
-# MARK_AS_ADVANCED(CURL_MALLOC_DEBUG)
-# IF(CURL_MALLOC_DEBUG)
-# SET(CSOURCES ${CSOURCES}
-# memdebug.c
-# )
-# ENDIF(CURL_MALLOC_DEBUG)
-
-# # only build compat strtoofft if we need to
-# IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
-# SET(CSOURCES ${CSOURCES}
-# strtoofft.c
-# )
-# ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
-
-
# The rest of the build
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include)
diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc
index c28b475..663190a 100644
--- a/Utilities/cmcurl/lib/Makefile.inc
+++ b/Utilities/cmcurl/lib/Makefile.inc
@@ -107,7 +107,7 @@ LIB_CFILES = \
base64.c \
bufref.c \
c-hyper.c \
- cf-http.c \
+ cf-https-connect.c \
cf-socket.c \
cfilters.c \
conncache.c \
@@ -223,7 +223,6 @@ LIB_CFILES = \
version.c \
version_win32.c \
warnless.c \
- wildcard.c \
ws.c
LIB_HFILES = \
@@ -233,7 +232,7 @@ LIB_HFILES = \
asyn.h \
bufref.h \
c-hyper.h \
- cf-http.h \
+ cf-https-connect.h \
cf-socket.h \
cfilters.h \
conncache.h \
@@ -352,7 +351,6 @@ LIB_HFILES = \
urldata.h \
version_win32.h \
warnless.h \
- wildcard.h \
ws.h
LIB_RCFILES = libcurl.rc
diff --git a/Utilities/cmcurl/lib/cf-http.c b/Utilities/cmcurl/lib/cf-https-connect.c
index 2ee3d4d..ed70ad0 100644
--- a/Utilities/cmcurl/lib/cf-http.c
+++ b/Utilities/cmcurl/lib/cf-https-connect.c
@@ -32,7 +32,7 @@
#include "cfilters.h"
#include "connect.h"
#include "multiif.h"
-#include "cf-http.h"
+#include "cf-https-connect.h"
#include "http2.h"
#include "vquic/vquic.h"
@@ -266,7 +266,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
}
else if(ctx->h21_baller.enabled)
- cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", TRNSPRT_TCP);
+ cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
+ cf->conn->transport);
ctx->state = CF_HC_CONNECT;
/* FALLTHROUGH */
@@ -280,7 +281,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
if(time_to_start_h21(cf, data, now)) {
- cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", TRNSPRT_TCP);
+ cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
+ cf->conn->transport);
}
if(cf_hc_baller_is_active(&ctx->h21_baller)) {
@@ -374,6 +376,55 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
|| cf_hc_baller_data_pending(&ctx->h21_baller, data);
}
+static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ int query)
+{
+ struct cf_hc_ctx *ctx = cf->ctx;
+ struct Curl_cfilter *cfb;
+ struct curltime t, tmax;
+
+ memset(&tmax, 0, sizeof(tmax));
+ memset(&t, 0, sizeof(t));
+ cfb = ctx->h21_baller.enabled? ctx->h21_baller.cf : NULL;
+ if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
+ if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+ tmax = t;
+ }
+ memset(&t, 0, sizeof(t));
+ cfb = ctx->h3_baller.enabled? ctx->h3_baller.cf : NULL;
+ if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
+ if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+ tmax = t;
+ }
+ return tmax;
+}
+
+static CURLcode cf_hc_query(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ int query, int *pres1, void *pres2)
+{
+ if(!cf->connected) {
+ switch(query) {
+ case CF_QUERY_TIMER_CONNECT: {
+ struct curltime *when = pres2;
+ *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
+ return CURLE_OK;
+ }
+ case CF_QUERY_TIMER_APPCONNECT: {
+ struct curltime *when = pres2;
+ *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
+ return CURLE_OK;
+ }
+ default:
+ break;
+ }
+ }
+ return cf->next?
+ cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+ CURLE_UNKNOWN_OPTION;
+}
+
static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
DEBUGF(LOG_CF(data, cf, "close"));
@@ -411,7 +462,7 @@ struct Curl_cftype Curl_cft_http_connect = {
Curl_cf_def_cntrl,
Curl_cf_def_conn_is_alive,
Curl_cf_def_conn_keep_alive,
- Curl_cf_def_query,
+ cf_hc_query,
};
static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
diff --git a/Utilities/cmcurl/lib/cf-http.h b/Utilities/cmcurl/lib/cf-https-connect.h
index 6a39527..6a39527 100644
--- a/Utilities/cmcurl/lib/cf-http.h
+++ b/Utilities/cmcurl/lib/cf-https-connect.h
diff --git a/Utilities/cmcurl/lib/cf-socket.c b/Utilities/cmcurl/lib/cf-socket.c
index 2549f34..6d9ace4 100644
--- a/Utilities/cmcurl/lib/cf-socket.c
+++ b/Utilities/cmcurl/lib/cf-socket.c
@@ -253,19 +253,6 @@ static CURLcode socket_open(struct Curl_easy *data,
else {
/* opensocket callback not set, so simply create the socket now */
*sockfd = socket(addr->family, addr->socktype, addr->protocol);
- if(!*sockfd && addr->socktype == SOCK_DGRAM) {
- /* This is icky and seems, at least, to happen on macOS:
- * we get sockfd == 0 and if called again, we get a valid one > 0.
- * If we close the 0, we sometimes get failures in multi poll, as
- * 0 seems also be the fd for the sockpair used for WAKEUP polling.
- * Very strange. Maybe this code should be ifdef'ed for macOS, but
- * on "real" OS, fd 0 is stdin and we never see that. So...
- */
- fake_sclose(*sockfd);
- *sockfd = socket(addr->family, addr->socktype, addr->protocol);
- DEBUGF(infof(data, "QUIRK: UDP socket() gave handle 0, 2nd attempt %d",
- (int)*sockfd));
- }
}
if(*sockfd == CURL_SOCKET_BAD)
@@ -338,20 +325,6 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
return socket_close(data, conn, FALSE, sock);
}
-bool Curl_socket_is_dead(curl_socket_t sock)
-{
- int sval;
- bool ret_val = TRUE;
-
- sval = SOCKET_READABLE(sock, 0);
- if(sval == 0)
- /* timeout */
- ret_val = FALSE;
-
- return ret_val;
-}
-
-
#ifdef USE_WINSOCK
/* When you run a program that uses the Windows Sockets API, you may
experience slow performance when you copy data to a TCP server.
@@ -522,7 +495,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
conn->ip_version = CURL_IPRESOLVE_V6;
#endif
- rc = Curl_resolv(data, dev, 0, FALSE, &h);
+ rc = Curl_resolv(data, dev, 80, FALSE, &h);
if(rc == CURLRESOLV_PENDING)
(void)Curl_resolver_wait_resolv(data, &h);
conn->ip_version = ipver;
@@ -1084,6 +1057,11 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
if(result)
goto out;
+ if(cf->connected) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
/* Connect TCP socket */
rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
if(-1 == rc) {
@@ -1449,22 +1427,6 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
case CF_CTRL_CONN_INFO_UPDATE:
cf_socket_active(cf, data);
break;
- case CF_CTRL_CONN_REPORT_STATS:
- switch(ctx->transport) {
- case TRNSPRT_UDP:
- case TRNSPRT_QUIC:
- /* Since UDP connected sockets work different from TCP, we use the
- * time of the first byte from the peer as the "connect" time. */
- if(ctx->got_first_byte) {
- Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at);
- break;
- }
- /* FALLTHROUGH */
- default:
- Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->connected_at);
- break;
- }
- break;
case CF_CTRL_DATA_SETUP:
Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
break;
@@ -1473,38 +1435,39 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
}
static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+ struct Curl_easy *data,
+ bool *input_pending)
{
struct cf_socket_ctx *ctx = cf->ctx;
- int sval;
+ struct pollfd pfd[1];
+ int r;
+ *input_pending = FALSE;
(void)data;
if(!ctx || ctx->sock == CURL_SOCKET_BAD)
return FALSE;
- sval = SOCKET_READABLE(ctx->sock, 0);
- if(sval == 0) {
- /* timeout */
- return TRUE;
- }
- else if(sval & CURL_CSELECT_ERR) {
- /* socket is in an error state */
+ /* Check with 0 timeout if there are any events pending on the socket */
+ pfd[0].fd = ctx->sock;
+ pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+ pfd[0].revents = 0;
+
+ r = Curl_poll(pfd, 1, 0);
+ if(r < 0) {
+ DEBUGF(LOG_CF(data, cf, "is_alive: poll error, assume dead"));
return FALSE;
}
- else if(sval & CURL_CSELECT_IN) {
- /* readable with no error. could still be closed */
-/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
-#ifdef MSG_PEEK
- /* use the socket */
- char buf;
- if(recv((RECV_TYPE_ARG1)ctx->sock, (RECV_TYPE_ARG2)&buf,
- (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
- return FALSE; /* FIN received */
- }
-#endif
+ else if(r == 0) {
+ DEBUGF(LOG_CF(data, cf, "is_alive: poll timeout, assume alive"));
return TRUE;
}
+ else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
+ DEBUGF(LOG_CF(data, cf, "is_alive: err/hup/etc events, assume dead"));
+ return FALSE;
+ }
+ DEBUGF(LOG_CF(data, cf, "is_alive: valid events, looks alive"));
+ *input_pending = TRUE;
return TRUE;
}
@@ -1527,6 +1490,24 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
else
*pres1 = -1;
return CURLE_OK;
+ case CF_QUERY_TIMER_CONNECT: {
+ struct curltime *when = pres2;
+ switch(ctx->transport) {
+ case TRNSPRT_UDP:
+ case TRNSPRT_QUIC:
+ /* Since UDP connected sockets work different from TCP, we use the
+ * time of the first byte from the peer as the "connect" time. */
+ if(ctx->got_first_byte) {
+ *when = ctx->first_byte_at;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ *when = ctx->connected_at;
+ break;
+ }
+ return CURLE_OK;
+ }
default:
break;
}
@@ -1826,7 +1807,6 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
Curl_conn_cf_add(data, conn, sockindex, cf);
conn->sock[sockindex] = ctx->sock;
- set_remote_ip(cf, data);
set_local_ip(cf, data);
ctx->active = TRUE;
ctx->connected_at = Curl_now();
@@ -1841,6 +1821,38 @@ out:
return result;
}
+static void set_accepted_remote_ip(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_socket_ctx *ctx = cf->ctx;
+#ifdef HAVE_GETPEERNAME
+ char buffer[STRERROR_LEN];
+ struct Curl_sockaddr_storage ssrem;
+ curl_socklen_t plen;
+
+ ctx->r_ip[0] = 0;
+ ctx->r_port = 0;
+ plen = sizeof(ssrem);
+ memset(&ssrem, 0, plen);
+ if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
+ int error = SOCKERRNO;
+ failf(data, "getpeername() failed with errno %d: %s",
+ error, Curl_strerror(error, buffer, sizeof(buffer)));
+ return;
+ }
+ if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
+ ctx->r_ip, &ctx->r_port)) {
+ failf(data, "ssrem inet_ntop() failed with errno %d: %s",
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+ return;
+ }
+#else
+ ctx->r_ip[0] = 0;
+ ctx->r_port = 0;
+ (void)data;
+#endif
+}
+
CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
struct connectdata *conn,
int sockindex, curl_socket_t *s)
@@ -1857,13 +1869,14 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
socket_close(data, conn, TRUE, ctx->sock);
ctx->sock = *s;
conn->sock[sockindex] = ctx->sock;
- set_remote_ip(cf, data);
+ set_accepted_remote_ip(cf, data);
set_local_ip(cf, data);
ctx->active = TRUE;
ctx->accepted = TRUE;
ctx->connected_at = Curl_now();
cf->connected = TRUE;
- DEBUGF(LOG_CF(data, cf, "Curl_conn_tcp_accepted_set(%d)", (int)ctx->sock));
+ DEBUGF(LOG_CF(data, cf, "accepted_set(sock=%d, remote=%s port=%d)",
+ (int)ctx->sock, ctx->r_ip, ctx->r_port));
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/cf-socket.h b/Utilities/cmcurl/lib/cf-socket.h
index f6eb810..0eec61a 100644
--- a/Utilities/cmcurl/lib/cf-socket.h
+++ b/Utilities/cmcurl/lib/cf-socket.h
@@ -70,13 +70,6 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t sock);
-/*
- * This function should return TRUE if the socket is to be assumed to
- * be dead. Most commonly this happens when the server has closed the
- * connection due to inactivity.
- */
-bool Curl_socket_is_dead(curl_socket_t sock);
-
/**
* Determine the curl code for a socket connect() == -1 with errno.
*/
diff --git a/Utilities/cmcurl/lib/cfilters.c b/Utilities/cmcurl/lib/cfilters.c
index 2af0dd8..e60d138 100644
--- a/Utilities/cmcurl/lib/cfilters.c
+++ b/Utilities/cmcurl/lib/cfilters.c
@@ -124,10 +124,11 @@ ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+ struct Curl_easy *data,
+ bool *input_pending)
{
return cf->next?
- cf->next->cft->is_alive(cf->next, data) :
+ cf->next->cft->is_alive(cf->next, data, input_pending) :
FALSE; /* pessimistic in absence of data */
}
@@ -370,9 +371,12 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
result = cf->cft->connect(cf, data, blocking, done);
if(!result && *done) {
Curl_conn_ev_update_info(data, data->conn);
- Curl_conn_ev_report_stats(data, data->conn);
+ Curl_conn_report_connect_stats(data, data->conn);
data->conn->keepalive = Curl_now();
}
+ else if(result) {
+ Curl_conn_report_connect_stats(data, data->conn);
+ }
}
return result;
@@ -608,16 +612,32 @@ void Curl_conn_ev_update_info(struct Curl_easy *data,
cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
}
-void Curl_conn_ev_report_stats(struct Curl_easy *data,
- struct connectdata *conn)
+void Curl_conn_report_connect_stats(struct Curl_easy *data,
+ struct connectdata *conn)
{
- cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_REPORT_STATS, 0, NULL);
+ struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
+ if(cf) {
+ struct curltime connected;
+ struct curltime appconnected;
+
+ memset(&connected, 0, sizeof(connected));
+ cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
+ if(connected.tv_sec || connected.tv_usec)
+ Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
+
+ memset(&appconnected, 0, sizeof(appconnected));
+ cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
+ if(appconnected.tv_sec || appconnected.tv_usec)
+ Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
+ }
}
-bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn)
+bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
+ bool *input_pending)
{
struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
- return cf && !cf->conn->bits.close && cf->cft->is_alive(cf, data);
+ return cf && !cf->conn->bits.close &&
+ cf->cft->is_alive(cf, data, input_pending);
}
CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
diff --git a/Utilities/cmcurl/lib/cfilters.h b/Utilities/cmcurl/lib/cfilters.h
index 94dc53f..317f2bb 100644
--- a/Utilities/cmcurl/lib/cfilters.h
+++ b/Utilities/cmcurl/lib/cfilters.h
@@ -85,7 +85,8 @@ typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf,
CURLcode *err); /* error to return */
typedef bool Curl_cft_conn_is_alive(struct Curl_cfilter *cf,
- struct Curl_easy *data);
+ struct Curl_easy *data,
+ bool *input_pending);
typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
struct Curl_easy *data);
@@ -109,8 +110,6 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
#define CF_CTRL_DATA_DONE_SEND 8 /* 0 NULL ignored */
/* update conn info at connection and data */
#define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0 NULL ignored */
-/* report conn statistics (timers) for connection and data */
-#define CF_CTRL_CONN_REPORT_STATS (256+1) /* 0 NULL ignored */
/**
* Handle event/control for the filter.
@@ -138,6 +137,8 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
#define CF_QUERY_MAX_CONCURRENT 1 /* number - */
#define CF_QUERY_CONNECT_REPLY_MS 2 /* number - */
#define CF_QUERY_SOCKET 3 /* - curl_socket_t */
+#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */
+#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */
/**
* Query the cfilter for properties. Filters ignorant of a query will
@@ -216,7 +217,8 @@ CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
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);
+ struct Curl_easy *data,
+ bool *input_pending);
CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
struct Curl_easy *data);
CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
@@ -435,15 +437,16 @@ void Curl_conn_ev_update_info(struct Curl_easy *data,
struct connectdata *conn);
/**
- * Inform connection filters to report statistics.
+ * Update connection statistics
*/
-void Curl_conn_ev_report_stats(struct Curl_easy *data,
- struct connectdata *conn);
+void Curl_conn_report_connect_stats(struct Curl_easy *data,
+ struct connectdata *conn);
/**
* Check if FIRSTSOCKET's cfilter chain deems connection alive.
*/
-bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn);
+bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
+ bool *input_pending);
/**
* Try to upkeep the connection filters at sockindex.
diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
index c21b96c..1c736da 100644
--- a/Utilities/cmcurl/lib/conncache.c
+++ b/Utilities/cmcurl/lib/conncache.c
@@ -45,13 +45,6 @@
#define HASHKEY_SIZE 128
-static void conn_llist_dtor(void *user, void *element)
-{
- struct connectdata *conn = element;
- (void)user;
- conn->bundle = NULL;
-}
-
static CURLcode bundle_create(struct connectbundle **bundlep)
{
DEBUGASSERT(*bundlep == NULL);
@@ -62,17 +55,12 @@ static CURLcode bundle_create(struct connectbundle **bundlep)
(*bundlep)->num_connections = 0;
(*bundlep)->multiuse = BUNDLE_UNKNOWN;
- Curl_llist_init(&(*bundlep)->conn_list, (Curl_llist_dtor) conn_llist_dtor);
+ Curl_llist_init(&(*bundlep)->conn_list, NULL);
return CURLE_OK;
}
static void bundle_destroy(struct connectbundle *bundle)
{
- if(!bundle)
- return;
-
- Curl_llist_destroy(&bundle->conn_list, NULL);
-
free(bundle);
}
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index 993a7f9..10d0c11 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -59,7 +59,7 @@
#include "strerror.h"
#include "cfilters.h"
#include "connect.h"
-#include "cf-http.h"
+#include "cf-https-connect.h"
#include "cf-socket.h"
#include "select.h"
#include "url.h" /* for Curl_safefree() */
@@ -957,6 +957,28 @@ static bool cf_he_data_pending(struct Curl_cfilter *cf,
return FALSE;
}
+static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ int query)
+{
+ struct cf_he_ctx *ctx = cf->ctx;
+ struct curltime t, tmax;
+ size_t i;
+
+ memset(&tmax, 0, sizeof(tmax));
+ for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+ struct eyeballer *baller = ctx->baller[i];
+
+ memset(&t, 0, sizeof(t));
+ if(baller && baller->cf &&
+ !baller->cf->cft->query(baller->cf, data, query, NULL, &t)) {
+ if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+ tmax = t;
+ }
+ }
+ return tmax;
+}
+
static CURLcode cf_he_query(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query, int *pres1, void *pres2)
@@ -984,7 +1006,16 @@ static CURLcode cf_he_query(struct Curl_cfilter *cf,
DEBUGF(LOG_CF(data, cf, "query connect reply: %dms", *pres1));
return CURLE_OK;
}
-
+ case CF_QUERY_TIMER_CONNECT: {
+ struct curltime *when = pres2;
+ *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
+ return CURLE_OK;
+ }
+ case CF_QUERY_TIMER_APPCONNECT: {
+ struct curltime *when = pres2;
+ *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
+ return CURLE_OK;
+ }
default:
break;
}
diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c
index a29d204..aa1e0cb 100644
--- a/Utilities/cmcurl/lib/content_encoding.c
+++ b/Utilities/cmcurl/lib/content_encoding.c
@@ -33,7 +33,15 @@
#endif
#ifdef HAVE_BROTLI
+#if defined(__GNUC__)
+/* Ignore -Wvla warnings in brotli headers */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wvla"
+#endif
#include <brotli/decode.h>
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
#endif
#ifdef HAVE_ZSTD
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index c457b2d..0c6e0f7 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/cookie.c
@@ -101,13 +101,14 @@ Example set of cookies:
#include "parsedate.h"
#include "rename.h"
#include "fopen.h"
+#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
-static void strstore(char **str, const char *newstr);
+static void strstore(char **str, const char *newstr, size_t len);
static void freecookie(struct Cookie *co)
{
@@ -122,15 +123,17 @@ static void freecookie(struct Cookie *co)
free(co);
}
-static bool tailmatch(const char *cooke_domain, const char *hostname)
+static bool tailmatch(const char *cookie_domain, size_t cookie_domain_len,
+ const char *hostname)
{
- size_t cookie_domain_len = strlen(cooke_domain);
size_t hostname_len = strlen(hostname);
if(hostname_len < cookie_domain_len)
return FALSE;
- if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
+ if(!strncasecompare(cookie_domain,
+ hostname + hostname_len-cookie_domain_len,
+ cookie_domain_len))
return FALSE;
/*
@@ -176,7 +179,7 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
/* #-fragments are already cut off! */
if(0 == strlen(uri_path) || uri_path[0] != '/') {
- strstore(&uri_path, "/");
+ strstore(&uri_path, "/", 1);
if(!uri_path)
return FALSE;
}
@@ -310,7 +313,7 @@ static char *sanitize_cookie_path(const char *cookie_path)
/* RFC6265 5.2.4 The Path Attribute */
if(new_path[0] != '/') {
/* Let cookie-path be the default-path. */
- strstore(&new_path, "/");
+ strstore(&new_path, "/", 1);
return new_path;
}
@@ -333,10 +336,9 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
if(list) {
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
while(list) {
- struct CookieInfo *newcookies = Curl_cookie_init(data,
- list->data,
- data->cookies,
- data->set.cookiesession);
+ struct CookieInfo *newcookies =
+ Curl_cookie_init(data, list->data, data->cookies,
+ data->set.cookiesession);
if(!newcookies)
/*
* Failure may be due to OOM or a bad cookie; both are ignored
@@ -360,10 +362,14 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
* parsing in a last-wins scenario. The caller is responsible for checking
* for OOM errors.
*/
-static void strstore(char **str, const char *newstr)
+static void strstore(char **str, const char *newstr, size_t len)
{
+ DEBUGASSERT(newstr);
+ DEBUGASSERT(str);
free(*str);
- *str = strdup(newstr);
+ *str = Curl_memdup(newstr, len + 1);
+ if(*str)
+ (*str)[len] = 0;
}
/*
@@ -425,15 +431,19 @@ static void remove_expired(struct CookieInfo *cookies)
}
/* Make sure domain contains a dot or is localhost. */
-static bool bad_domain(const char *domain)
+static bool bad_domain(const char *domain, size_t len)
{
- if(strcasecompare(domain, "localhost"))
+ if((len == 9) && strncasecompare(domain, "localhost", 9))
return FALSE;
else {
/* there must be a dot present, but that dot must not be a trailing dot */
- char *dot = strchr(domain, '.');
- if(dot)
- return dot[1] ? FALSE : TRUE;
+ char *dot = memchr(domain, '.', len);
+ if(dot) {
+ size_t i = dot - domain;
+ if((len - i) > 1)
+ /* the dot is not the last byte */
+ return FALSE;
+ }
}
return TRUE;
}
@@ -513,10 +523,9 @@ Curl_cookie_add(struct Curl_easy *data,
if(httpheader) {
/* This line was read off an HTTP-header */
- char name[MAX_NAME];
- char what[MAX_NAME];
+ const char *namep;
+ const char *valuep;
const char *ptr;
- const char *semiptr;
size_t linelength = strlen(lineptr);
if(linelength > MAX_COOKIE_LINE) {
@@ -525,73 +534,65 @@ Curl_cookie_add(struct Curl_easy *data,
return NULL;
}
- semiptr = strchr(lineptr, ';'); /* first, find a semicolon */
-
- while(*lineptr && ISBLANK(*lineptr))
- lineptr++;
-
ptr = lineptr;
do {
- /* we have a <what>=<this> pair or a stand-alone word here */
- name[0] = what[0] = 0; /* init the buffers */
- if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\t\r\n=] =%"
- MAX_NAME_TXT "[^;\r\n]",
- name, what)) {
- /*
- * Use strstore() below to properly deal with received cookie
- * headers that have the same string property set more than once,
- * and then we use the last one.
- */
- const char *whatptr;
+ size_t vlen;
+ size_t nlen;
+
+ while(*ptr && ISBLANK(*ptr))
+ ptr++;
+
+ /* we have a <name>=<value> pair or a stand-alone word here */
+ nlen = strcspn(ptr, ";\t\r\n=");
+ if(nlen) {
bool done = FALSE;
- bool sep;
- size_t len = strlen(what);
- size_t nlen = strlen(name);
- const char *endofn = &ptr[ nlen ];
+ bool sep = FALSE;
- /*
- * Check for too long individual name or contents, or too long
- * combination of name + contents. Chrome and Firefox support 4095 or
- * 4096 bytes combo
- */
- if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
- ((nlen + len) > MAX_NAME)) {
- freecookie(co);
- infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
- nlen, len);
- return NULL;
- }
+ namep = ptr;
+ ptr += nlen;
- /* name ends with a '=' ? */
- sep = (*endofn == '=')?TRUE:FALSE;
+ /* trim trailing spaces and tabs after name */
+ while(nlen && ISBLANK(namep[nlen - 1]))
+ nlen--;
- if(nlen) {
- endofn--; /* move to the last character */
- if(ISBLANK(*endofn)) {
- /* skip trailing spaces in name */
- while(*endofn && ISBLANK(*endofn) && nlen) {
- endofn--;
- nlen--;
- }
- name[nlen] = 0; /* new end of name */
+ 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--;
+
+ /* Skip leading whitespace from the value */
+ while(vlen && ISBLANK(*valuep)) {
+ valuep++;
+ vlen--;
}
- }
- /* Strip off trailing whitespace from the 'what' */
- while(len && ISBLANK(what[len-1])) {
- what[len-1] = 0;
- len--;
+ /* Reject cookies with a TAB inside the value */
+ if(memchr(valuep, '\t', vlen)) {
+ freecookie(co);
+ infof(data, "cookie contains TAB, dropping");
+ return NULL;
+ }
+ }
+ else {
+ valuep = NULL;
+ vlen = 0;
}
- /* Skip leading whitespace from the 'what' */
- whatptr = what;
- while(*whatptr && ISBLANK(*whatptr))
- whatptr++;
-
- /* Reject cookies with a TAB inside the content */
- if(strchr(whatptr, '\t')) {
+ /*
+ * Check for too long individual name or contents, or too long
+ * 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)) {
freecookie(co);
- infof(data, "cookie contains TAB, dropping");
+ infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
+ nlen, vlen);
return NULL;
}
@@ -601,13 +602,19 @@ Curl_cookie_add(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 > 3 && name[0] == '_' && name[1] == '_') {
- if(strncasecompare("__Secure-", name, 9))
+ if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
+ if(strncasecompare("__Secure-", namep, 9))
co->prefix |= COOKIE_PREFIX__SECURE;
- else if(strncasecompare("__Host-", name, 7))
+ else if(strncasecompare("__Host-", namep, 7))
co->prefix |= COOKIE_PREFIX__HOST;
}
+ /*
+ * Use strstore() below to properly deal with received cookie
+ * headers that have the same string property set more than once,
+ * and then we use the last one.
+ */
+
if(!co->name) {
/* The very first name/value pair is the actual cookie name */
if(!sep) {
@@ -615,20 +622,20 @@ Curl_cookie_add(struct Curl_easy *data,
badcookie = TRUE;
break;
}
- co->name = strdup(name);
- co->value = strdup(whatptr);
+ strstore(&co->name, namep, nlen);
+ strstore(&co->value, valuep, vlen);
done = TRUE;
if(!co->name || !co->value) {
badcookie = TRUE;
break;
}
- if(invalid_octets(whatptr) || invalid_octets(name)) {
+ if(invalid_octets(co->value) || invalid_octets(co->name)) {
infof(data, "invalid octets in name/value, cookie dropped");
badcookie = TRUE;
break;
}
}
- else if(!len) {
+ else if(!vlen) {
/*
* this was a "<name>=" with no content, and we must allow
* 'secure' and 'httponly' specified this weirdly
@@ -639,7 +646,7 @@ Curl_cookie_add(struct Curl_easy *data,
* using a secure protocol, or when the cookie is being set by
* reading from file
*/
- if(strcasecompare("secure", name)) {
+ if((nlen == 6) && strncasecompare("secure", namep, 6)) {
if(secure || !c->running) {
co->secure = TRUE;
}
@@ -648,7 +655,7 @@ Curl_cookie_add(struct Curl_easy *data,
break;
}
}
- else if(strcasecompare("httponly", name))
+ else if((nlen == 8) && strncasecompare("httponly", namep, 8))
co->httponly = TRUE;
else if(sep)
/* there was a '=' so we're not done parsing this field */
@@ -656,8 +663,8 @@ Curl_cookie_add(struct Curl_easy *data,
}
if(done)
;
- else if(strcasecompare("path", name)) {
- strstore(&co->path, whatptr);
+ else if((nlen == 4) && strncasecompare("path", namep, 4)) {
+ strstore(&co->path, valuep, vlen);
if(!co->path) {
badcookie = TRUE; /* out of memory bad */
break;
@@ -669,7 +676,8 @@ Curl_cookie_add(struct Curl_easy *data,
break;
}
}
- else if(strcasecompare("domain", name) && whatptr[0]) {
+ else if((nlen == 6) &&
+ strncasecompare("domain", namep, 6) && vlen) {
bool is_ip;
/*
@@ -677,8 +685,10 @@ Curl_cookie_add(struct Curl_easy *data,
* the given domain is not valid and thus cannot be set.
*/
- if('.' == whatptr[0])
- whatptr++; /* ignore preceding dot */
+ if('.' == valuep[0]) {
+ valuep++; /* ignore preceding dot */
+ vlen--;
+ }
#ifndef USE_LIBPSL
/*
@@ -686,16 +696,17 @@ Curl_cookie_add(struct Curl_easy *data,
* TLD or otherwise "protected" suffix. To reduce risk, we require a
* dot OR the exact host name being "localhost".
*/
- if(bad_domain(whatptr))
+ if(bad_domain(valuep, vlen))
domain = ":";
#endif
- is_ip = Curl_host_is_ipnum(domain ? domain : whatptr);
+ is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
if(!domain
- || (is_ip && !strcmp(whatptr, domain))
- || (!is_ip && tailmatch(whatptr, domain))) {
- strstore(&co->domain, whatptr);
+ || (is_ip && !strncmp(valuep, domain, vlen) &&
+ (vlen == strlen(domain)))
+ || (!is_ip && tailmatch(valuep, vlen, domain))) {
+ strstore(&co->domain, valuep, vlen);
if(!co->domain) {
badcookie = TRUE;
break;
@@ -711,17 +722,17 @@ Curl_cookie_add(struct Curl_easy *data,
*/
badcookie = TRUE;
infof(data, "skipped cookie with bad tailmatch domain: %s",
- whatptr);
+ valuep);
}
}
- else if(strcasecompare("version", name)) {
- strstore(&co->version, whatptr);
+ else if((nlen == 7) && strncasecompare("version", namep, 7)) {
+ strstore(&co->version, valuep, vlen);
if(!co->version) {
badcookie = TRUE;
break;
}
}
- else if(strcasecompare("max-age", name)) {
+ else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
/*
* Defined in RFC2109:
*
@@ -731,14 +742,14 @@ Curl_cookie_add(struct Curl_easy *data,
* client should discard the cookie. A value of zero means the
* cookie should be discarded immediately.
*/
- strstore(&co->maxage, whatptr);
+ strstore(&co->maxage, valuep, vlen);
if(!co->maxage) {
badcookie = TRUE;
break;
}
}
- else if(strcasecompare("expires", name)) {
- strstore(&co->expirestr, whatptr);
+ else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
+ strstore(&co->expirestr, valuep, vlen);
if(!co->expirestr) {
badcookie = TRUE;
break;
@@ -753,24 +764,13 @@ Curl_cookie_add(struct Curl_easy *data,
/* this is an "illegal" <what>=<this> pair */
}
- if(!semiptr || !*semiptr) {
- /* we already know there are no more cookies */
- semiptr = NULL;
- continue;
- }
-
- ptr = semiptr + 1;
while(*ptr && ISBLANK(*ptr))
ptr++;
- semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
-
- if(!semiptr && *ptr)
- /*
- * There are no more semicolons, but there's a final name=value pair
- * coming up
- */
- semiptr = strchr(ptr, '\0');
- } while(semiptr);
+ if(*ptr == ';')
+ ptr++;
+ else
+ break;
+ } while(1);
if(co->maxage) {
CURLofft offt;
@@ -1057,7 +1057,7 @@ Curl_cookie_add(struct Curl_easy *data,
Curl_psl_release(data);
}
else
- acceptable = !bad_domain(domain);
+ acceptable = !bad_domain(domain, strlen(domain));
if(!acceptable) {
infof(data, "cookie '%s' dropped, domain '%s' must not "
@@ -1447,7 +1447,8 @@ struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
/* now check if the domain is correct */
if(!co->domain ||
- (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
+ (co->tailmatch && !is_ip &&
+ tailmatch(co->domain, co->domain? strlen(co->domain):0, host)) ||
((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
/*
* the right part of the host matches the domain stuff in the
@@ -1798,11 +1799,6 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
CURLcode res;
if(data->set.str[STRING_COOKIEJAR]) {
- /* If there is a list of cookie files to read, do it first so that
- we have all the told files read before we write the new jar.
- Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
- Curl_cookie_loadfiles(data);
-
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
/* if we have a destination file for all the cookies to get dumped to */
diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c
index c4c4f88..c6fe125 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.c
+++ b/Utilities/cmcurl/lib/curl_gssapi.c
@@ -34,10 +34,16 @@
#include "curl_memory.h"
#include "memdebug.h"
-gss_OID_desc Curl_spnego_mech_oid = {
+#if defined(__GNUC__)
+#define CURL_ALIGN8 __attribute__ ((aligned(8)))
+#else
+#define CURL_ALIGN8
+#endif
+
+gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = {
6, (char *)"\x2b\x06\x01\x05\x05\x02"
};
-gss_OID_desc Curl_krb5_mech_oid = {
+gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = {
9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
};
diff --git a/Utilities/cmcurl/lib/curl_log.c b/Utilities/cmcurl/lib/curl_log.c
index b5ce1c7..2301cff 100644
--- a/Utilities/cmcurl/lib/curl_log.c
+++ b/Utilities/cmcurl/lib/curl_log.c
@@ -38,7 +38,7 @@
#include "connect.h"
#include "http2.h"
#include "http_proxy.h"
-#include "cf-http.h"
+#include "cf-https-connect.h"
#include "socks.h"
#include "strtok.h"
#include "vtls/vtls.h"
diff --git a/Utilities/cmcurl/lib/curl_path.c b/Utilities/cmcurl/lib/curl_path.c
index 2df8687..977e533 100644
--- a/Utilities/cmcurl/lib/curl_path.c
+++ b/Utilities/cmcurl/lib/curl_path.c
@@ -32,70 +32,65 @@
#include "escape.h"
#include "memdebug.h"
+#define MAX_SSHPATH_LEN 100000 /* arbitrary */
+
/* figure out the path to work with in this particular request */
CURLcode Curl_getworkingpath(struct Curl_easy *data,
char *homedir, /* when SFTP is used */
char **path) /* returns the allocated
real path to work with */
{
- char *real_path = NULL;
char *working_path;
size_t working_path_len;
+ struct dynbuf npath;
CURLcode result =
Curl_urldecode(data->state.up.path, 0, &working_path,
&working_path_len, REJECT_ZERO);
if(result)
return result;
+ /* new path to switch to in case we need to */
+ Curl_dyn_init(&npath, MAX_SSHPATH_LEN);
+
/* Check for /~/, indicating relative to the user's home directory */
- if(data->conn->handler->protocol & CURLPROTO_SCP) {
- real_path = malloc(working_path_len + 1);
- if(!real_path) {
+ if((data->conn->handler->protocol & CURLPROTO_SCP) &&
+ (working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) {
+ /* It is referenced to the home directory, so strip the leading '/~/' */
+ if(Curl_dyn_addn(&npath, &working_path[3], working_path_len - 3)) {
free(working_path);
return CURLE_OUT_OF_MEMORY;
}
- if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
- /* It is referenced to the home directory, so strip the leading '/~/' */
- memcpy(real_path, working_path + 3, working_path_len - 2);
- else
- memcpy(real_path, working_path, 1 + working_path_len);
}
- else if(data->conn->handler->protocol & CURLPROTO_SFTP) {
- if((working_path_len > 1) && (working_path[1] == '~')) {
- size_t homelen = strlen(homedir);
- real_path = malloc(homelen + working_path_len + 1);
- if(!real_path) {
- free(working_path);
- return CURLE_OUT_OF_MEMORY;
- }
- /* It is referenced to the home directory, so strip the
- leading '/' */
- memcpy(real_path, homedir, homelen);
- /* Only add a trailing '/' if homedir does not end with one */
- if(homelen == 0 || real_path[homelen - 1] != '/') {
- real_path[homelen] = '/';
- homelen++;
- real_path[homelen] = '\0';
- }
- if(working_path_len > 3) {
- memcpy(real_path + homelen, working_path + 3,
- 1 + working_path_len -3);
- }
+ else if((data->conn->handler->protocol & CURLPROTO_SFTP) &&
+ (working_path_len > 2) && !memcmp(working_path, "/~/", 3)) {
+ size_t len;
+ const char *p;
+ int copyfrom = 3;
+ if(Curl_dyn_add(&npath, homedir)) {
+ free(working_path);
+ return CURLE_OUT_OF_MEMORY;
}
- else {
- real_path = malloc(working_path_len + 1);
- if(!real_path) {
- free(working_path);
- return CURLE_OUT_OF_MEMORY;
- }
- memcpy(real_path, working_path, 1 + working_path_len);
+ /* Copy a separating '/' if homedir does not end with one */
+ len = Curl_dyn_len(&npath);
+ p = Curl_dyn_ptr(&npath);
+ if(len && (p[len-1] != '/'))
+ copyfrom = 2;
+
+ if(Curl_dyn_addn(&npath,
+ &working_path[copyfrom], working_path_len - copyfrom)) {
+ free(working_path);
+ return CURLE_OUT_OF_MEMORY;
}
}
- free(working_path);
+ if(Curl_dyn_len(&npath)) {
+ free(working_path);
- /* store the pointer for the caller to receive */
- *path = real_path;
+ /* store the pointer for the caller to receive */
+ *path = Curl_dyn_ptr(&npath);
+ }
+ else
+ *path = working_path;
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index b58f813..06fb613 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -456,8 +456,8 @@
# endif
#endif
-#if (SIZEOF_CURL_OFF_T == 4)
-# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
+#if (SIZEOF_CURL_OFF_T < 8)
+#error "too small curl_off_t"
#else
/* assume SIZEOF_CURL_OFF_T == 8 */
# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h
index e68eb50..dde7229 100644
--- a/Utilities/cmcurl/lib/curl_setup_once.h
+++ b/Utilities/cmcurl/lib/curl_setup_once.h
@@ -69,6 +69,14 @@
#include <unistd.h>
#endif
+#ifdef USE_WOLFSSL
+# if defined(HAVE_STDINT_H)
+# include <stdint.h>
+# elif defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+# endif
+#endif
+
#ifdef __hpux
# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
# ifdef _APP32_64BIT_OFF_T
diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c
index 2e6a377..922d757 100644
--- a/Utilities/cmcurl/lib/doh.c
+++ b/Utilities/cmcurl/lib/doh.c
@@ -952,7 +952,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
/* we got a response, store it in the cache */
- dns = Curl_cache_addr(data, ai, dohp->host, dohp->port);
+ dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
diff --git a/Utilities/cmcurl/lib/dynbuf.c b/Utilities/cmcurl/lib/dynbuf.c
index 847f6f6..bd3b935 100644
--- a/Utilities/cmcurl/lib/dynbuf.c
+++ b/Utilities/cmcurl/lib/dynbuf.c
@@ -99,8 +99,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
include that as well when it uses this code */
void *p = realloc(s->bufr, a);
if(!p) {
- Curl_safefree(s->bufr);
- s->leng = s->allc = 0;
+ Curl_dyn_free(s);
return CURLE_OUT_OF_MEMORY;
}
s->bufr = p;
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index db03026..27124a7 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/easy.c
@@ -1228,7 +1228,6 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
return result;
*n = (size_t)n1;
- infof(data, "reached %s:%d", __FILE__, __LINE__);
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index 8c72874..ef9ec1e 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -436,6 +436,12 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
bool connected;
DEBUGF(infof(data, "ftp InitiateTransfer()"));
+ if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port &&
+ !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
+ result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
+ if(result)
+ return result;
+ }
result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected);
if(result || !connected)
return result;
@@ -1795,6 +1801,29 @@ static char *control_address(struct connectdata *conn)
return conn->primary_ip;
}
+static bool match_pasv_6nums(const char *p,
+ unsigned int *array) /* 6 numbers */
+{
+ int i;
+ for(i = 0; i < 6; i++) {
+ unsigned long num;
+ char *endp;
+ if(i) {
+ if(*p != ',')
+ return FALSE;
+ p++;
+ }
+ if(!ISDIGIT(*p))
+ return FALSE;
+ num = strtoul(p, &endp, 10);
+ if(num > 255)
+ return FALSE;
+ array[i] = (unsigned int)num;
+ p = endp;
+ }
+ return TRUE;
+}
+
static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
int ftpcode)
{
@@ -1814,27 +1843,18 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
/* positive EPSV response */
char *ptr = strchr(str, '(');
if(ptr) {
- unsigned int num;
- char separator[4];
+ char sep;
ptr++;
- if(5 == sscanf(ptr, "%c%c%c%u%c",
- &separator[0],
- &separator[1],
- &separator[2],
- &num,
- &separator[3])) {
- const char sep1 = separator[0];
- int i;
-
- /* The four separators should be identical, or else this is an oddly
- formatted reply and we bail out immediately. */
- for(i = 1; i<4; i++) {
- if(separator[i] != sep1) {
- ptr = NULL; /* set to NULL to signal error */
- break;
- }
- }
- if(num > 0xffff) {
+ /* |||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) {
failf(data, "Illegal port number in EPSV reply");
return CURLE_FTP_WEIRD_PASV_REPLY;
}
@@ -1856,8 +1876,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
else if((ftpc->count1 == 1) &&
(ftpcode == 227)) {
/* positive PASV response */
- unsigned int ip[4] = {0, 0, 0, 0};
- unsigned int port[2] = {0, 0};
+ unsigned int ip[6];
/*
* Scan for a sequence of six comma-separated numbers and use them as
@@ -1869,15 +1888,12 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
* "227 Entering passive mode. 127,0,0,1,4,51"
*/
while(*str) {
- if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
- &ip[0], &ip[1], &ip[2], &ip[3],
- &port[0], &port[1]))
+ if(match_pasv_6nums(str, ip))
break;
str++;
}
- if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) ||
- (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) {
+ if(!*str) {
failf(data, "Couldn't interpret the 227-response");
return CURLE_FTP_WEIRD_227_FORMAT;
}
@@ -1897,7 +1913,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
if(!ftpc->newhost)
return CURLE_OUT_OF_MEMORY;
- ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
+ ftpc->newport = (unsigned short)(((ip[4]<<8) + ip[5]) & 0xffff);
}
else if(ftpc->count1 == 0) {
/* EPSV failed, move on to PASV */
@@ -2032,6 +2048,30 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data,
return result;
}
+static int twodigit(const char *p)
+{
+ return (p[0]-'0') * 10 + (p[1]-'0');
+}
+
+static bool ftp_213_date(const char *p, int *year, int *month, int *day,
+ int *hour, int *minute, int *second)
+{
+ size_t len = strlen(p);
+ if(len < 14)
+ return FALSE;
+ *year = twodigit(&p[0]) * 100 + twodigit(&p[2]);
+ *month = twodigit(&p[4]);
+ *day = twodigit(&p[6]);
+ *hour = twodigit(&p[8]);
+ *minute = twodigit(&p[10]);
+ *second = twodigit(&p[12]);
+
+ if((*month > 12) || (*day > 31) || (*hour > 23) || (*minute > 59) ||
+ (*second > 60))
+ return FALSE;
+ return TRUE;
+}
+
static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
int ftpcode)
{
@@ -2046,8 +2086,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
last .sss part is optional and means fractions of a second */
int year, month, day, hour, minute, second;
- if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
- &year, &month, &day, &hour, &minute, &second)) {
+ if(ftp_213_date(&data->state.buffer[4],
+ &year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
char timebuf[24];
msnprintf(timebuf, sizeof(timebuf),
@@ -2635,7 +2675,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
int ftpcode;
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
- static const char ftpauth[][4] = { "SSL", "TLS" };
+ static const char * const ftpauth[] = { "SSL", "TLS" };
size_t nread = 0;
if(pp->sendleft)
@@ -3221,7 +3261,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
if(data->state.wildcardmatch) {
if(data->set.chunk_end && ftpc->file) {
Curl_set_in_callback(data, true);
- data->set.chunk_end(data->wildcard.customptr);
+ data->set.chunk_end(data->set.wildcardptr);
Curl_set_in_callback(data, false);
}
ftpc->known_filesize = -1;
@@ -3728,7 +3768,7 @@ static CURLcode init_wc_data(struct Curl_easy *data)
char *last_slash;
struct FTP *ftp = data->req.p.ftp;
char *path = ftp->path;
- struct WildcardData *wildcard = &(data->wildcard);
+ struct WildcardData *wildcard = data->wildcard;
CURLcode result = CURLE_OK;
struct ftp_wc *ftpwc = NULL;
@@ -3776,7 +3816,7 @@ static CURLcode init_wc_data(struct Curl_easy *data)
goto fail;
}
- wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */
+ wildcard->ftpwc = ftpwc; /* put it to the WildcardData tmp pointer */
wildcard->dtor = wc_data_dtor;
/* wildcard does not support NOCWD option (assert it?) */
@@ -3814,13 +3854,13 @@ static CURLcode init_wc_data(struct Curl_easy *data)
}
Curl_safefree(wildcard->pattern);
wildcard->dtor = ZERO_NULL;
- wildcard->protdata = NULL;
+ wildcard->ftpwc = NULL;
return result;
}
static CURLcode wc_statemach(struct Curl_easy *data)
{
- struct WildcardData * const wildcard = &(data->wildcard);
+ struct WildcardData * const wildcard = data->wildcard;
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
@@ -3837,7 +3877,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
case CURLWC_MATCHING: {
/* In this state is LIST response successfully parsed, so lets restore
previous WRITEFUNCTION callback and WRITEDATA pointer */
- struct ftp_wc *ftpwc = wildcard->protdata;
+ struct ftp_wc *ftpwc = wildcard->ftpwc;
data->set.fwrite_func = ftpwc->backup.write_function;
data->set.out = ftpwc->backup.file_descriptor;
ftpwc->backup.write_function = ZERO_NULL;
@@ -3876,7 +3916,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
long userresponse;
Curl_set_in_callback(data, true);
userresponse = data->set.chunk_bgn(
- finfo, wildcard->customptr, (int)wildcard->filelist.size);
+ finfo, data->set.wildcardptr, (int)wildcard->filelist.size);
Curl_set_in_callback(data, false);
switch(userresponse) {
case CURL_CHUNK_BGN_FUNC_SKIP:
@@ -3916,7 +3956,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
case CURLWC_SKIP: {
if(data->set.chunk_end) {
Curl_set_in_callback(data, true);
- data->set.chunk_end(data->wildcard.customptr);
+ data->set.chunk_end(data->set.wildcardptr);
Curl_set_in_callback(data, false);
}
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
@@ -3926,7 +3966,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
}
case CURLWC_CLEAN: {
- struct ftp_wc *ftpwc = wildcard->protdata;
+ struct ftp_wc *ftpwc = wildcard->ftpwc;
result = CURLE_OK;
if(ftpwc)
result = Curl_ftp_parselist_geterror(ftpwc->parser);
@@ -3939,7 +3979,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
case CURLWC_ERROR:
case CURLWC_CLEAR:
if(wildcard->dtor)
- wildcard->dtor(wildcard->protdata);
+ wildcard->dtor(wildcard->ftpwc);
return result;
}
}
@@ -3966,8 +4006,8 @@ static CURLcode ftp_do(struct Curl_easy *data, bool *done)
if(data->state.wildcardmatch) {
result = wc_statemach(data);
- if(data->wildcard.state == CURLWC_SKIP ||
- data->wildcard.state == CURLWC_DONE) {
+ if(data->wildcard->state == CURLWC_SKIP ||
+ data->wildcard->state == CURLWC_DONE) {
/* do not call ftp_regular_transfer */
return CURLE_OK;
}
@@ -4053,6 +4093,8 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
}
freedirs(ftpc);
+ Curl_safefree(ftpc->account);
+ Curl_safefree(ftpc->alternative_to_user);
Curl_safefree(ftpc->prevpath);
Curl_safefree(ftpc->server_os);
Curl_pp_disconnect(pp);
@@ -4322,11 +4364,31 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
char *type;
struct FTP *ftp;
CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
- data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
+ ftp = calloc(sizeof(struct FTP), 1);
if(!ftp)
return CURLE_OUT_OF_MEMORY;
+ /* clone connection related data that is FTP specific */
+ if(data->set.str[STRING_FTP_ACCOUNT]) {
+ ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]);
+ if(!ftpc->account) {
+ free(ftp);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) {
+ ftpc->alternative_to_user =
+ strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
+ if(!ftpc->alternative_to_user) {
+ Curl_safefree(ftpc->account);
+ free(ftp);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ data->req.p.ftp = ftp;
+
ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
/* FTP URLs support an extension like ";type=<typecode>" that
@@ -4361,7 +4423,9 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
/* get some initial data into the ftp struct */
ftp->transfer = PPTRANSFER_BODY;
ftp->downloadsize = 0;
- conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
+ ftpc->known_filesize = -1; /* unknown size for now */
+ ftpc->use_ssl = data->set.use_ssl;
+ ftpc->ccc = data->set.ftp_ccc;
return result;
}
diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h
index 65efa6f..977fc88 100644
--- a/Utilities/cmcurl/lib/ftp.h
+++ b/Utilities/cmcurl/lib/ftp.h
@@ -120,6 +120,8 @@ struct FTP {
struct */
struct ftp_conn {
struct pingpong pp;
+ char *account;
+ char *alternative_to_user;
char *entrypath; /* the PWD reply when we logged on */
char *file; /* url-decoded file name (or path) */
char **dirs; /* realloc()ed array for path components */
@@ -143,6 +145,9 @@ struct ftp_conn {
ftpstate state; /* always use ftp.c:state() to change state! */
ftpstate state_saved; /* transfer type saved to be reloaded after data
connection is established */
+ unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
+ IMAP or POP3 or others! (type: curl_usessl)*/
+ unsigned char ccc; /* ccc level for this connection */
BIT(ftp_trying_alternative);
BIT(dont_check); /* Set to TRUE to prevent the final (post-transfer)
file size and 226/250 status check. It should still
diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c
index f7c6434..39001e3 100644
--- a/Utilities/cmcurl/lib/ftplistparser.c
+++ b/Utilities/cmcurl/lib/ftplistparser.c
@@ -181,6 +181,43 @@ struct ftp_parselist_data {
} offsets;
};
+static void fileinfo_dtor(void *user, void *element)
+{
+ (void)user;
+ Curl_fileinfo_cleanup(element);
+}
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc)
+{
+ Curl_llist_init(&wc->filelist, fileinfo_dtor);
+ wc->state = CURLWC_INIT;
+
+ return CURLE_OK;
+}
+
+void Curl_wildcard_dtor(struct WildcardData **wcp)
+{
+ struct WildcardData *wc = *wcp;
+ if(!wc)
+ return;
+
+ if(wc->dtor) {
+ wc->dtor(wc->ftpwc);
+ wc->dtor = ZERO_NULL;
+ wc->ftpwc = NULL;
+ }
+ DEBUGASSERT(wc->ftpwc == NULL);
+
+ Curl_llist_destroy(&wc->filelist, NULL);
+ free(wc->path);
+ wc->path = NULL;
+ free(wc->pattern);
+ wc->pattern = NULL;
+ wc->state = CURLWC_INIT;
+ free(wc);
+ *wcp = NULL;
+}
+
struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
{
return calloc(1, sizeof(struct ftp_parselist_data));
@@ -274,8 +311,8 @@ static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
struct fileinfo *infop)
{
curl_fnmatch_callback compare;
- struct WildcardData *wc = &data->wildcard;
- struct ftp_wc *ftpwc = wc->protdata;
+ struct WildcardData *wc = data->wildcard;
+ struct ftp_wc *ftpwc = wc->ftpwc;
struct Curl_llist *llist = &wc->filelist;
struct ftp_parselist_data *parser = ftpwc->parser;
bool add = TRUE;
@@ -330,7 +367,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
{
size_t bufflen = size*nmemb;
struct Curl_easy *data = (struct Curl_easy *)connptr;
- struct ftp_wc *ftpwc = data->wildcard.protdata;
+ struct ftp_wc *ftpwc = data->wildcard->ftpwc;
struct ftp_parselist_data *parser = ftpwc->parser;
struct fileinfo *infop;
struct curl_fileinfo *finfo;
diff --git a/Utilities/cmcurl/lib/ftplistparser.h b/Utilities/cmcurl/lib/ftplistparser.h
index 3d9a43b..5ba1f6a 100644
--- a/Utilities/cmcurl/lib/ftplistparser.h
+++ b/Utilities/cmcurl/lib/ftplistparser.h
@@ -39,5 +39,39 @@ struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void);
void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data);
+/* list of wildcard process states */
+typedef enum {
+ CURLWC_CLEAR = 0,
+ CURLWC_INIT = 1,
+ CURLWC_MATCHING, /* library is trying to get list of addresses for
+ downloading */
+ CURLWC_DOWNLOADING,
+ CURLWC_CLEAN, /* deallocate resources and reset settings */
+ CURLWC_SKIP, /* skip over concrete file */
+ CURLWC_ERROR, /* error cases */
+ CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop
+ will end */
+} wildcard_states;
+
+typedef void (*wildcard_dtor)(void *ptr);
+
+/* struct keeping information about wildcard download process */
+struct WildcardData {
+ char *path; /* path to the directory, where we trying wildcard-match */
+ char *pattern; /* wildcard pattern */
+ struct Curl_llist filelist; /* llist with struct Curl_fileinfo */
+ struct ftp_wc *ftpwc; /* pointer to FTP wildcard data */
+ wildcard_dtor dtor;
+ unsigned char state; /* wildcard_states */
+};
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc);
+void Curl_wildcard_dtor(struct WildcardData **wcp);
+
+struct Curl_easy;
+
+#else
+/* FTP is disabled */
+#define Curl_wildcard_dtor(x)
#endif /* CURL_DISABLE_FTP */
#endif /* HEADER_CURL_FTPLISTPARSER_H */
diff --git a/Utilities/cmcurl/lib/headers.c b/Utilities/cmcurl/lib/headers.c
index 22e0e01..6cd7e31 100644
--- a/Utilities/cmcurl/lib/headers.c
+++ b/Utilities/cmcurl/lib/headers.c
@@ -38,14 +38,13 @@
/* Generate the curl_header struct for the user. This function MUST assign all
struct fields in the output struct. */
-static void copy_header_external(struct Curl_easy *data,
- struct Curl_header_store *hs,
+static void copy_header_external(struct Curl_header_store *hs,
size_t index,
size_t amount,
struct Curl_llist_element *e,
- struct curl_header **hout)
+ struct curl_header *hout)
{
- struct curl_header *h = *hout = &data->state.headerout;
+ struct curl_header *h = hout;
h->name = hs->name;
h->value = hs->value;
h->amount = amount;
@@ -118,7 +117,9 @@ CURLHcode curl_easy_header(CURL *easy,
return CURLHE_MISSING;
}
/* this is the name we want */
- copy_header_external(data, hs, nameindex, amount, e_pick, hout);
+ copy_header_external(hs, nameindex, amount, e_pick,
+ &data->state.headerout[0]);
+ *hout = &data->state.headerout[0];
return CURLHE_OK;
}
@@ -132,7 +133,6 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
struct Curl_llist_element *pick;
struct Curl_llist_element *e;
struct Curl_header_store *hs;
- struct curl_header *hout;
size_t amount = 0;
size_t index = 0;
@@ -179,8 +179,9 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
index = amount - 1;
}
- copy_header_external(data, hs, index, amount, pick, &hout);
- return hout;
+ copy_header_external(hs, index, amount, pick,
+ &data->state.headerout[1]);
+ return &data->state.headerout[1];
}
static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c
index 536eb73..2f6762c 100644
--- a/Utilities/cmcurl/lib/hostasyn.c
+++ b/Utilities/cmcurl/lib/hostasyn.c
@@ -78,7 +78,7 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns = Curl_cache_addr(data, ai,
- data->state.async.hostname,
+ data->state.async.hostname, 0,
data->state.async.port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index 9738806..d0dc2e8 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -167,18 +167,25 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
/*
* Create a hostcache id string for the provided host + port, to be used by
- * the DNS caching. Without alloc.
+ * the DNS caching. Without alloc. Return length of the id string.
*/
-static void
-create_hostcache_id(const char *name, int port, char *ptr, size_t buflen)
+static size_t
+create_hostcache_id(const char *name,
+ size_t nlen, /* 0 or actual name length */
+ int port, char *ptr, size_t buflen)
{
- size_t len = strlen(name);
+ size_t len = nlen ? nlen : strlen(name);
+ size_t olen = 0;
+ DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN);
if(len > (buflen - 7))
len = buflen - 7;
/* store and lower case the name */
- while(len--)
+ while(len--) {
*ptr++ = Curl_raw_tolower(*name++);
- msnprintf(ptr, 7, ":%u", port);
+ olen++;
+ }
+ olen += msnprintf(ptr, 7, ":%u", port);
+ return olen;
}
struct hostcache_prune_data {
@@ -260,20 +267,18 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
int port)
{
struct Curl_dns_entry *dns = NULL;
- size_t entry_len;
char entry_id[MAX_HOSTCACHE_LEN];
/* Create an entry id, based upon the hostname and port */
- create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
- entry_len = strlen(entry_id);
+ size_t entry_len = create_hostcache_id(hostname, 0, port,
+ entry_id, sizeof(entry_id));
/* See if its already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
/* No entry found in cache, check if we might have a wildcard entry */
if(!dns && data->state.wildcard_resolve) {
- create_hostcache_id("*", port, entry_id, sizeof(entry_id));
- entry_len = strlen(entry_id);
+ entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id));
/* See if it's already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
@@ -438,6 +443,7 @@ struct Curl_dns_entry *
Curl_cache_addr(struct Curl_easy *data,
struct Curl_addrinfo *addr,
const char *hostname,
+ size_t hostlen, /* length or zero */
int port)
{
char entry_id[MAX_HOSTCACHE_LEN];
@@ -461,8 +467,8 @@ Curl_cache_addr(struct Curl_easy *data,
}
/* Create an entry id, based upon the hostname and port */
- create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
- entry_len = strlen(entry_id);
+ entry_len = create_hostcache_id(hostname, hostlen, port,
+ entry_id, sizeof(entry_id));
dns->inuse = 1; /* the cache has the first reference */
dns->addr = addr; /* this is the address(es) */
@@ -791,7 +797,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
/* we got a response, store it in the cache */
- dns = Curl_cache_addr(data, addr, hostname, port);
+ dns = Curl_cache_addr(data, addr, hostname, 0, port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -1059,8 +1065,7 @@ void Curl_hostcache_clean(struct Curl_easy *data,
CURLcode Curl_loadhostpairs(struct Curl_easy *data)
{
struct curl_slist *hostp;
- char hostname[256];
- int port = 0;
+ char *host_end;
/* Default is no wildcard found */
data->state.wildcard_resolve = false;
@@ -1070,18 +1075,25 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
if(!hostp->data)
continue;
if(hostp->data[0] == '-') {
+ unsigned long num = 0;
size_t entry_len;
-
- if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
- infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'",
+ 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;
+ }
+ if(!host_end) {
+ infof(data, "Bad syntax CURLOPT_RESOLVE removal entry '%s'",
hostp->data);
continue;
}
-
/* Create an entry id, based upon the hostname and port */
- create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
- entry_len = strlen(entry_id);
-
+ 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);
@@ -1102,25 +1114,22 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
char *addr_begin;
char *addr_end;
char *port_ptr;
+ int port = 0;
char *end_ptr;
bool permanent = TRUE;
- char *host_begin;
- char *host_end;
unsigned long tmp_port;
bool error = true;
+ char *host_begin = hostp->data;
+ size_t hlen = 0;
- host_begin = hostp->data;
if(host_begin[0] == '+') {
host_begin++;
permanent = FALSE;
}
host_end = strchr(host_begin, ':');
- if(!host_end ||
- ((host_end - host_begin) >= (ptrdiff_t)sizeof(hostname)))
+ if(!host_end)
goto err;
-
- memcpy(hostname, host_begin, host_end - host_begin);
- hostname[host_end - host_begin] = '\0';
+ hlen = host_end - host_begin;
port_ptr = host_end + 1;
tmp_port = strtoul(port_ptr, &end_ptr, 10);
@@ -1196,8 +1205,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
}
/* Create an entry id, based upon the hostname and port */
- create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
- entry_len = strlen(entry_id);
+ entry_len = create_hostcache_id(host_begin, hlen, port,
+ entry_id, sizeof(entry_id));
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
@@ -1206,8 +1215,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
if(dns) {
- infof(data, "RESOLVE %s:%d is - old addresses discarded",
- hostname, port);
+ infof(data, "RESOLVE %.*s:%d is - old addresses discarded",
+ (int)hlen, host_begin, 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,
@@ -1223,7 +1232,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
}
/* put this new host in the cache */
- dns = Curl_cache_addr(data, head, hostname, port);
+ dns = Curl_cache_addr(data, head, host_begin, hlen, port);
if(dns) {
if(permanent)
dns->timestamp = 0; /* mark as permanent */
@@ -1239,13 +1248,13 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
Curl_freeaddrinfo(head);
return CURLE_OUT_OF_MEMORY;
}
- infof(data, "Added %s:%d:%s to DNS cache%s",
- hostname, port, addresses, permanent ? "" : " (non-permanent)");
+ infof(data, "Added %.*s:%d:%s to DNS cache%s",
+ (int)hlen, host_begin, port, addresses,
+ permanent ? "" : " (non-permanent)");
/* Wildcard hostname */
- if(hostname[0] == '*' && hostname[1] == '\0') {
- infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks",
- hostname, port);
+ if((hlen == 1) && (host_begin[0] == '*')) {
+ infof(data, "RESOLVE *:%d using wildcard", port);
data->state.wildcard_resolve = true;
}
}
diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h
index e0d13cd..4b5481f 100644
--- a/Utilities/cmcurl/lib/hostip.h
+++ b/Utilities/cmcurl/lib/hostip.h
@@ -178,7 +178,7 @@ Curl_fetch_addr(struct Curl_easy *data,
*/
struct Curl_dns_entry *
Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr,
- const char *hostname, int port);
+ const char *hostname, size_t hostlen, int port);
#ifndef INADDR_NONE
#define CURL_INADDR_NONE (in_addr_t) ~0
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index cb585e7..faa486c 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -88,6 +88,7 @@
#include "hsts.h"
#include "ws.h"
#include "c-hyper.h"
+#include "curl_ctype.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -233,15 +234,12 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
Curl_mime_initpart(&http->form);
data->req.p.http = http;
+ connkeep(conn, "HTTP default");
- if((data->state.httpwant == CURL_HTTP_VERSION_3)
- || (data->state.httpwant == CURL_HTTP_VERSION_3ONLY)) {
+ if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
CURLcode result = Curl_conn_may_http3(data, conn);
if(result)
return result;
-
- /* TODO: HTTP lower version eyeballing */
- conn->transport = TRNSPRT_QUIC;
}
return CURLE_OK;
@@ -2342,7 +2340,16 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
return result;
}
- if(http->postsize) {
+ /* For really small puts we don't use Expect: headers at all, and for
+ the somewhat bigger ones we allow the app to disable it. Just make
+ sure that the expect100header is always set to the preferred value
+ here. */
+ ptr = Curl_checkheaders(data, STRCONST("Expect"));
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
+ }
+ else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
result = expect100(data, conn, r);
if(result)
return result;
@@ -4155,11 +4162,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(!k->headerline++) {
/* This is the first header, it MUST be the error code line
or else we consider this to be the body right away! */
- int httpversion_major;
- int rtspversion_major;
- int nc = 0;
-#define HEADER1 headp /* no conversion needed, just use headp */
-
+ bool fine_statusline = FALSE;
if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
/*
* https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
@@ -4168,39 +4171,60 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* says. We allow any three-digit number here, but we cannot make
* guarantees on future behaviors since it isn't within the protocol.
*/
- char separator;
- char twoorthree[2];
int httpversion = 0;
- char digit4 = 0;
- nc = sscanf(HEADER1,
- " HTTP/%1d.%1d%c%3d%c",
- &httpversion_major,
- &httpversion,
- &separator,
- &k->httpcode,
- &digit4);
-
- if(nc == 1 && httpversion_major >= 2 &&
- 2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) {
- conn->httpversion = 0;
- nc = 4;
- separator = ' ';
- }
-
- /* There can only be a 4th response code digit stored in 'digit4' if
- all the other fields were parsed and stored first, so nc is 5 when
- digit4 a digit.
-
- The sscanf() line above will also allow zero-prefixed and negative
- numbers, so we check for that too here.
- */
- else if(ISDIGIT(digit4) || (nc >= 4 && k->httpcode < 100)) {
- failf(data, "Unsupported response code in HTTP response");
- return CURLE_UNSUPPORTED_PROTOCOL;
+ char *p = headp;
+
+ while(*p && ISBLANK(*p))
+ p++;
+ if(!strncmp(p, "HTTP/", 5)) {
+ p += 5;
+ switch(*p) {
+ case '1':
+ p++;
+ if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
+ if(ISBLANK(p[2])) {
+ httpversion = 10 + (p[1] - '0');
+ 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;
+ }
+ }
+ }
+ if(!fine_statusline) {
+ failf(data, "Unsupported HTTP/1 subversion in response");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+ break;
+ case '2':
+ case '3':
+ if(!ISBLANK(p[1]))
+ break;
+ httpversion = (*p - '0') * 10;
+ p += 2;
+ 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))
+ break;
+ fine_statusline = TRUE;
+ }
+ break;
+ default: /* unsupported */
+ failf(data, "Unsupported HTTP version in response");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
}
- if((nc >= 4) && (' ' == separator)) {
- httpversion += 10 * httpversion_major;
+ if(fine_statusline) {
+ if(k->httpcode < 100) {
+ failf(data, "Unsupported response code in HTTP response");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
switch(httpversion) {
case 10:
case 11:
@@ -4227,51 +4251,50 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
}
}
- else if(!nc) {
- /* this is the real world, not a Nirvana
- NCSA 1.5.x returns this crap when asked for HTTP/1.1
- */
- nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode);
- conn->httpversion = 10;
-
+ else {
/* If user has set option HTTP200ALIASES,
compare header line against list of aliases
*/
- if(!nc) {
- statusline check =
- checkhttpprefix(data,
- Curl_dyn_ptr(&data->state.headerb),
- Curl_dyn_len(&data->state.headerb));
- if(check == STATUS_DONE) {
- nc = 1;
- k->httpcode = 200;
- conn->httpversion = 10;
- }
+ statusline check =
+ checkhttpprefix(data,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
+ if(check == STATUS_DONE) {
+ fine_statusline = TRUE;
+ k->httpcode = 200;
+ conn->httpversion = 10;
}
}
- else {
- failf(data, "Unsupported HTTP version in response");
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
}
else if(conn->handler->protocol & CURLPROTO_RTSP) {
- char separator;
- int rtspversion;
- nc = sscanf(HEADER1,
- " RTSP/%1d.%1d%c%3d",
- &rtspversion_major,
- &rtspversion,
- &separator,
- &k->httpcode);
- if((nc == 4) && (' ' == separator)) {
- conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
- }
- else {
- nc = 0;
+ char *p = headp;
+ 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;
+ conn->httpversion = 11; /* RTSP acts like HTTP 1.1 */
+ }
+ }
+ }
+ }
+ }
+ if(!fine_statusline)
+ return CURLE_WEIRD_SERVER_REPLY;
}
}
- if(nc) {
+ if(fine_statusline) {
result = Curl_http_statusline(data, conn);
if(result)
return result;
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index bdb5e73..b0ce87d 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -98,7 +98,6 @@ static size_t populate_binsettings(uint8_t *binsettings,
struct cf_h2_ctx {
nghttp2_session *h2;
uint32_t max_concurrent_streams;
- bool enable_push;
/* The easy handle used in the current filter call, cleared at return */
struct cf_call_data call_data;
@@ -116,6 +115,10 @@ struct cf_h2_ctx {
int32_t pause_stream_id; /* stream ID which paused
nghttp2_session_mem_recv */
size_t drain_total; /* sum of all stream's UrlState.drain */
+ int32_t goaway_error;
+ int32_t last_stream_id;
+ BIT(goaway);
+ BIT(enable_push);
};
/* How to access `call_data` from a cf_h2 filter */
@@ -364,41 +367,42 @@ static void http2_stream_free(struct HTTP *stream)
}
/*
+ * Returns nonzero if current HTTP/2 session should be closed.
+ */
+static int should_close_session(struct cf_h2_ctx *ctx)
+{
+ return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) &&
+ !nghttp2_session_want_write(ctx->h2);
+}
+
+/*
* The server may send us data at any point (e.g. PING frames). Therefore,
* we cannot assume that an HTTP/2 socket is dead just because it is readable.
*
* Check the lower filters first and, if successful, peek at the socket
* and distinguish between closed and data.
*/
-static bool http2_connisdead(struct Curl_cfilter *cf, struct Curl_easy *data)
+static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
+ bool *input_pending)
{
struct cf_h2_ctx *ctx = cf->ctx;
- int sval;
- bool dead = TRUE;
+ bool alive = TRUE;
- if(!cf->next || !cf->next->cft->is_alive(cf->next, data))
- return TRUE;
+ *input_pending = FALSE;
+ if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+ return FALSE;
- sval = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0);
- if(sval == 0) {
- /* timeout */
- dead = FALSE;
- }
- else if(sval & CURL_CSELECT_ERR) {
- /* socket is in an error state */
- dead = TRUE;
- }
- else if(sval & CURL_CSELECT_IN) {
+ if(*input_pending) {
/* This happens before we've sent off a request and the connection is
not in use by any other transfer, there shouldn't be any data here,
only "protocol frames" */
CURLcode result;
ssize_t nread = -1;
+ *input_pending = FALSE;
Curl_attach_connection(data, cf->conn);
nread = Curl_conn_cf_recv(cf->next, data,
ctx->inbuf, H2_BUFSIZE, &result);
- dead = FALSE;
if(nread != -1) {
DEBUGF(LOG_CF(data, cf, "%d bytes stray data read before trying "
"h2 connection", (int)nread));
@@ -406,15 +410,19 @@ static bool http2_connisdead(struct Curl_cfilter *cf, struct Curl_easy *data)
ctx->inbuflen = nread;
if(h2_process_pending_input(cf, data, &result) < 0)
/* immediate error, considered dead */
- dead = TRUE;
+ alive = FALSE;
+ else {
+ alive = !should_close_session(ctx);
+ }
}
- else
+ else {
/* the read failed so let's say this is dead anyway */
- dead = TRUE;
+ alive = FALSE;
+ }
Curl_detach_connection(data);
}
- return dead;
+ return alive;
}
static CURLcode http2_send_ping(struct Curl_cfilter *cf,
@@ -815,7 +823,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
ctx->max_concurrent_streams = nghttp2_session_get_remote_settings(
session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
ctx->enable_push = nghttp2_session_get_remote_settings(
- session, NGHTTP2_SETTINGS_ENABLE_PUSH);
+ session, NGHTTP2_SETTINGS_ENABLE_PUSH) != 0;
DEBUGF(LOG_CF(data, cf, "MAX_CONCURRENT_STREAMS == %d",
ctx->max_concurrent_streams));
DEBUGF(LOG_CF(data, cf, "ENABLE_PUSH == %s",
@@ -829,9 +837,12 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
break;
}
case NGHTTP2_GOAWAY:
+ ctx->goaway = TRUE;
+ ctx->goaway_error = frame->goaway.error_code;
+ ctx->last_stream_id = frame->goaway.last_stream_id;
if(data) {
infof(data, "recveived GOAWAY, error=%d, last_stream=%u",
- frame->goaway.error_code, frame->goaway.last_stream_id);
+ ctx->goaway_error, ctx->last_stream_id);
multi_connchanged(data->multi);
}
break;
@@ -858,7 +869,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
switch(frame->hd.type) {
case NGHTTP2_DATA:
- /* If body started on this stream, then receiving DATA is illegal. */
+ /* If !body started on this stream, then receiving DATA is illegal. */
DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv frame DATA", stream_id));
if(!stream->bodystarted) {
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
@@ -940,7 +951,21 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
break;
case NGHTTP2_RST_STREAM:
DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv RST", stream_id));
+ stream->closed = TRUE;
stream->reset = TRUE;
+ drain_this(cf, data);
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ break;
+ case NGHTTP2_WINDOW_UPDATE:
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv WINDOW_UPDATE", stream_id));
+ if((data_s->req.keepon & KEEP_SEND_HOLD) &&
+ (data_s->req.keepon & KEEP_SEND)) {
+ data_s->req.keepon &= ~KEEP_SEND_HOLD;
+ drain_this(cf, data_s);
+ Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] un-holding after win update",
+ stream_id));
+ }
break;
default:
DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv frame %x",
@@ -1006,18 +1031,6 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_PAUSE;
}
-#if 0
- /* pause execution of nghttp2 if we received data for another handle
- in order to process them first. */
- if(CF_DATA_CURRENT(cf) != data_s) {
- ctx->pause_stream_id = stream_id;
- DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] not call_data -> NGHTTP2_ERR_PAUSE",
- stream_id));
- drain_this(cf, data_s);
- return NGHTTP2_ERR_PAUSE;
- }
-#endif
-
return 0;
}
@@ -1030,44 +1043,43 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
struct HTTP *stream;
int rv;
(void)session;
- (void)stream_id;
- if(stream_id) {
- /* get the stream from the hash based on Stream ID, stream ID zero is for
- connection-oriented stuff */
- data_s = nghttp2_session_get_stream_user_data(session, stream_id);
- if(!data_s) {
- /* We could get stream ID not in the hash. For example, if we
- decided to reject stream (e.g., PUSH_PROMISE). */
- return 0;
- }
- DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] on_stream_close(), %s (err %d)",
- stream_id, nghttp2_http2_strerror(error_code), error_code));
- stream = data_s->req.p.http;
- if(!stream)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ /* get the stream from the hash based on Stream ID, stream ID zero is for
+ connection-oriented stuff */
+ data_s = stream_id?
+ nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
+ if(!data_s) {
+ return 0;
+ }
+ stream = data_s->req.p.http;
+ DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] on_stream_close(), %s (err %d)",
+ stream_id, nghttp2_http2_strerror(error_code), error_code));
+ if(!stream)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
- stream->closed = TRUE;
- if(CF_DATA_CURRENT(cf) != data_s) {
- drain_this(cf, data_s);
- Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
- }
- stream->error = error_code;
+ stream->closed = TRUE;
+ stream->error = error_code;
+ if(stream->error)
+ stream->reset = TRUE;
- /* remove the entry from the hash as the stream is now gone */
- rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
- if(rv) {
- infof(data_s, "http/2: failed to clear user_data for stream %u",
- stream_id);
- DEBUGASSERT(0);
- }
- if(stream_id == ctx->pause_stream_id) {
- DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed the pause stream",
- stream_id));
- ctx->pause_stream_id = 0;
- }
- DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed, cleared", stream_id));
+ if(CF_DATA_CURRENT(cf) != data_s) {
+ drain_this(cf, data_s);
+ Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
}
+
+ /* remove `data_s` from the nghttp2 stream */
+ rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
+ if(rv) {
+ infof(data_s, "http/2: failed to clear user_data for stream %u",
+ stream_id);
+ DEBUGASSERT(0);
+ }
+ if(stream_id == ctx->pause_stream_id) {
+ DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed the pause stream",
+ stream_id));
+ ctx->pause_stream_id = 0;
+ }
+ DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed now", stream_id));
return 0;
}
@@ -1383,7 +1395,8 @@ static void http2_data_done(struct Curl_cfilter *cf,
ctx->pause_stream_id = 0;
}
- if(premature || (!stream->closed && stream->stream_id)) {
+ (void)premature;
+ if(!stream->closed && stream->stream_id) {
/* RST_STREAM */
DEBUGF(LOG_CF(data, cf, "[h2sid=%u] RST", stream->stream_id));
if(!nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
@@ -1446,15 +1459,6 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
}
/*
- * Returns nonzero if current HTTP/2 session should be closed.
- */
-static int should_close_session(struct cf_h2_ctx *ctx)
-{
- return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) &&
- !nghttp2_session_want_write(ctx->h2);
-}
-
-/*
* h2_process_pending_input() processes pending input left in
* httpc->inbuf. Then, call h2_session_send() to send pending data.
* This function returns 0 if it succeeds, or -1 and error code will
@@ -1586,8 +1590,6 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
}
}
- /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
- stream->closed = FALSE;
if(stream->error == NGHTTP2_REFUSED_STREAM) {
DEBUGF(LOG_CF(data, cf, "[h2sid=%u] REFUSED_STREAM, try again on a new "
"connection", stream->stream_id));
@@ -1603,6 +1605,11 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
*err = CURLE_HTTP2_STREAM;
return -1;
}
+ else if(stream->reset) {
+ failf(data, "HTTP/2 stream %u was reset", stream->stream_id);
+ *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
+ return -1;
+ }
if(!stream->bodystarted) {
failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
@@ -1638,7 +1645,7 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
stream->close_handled = TRUE;
- DEBUGF(LOG_CF(data, cf, "http2_recv returns 0, http2_handle_stream_close"));
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] closed cleanly", stream->stream_id));
return 0;
}
@@ -1720,9 +1727,29 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
struct HTTP *stream = data->req.p.http;
ssize_t nread = -1;
struct cf_call_data save;
+ bool conn_is_closed = FALSE;
CF_DATA_SAVE(save, cf, data);
+ /* If the h2 session has told us to GOAWAY with an error AND
+ * indicated the highest stream id it has processes AND
+ * the stream we are trying to read has a higher id, this
+ * means we will most likely not receive any more for it.
+ * Treat this as if the server explicitly had RST the stream */
+ if((ctx->goaway && ctx->goaway_error &&
+ ctx->last_stream_id > 0 &&
+ ctx->last_stream_id < stream->stream_id)) {
+ stream->reset = TRUE;
+ }
+
+ /* If a stream is RST, it does not matter what state the h2 session
+ * is in, our answer to receiving data is always the same. */
+ if(stream->reset) {
+ *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
+ nread = -1;
+ goto out;
+ }
+
if(should_close_session(ctx)) {
DEBUGF(LOG_CF(data, cf, "http2_recv: nothing to do in this session"));
if(cf->conn->bits.close) {
@@ -1763,7 +1790,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
}
- DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv: win %u/%u",
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv: win %u/%u",
stream->stream_id,
nghttp2_session_get_local_window_size(ctx->h2),
nghttp2_session_get_stream_local_window_size(ctx->h2,
@@ -1846,57 +1873,40 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
stream->memlen = 0;
if(ctx->inbuflen > 0) {
- DEBUGF(LOG_CF(data, cf, "Use data left in connection buffer, nread=%zd",
- ctx->inbuflen - ctx->nread_inbuf));
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] %zd bytes in inbuf",
+ stream->stream_id, ctx->inbuflen - ctx->nread_inbuf));
if(h2_process_pending_input(cf, data, err))
return -1;
}
- while(stream->memlen == 0 /* have no data for this stream */
- && !ctx->pause_stream_id /* we are not paused either */
- && ctx->inbuflen == 0) { /* and out input buffer is empty */
+ while(stream->memlen == 0 && /* have no data for this stream */
+ !stream->closed && /* and it is not closed/reset */
+ !ctx->pause_stream_id && /* we are not paused either */
+ ctx->inbuflen == 0 && /* and out input buffer is empty */
+ !conn_is_closed) { /* and connection is not closed */
/* Receive data from the "lower" filters */
nread = Curl_conn_cf_recv(cf->next, data, ctx->inbuf, H2_BUFSIZE, err);
if(nread < 0) {
- if(*err != CURLE_AGAIN)
- failf(data, "Failed receiving HTTP2 data");
- else if(stream->closed) {
- /* received when the stream was already closed! */
- nread = http2_handle_stream_close(cf, data, stream, err);
- goto out;
+ DEBUGASSERT(*err);
+ if(*err == CURLE_AGAIN) {
+ break;
}
-
- /* nothing to read from the lower layers, clear drain */
- drained_transfer(cf, data);
- nread = -1;
- goto out;
+ failf(data, "Failed receiving HTTP2 data");
+ conn_is_closed = TRUE;
}
else if(nread == 0) {
- if(!stream->closed) {
- /* This will happen when the server or proxy server is SIGKILLed
- during data transfer. We should emit an error since our data
- received may be incomplete. */
- failf(data, "HTTP/2 stream %u was not closed cleanly before"
- " end of the underlying stream",
- stream->stream_id);
- drained_transfer(cf, data);
- *err = CURLE_PARTIAL_FILE;
- nread = -1;
- goto out;
- }
-
- DEBUGF(LOG_CF(data, cf, "[h2sid=%u] end of stream",
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] underlying connection is closed",
stream->stream_id));
- *err = CURLE_OK;
- nread = 0;
- goto out;
+ conn_is_closed = TRUE;
+ }
+ else {
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] read %zd from connection",
+ stream->stream_id, nread));
+ ctx->inbuflen = nread;
+ DEBUGASSERT(ctx->nread_inbuf == 0);
+ if(h2_process_pending_input(cf, data, err))
+ return -1;
}
-
- DEBUGF(LOG_CF(data, cf, "read %zd from connection", nread));
- ctx->inbuflen = nread;
- DEBUGASSERT(ctx->nread_inbuf == 0);
- if(h2_process_pending_input(cf, data, err))
- return -1;
}
}
@@ -1933,11 +1943,18 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
*err = CURLE_OK;
nread = retlen;
- DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_h2_recv -> %zd",
- stream->stream_id, nread));
goto out;
}
+ if(conn_is_closed && !stream->closed) {
+ /* underlying connection is closed and we have nothing for the stream.
+ * Treat this as a RST */
+ stream->closed = stream->reset = TRUE;
+ failf(data, "HTTP/2 stream %u was not closed cleanly before"
+ " end of the underlying connection",
+ stream->stream_id);
+ }
+
if(stream->closed) {
nread = http2_handle_stream_close(cf, data, stream, err);
goto out;
@@ -1950,9 +1967,9 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
*err = CURLE_AGAIN;
nread = -1;
- DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv -> AGAIN",
- stream->stream_id));
out:
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv -> %zd, %d",
+ stream->stream_id, nread, *err));
CF_DATA_RESTORE(cf, save);
return nread;
}
@@ -1976,19 +1993,20 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
CURLcode result;
struct h2h3req *hreq;
struct cf_call_data save;
+ ssize_t nwritten;
CF_DATA_SAVE(save, cf, data);
- DEBUGF(LOG_CF(data, cf, "send len=%zu", len));
+ DEBUGF(LOG_CF(data, cf, "cf_send(len=%zu) start", len));
if(stream->stream_id != -1) {
if(stream->close_handled) {
infof(data, "stream %u closed", stream->stream_id);
*err = CURLE_HTTP2_STREAM;
- len = -1;
+ nwritten = -1;
goto out;
}
else if(stream->closed) {
- len = http2_handle_stream_close(cf, data, stream, err);
+ nwritten = http2_handle_stream_close(cf, data, stream, err);
goto out;
}
/* If stream_id != -1, we have dispatched request HEADERS, and now
@@ -1998,26 +2016,24 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
rv = nghttp2_session_resume_data(ctx->h2, stream->stream_id);
if(nghttp2_is_fatal(rv)) {
*err = CURLE_SEND_ERROR;
- len = -1;
+ nwritten = -1;
goto out;
}
result = h2_session_send(cf, data);
if(result) {
*err = result;
- len = -1;
+ nwritten = -1;
goto out;
}
- len -= stream->upload_len;
- /* Nullify here because we call nghttp2_session_send() and they
- might refer to the old buffer. */
+ nwritten = (ssize_t)len - (ssize_t)stream->upload_len;
stream->upload_mem = NULL;
stream->upload_len = 0;
if(should_close_session(ctx)) {
DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
*err = CURLE_HTTP2;
- len = -1;
+ nwritten = -1;
goto out;
}
@@ -2029,26 +2045,36 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
nghttp2_session_resume_data(ctx->h2, stream->stream_id);
}
-#ifdef DEBUG_HTTP2
- if(!len) {
- infof(data, "http2_send: easy %p (stream %u) win %u/%u",
- data, stream->stream_id,
- nghttp2_session_get_remote_window_size(ctx->h2),
- nghttp2_session_get_stream_remote_window_size(ctx->h2,
- stream->stream_id)
- );
-
+ if(!nwritten) {
+ size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2,
+ stream->stream_id);
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_send: win %u/%zu",
+ stream->stream_id,
+ nghttp2_session_get_remote_window_size(ctx->h2), rwin));
+ if(rwin == 0) {
+ /* We cannot upload more as the stream's remote window size
+ * is 0. We need to receive WIN_UPDATEs before we can continue.
+ */
+ data->req.keepon |= KEEP_SEND_HOLD;
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] holding send as remote flow "
+ "window is exhausted", stream->stream_id));
+ }
}
- infof(data, "http2_send returns %zu for stream %u", len,
- stream->stream_id);
-#endif
+ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_send returns %zd ",
+ stream->stream_id, nwritten));
+
+ /* handled writing BODY for open stream. */
goto out;
}
-
+ /* Stream has not been opened yet. `buf` is expected to contain
+ * request headers. */
+ /* TODO: this assumes that the `buf` and `len` we are called with
+ * is *all* HEADERs and no body. We have no way to determine here
+ * if that is indeed the case. */
result = Curl_pseudo_headers(data, buf, len, NULL, &hreq);
if(result) {
*err = result;
- len = -1;
+ nwritten = -1;
goto out;
}
nheader = hreq->entries;
@@ -2057,7 +2083,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!nva) {
Curl_pseudo_free(hreq);
*err = CURLE_OUT_OF_MEMORY;
- len = -1;
+ nwritten = -1;
goto out;
}
else {
@@ -2104,25 +2130,28 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGF(LOG_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
nghttp2_strerror(stream_id), stream_id));
*err = CURLE_SEND_ERROR;
- len = -1;
+ nwritten = -1;
goto out;
}
infof(data, "Using Stream ID: %u (easy handle %p)",
stream_id, (void *)data);
stream->stream_id = stream_id;
+ /* See TODO above. We assume that the whole buf was consumed by
+ * generating the request headers. */
+ nwritten = len;
result = h2_session_send(cf, data);
if(result) {
*err = result;
- len = -1;
+ nwritten = -1;
goto out;
}
if(should_close_session(ctx)) {
DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
*err = CURLE_HTTP2;
- len = -1;
+ nwritten = -1;
goto out;
}
@@ -2137,7 +2166,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
out:
CF_DATA_RESTORE(cf, save);
- return len;
+ return nwritten;
}
static int cf_h2_get_select_socks(struct Curl_cfilter *cf,
@@ -2160,7 +2189,7 @@ static int cf_h2_get_select_socks(struct Curl_cfilter *cf,
/* we're (still uploading OR the HTTP/2 layer wants to send data) AND
there's a window to send data in */
- if((((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
+ if((((k->keepon & KEEP_SENDBITS) == KEEP_SEND) ||
nghttp2_session_want_write(ctx->h2)) &&
(nghttp2_session_get_remote_window_size(ctx->h2) &&
nghttp2_session_get_stream_remote_window_size(ctx->h2,
@@ -2329,14 +2358,17 @@ static bool cf_h2_data_pending(struct Curl_cfilter *cf,
}
static bool cf_h2_is_alive(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+ struct Curl_easy *data,
+ bool *input_pending)
{
struct cf_h2_ctx *ctx = cf->ctx;
CURLcode result;
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
- result = (ctx && ctx->h2 && !http2_connisdead(cf, data));
+ result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending));
+ DEBUGF(LOG_CF(data, cf, "conn alive -> %d, input_pending=%d",
+ result, *input_pending));
CF_DATA_RESTORE(cf, save);
return result;
}
@@ -2479,7 +2511,8 @@ bool Curl_http2_may_switch(struct Curl_easy *data,
int sockindex)
{
(void)sockindex;
- if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+ if(!Curl_conn_is_http2(data, conn, sockindex) &&
+ data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
/* We don't support HTTP/2 proxies yet. Also it's debatable
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
index f8ce169..7d50cff 100644
--- a/Utilities/cmcurl/lib/http_aws_sigv4.c
+++ b/Utilities/cmcurl/lib/http_aws_sigv4.c
@@ -58,13 +58,15 @@
#define TIMESTAMP_SIZE 17
-static void sha256_to_hex(char *dst, unsigned char *sha, size_t dst_l)
+/* hex-encoded with trailing null */
+#define SHA256_HEX_LENGTH (2 * SHA256_DIGEST_LENGTH + 1)
+
+static void sha256_to_hex(char *dst, unsigned char *sha)
{
int i;
- DEBUGASSERT(dst_l >= 65);
- for(i = 0; i < 32; ++i) {
- msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]);
+ for(i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+ msnprintf(dst + (i * 2), SHA256_HEX_LENGTH - (i * 2), "%02x", sha[i]);
}
}
@@ -135,6 +137,7 @@ static CURLcode make_headers(struct Curl_easy *data,
char *timestamp,
char *provider1,
char **date_header,
+ char *content_sha256_header,
struct dynbuf *canonical_headers,
struct dynbuf *signed_headers)
{
@@ -189,6 +192,13 @@ static CURLcode make_headers(struct Curl_easy *data,
}
+ if (*content_sha256_header) {
+ tmp_head = curl_slist_append(head, content_sha256_header);
+ if(!tmp_head)
+ goto fail;
+ head = tmp_head;
+ }
+
for(l = data->set.headers; l; l = l->next) {
tmp_head = curl_slist_append(head, l->data);
if(!tmp_head)
@@ -267,6 +277,9 @@ fail:
}
#define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256"))
+/* add 2 for ": " between header name and value */
+#define CONTENT_SHA256_HDR_LEN (CONTENT_SHA256_KEY_LEN + 2 + \
+ SHA256_HEX_LENGTH)
/* try to parse a payload hash from the content-sha256 header */
static char *parse_content_sha_hdr(struct Curl_easy *data,
@@ -300,6 +313,63 @@ static char *parse_content_sha_hdr(struct Curl_easy *data,
return value;
}
+static CURLcode calc_payload_hash(struct Curl_easy *data,
+ unsigned char *sha_hash, char *sha_hex)
+{
+ const char *post_data = data->set.postfields;
+ size_t post_data_len = 0;
+ CURLcode result;
+
+ if(post_data) {
+ if(data->set.postfieldsize < 0)
+ post_data_len = strlen(post_data);
+ else
+ post_data_len = (size_t)data->set.postfieldsize;
+ }
+ result = Curl_sha256it(sha_hash, (const unsigned char *) post_data,
+ post_data_len);
+ if(!result)
+ sha256_to_hex(sha_hex, sha_hash);
+ return result;
+}
+
+#define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD"
+
+static CURLcode calc_s3_payload_hash(struct Curl_easy *data,
+ Curl_HttpReq httpreq, char *provider1,
+ unsigned char *sha_hash,
+ char *sha_hex, char *header)
+{
+ bool empty_method = (httpreq == HTTPREQ_GET || httpreq == HTTPREQ_HEAD);
+ /* The request method or filesize indicate no request payload */
+ bool empty_payload = (empty_method || data->set.filesize == 0);
+ /* The POST payload is in memory */
+ bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields);
+ CURLcode ret = CURLE_OUT_OF_MEMORY;
+
+ if(empty_payload || post_payload) {
+ /* Calculate a real hash when we know the request payload */
+ ret = calc_payload_hash(data, sha_hash, sha_hex);
+ if(ret)
+ goto fail;
+ }
+ else {
+ /* Fall back to s3's UNSIGNED-PAYLOAD */
+ size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1;
+ DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */
+ memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len);
+ sha_hex[len] = 0;
+ }
+
+ /* format the required content-sha256 header */
+ msnprintf(header, CONTENT_SHA256_HDR_LEN,
+ "x-%s-content-sha256: %s", provider1, sha_hex);
+
+ ret = CURLE_OK;
+fail:
+ return ret;
+}
+
CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
{
CURLcode ret = CURLE_OUT_OF_MEMORY;
@@ -310,6 +380,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
char provider1[MAX_SIGV4_LEN + 1]="";
char region[MAX_SIGV4_LEN + 1]="";
char service[MAX_SIGV4_LEN + 1]="";
+ bool sign_as_s3 = false;
const char *hostname = conn->host.name;
time_t clock;
struct tm tm;
@@ -318,20 +389,21 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
struct dynbuf canonical_headers;
struct dynbuf signed_headers;
char *date_header = NULL;
+ Curl_HttpReq httpreq;
+ const char *method = NULL;
char *payload_hash = NULL;
size_t payload_hash_len = 0;
- const char *post_data = data->set.postfields;
- size_t post_data_len = 0;
- unsigned char sha_hash[32];
- char sha_hex[65];
+ unsigned char sha_hash[SHA256_DIGEST_LENGTH];
+ char sha_hex[SHA256_HEX_LENGTH];
+ char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
char *canonical_request = NULL;
char *request_type = NULL;
char *credential_scope = NULL;
char *str_to_sign = NULL;
const char *user = data->state.aptr.user ? data->state.aptr.user : "";
char *secret = NULL;
- unsigned char sign0[32] = {0};
- unsigned char sign1[32] = {0};
+ unsigned char sign0[SHA256_DIGEST_LENGTH] = {0};
+ unsigned char sign1[SHA256_DIGEST_LENGTH] = {0};
char *auth_headers = NULL;
DEBUGASSERT(!proxy);
@@ -408,6 +480,29 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
}
}
+ Curl_http_method(data, conn, &method, &httpreq);
+
+ /* AWS S3 requires a x-amz-content-sha256 header, and supports special
+ * values like UNSIGNED-PAYLOAD */
+ sign_as_s3 = (strcasecompare(provider0, "aws") &&
+ strcasecompare(service, "s3"));
+
+ payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len);
+
+ if(!payload_hash) {
+ if(sign_as_s3)
+ ret = calc_s3_payload_hash(data, httpreq, provider1, sha_hash,
+ sha_hex, content_sha256_hdr);
+ else
+ ret = calc_payload_hash(data, sha_hash, sha_hex);
+ if(ret)
+ goto fail;
+
+ payload_hash = sha_hex;
+ /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */
+ payload_hash_len = strlen(sha_hex);
+ }
+
#ifdef DEBUGBUILD
{
char *force_timestamp = getenv("CURL_FORCETIME");
@@ -429,54 +524,37 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
}
ret = make_headers(data, hostname, timestamp, provider1,
- &date_header, &canonical_headers, &signed_headers);
+ &date_header, content_sha256_hdr,
+ &canonical_headers, &signed_headers);
if(ret)
goto fail;
ret = CURLE_OUT_OF_MEMORY;
+ if(*content_sha256_hdr) {
+ /* make_headers() needed this without the \r\n for canonicalization */
+ size_t hdrlen = strlen(content_sha256_hdr);
+ DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr));
+ memcpy(content_sha256_hdr + hdrlen, "\r\n", 3);
+ }
+
memcpy(date, timestamp, sizeof(date));
date[sizeof(date) - 1] = 0;
- payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len);
-
- if(!payload_hash) {
- if(post_data) {
- if(data->set.postfieldsize < 0)
- post_data_len = strlen(post_data);
- else
- post_data_len = (size_t)data->set.postfieldsize;
- }
- if(Curl_sha256it(sha_hash, (const unsigned char *) post_data,
- post_data_len))
- goto fail;
-
- sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
- payload_hash = sha_hex;
- payload_hash_len = strlen(sha_hex);
- }
-
- {
- Curl_HttpReq httpreq;
- const char *method;
-
- Curl_http_method(data, conn, &method, &httpreq);
-
- canonical_request =
- curl_maprintf("%s\n" /* HTTPRequestMethod */
- "%s\n" /* CanonicalURI */
- "%s\n" /* CanonicalQueryString */
- "%s\n" /* CanonicalHeaders */
- "%s\n" /* SignedHeaders */
- "%.*s", /* HashedRequestPayload in hex */
- method,
- data->state.up.path,
- data->state.up.query ? data->state.up.query : "",
- Curl_dyn_ptr(&canonical_headers),
- Curl_dyn_ptr(&signed_headers),
- (int)payload_hash_len, payload_hash);
- if(!canonical_request)
- goto fail;
- }
+ canonical_request =
+ curl_maprintf("%s\n" /* HTTPRequestMethod */
+ "%s\n" /* CanonicalURI */
+ "%s\n" /* CanonicalQueryString */
+ "%s\n" /* CanonicalHeaders */
+ "%s\n" /* SignedHeaders */
+ "%.*s", /* HashedRequestPayload in hex */
+ method,
+ data->state.up.path,
+ data->state.up.query ? data->state.up.query : "",
+ Curl_dyn_ptr(&canonical_headers),
+ Curl_dyn_ptr(&signed_headers),
+ (int)payload_hash_len, payload_hash);
+ if(!canonical_request)
+ goto fail;
/* provider 0 lowercase */
Curl_strntolower(provider0, provider0, strlen(provider0));
@@ -493,7 +571,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
strlen(canonical_request)))
goto fail;
- sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+ sha256_to_hex(sha_hex, sha_hash);
/* provider 0 uppercase */
Curl_strntoupper(provider0, provider0, strlen(provider0));
@@ -527,20 +605,22 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
- sha256_to_hex(sha_hex, sign0, sizeof(sha_hex));
+ sha256_to_hex(sha_hex, sign0);
/* provider 0 uppercase */
auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
"Credential=%s/%s, "
"SignedHeaders=%s, "
"Signature=%s\r\n"
- "%s\r\n",
+ "%s\r\n"
+ "%s", /* optional sha256 header includes \r\n */
provider0,
user,
credential_scope,
Curl_dyn_ptr(&signed_headers),
sha_hex,
- date_header);
+ date_header,
+ content_sha256_hdr);
if(!auth_headers) {
goto fail;
}
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index fdd092d..9f214a3 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -403,7 +403,6 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
{
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
- int subversion = 0;
(void)cf;
if((checkprefix("WWW-Authenticate:", header) &&
@@ -461,11 +460,14 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
STRCONST("Proxy-Connection:"),
STRCONST("close")))
ts->close_connection = TRUE;
- else if(2 == sscanf(header, "HTTP/1.%d %d",
- &subversion,
- &k->httpcode)) {
+ else if(!strncmp(header, "HTTP/1.", 7) &&
+ ((header[7] == '0') || (header[7] == '1')) &&
+ (header[8] == ' ') &&
+ ISDIGIT(header[9]) && ISDIGIT(header[10]) && ISDIGIT(header[11]) &&
+ !ISDIGIT(header[12])) {
/* store the HTTP code from the proxy */
- data->info.httpproxycode = k->httpcode;
+ data->info.httpproxycode = k->httpcode = (header[9] - '0') * 100 +
+ (header[10] - '0') * 10 + (header[11] - '0');
}
return result;
}
diff --git a/Utilities/cmcurl/lib/idn.c b/Utilities/cmcurl/lib/idn.c
index abba895..5f4b07e 100644
--- a/Utilities/cmcurl/lib/idn.c
+++ b/Utilities/cmcurl/lib/idn.c
@@ -184,6 +184,11 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host)
if(!Curl_is_ASCII_name(host->name)) {
char *decoded = idn_decode(host->name);
if(decoded) {
+ if(!*decoded) {
+ /* zero length is a bad host name */
+ Curl_idn_free(decoded);
+ return CURLE_URL_MALFORMAT;
+ }
/* successful */
host->encalloc = decoded;
/* change the name pointer to point to the encoded hostname */
diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/inet_ntop.c
index 024f8da..770ed3a 100644
--- a/Utilities/cmcurl/lib/inet_ntop.c
+++ b/Utilities/cmcurl/lib/inet_ntop.c
@@ -42,6 +42,15 @@
#define INT16SZ 2
/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
+/*
* Format an IPv4 address, more or less like inet_ntop().
*
* Returns `dst' (as a const)
@@ -72,7 +81,6 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
return dst;
}
-#ifdef ENABLE_IPV6
/*
* Convert IPv6 binary address into presentation (printable) format.
*/
@@ -168,7 +176,6 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
strcpy(dst, tmp);
return dst;
}
-#endif /* ENABLE_IPV6 */
/*
* Convert a network format address to presentation format.
@@ -187,10 +194,8 @@ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
switch(af) {
case AF_INET:
return inet_ntop4((const unsigned char *)src, buf, size);
-#ifdef ENABLE_IPV6
case AF_INET6:
return inet_ntop6((const unsigned char *)src, buf, size);
-#endif
default:
errno = EAFNOSUPPORT;
return NULL;
diff --git a/Utilities/cmcurl/lib/inet_pton.c b/Utilities/cmcurl/lib/inet_pton.c
index f2e17b8..7d3c698 100644
--- a/Utilities/cmcurl/lib/inet_pton.c
+++ b/Utilities/cmcurl/lib/inet_pton.c
@@ -39,14 +39,21 @@
#define INT16SZ 2
/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
+/*
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static int inet_pton4(const char *src, unsigned char *dst);
-#ifdef ENABLE_IPV6
static int inet_pton6(const char *src, unsigned char *dst);
-#endif
/* int
* inet_pton(af, src, dst)
@@ -70,10 +77,8 @@ Curl_inet_pton(int af, const char *src, void *dst)
switch(af) {
case AF_INET:
return (inet_pton4(src, (unsigned char *)dst));
-#ifdef ENABLE_IPV6
case AF_INET6:
return (inet_pton6(src, (unsigned char *)dst));
-#endif
default:
errno = EAFNOSUPPORT;
return (-1);
@@ -135,7 +140,6 @@ inet_pton4(const char *src, unsigned char *dst)
return (1);
}
-#ifdef ENABLE_IPV6
/* int
* inet_pton6(src, dst)
* convert presentation level address to network order binary form.
@@ -234,6 +238,5 @@ inet_pton6(const char *src, unsigned char *dst)
memcpy(dst, tmp, IN6ADDRSZ);
return (1);
}
-#endif /* ENABLE_IPV6 */
#endif /* HAVE_INET_PTON */
diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c
index 3cd64e1..a71779a 100644
--- a/Utilities/cmcurl/lib/krb5.c
+++ b/Utilities/cmcurl/lib/krb5.c
@@ -721,8 +721,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
return 0;
if(buf[3] != '-')
- /* safe to ignore return code */
- (void)sscanf(buf, "%d", &ret_code);
+ ret_code = atoi(buf);
if(buf[decoded_len - 1] == '\n')
buf[decoded_len - 1] = '\0';
@@ -765,8 +764,9 @@ static int sec_set_protection_level(struct Curl_easy *data)
pbsz = strstr(data->state.buffer, "PBSZ=");
if(pbsz) {
- /* ignore return code, use default value if it fails */
- (void)sscanf(pbsz, "PBSZ=%u", &buffer_size);
+ /* stick to default value if the check fails */
+ if(!strncmp(pbsz, "PBSZ=", 5) && ISDIGIT(pbsz[5]))
+ buffer_size = atoi(&pbsz[5]);
if(buffer_size < conn->buffer_size)
conn->buffer_size = buffer_size;
}
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index 5e53f4c..595e4b3 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -140,6 +140,14 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp);
#define ldap_err2string ldap_err2stringA
#endif
+#if defined(USE_WIN32_LDAP) && defined(_MSC_VER) && (_MSC_VER <= 1600)
+/* Workaround for warning:
+ 'type cast' : conversion from 'int' to 'void *' of greater size */
+#undef LDAP_OPT_ON
+#undef LDAP_OPT_OFF
+#define LDAP_OPT_ON ((void *)(size_t)1)
+#define LDAP_OPT_OFF ((void *)(size_t)0)
+#endif
static CURLcode ldap_do(struct Curl_easy *data, bool *done);
diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c
index 0b54bc0..47af369 100644
--- a/Utilities/cmcurl/lib/mqtt.c
+++ b/Utilities/cmcurl/lib/mqtt.c
@@ -122,8 +122,9 @@ static CURLcode mqtt_send(struct Curl_easy *data,
struct MQTT *mq = data->req.p.mqtt;
ssize_t n;
result = Curl_write(data, sockfd, buf, len, &n);
- if(!result)
- Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
+ if(result)
+ return result;
+ Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
if(len != (size_t)n) {
size_t nsend = len - n;
char *sendleftovers = Curl_memdup(&buf[n], nsend);
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index f020a0b..731b259 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -445,9 +445,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
sockhash_destroy(&multi->sockhash);
Curl_hash_destroy(&multi->hostcache);
Curl_conncache_destroy(&multi->conn_cache);
- Curl_llist_destroy(&multi->msglist, NULL);
- Curl_llist_destroy(&multi->pending, NULL);
-
free(multi);
return NULL;
}
@@ -459,6 +456,42 @@ struct Curl_multi *curl_multi_init(void)
CURL_DNS_HASH_SIZE);
}
+static void link_easy(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ /* We add the new easy entry last in the list. */
+ data->next = NULL; /* end of the line */
+ if(multi->easyp) {
+ struct Curl_easy *last = multi->easylp;
+ last->next = data;
+ data->prev = last;
+ multi->easylp = data; /* the new last node */
+ }
+ else {
+ /* first node, make prev NULL! */
+ data->prev = NULL;
+ multi->easylp = multi->easyp = data; /* both first and last */
+ }
+}
+
+/* unlink the given easy handle from the linked list of easy handles */
+static void unlink_easy(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ /* make the previous node point to our next */
+ if(data->prev)
+ data->prev->next = data->next;
+ else
+ multi->easyp = data->next; /* point to first node */
+
+ /* make our next point to our previous node */
+ if(data->next)
+ data->next->prev = data->prev;
+ else
+ multi->easylp = data->prev; /* point to last node */
+}
+
+
CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
struct Curl_easy *data)
{
@@ -554,19 +587,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->psl = &multi->psl;
#endif
- /* We add the new entry last in the list. */
- data->next = NULL; /* end of the line */
- if(multi->easyp) {
- struct Curl_easy *last = multi->easylp;
- last->next = data;
- data->prev = last;
- multi->easylp = data; /* the new last node */
- }
- else {
- /* first node, make prev NULL! */
- data->prev = NULL;
- multi->easylp = multi->easyp = data; /* both first and last */
- }
+ link_easy(multi, data);
/* increase the node-counter */
multi->num_easy++;
@@ -841,10 +862,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
Curl_wildcard_dtor(&data->wildcard);
- /* destroy the timeout list that is held in the easy handle, do this *after*
- multi_done() as that may actually call Curl_expire that uses this */
- Curl_llist_destroy(&data->state.timeoutlist, NULL);
-
/* change state without using multistate(), only to make singlesocket() do
what we want */
data->mstate = MSTATE_COMPLETED;
@@ -917,17 +934,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
}
}
- /* make the previous node point to our next */
- if(data->prev)
- data->prev->next = data->next;
- else
- multi->easyp = data->next; /* point to first node */
-
- /* make our next point to our previous node */
- if(data->next)
- data->next->prev = data->prev;
- else
- multi->easylp = data->prev; /* point to last node */
+ unlink_easy(multi, data);
/* NOTE NOTE NOTE
We do not touch the easy handle here! */
@@ -976,7 +983,7 @@ void Curl_attach_connection(struct Curl_easy *data,
data->conn = conn;
Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
&data->conn_queue);
- if(conn->handler->attach)
+ if(conn->handler && conn->handler->attach)
conn->handler->attach(data, conn);
Curl_conn_ev_data_attach(conn, data);
}
@@ -2192,7 +2199,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifndef CURL_DISABLE_FTP
/* some steps needed for wildcard matching */
if(data->state.wildcardmatch) {
- struct WildcardData *wc = &data->wildcard;
+ struct WildcardData *wc = data->wildcard;
if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
/* skip some states if it is important */
multi_done(data, CURLE_OK, FALSE);
@@ -2344,7 +2351,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifndef CURL_DISABLE_FTP
if(data->state.wildcardmatch &&
((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
- data->wildcard.state = CURLWC_DONE;
+ data->wildcard->state = CURLWC_DONE;
}
#endif
multistate(data, MSTATE_DONE);
@@ -2574,7 +2581,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifndef CURL_DISABLE_FTP
if(data->state.wildcardmatch) {
- if(data->wildcard.state != CURLWC_DONE) {
+ if(data->wildcard->state != CURLWC_DONE) {
/* if a wildcard is set and we are not ending -> lets start again
with MSTATE_INIT */
multistate(data, MSTATE_INIT);
@@ -2706,18 +2713,25 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
return CURLM_RECURSIVE_API_CALL;
data = multi->easyp;
- while(data) {
+ if(data) {
CURLMcode result;
+ bool nosig = data->set.no_signal;
SIGPIPE_VARIABLE(pipe_st);
-
sigpipe_ignore(data, &pipe_st);
- result = multi_runsingle(multi, &now, data);
+ /* Do the loop and only alter the signal ignore state if the next handle
+ has a different NO_SIGNAL state than the previous */
+ do {
+ if(data->set.no_signal != nosig) {
+ sigpipe_restore(&pipe_st);
+ sigpipe_ignore(data, &pipe_st);
+ nosig = data->set.no_signal;
+ }
+ result = multi_runsingle(multi, &now, data);
+ if(result)
+ returncode = result;
+ data = data->next; /* operate on next handle */
+ } while(data);
sigpipe_restore(&pipe_st);
-
- if(result)
- returncode = result;
-
- data = data->next; /* operate on next handle */
}
/*
@@ -2788,9 +2802,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
sockhash_destroy(&multi->sockhash);
Curl_conncache_destroy(&multi->conn_cache);
- Curl_llist_destroy(&multi->msglist, NULL);
- Curl_llist_destroy(&multi->pending, NULL);
-
Curl_hash_destroy(&multi->hostcache);
Curl_psl_destroy(&multi->psl);
diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c
index 82ac1d8..1662dd3 100644
--- a/Utilities/cmcurl/lib/parsedate.c
+++ b/Utilities/cmcurl/lib/parsedate.c
@@ -212,56 +212,55 @@ static int checkday(const char *check, size_t len)
{
int i;
const char * const *what;
- bool found = FALSE;
if(len > 3)
what = &weekday[0];
- else
+ else if(len == 3)
what = &Curl_wkday[0];
+ else
+ return -1; /* too short */
for(i = 0; i<7; i++) {
- if(strcasecompare(check, what[0])) {
- found = TRUE;
- break;
- }
+ size_t ilen = strlen(what[0]);
+ if((ilen == len) &&
+ strncasecompare(check, what[0], len))
+ return i;
what++;
}
- return found?i:-1;
+ return -1;
}
-static int checkmonth(const char *check)
+static int checkmonth(const char *check, size_t len)
{
int i;
- const char * const *what;
- bool found = FALSE;
+ const char * const *what = &Curl_month[0];
+ if(len != 3)
+ return -1; /* not a month */
- what = &Curl_month[0];
for(i = 0; i<12; i++) {
- if(strcasecompare(check, what[0])) {
- found = TRUE;
- break;
- }
+ if(strncasecompare(check, what[0], 3))
+ return i;
what++;
}
- return found?i:-1; /* return the offset or -1, no real offset is -1 */
+ return -1; /* return the offset or -1, no real offset is -1 */
}
/* return the time zone offset between GMT and the input one, in number
of seconds or -1 if the timezone wasn't found/legal */
-static int checktz(const char *check)
+static int checktz(const char *check, size_t len)
{
unsigned int i;
- const struct tzinfo *what;
- bool found = FALSE;
+ const struct tzinfo *what = tz;
+ if(len > 4) /* longer than any valid timezone */
+ return -1;
- what = tz;
for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
- if(strcasecompare(check, what->name)) {
- found = TRUE;
- break;
- }
+ size_t ilen = strlen(what->name);
+ if((ilen == len) &&
+ strncasecompare(check, what->name, len))
+ return what->offset*60;
what++;
}
- return found?what->offset*60:-1;
+ return -1;
}
static void skip(const char **date)
@@ -294,6 +293,53 @@ static time_t time2epoch(int sec, int min, int hour,
+ hour) * 60 + min) * 60 + sec;
}
+/* Returns the value of a single-digit or two-digit decimal number, return
+ then pointer to after the number. The 'date' pointer is known to point to a
+ digit. */
+static int oneortwodigit(const char *date, const char **endp)
+{
+ int num = date[0] - '0';
+ if(ISDIGIT(date[1])) {
+ *endp = &date[2];
+ return num*10 + (date[1] - '0');
+ }
+ *endp = &date[1];
+ return num;
+}
+
+
+/* HH:MM:SS or HH:MM and accept single-digits too */
+static bool match_time(const char *date,
+ int *h, int *m, int *s, char **endp)
+{
+ const char *p;
+ int hh, mm, ss = 0;
+ hh = oneortwodigit(date, &p);
+ if((hh < 24) && (*p == ':') && ISDIGIT(p[1])) {
+ mm = oneortwodigit(&p[1], &p);
+ if(mm < 60) {
+ if((*p == ':') && ISDIGIT(p[1])) {
+ ss = oneortwodigit(&p[1], &p);
+ if(ss <= 60) {
+ /* valid HH:MM:SS */
+ goto match;
+ }
+ }
+ else {
+ /* valid HH:MM */
+ goto match;
+ }
+ }
+ }
+ return FALSE; /* not a time string */
+ match:
+ *h = hh;
+ *m = mm;
+ *s = ss;
+ *endp = (char *)p;
+ return TRUE;
+}
+
/*
* parsedate()
*
@@ -305,6 +351,9 @@ static time_t time2epoch(int sec, int min, int hour,
* PARSEDATE_SOONER - time underflow at the low end of time_t
*/
+/* Wednesday is the longest name this parser knows about */
+#define NAME_LEN 12
+
static int parsedate(const char *date, time_t *output)
{
time_t t = 0;
@@ -327,32 +376,32 @@ static int parsedate(const char *date, time_t *output)
if(ISALPHA(*date)) {
/* a name coming up */
- char buf[32]="";
- size_t len;
- if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz]", buf))
- len = strlen(buf);
- else
- len = 0;
-
- if(wdaynum == -1) {
- wdaynum = checkday(buf, len);
- if(wdaynum != -1)
- found = TRUE;
- }
- if(!found && (monnum == -1)) {
- monnum = checkmonth(buf);
- if(monnum != -1)
- found = TRUE;
+ size_t len = 0;
+ const char *p = date;
+ while(ISALPHA(*p) && (len < NAME_LEN)) {
+ p++;
+ len++;
}
- if(!found && (tzoff == -1)) {
- /* this just must be a time zone string */
- tzoff = checktz(buf);
- if(tzoff != -1)
- found = TRUE;
- }
+ if(len != NAME_LEN) {
+ if(wdaynum == -1) {
+ wdaynum = checkday(date, len);
+ if(wdaynum != -1)
+ found = TRUE;
+ }
+ if(!found && (monnum == -1)) {
+ monnum = checkmonth(date, len);
+ if(monnum != -1)
+ found = TRUE;
+ }
+ if(!found && (tzoff == -1)) {
+ /* this just must be a time zone string */
+ tzoff = checktz(date, len);
+ if(tzoff != -1)
+ found = TRUE;
+ }
+ }
if(!found)
return PARSEDATE_FAIL; /* bad string */
@@ -362,18 +411,10 @@ static int parsedate(const char *date, time_t *output)
/* a digit */
int val;
char *end;
- int len = 0;
if((secnum == -1) &&
- (3 == sscanf(date, "%02d:%02d:%02d%n",
- &hournum, &minnum, &secnum, &len))) {
- /* time stamp! */
- date += len;
- }
- else if((secnum == -1) &&
- (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) {
- /* time stamp without seconds */
- date += len;
- secnum = 0;
+ match_time(date, &hournum, &minnum, &secnum, &end)) {
+ /* time stamp */
+ date = end;
}
else {
long lval;
diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c
index a222888..6092b78 100644
--- a/Utilities/cmcurl/lib/progress.c
+++ b/Utilities/cmcurl/lib/progress.c
@@ -87,8 +87,6 @@ static char *max5data(curl_off_t bytes, char *max5)
CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
(bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
-#if (SIZEOF_CURL_OFF_T > 4)
-
else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
/* 'XXXXM' is good until we're at 10000MB or above */
msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
@@ -111,15 +109,8 @@ static char *max5data(curl_off_t bytes, char *max5)
/* up to 10000PB, display without decimal: XXXXP */
msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
- /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number
- can hold, but our data type is signed so 8192PB will be the maximum. */
-
-#else
-
- else
- msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
-
-#endif
+ /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can
+ hold, but our data type is signed so 8192PB will be the maximum. */
return max5;
}
diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c
index 4b6ac07..9abb722 100644
--- a/Utilities/cmcurl/lib/rand.c
+++ b/Utilities/cmcurl/lib/rand.c
@@ -30,6 +30,10 @@
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
+#ifdef HAVE_ARC4RANDOM
+/* Some platforms might have the prototype missing (ubuntu + libressl) */
+uint32_t arc4random(void);
+#endif
#include <curl/curl.h>
#include "vtls/vtls.h"
@@ -143,6 +147,11 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
}
#endif
+#ifdef HAVE_ARC4RANDOM
+ *rnd = (unsigned int)arc4random();
+ return CURLE_OK;
+#endif
+
#if defined(RANDOM_FILE) && !defined(WIN32)
if(!seeded) {
/* if there's a random file to read a seed from, use it */
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c
index 9d27929..aef3560 100644
--- a/Utilities/cmcurl/lib/rtsp.c
+++ b/Utilities/cmcurl/lib/rtsp.c
@@ -145,7 +145,8 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data,
(void)data;
if(checks_to_perform & CONNCHECK_ISDEAD) {
- if(!Curl_conn_is_alive(data, conn))
+ bool input_pending;
+ if(!Curl_conn_is_alive(data, conn, &input_pending))
ret_val |= CONNRESULT_DEAD;
}
@@ -755,12 +756,14 @@ CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len)
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
{
- long CSeq = 0;
-
if(checkprefix("CSeq:", header)) {
- /* Store the received CSeq. Match is verified in rtsp_done */
- int nc = sscanf(&header[4], ": %ld", &CSeq);
- if(nc == 1) {
+ long CSeq = 0;
+ char *endp;
+ 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 */
diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c
index 3b8d468..61cce61 100644
--- a/Utilities/cmcurl/lib/select.c
+++ b/Utilities/cmcurl/lib/select.c
@@ -230,14 +230,14 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
if(readfd0 != CURL_SOCKET_BAD) {
if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
r |= CURL_CSELECT_IN;
- if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+ if(pfd[num].revents & (POLLPRI|POLLNVAL))
r |= CURL_CSELECT_ERR;
num++;
}
if(readfd1 != CURL_SOCKET_BAD) {
if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
r |= CURL_CSELECT_IN2;
- if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+ if(pfd[num].revents & (POLLPRI|POLLNVAL))
r |= CURL_CSELECT_ERR;
num++;
}
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index 604693a..6bb8879 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/setopt.c
@@ -899,7 +899,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURL_HTTP_VERSION_NONE:
#ifdef USE_HTTP2
/* TODO: this seems an undesirable quirk to force a behaviour on
- * lower implementations that they should recognize independantly? */
+ * lower implementations that they should recognize independently? */
arg = CURL_HTTP_VERSION_2TLS;
#endif
/* accepted */
@@ -2369,7 +2369,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST))
return CURLE_BAD_FUNCTION_ARGUMENT;
- data->set.use_ssl = (curl_usessl)arg;
+ data->set.use_ssl = (unsigned char)arg;
break;
case CURLOPT_SSL_OPTIONS:
@@ -2849,7 +2849,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
break;
case CURLOPT_CHUNK_DATA:
- data->wildcard.customptr = va_arg(param, void *);
+ data->set.wildcardptr = va_arg(param, void *);
break;
case CURLOPT_FNMATCH_DATA:
data->set.fnmatch_data = va_arg(param, void *);
diff --git a/Utilities/cmcurl/lib/sigpipe.h b/Utilities/cmcurl/lib/sigpipe.h
index 14ab25b..48761ad 100644
--- a/Utilities/cmcurl/lib/sigpipe.h
+++ b/Utilities/cmcurl/lib/sigpipe.h
@@ -50,7 +50,6 @@ static void sigpipe_ignore(struct Curl_easy *data,
if(!data->set.no_signal) {
struct sigaction action;
/* first, extract the existing situation */
- memset(&ig->old_pipe_act, 0, sizeof(struct sigaction));
sigaction(SIGPIPE, NULL, &ig->old_pipe_act);
action = ig->old_pipe_act;
/* ignore this signal */
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
index dc0abe7..0762004 100644
--- a/Utilities/cmcurl/lib/smb.c
+++ b/Utilities/cmcurl/lib/smb.c
@@ -25,8 +25,7 @@
#include "curl_setup.h"
-#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
- (SIZEOF_CURL_OFF_T > 4)
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
#define BUILDING_CURL_SMB_C
diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c
index a964bfd..e4ffd85 100644
--- a/Utilities/cmcurl/lib/telnet.c
+++ b/Utilities/cmcurl/lib/telnet.c
@@ -770,22 +770,32 @@ static void printsub(struct Curl_easy *data,
}
}
+static bool str_is_nonascii(const char *str)
+{
+ size_t len = strlen(str);
+ while(len--) {
+ if(*str & 0x80)
+ return TRUE;
+ str++;
+ }
+ return FALSE;
+}
+
static CURLcode check_telnet_options(struct Curl_easy *data)
{
struct curl_slist *head;
struct curl_slist *beg;
- char option_keyword[128] = "";
- char option_arg[256] = "";
struct TELNET *tn = data->req.p.telnet;
- struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
- int binary_option;
/* Add the user name as an environment variable if it
was given on the command line */
if(data->state.aptr.user) {
- msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
- beg = curl_slist_append(tn->telnet_vars, option_arg);
+ char buffer[256];
+ if(str_is_nonascii(data->conn->user))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user);
+ beg = curl_slist_append(tn->telnet_vars, buffer);
if(!beg) {
curl_slist_free_all(tn->telnet_vars);
tn->telnet_vars = NULL;
@@ -795,68 +805,100 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
}
- for(head = data->set.telnet_options; head; head = head->next) {
- if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
- option_keyword, option_arg) == 2) {
-
- /* Terminal type */
- if(strcasecompare(option_keyword, "TTYPE")) {
- strncpy(tn->subopt_ttype, option_arg, 31);
- tn->subopt_ttype[31] = 0; /* String termination */
- tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+ for(head = data->set.telnet_options; head && !result; head = head->next) {
+ size_t olen;
+ char *option = head->data;
+ char *arg;
+ char *sep = strchr(option, '=');
+ if(sep) {
+ olen = sep - option;
+ arg = ++sep;
+ if(str_is_nonascii(arg))
continue;
- }
+ switch(olen) {
+ case 5:
+ /* Terminal type */
+ if(strncasecompare(option, "TTYPE", 5)) {
+ strncpy(tn->subopt_ttype, arg, 31);
+ tn->subopt_ttype[31] = 0; /* String termination */
+ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+ }
+ else
+ result = CURLE_UNKNOWN_OPTION;
+ break;
- /* Display variable */
- if(strcasecompare(option_keyword, "XDISPLOC")) {
- strncpy(tn->subopt_xdisploc, option_arg, 127);
- tn->subopt_xdisploc[127] = 0; /* String termination */
- tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
- continue;
- }
+ case 8:
+ /* Display variable */
+ if(strncasecompare(option, "XDISPLOC", 8)) {
+ strncpy(tn->subopt_xdisploc, arg, 127);
+ tn->subopt_xdisploc[127] = 0; /* String termination */
+ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
+ }
+ else
+ result = CURLE_UNKNOWN_OPTION;
+ break;
- /* Environment variable */
- if(strcasecompare(option_keyword, "NEW_ENV")) {
- beg = curl_slist_append(tn->telnet_vars, option_arg);
- if(!beg) {
- result = CURLE_OUT_OF_MEMORY;
- break;
+ case 7:
+ /* Environment variable */
+ if(strncasecompare(option, "NEW_ENV", 7)) {
+ beg = curl_slist_append(tn->telnet_vars, arg);
+ if(!beg) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ tn->telnet_vars = beg;
+ tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
}
- tn->telnet_vars = beg;
- tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
- continue;
- }
+ else
+ result = CURLE_UNKNOWN_OPTION;
+ break;
- /* Window Size */
- if(strcasecompare(option_keyword, "WS")) {
- if(sscanf(option_arg, "%hu%*[xX]%hu",
- &tn->subopt_wsx, &tn->subopt_wsy) == 2)
- tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
- else {
- failf(data, "Syntax error in telnet option: %s", head->data);
- result = CURLE_SETOPT_OPTION_SYNTAX;
- break;
+ 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) {
+ failf(data, "Syntax error in telnet option: %s", head->data);
+ result = CURLE_SETOPT_OPTION_SYNTAX;
+ }
}
- continue;
- }
+ else
+ result = CURLE_UNKNOWN_OPTION;
+ break;
- /* To take care or not of the 8th bit in data exchange */
- if(strcasecompare(option_keyword, "BINARY")) {
- binary_option = atoi(option_arg);
- if(binary_option != 1) {
- tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
- tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+ case 6:
+ /* To take care or not of the 8th bit in data exchange */
+ if(strncasecompare(option, "BINARY", 6)) {
+ int binary_option = atoi(arg);
+ if(binary_option != 1) {
+ tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+ tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+ }
}
- continue;
+ else
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ default:
+ failf(data, "Unknown telnet option %s", head->data);
+ result = CURLE_UNKNOWN_OPTION;
+ break;
}
-
- failf(data, "Unknown telnet option %s", head->data);
- result = CURLE_UNKNOWN_OPTION;
- break;
}
- failf(data, "Syntax error in telnet option: %s", head->data);
- result = CURLE_SETOPT_OPTION_SYNTAX;
- break;
+ else {
+ failf(data, "Syntax error in telnet option: %s", head->data);
+ result = CURLE_SETOPT_OPTION_SYNTAX;
+ }
}
if(result) {
@@ -881,8 +923,6 @@ static void suboption(struct Curl_easy *data)
ssize_t bytes_written;
size_t len;
int err;
- char varname[128] = "";
- char varval[128] = "";
struct TELNET *tn = data->req.p.telnet;
struct connectdata *conn = data->conn;
@@ -920,19 +960,18 @@ static void suboption(struct Curl_easy *data)
for(v = tn->telnet_vars; v; v = v->next) {
size_t tmplen = (strlen(v->data) + 1);
- /* Add the variable only if it fits */
+ /* Add the variable if it fits */
if(len + tmplen < (int)sizeof(temp)-6) {
- int rv;
- char sep[2] = "";
- varval[0] = 0;
- rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval);
- if(rv == 1)
+ char *s = strchr(v->data, ',');
+ if(!s)
len += msnprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%s", CURL_NEW_ENV_VAR, varname);
- else if(rv >= 2)
+ "%c%s", CURL_NEW_ENV_VAR, v->data);
+ else {
+ size_t vlen = s - v->data;
len += msnprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
- CURL_NEW_ENV_VALUE, varval);
+ "%c%.*s%c%s", CURL_NEW_ENV_VAR,
+ (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s);
+ }
}
}
msnprintf((char *)&temp[len], sizeof(temp) - len,
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index 69df214..a283952 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -980,7 +980,15 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
if(result)
return result;
- win_update_buffer_size(conn->writesockfd);
+#if defined(WIN32) && defined(USE_WINSOCK)
+ {
+ struct curltime n = Curl_now();
+ if(Curl_timediff(n, k->last_sndbuf_update) > 1000) {
+ win_update_buffer_size(conn->writesockfd);
+ k->last_sndbuf_update = n;
+ }
+ }
+#endif
if(k->pendingheader) {
/* parts of what was sent was header */
@@ -1226,8 +1234,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
}
/* Now update the "done" boolean we return */
- *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND|
- KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE;
+ *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE;
result = CURLE_OK;
out:
if(result)
@@ -1394,7 +1401,13 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
#ifndef CURL_DISABLE_FTP
data->state.wildcardmatch = data->set.wildcard_enabled;
if(data->state.wildcardmatch) {
- struct WildcardData *wc = &data->wildcard;
+ struct WildcardData *wc;
+ if(!data->wildcard) {
+ data->wildcard = calloc(1, sizeof(struct WildcardData));
+ if(!data->wildcard)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ wc = data->wildcard;
if(wc->state < CURLWC_INIT) {
result = Curl_wildcard_init(wc); /* init wildcard structures */
if(result)
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index 1bb93df..f7b4bbb 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -288,33 +288,6 @@ static const struct Curl_handler * const protocols[] = {
(struct Curl_handler *) NULL
};
-/*
- * Dummy handler for undefined protocol schemes.
- */
-
-static const struct Curl_handler Curl_handler_dummy = {
- "<no protocol>", /* scheme */
- ZERO_NULL, /* setup_connection */
- ZERO_NULL, /* do_it */
- ZERO_NULL, /* done */
- ZERO_NULL, /* do_more */
- ZERO_NULL, /* connect_it */
- ZERO_NULL, /* connecting */
- ZERO_NULL, /* doing */
- ZERO_NULL, /* proto_getsock */
- ZERO_NULL, /* doing_getsock */
- ZERO_NULL, /* domore_getsock */
- ZERO_NULL, /* perform_getsock */
- ZERO_NULL, /* disconnect */
- ZERO_NULL, /* readwrite */
- ZERO_NULL, /* connection_check */
- ZERO_NULL, /* attach connection */
- 0, /* defport */
- 0, /* protocol */
- 0, /* family */
- PROTOPT_NONE /* flags */
-};
-
void Curl_freeset(struct Curl_easy *data)
{
/* Free all dynamic strings stored in the data->set substructure. */
@@ -341,6 +314,11 @@ void Curl_freeset(struct Curl_easy *data)
data->state.url = NULL;
Curl_mime_cleanpart(&data->set.mimepost);
+
+#ifndef CURL_DISABLE_COOKIES
+ curl_slist_free_all(data->set.cookielist);
+ data->set.cookielist = NULL;
+#endif
}
/* free the URL pieces */
@@ -431,9 +409,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_dyn_free(&data->state.headerb);
Curl_safefree(data->state.ulbuf);
Curl_flush_cookies(data, TRUE);
-#ifndef CURL_DISABLE_COOKIES
- curl_slist_free_all(data->set.cookielist); /* clean up list */
-#endif
Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
Curl_altsvc_cleanup(&data->asi);
Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
@@ -752,8 +727,6 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
-
- Curl_llist_destroy(&conn->easyq, NULL);
Curl_safefree(conn->localdev);
Curl_free_primary_ssl_config(&conn->ssl_config);
@@ -823,7 +796,7 @@ void Curl_disconnect(struct Curl_easy *data,
disconnect and shutdown */
Curl_attach_connection(data, conn);
- if(conn->handler->disconnect)
+ if(conn->handler && conn->handler->disconnect)
/* This is set if protocol-specific cleanups should be made */
conn->handler->disconnect(data, conn, dead_connection);
@@ -965,7 +938,20 @@ static bool extract_if_dead(struct connectdata *conn,
}
else {
- dead = !Curl_conn_is_alive(data, conn);
+ bool input_pending;
+
+ dead = !Curl_conn_is_alive(data, conn, &input_pending);
+ if(input_pending) {
+ /* For reuse, we want a "clean" connection state. The includes
+ * that we expect - in general - no waiting input data. Input
+ * waiting might be a TLS Notify Close, for example. We reject
+ * that.
+ * For protocols where data from other other end may arrive at
+ * any time (HTTP/2 PING for example), the protocol handler needs
+ * to install its own `connection_check` callback.
+ */
+ dead = TRUE;
+ }
}
if(dead) {
@@ -1170,14 +1156,14 @@ ConnectionExists(struct Curl_easy *data,
continue;
}
}
+ }
- if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
- foundPendingCandidate = TRUE;
- /* Don't pick a connection that hasn't connected yet */
- infof(data, "Connection #%ld isn't open enough, can't reuse",
- check->connection_id);
- continue;
- }
+ if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
+ foundPendingCandidate = TRUE;
+ /* Don't pick a connection that hasn't connected yet */
+ infof(data, "Connection #%ld isn't open enough, can't reuse",
+ check->connection_id);
+ continue;
}
#ifdef USE_UNIX_SOCKETS
@@ -1291,6 +1277,11 @@ ConnectionExists(struct Curl_easy *data,
}
}
+ /* GSS delegation differences do not actually affect every connection
+ and auth method, but this check takes precaution before efficiency */
+ if(needle->gssapi_delegation != check->gssapi_delegation)
+ continue;
+
/* If multiplexing isn't enabled on the h2 connection and h1 is
explicitly requested, handle it: */
if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
@@ -1299,11 +1290,24 @@ ConnectionExists(struct Curl_easy *data,
|| ((check->httpversion >= 30) &&
(data->state.httpwant < CURL_HTTP_VERSION_3))))
continue;
-
- if(get_protocol_family(needle->handler) == PROTO_FAMILY_SSH) {
+#ifdef USE_SSH
+ else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
if(!ssh_config_matches(needle, check))
continue;
}
+#endif
+#ifndef CURL_DISABLE_FTP
+ else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
+ /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
+ if(Curl_timestrcmp(needle->proto.ftpc.account,
+ check->proto.ftpc.account) ||
+ Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
+ check->proto.ftpc.alternative_to_user) ||
+ (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
+ (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
+ continue;
+ }
+#endif
if((needle->handler->flags&PROTOPT_SSL)
#ifndef CURL_DISABLE_PROXY
@@ -1494,10 +1498,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
if(!conn)
return NULL;
- conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined
- already from start to avoid NULL
- situations and checks */
-
/* and we setup a few fields in case we end up actually using this struct */
conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
@@ -1589,11 +1589,11 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->fclosesocket = data->set.fclosesocket;
conn->closesocket_client = data->set.closesocket_client;
conn->lastused = Curl_now(); /* used now */
+ conn->gssapi_delegation = data->set.gssapi_delegation;
return conn;
error:
- Curl_llist_destroy(&conn->easyq, NULL);
free(conn->localdev);
free(conn);
return NULL;
diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index 29927b3..62e3233 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/urlapi.c
@@ -57,6 +57,15 @@
/* scheme is not URL encoded, the longest libcurl supported ones are... */
#define MAX_SCHEME_LEN 40
+/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
/* Internal representation of CURLU. Point to URL-encoded strings. */
struct Curl_URL {
char *scheme;
@@ -599,7 +608,8 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
return CURLUE_BAD_IPV6;
/* hostname is fine */
}
-#ifdef ENABLE_IPV6
+
+ /* Check the IPv6 address. */
{
char dest[16]; /* fits a binary IPv6 address */
char norm[MAX_IPADR_LEN];
@@ -616,11 +626,10 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
}
hostname[hlen] = ']'; /* restore ending bracket */
}
-#endif
}
else {
/* letters from the second string are not ok */
- len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()");
+ len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()%");
if(hlen != len)
/* hostname with bad content */
return CURLUE_BAD_HOSTNAME;
@@ -1341,7 +1350,7 @@ void curl_url_cleanup(CURLU *u)
} \
} while(0)
-CURLU *curl_url_dup(CURLU *in)
+CURLU *curl_url_dup(const CURLU *in)
{
struct Curl_URL *u = calloc(sizeof(struct Curl_URL), 1);
if(u) {
@@ -1362,10 +1371,10 @@ CURLU *curl_url_dup(CURLU *in)
return NULL;
}
-CURLUcode curl_url_get(CURLU *u, CURLUPart what,
+CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
char **part, unsigned int flags)
{
- char *ptr;
+ const char *ptr;
CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
char portbuf[7];
bool urldecode = (flags & CURLU_URLDECODE)?1:0;
@@ -1432,11 +1441,8 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
break;
case CURLUPART_PATH:
ptr = u->path;
- if(!ptr) {
- ptr = u->path = strdup("/");
- if(!u->path)
- return CURLUE_OUT_OF_MEMORY;
- }
+ if(!ptr)
+ ptr = "/";
break;
case CURLUPART_QUERY:
ptr = u->query;
@@ -1546,8 +1552,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
return CURLUE_OUT_OF_MEMORY;
host++;
}
- free(u->host);
- u->host = Curl_dyn_ptr(&enc);
+ allochost = Curl_dyn_ptr(&enc);
}
}
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index 4cfffa7..8b54518 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -168,7 +168,7 @@ typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
#include "rtsp.h"
#include "smb.h"
#include "mqtt.h"
-#include "wildcard.h"
+#include "ftplistparser.h"
#include "multihandle.h"
#include "c-hyper.h"
#include "cf-socket.h"
@@ -687,6 +687,10 @@ struct SingleRequest {
#ifndef CURL_DISABLE_DOH
struct dohdata *doh; /* DoH specific data for this request */
#endif
+#if defined(WIN32) && defined(USE_WINSOCK)
+ struct curltime last_sndbuf_update; /* last time readwrite_upload called
+ win_update_buffer_size */
+#endif
unsigned char setcookies;
unsigned char writer_stack_depth; /* Unencoding stack depth. */
BIT(header); /* incoming data has HTTP header */
@@ -1057,6 +1061,7 @@ struct connectdata {
unsigned char ip_version; /* copied from the Curl_easy at creation time */
unsigned char httpversion; /* the HTTP version*10 reported by the server */
unsigned char connect_only;
+ unsigned char gssapi_delegation; /* inherited from set.gssapi_delegation */
};
/* The end of connectdata. */
@@ -1374,7 +1379,7 @@ struct UrlState {
struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
headers */
struct Curl_llist httphdrs; /* received headers */
- struct curl_header headerout; /* for external purposes */
+ struct curl_header headerout[2]; /* for external purposes */
struct Curl_header_store *prevhead; /* the latest added header */
trailers_state trailers_state; /* whether we are sending trailers
and what stage are we at */
@@ -1713,8 +1718,6 @@ struct UserDefined {
#ifndef CURL_DISABLE_NETRC
unsigned char use_netrc; /* enum CURL_NETRC_OPTION values */
#endif
- curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
- IMAP or POP3 or others! */
unsigned int new_file_perms; /* when creating remote files */
char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
struct curl_blob *blobs[BLOB_LAST];
@@ -1739,6 +1742,7 @@ struct UserDefined {
curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds
to pattern (e.g. if WILDCARDMATCH is on) */
void *fnmatch_data;
+ void *wildcardptr;
#endif
/* GSS-API credential delegation, see the documentation of
CURLOPT_GSSAPI_DELEGATION */
@@ -1773,6 +1777,8 @@ struct UserDefined {
BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
recipients */
#endif
+ unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
+ IMAP or POP3 or others! (type: curl_usessl)*/
unsigned char connect_only; /* make connection/request, then let
application use the socket */
BIT(is_fread_set); /* has read callback been set to non-NULL? */
@@ -1934,7 +1940,7 @@ struct Curl_easy {
struct UrlState state; /* struct for fields used for state info and
other dynamic purposes */
#ifndef CURL_DISABLE_FTP
- struct WildcardData wildcard; /* wildcard download state info */
+ struct WildcardData *wildcard; /* wildcard download state info */
#endif
struct PureInfo info; /* stats, reports and info data */
struct curl_tlssessioninfo tsi; /* Information about the TLS session, only
diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c
index 55b54a0..5800ad3 100644
--- a/Utilities/cmcurl/lib/version.c
+++ b/Utilities/cmcurl/lib/version.c
@@ -62,7 +62,15 @@
#endif
#ifdef HAVE_BROTLI
+#if defined(__GNUC__)
+/* Ignore -Wvla warnings in brotli headers */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wvla"
+#endif
#include <brotli/decode.h>
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
#endif
#ifdef HAVE_ZSTD
@@ -357,8 +365,7 @@ static const char * const protocols[] = {
#ifdef USE_SSH
"sftp",
#endif
-#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
- (SIZEOF_CURL_OFF_T > 4)
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
"smb",
# ifdef USE_SSL
"smbs",
diff --git a/Utilities/cmcurl/lib/vquic/curl_msh3.c b/Utilities/cmcurl/lib/vquic/curl_msh3.c
index 1930703..5308999 100644
--- a/Utilities/cmcurl/lib/vquic/curl_msh3.c
+++ b/Utilities/cmcurl/lib/vquic/curl_msh3.c
@@ -548,7 +548,6 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
struct HTTP *stream = data->req.p.http;
CURLcode result = CURLE_OK;
@@ -579,11 +578,6 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
DEBUGF(LOG_CF(data, cf, "req: update info"));
cf_msh3_active(cf, data);
break;
- case CF_CTRL_CONN_REPORT_STATS:
- if(cf->sockindex == FIRSTSOCKET)
- Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
- break;
-
default:
break;
}
@@ -753,6 +747,19 @@ static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
*pres1 = 100;
return CURLE_OK;
}
+ case CF_QUERY_TIMER_CONNECT: {
+ struct curltime *when = pres2;
+ /* we do not know when the first byte arrived */
+ if(cf->connected)
+ *when = ctx->handshake_at;
+ return CURLE_OK;
+ }
+ case CF_QUERY_TIMER_APPCONNECT: {
+ struct curltime *when = pres2;
+ if(cf->connected)
+ *when = ctx->handshake_at;
+ return CURLE_OK;
+ }
default:
break;
}
@@ -762,11 +769,13 @@ static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
}
static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+ struct Curl_easy *data,
+ bool *input_pending)
{
struct cf_msh3_ctx *ctx = cf->ctx;
(void)data;
+ *input_pending = FALSE;
return ctx && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD && ctx->qconn &&
ctx->connected;
}
diff --git a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
index ffdaead..d2d0a3a 100644
--- a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
+++ b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
@@ -64,6 +64,8 @@
#include "vtls/vtls.h"
#include "curl_ngtcp2.h"
+#include "warnless.h"
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -901,7 +903,7 @@ static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf,
rv |= GETSOCK_READSOCK(0);
/* we're still uploading or the HTTP/2 layer wants to send data */
- if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND &&
+ if((k->keepon & KEEP_SENDBITS) == KEEP_SEND &&
(!stream->h3out || stream->h3out->used < H3_SEND_SIZE) &&
ngtcp2_conn_get_cwnd_left(ctx->qconn) &&
ngtcp2_conn_get_max_data_left(ctx->qconn) &&
@@ -951,7 +953,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
}
/*
- * write_resp_raw() copies resonse data in raw format to the `data`'s
+ * write_resp_raw() copies response data in raw format to the `data`'s
* receive buffer. If not enough space is available, it appends to the
* `data`'s overflow buffer.
*/
@@ -1762,7 +1764,7 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
ssize_t recvd;
int rv;
uint8_t buf[65536];
- size_t bufsize = sizeof(buf);
+ int bufsize = (int)sizeof(buf);
size_t pktcount = 0, total_recvd = 0;
struct sockaddr_storage remote_addr;
socklen_t remote_addrlen;
@@ -2107,13 +2109,6 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
}
}
break;
- case CF_CTRL_CONN_REPORT_STATS:
- if(cf->sockindex == FIRSTSOCKET) {
- if(ctx->got_first_byte)
- Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at);
- Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
- }
- break;
default:
break;
}
@@ -2127,7 +2122,6 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
if(ctx->qlogfd != -1) {
close(ctx->qlogfd);
- ctx->qlogfd = -1;
}
#ifdef USE_OPENSSL
if(ctx->ssl)
@@ -2155,6 +2149,7 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
ngtcp2_conn_del(ctx->qconn);
memset(ctx, 0, sizeof(*ctx));
+ ctx->qlogfd = -1;
ctx->call_data = save;
}
@@ -2176,7 +2171,7 @@ static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
(uint8_t *)buffer, sizeof(buffer),
&ctx->last_error, ts);
if(rc > 0) {
- while((send(ctx->q.sockfd, buffer, rc, 0) == -1) &&
+ while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) &&
SOCKERRNO == EINTR);
}
@@ -2200,6 +2195,7 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
}
cf->ctx = NULL;
/* No CF_DATA_RESTORE(cf, save) possible */
+ (void)save;
}
/*
@@ -2428,6 +2424,18 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
else
*pres1 = -1;
return CURLE_OK;
+ case CF_QUERY_TIMER_CONNECT: {
+ struct curltime *when = pres2;
+ if(ctx->got_first_byte)
+ *when = ctx->first_byte_at;
+ return CURLE_OK;
+ }
+ case CF_QUERY_TIMER_APPCONNECT: {
+ struct curltime *when = pres2;
+ if(cf->connected)
+ *when = ctx->handshake_at;
+ return CURLE_OK;
+ }
default:
break;
}
@@ -2436,6 +2444,32 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
CURLE_UNKNOWN_OPTION;
}
+static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *input_pending)
+{
+ bool alive = TRUE;
+
+ *input_pending = FALSE;
+ if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+ return FALSE;
+
+ if(*input_pending) {
+ /* This happens before we've sent off a request and the connection is
+ not in use by any other transfer, there shouldn't be any data here,
+ only "protocol frames" */
+ *input_pending = FALSE;
+ Curl_attach_connection(data, cf->conn);
+ if(cf_process_ingress(cf, data))
+ alive = FALSE;
+ else {
+ alive = TRUE;
+ }
+ Curl_detach_connection(data);
+ }
+
+ return alive;
+}
struct Curl_cftype Curl_cft_http3 = {
"HTTP/3",
@@ -2450,7 +2484,7 @@ struct Curl_cftype Curl_cft_http3 = {
cf_ngtcp2_send,
cf_ngtcp2_recv,
cf_ngtcp2_data_event,
- Curl_cf_def_conn_is_alive,
+ cf_ngtcp2_conn_is_alive,
Curl_cf_def_conn_keep_alive,
cf_ngtcp2_query,
};
@@ -2470,6 +2504,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+ ctx->qlogfd = -1;
cf_ngtcp2_ctx_clear(ctx);
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
diff --git a/Utilities/cmcurl/lib/vquic/curl_quiche.c b/Utilities/cmcurl/lib/vquic/curl_quiche.c
index 54408d7..87a221c 100644
--- a/Utilities/cmcurl/lib/vquic/curl_quiche.c
+++ b/Utilities/cmcurl/lib/vquic/curl_quiche.c
@@ -444,7 +444,7 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
struct cf_quiche_ctx *ctx = cf->ctx;
int64_t stream3_id = data->req.p.http? data->req.p.http->stream3_id : -1;
uint8_t buf[65536];
- size_t bufsize = sizeof(buf);
+ int bufsize = (int)sizeof(buf);
struct sockaddr_storage remote_addr;
socklen_t remote_addrlen;
quiche_recv_info recv_info;
@@ -950,7 +950,7 @@ static int cf_quiche_get_select_socks(struct Curl_cfilter *cf,
rv |= GETSOCK_READSOCK(0);
/* we're still uploading or the HTTP/3 layer wants to send data */
- if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND)
+ if(((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
&& stream_is_writeable(cf, data))
rv |= GETSOCK_WRITESOCK(0);
@@ -1016,13 +1016,6 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
case CF_CTRL_DATA_IDLE:
/* anything to do? */
break;
- case CF_CTRL_CONN_REPORT_STATS:
- if(cf->sockindex == FIRSTSOCKET) {
- if(ctx->got_first_byte)
- Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at);
- Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
- }
- break;
default:
break;
}
@@ -1346,6 +1339,18 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
else
*pres1 = -1;
return CURLE_OK;
+ case CF_QUERY_TIMER_CONNECT: {
+ struct curltime *when = pres2;
+ if(ctx->got_first_byte)
+ *when = ctx->first_byte_at;
+ return CURLE_OK;
+ }
+ case CF_QUERY_TIMER_APPCONNECT: {
+ struct curltime *when = pres2;
+ if(cf->connected)
+ *when = ctx->handshake_at;
+ return CURLE_OK;
+ }
default:
break;
}
@@ -1354,6 +1359,32 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
CURLE_UNKNOWN_OPTION;
}
+static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *input_pending)
+{
+ bool alive = TRUE;
+
+ *input_pending = FALSE;
+ if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+ return FALSE;
+
+ if(*input_pending) {
+ /* This happens before we've sent off a request and the connection is
+ not in use by any other transfer, there shouldn't be any data here,
+ only "protocol frames" */
+ *input_pending = FALSE;
+ Curl_attach_connection(data, cf->conn);
+ if(cf_process_ingress(cf, data))
+ alive = FALSE;
+ else {
+ alive = TRUE;
+ }
+ Curl_detach_connection(data);
+ }
+
+ return alive;
+}
struct Curl_cftype Curl_cft_http3 = {
"HTTP/3",
@@ -1368,7 +1399,7 @@ struct Curl_cftype Curl_cft_http3 = {
cf_quiche_send,
cf_quiche_recv,
cf_quiche_data_event,
- Curl_cf_def_conn_is_alive,
+ cf_quiche_conn_is_alive,
Curl_cf_def_conn_keep_alive,
cf_quiche_query,
};
diff --git a/Utilities/cmcurl/lib/vquic/vquic.c b/Utilities/cmcurl/lib/vquic/vquic.c
index 5f4f30d..bbdeabd 100644
--- a/Utilities/cmcurl/lib/vquic/vquic.c
+++ b/Utilities/cmcurl/lib/vquic/vquic.c
@@ -167,7 +167,8 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
*psent = 0;
- while((sent = send(qctx->sockfd, (const char *)pkt, pktlen, 0)) == -1 &&
+ while((sent = send(qctx->sockfd,
+ (const char *)pkt, (SEND_TYPE_ARG3)pktlen, 0)) == -1 &&
SOCKERRNO == EINTR)
;
@@ -363,6 +364,10 @@ bool Curl_conn_is_http3(const struct Curl_easy *data,
CURLcode Curl_conn_may_http3(struct Curl_easy *data,
const struct connectdata *conn)
{
+ if(conn->transport == TRNSPRT_UNIX) {
+ /* cannot do QUIC over a unix domain socket */
+ return CURLE_QUIC_CONNECT_ERROR;
+ }
if(!(conn->handler->flags & PROTOPT_SSL)) {
failf(data, "HTTP/3 requested for non-HTTPS URL");
return CURLE_URL_MALFORMAT;
diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c
index 1115318..b31f741 100644
--- a/Utilities/cmcurl/lib/vssh/libssh.c
+++ b/Utilities/cmcurl/lib/vssh/libssh.c
@@ -685,7 +685,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
struct ssh_conn *sshc = &conn->proto.sshc;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc = SSH_NO_ERROR, err;
- char *new_readdir_line;
int seekerr = CURL_SEEKFUNC_OK;
const char *err_msg;
*block = 0; /* we're not blocking by default */
@@ -1432,7 +1431,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
case SSH_SFTP_READDIR:
-
+ Curl_dyn_reset(&sshc->readdir_buf);
if(sshc->readdir_attrs)
sftp_attributes_free(sshc->readdir_attrs);
@@ -1468,17 +1467,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->readdir_len);
}
else {
- sshc->readdir_currLen = strlen(sshc->readdir_longentry);
- sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
- sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
- if(!sshc->readdir_line) {
- state(data, SSH_SFTP_CLOSE);
+ if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ state(data, SSH_STOP);
break;
}
- memcpy(sshc->readdir_line, sshc->readdir_longentry,
- sshc->readdir_currLen);
if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
SSH_S_IFLNK)) {
@@ -1541,24 +1535,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->readdir_linkPath);
- /* get room for the filename and extra output */
- sshc->readdir_totalLen += 4 + sshc->readdir_len;
- new_readdir_line = Curl_saferealloc(sshc->readdir_line,
- sshc->readdir_totalLen);
- if(!new_readdir_line) {
- sshc->readdir_line = NULL;
- state(data, SSH_SFTP_CLOSE);
+ if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
+ sshc->readdir_filename)) {
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
- sshc->readdir_line = new_readdir_line;
-
- sshc->readdir_currLen += msnprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen,
- " -> %s",
- sshc->readdir_filename);
sftp_attributes_free(sshc->readdir_link_attrs);
sshc->readdir_link_attrs = NULL;
@@ -1568,21 +1549,19 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_SFTP_READDIR_BOTTOM);
/* FALLTHROUGH */
case SSH_SFTP_READDIR_BOTTOM:
- sshc->readdir_currLen += msnprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen, "\n");
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- sshc->readdir_line,
- sshc->readdir_currLen);
+ if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
+ result = CURLE_OUT_OF_MEMORY;
+ else
+ result = Curl_client_write(data, CLIENTWRITE_BODY,
+ Curl_dyn_ptr(&sshc->readdir_buf),
+ Curl_dyn_len(&sshc->readdir_buf));
if(!result) {
/* output debug output if that is requested */
- Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
- sshc->readdir_currLen);
- data->req.bytecount += sshc->readdir_currLen;
+ Curl_debug(data, CURLINFO_DATA_OUT, Curl_dyn_ptr(&sshc->readdir_buf),
+ Curl_dyn_len(&sshc->readdir_buf));
+ data->req.bytecount += Curl_dyn_len(&sshc->readdir_buf);
}
- Curl_safefree(sshc->readdir_line);
ssh_string_free_char(sshc->readdir_tmp);
sshc->readdir_tmp = NULL;
@@ -2021,7 +2000,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->rsa);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
- Curl_safefree(sshc->readdir_line);
+ Curl_dyn_free(&sshc->readdir_buf);
Curl_safefree(sshc->readdir_linkPath);
SSH_STRING_FREE_CHAR(sshc->homedir);
@@ -2166,11 +2145,12 @@ static CURLcode myssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
struct SSHPROTO *ssh;
- (void)conn;
+ struct ssh_conn *sshc = &conn->proto.sshc;
data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
if(!ssh)
return CURLE_OUT_OF_MEMORY;
+ Curl_dyn_init(&sshc->readdir_buf, PATH_MAX * 2);
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index 4703eb5..f1154dc 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/vssh/libssh2.c
@@ -100,10 +100,11 @@
/* Local functions: */
static const char *sftp_libssh2_strerror(unsigned long err);
+#ifdef CURL_LIBSSH2_DEBUG
static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
static LIBSSH2_FREE_FUNC(my_libssh2_free);
-
+#endif
static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data);
static CURLcode ssh_connect(struct Curl_easy *data, bool *done);
static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done);
@@ -283,6 +284,8 @@ static CURLcode libssh2_session_error_to_CURLE(int err)
return CURLE_SSH;
}
+#ifdef CURL_LIBSSH2_DEBUG
+
static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
{
(void)abstract; /* arg not used */
@@ -302,6 +305,8 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free)
free(ptr);
}
+#endif
+
/*
* SSH State machine related code
*/
@@ -2400,7 +2405,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename);
if(result) {
- sshc->readdir_line = NULL;
Curl_safefree(sshp->readdir_filename);
Curl_safefree(sshp->readdir_longentry);
state(data, SSH_SFTP_CLOSE);
@@ -3004,12 +3008,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->rsa_pub);
Curl_safefree(sshc->rsa);
-
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
-
Curl_safefree(sshc->homedir);
- Curl_safefree(sshc->readdir_line);
/* the code we are about to return */
result = sshc->actualcode;
@@ -3268,9 +3269,13 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
sock = conn->sock[FIRSTSOCKET];
#endif /* CURL_LIBSSH2_DEBUG */
+#ifdef CURL_LIBSSH2_DEBUG
sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
my_libssh2_free,
my_libssh2_realloc, data);
+#else
+ sshc->ssh_session = libssh2_session_init();
+#endif
if(!sshc->ssh_session) {
failf(data, "Failure initialising ssh session");
return CURLE_FAILED_INIT;
diff --git a/Utilities/cmcurl/lib/vssh/ssh.h b/Utilities/cmcurl/lib/vssh/ssh.h
index 7c25555..1e1b137 100644
--- a/Utilities/cmcurl/lib/vssh/ssh.h
+++ b/Utilities/cmcurl/lib/vssh/ssh.h
@@ -147,7 +147,6 @@ struct ssh_conn {
char *homedir; /* when doing SFTP we figure out home dir in the
connect phase */
- char *readdir_line;
/* end of READDIR stuff */
int secondCreateDirs; /* counter use by the code to see if the
@@ -158,7 +157,8 @@ struct ssh_conn {
#if defined(USE_LIBSSH)
char *readdir_linkPath;
- size_t readdir_len, readdir_totalLen, readdir_currLen;
+ size_t readdir_len;
+ struct dynbuf readdir_buf;
/* our variables */
unsigned kbd_state; /* 0 or 1 */
ssh_key privkey;
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index 774cbdd..12c0390 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -1536,36 +1536,6 @@ static void nss_cleanup(void)
initialized = 0;
}
-/*
- * This function uses SSL_peek to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-static int nss_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_backend_data *backend = connssl->backend;
- int rc;
- char buf;
-
- (void)data;
- DEBUGASSERT(backend);
-
- rc =
- PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK,
- PR_SecondsToInterval(1));
- if(rc > 0)
- return 1; /* connection still in place */
-
- if(rc == 0)
- return 0; /* connection has been closed */
-
- return -1; /* connection status unknown */
-}
-
static void close_one(struct ssl_connect_data *connssl)
{
/* before the cleanup, check whether we are using a client certificate */
@@ -2524,7 +2494,7 @@ const struct Curl_ssl Curl_ssl_nss = {
nss_init, /* init */
nss_cleanup, /* cleanup */
nss_version, /* version */
- nss_check_cxn, /* check_cxn */
+ Curl_none_check_cxn, /* check_cxn */
/* NSS has no shutdown function provided and thus always fail */
Curl_none_shutdown, /* shutdown */
nss_data_pending, /* data_pending */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index e3a50bd..2ba53d9 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -1788,63 +1788,6 @@ static void ossl_cleanup(void)
Curl_tls_keylog_close();
}
-/*
- * This function is used to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-static int ossl_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- /* SSL_peek takes data out of the raw recv buffer without peeking so we use
- recv MSG_PEEK instead. Bug #795 */
-#ifdef MSG_PEEK
- char buf;
- ssize_t nread;
- curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
- if(sock == CURL_SOCKET_BAD)
- return 0; /* no socket, consider closed */
- nread = recv((RECV_TYPE_ARG1)sock,
- (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1,
- (RECV_TYPE_ARG4)MSG_PEEK);
- if(nread == 0)
- return 0; /* connection has been closed */
- if(nread == 1)
- return 1; /* connection still in place */
- else if(nread == -1) {
- int err = SOCKERRNO;
- if(err == EINPROGRESS ||
-#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK)
- err == EAGAIN ||
-#endif
- err == EWOULDBLOCK)
- return 1; /* connection still in place */
- if(err == ECONNRESET ||
-#ifdef ECONNABORTED
- err == ECONNABORTED ||
-#endif
-#ifdef ENETDOWN
- err == ENETDOWN ||
-#endif
-#ifdef ENETRESET
- err == ENETRESET ||
-#endif
-#ifdef ESHUTDOWN
- err == ESHUTDOWN ||
-#endif
-#ifdef ETIMEDOUT
- err == ETIMEDOUT ||
-#endif
- err == ENOTCONN)
- return 0; /* connection has been closed */
- }
-#endif
- (void)data;
- return -1; /* connection status unknown */
-}
-
/* Selects an OpenSSL crypto engine
*/
static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine)
@@ -4836,7 +4779,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_init, /* init */
ossl_cleanup, /* cleanup */
ossl_version, /* version */
- ossl_check_cxn, /* check_cxn */
+ Curl_none_check_cxn, /* check_cxn */
ossl_shutdown, /* shutdown */
ossl_data_pending, /* data_pending */
ossl_random, /* random */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index 452fa40..6f94c7e 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -264,128 +264,133 @@ set_ssl_version_min_max(DWORD *enabled_protocols,
/* longest is 26, buffer is slightly bigger */
#define LONGEST_ALG_ID 32
-#define CIPHEROPTION(X) \
- if(strcmp(#X, tmp) == 0) \
- return X
+#define CIPHEROPTION(x) {#x, x}
-static int
-get_alg_id_by_name(char *name)
-{
- char tmp[LONGEST_ALG_ID] = { 0 };
- char *nameEnd = strchr(name, ':');
- size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
+struct algo {
+ const char *name;
+ int id;
+};
- /* reject too-long alg names */
- if(n > (LONGEST_ALG_ID - 1))
- return 0;
-
- strncpy(tmp, name, n);
- tmp[n] = 0;
- CIPHEROPTION(CALG_MD2);
- CIPHEROPTION(CALG_MD4);
- CIPHEROPTION(CALG_MD5);
- CIPHEROPTION(CALG_SHA);
- CIPHEROPTION(CALG_SHA1);
- CIPHEROPTION(CALG_MAC);
- CIPHEROPTION(CALG_RSA_SIGN);
- CIPHEROPTION(CALG_DSS_SIGN);
+static const struct algo algs[]= {
+ CIPHEROPTION(CALG_MD2),
+ CIPHEROPTION(CALG_MD4),
+ CIPHEROPTION(CALG_MD5),
+ CIPHEROPTION(CALG_SHA),
+ CIPHEROPTION(CALG_SHA1),
+ CIPHEROPTION(CALG_MAC),
+ CIPHEROPTION(CALG_RSA_SIGN),
+ CIPHEROPTION(CALG_DSS_SIGN),
/* ifdefs for the options that are defined conditionally in wincrypt.h */
#ifdef CALG_NO_SIGN
- CIPHEROPTION(CALG_NO_SIGN);
+ CIPHEROPTION(CALG_NO_SIGN),
#endif
- CIPHEROPTION(CALG_RSA_KEYX);
- CIPHEROPTION(CALG_DES);
+ CIPHEROPTION(CALG_RSA_KEYX),
+ CIPHEROPTION(CALG_DES),
#ifdef CALG_3DES_112
- CIPHEROPTION(CALG_3DES_112);
+ CIPHEROPTION(CALG_3DES_112),
#endif
- CIPHEROPTION(CALG_3DES);
- CIPHEROPTION(CALG_DESX);
- CIPHEROPTION(CALG_RC2);
- CIPHEROPTION(CALG_RC4);
- CIPHEROPTION(CALG_SEAL);
+ CIPHEROPTION(CALG_3DES),
+ CIPHEROPTION(CALG_DESX),
+ CIPHEROPTION(CALG_RC2),
+ CIPHEROPTION(CALG_RC4),
+ CIPHEROPTION(CALG_SEAL),
#ifdef CALG_DH_SF
- CIPHEROPTION(CALG_DH_SF);
+ CIPHEROPTION(CALG_DH_SF),
#endif
- CIPHEROPTION(CALG_DH_EPHEM);
+ CIPHEROPTION(CALG_DH_EPHEM),
#ifdef CALG_AGREEDKEY_ANY
- CIPHEROPTION(CALG_AGREEDKEY_ANY);
+ CIPHEROPTION(CALG_AGREEDKEY_ANY),
#endif
#ifdef CALG_HUGHES_MD5
- CIPHEROPTION(CALG_HUGHES_MD5);
+ CIPHEROPTION(CALG_HUGHES_MD5),
#endif
- CIPHEROPTION(CALG_SKIPJACK);
+ CIPHEROPTION(CALG_SKIPJACK),
#ifdef CALG_TEK
- CIPHEROPTION(CALG_TEK);
+ CIPHEROPTION(CALG_TEK),
#endif
- CIPHEROPTION(CALG_CYLINK_MEK);
- CIPHEROPTION(CALG_SSL3_SHAMD5);
+ CIPHEROPTION(CALG_CYLINK_MEK),
+ CIPHEROPTION(CALG_SSL3_SHAMD5),
#ifdef CALG_SSL3_MASTER
- CIPHEROPTION(CALG_SSL3_MASTER);
+ CIPHEROPTION(CALG_SSL3_MASTER),
#endif
#ifdef CALG_SCHANNEL_MASTER_HASH
- CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
+ CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH),
#endif
#ifdef CALG_SCHANNEL_MAC_KEY
- CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
+ CIPHEROPTION(CALG_SCHANNEL_MAC_KEY),
#endif
#ifdef CALG_SCHANNEL_ENC_KEY
- CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
+ CIPHEROPTION(CALG_SCHANNEL_ENC_KEY),
#endif
#ifdef CALG_PCT1_MASTER
- CIPHEROPTION(CALG_PCT1_MASTER);
+ CIPHEROPTION(CALG_PCT1_MASTER),
#endif
#ifdef CALG_SSL2_MASTER
- CIPHEROPTION(CALG_SSL2_MASTER);
+ CIPHEROPTION(CALG_SSL2_MASTER),
#endif
#ifdef CALG_TLS1_MASTER
- CIPHEROPTION(CALG_TLS1_MASTER);
+ CIPHEROPTION(CALG_TLS1_MASTER),
#endif
#ifdef CALG_RC5
- CIPHEROPTION(CALG_RC5);
+ CIPHEROPTION(CALG_RC5),
#endif
#ifdef CALG_HMAC
- CIPHEROPTION(CALG_HMAC);
+ CIPHEROPTION(CALG_HMAC),
#endif
#ifdef CALG_TLS1PRF
- CIPHEROPTION(CALG_TLS1PRF);
+ CIPHEROPTION(CALG_TLS1PRF),
#endif
#ifdef CALG_HASH_REPLACE_OWF
- CIPHEROPTION(CALG_HASH_REPLACE_OWF);
+ CIPHEROPTION(CALG_HASH_REPLACE_OWF),
#endif
#ifdef CALG_AES_128
- CIPHEROPTION(CALG_AES_128);
+ CIPHEROPTION(CALG_AES_128),
#endif
#ifdef CALG_AES_192
- CIPHEROPTION(CALG_AES_192);
+ CIPHEROPTION(CALG_AES_192),
#endif
#ifdef CALG_AES_256
- CIPHEROPTION(CALG_AES_256);
+ CIPHEROPTION(CALG_AES_256),
#endif
#ifdef CALG_AES
- CIPHEROPTION(CALG_AES);
+ CIPHEROPTION(CALG_AES),
#endif
#ifdef CALG_SHA_256
- CIPHEROPTION(CALG_SHA_256);
+ CIPHEROPTION(CALG_SHA_256),
#endif
#ifdef CALG_SHA_384
- CIPHEROPTION(CALG_SHA_384);
+ CIPHEROPTION(CALG_SHA_384),
#endif
#ifdef CALG_SHA_512
- CIPHEROPTION(CALG_SHA_512);
+ CIPHEROPTION(CALG_SHA_512),
#endif
#ifdef CALG_ECDH
- CIPHEROPTION(CALG_ECDH);
+ CIPHEROPTION(CALG_ECDH),
#endif
#ifdef CALG_ECMQV
- CIPHEROPTION(CALG_ECMQV);
+ CIPHEROPTION(CALG_ECMQV),
#endif
#ifdef CALG_ECDSA
- CIPHEROPTION(CALG_ECDSA);
+ CIPHEROPTION(CALG_ECDSA),
#endif
#ifdef CALG_ECDH_EPHEM
- CIPHEROPTION(CALG_ECDH_EPHEM);
+ CIPHEROPTION(CALG_ECDH_EPHEM),
#endif
- return 0;
+ {NULL, 0},
+};
+
+static int
+get_alg_id_by_name(char *name)
+{
+ char *nameEnd = strchr(name, ':');
+ size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
+ int i;
+
+ for(i = 0; algs[i].name; i++) {
+ if((n == strlen(algs[i].name) && !strncmp(algs[i].name, name, n)))
+ return algs[i].id;
+ }
+ return 0; /* not found */
}
#define NUM_CIPHERS 47 /* There are 47 options listed above */
@@ -1201,18 +1206,18 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* The first four bytes will be an unsigned int indicating number
of bytes of data in the rest of the buffer. */
extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
- cur += sizeof(unsigned int);
+ cur += (int)sizeof(unsigned int);
/* The next four bytes are an indicator that this buffer will contain
ALPN data, as opposed to NPN, for example. */
*(unsigned int *)(void *)&alpn_buffer[cur] =
SecApplicationProtocolNegotiationExt_ALPN;
- cur += sizeof(unsigned int);
+ cur += (int)sizeof(unsigned int);
/* The next two bytes will be an unsigned short indicating the number
of bytes used to list the preferred protocols. */
list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
- cur += sizeof(unsigned short);
+ cur += (int)sizeof(unsigned short);
list_start_index = cur;
@@ -1225,7 +1230,9 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
cur += proto.len;
*list_len = curlx_uitous(cur - list_start_index);
- *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
+ *extension_len = *list_len +
+ (unsigned short)sizeof(unsigned int) +
+ (unsigned short)sizeof(unsigned short);
InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index 2e98169..7f55fb5 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ b/Utilities/cmcurl/lib/vtls/sectransp.c
@@ -2150,50 +2150,39 @@ static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
return sep_end - in;
}
+#define MAX_CERTS_SIZE (50*1024*1024) /* arbitrary - to catch mistakes */
+
static int read_cert(const char *file, unsigned char **out, size_t *outlen)
{
int fd;
- ssize_t n, len = 0, cap = 512;
- unsigned char buf[512], *data;
+ ssize_t n;
+ unsigned char buf[512];
+ struct dynbuf certs;
+
+ Curl_dyn_init(&certs, MAX_CERTS_SIZE);
fd = open(file, 0);
if(fd < 0)
return -1;
- data = malloc(cap);
- if(!data) {
- close(fd);
- return -1;
- }
-
for(;;) {
n = read(fd, buf, sizeof(buf));
+ if(!n)
+ break;
if(n < 0) {
close(fd);
- free(data);
+ Curl_dyn_free(&certs);
return -1;
}
- else if(n == 0) {
+ if(Curl_dyn_addn(&certs, buf, n)) {
close(fd);
- break;
- }
-
- if(len + n >= cap) {
- cap *= 2;
- data = Curl_saferealloc(data, cap);
- if(!data) {
- close(fd);
- return -1;
- }
+ return -1;
}
-
- memcpy(data + len, buf, n);
- len += n;
}
- data[len] = '\0';
+ close(fd);
- *out = data;
- *outlen = len;
+ *out = Curl_dyn_uptr(&certs);
+ *outlen = Curl_dyn_len(&certs);
return 0;
}
@@ -2202,16 +2191,18 @@ static int append_cert_to_array(struct Curl_easy *data,
const unsigned char *buf, size_t buflen,
CFMutableArrayRef array)
{
- CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
char *certp;
CURLcode result;
+ SecCertificateRef cacert;
+ CFDataRef certdata;
+
+ certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
if(!certdata) {
failf(data, "SSL: failed to allocate array for CA certificate");
return CURLE_OUT_OF_MEMORY;
}
- SecCertificateRef cacert =
- SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
+ cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
CFRelease(certdata);
if(!cacert) {
failf(data, "SSL: failed to create SecCertificate from CA certificate");
@@ -2425,11 +2416,15 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
do {
SecTrustRef trust;
- OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
+ OSStatus ret;
+ SecKeyRef keyRef;
+ OSStatus success;
+
+ ret = SSLCopyPeerTrust(ctx, &trust);
if(ret != noErr || !trust)
break;
- SecKeyRef keyRef = SecTrustCopyPublicKey(trust);
+ keyRef = SecTrustCopyPublicKey(trust);
CFRelease(trust);
if(!keyRef)
break;
@@ -2443,8 +2438,8 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
#elif SECTRANSP_PINNEDPUBKEY_V2
- OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
- &publicKeyBits);
+ success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
+ &publicKeyBits);
CFRelease(keyRef);
if(success != errSecSuccess || !publicKeyBits)
break;
@@ -2987,12 +2982,13 @@ static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
+ CURLcode result;
DEBUGF(LOG_CF(data, cf, "connect_step3"));
/* There is no step 3!
* Well, okay, let's collect server certificates, and if verbose mode is on,
* let's print the details of the server certificates. */
- const CURLcode result = collect_server_cert(cf, data);
+ result = collect_server_cert(cf, data);
if(result)
return result;
@@ -3237,35 +3233,6 @@ static size_t sectransp_version(char *buffer, size_t size)
return msnprintf(buffer, size, "SecureTransport");
}
-/*
- * This function uses SSLGetSessionState to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-static int sectransp_check_cxn(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct ssl_backend_data *backend = connssl->backend;
- OSStatus err;
- SSLSessionState state;
-
- (void)data;
- DEBUGASSERT(backend);
-
- if(backend->ssl_ctx) {
- DEBUGF(LOG_CF(data, cf, "check connection"));
- err = SSLGetSessionState(backend->ssl_ctx, &state);
- if(err == noErr)
- return state == kSSLConnected || state == kSSLHandshake;
- return -1;
- }
- return 0;
-}
-
static bool sectransp_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
@@ -3410,13 +3377,15 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
again:
+ *curlcode = CURLE_OK;
err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed);
if(err != noErr) {
switch(err) {
case errSSLWouldBlock: /* return how much we read (if anything) */
- if(processed)
+ if(processed) {
return (ssize_t)processed;
+ }
*curlcode = CURLE_AGAIN;
return -1L;
break;
@@ -3428,7 +3397,7 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf,
case errSSLClosedGraceful:
case errSSLClosedNoNotify:
*curlcode = CURLE_OK;
- return -1L;
+ return 0;
break;
/* The below is errSSLPeerAuthCompleted; it's not defined in
@@ -3439,8 +3408,10 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf,
CURLcode result = verify_cert(cf, data, conn_config->CAfile,
conn_config->ca_info_blob,
backend->ssl_ctx);
- if(result)
- return result;
+ if(result) {
+ *curlcode = result;
+ return -1;
+ }
}
goto again;
default:
@@ -3477,7 +3448,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
Curl_none_init, /* init */
Curl_none_cleanup, /* cleanup */
sectransp_version, /* version */
- sectransp_check_cxn, /* check_cxn */
+ Curl_none_check_cxn, /* check_cxn */
sectransp_shutdown, /* shutdown */
sectransp_data_pending, /* data_pending */
sectransp_random, /* random */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index 15f6844..144e6ee 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -1604,16 +1604,11 @@ static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2)
{
- struct ssl_connect_data *connssl = cf->ctx;
struct cf_call_data save;
(void)arg1;
(void)arg2;
switch(event) {
- case CF_CTRL_CONN_REPORT_STATS:
- if(cf->sockindex == FIRSTSOCKET && !Curl_ssl_cf_is_proxy(cf))
- Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done);
- break;
case CF_CTRL_DATA_ATTACH:
if(Curl_ssl->attach_data) {
CF_DATA_SAVE(save, cf, data);
@@ -1634,10 +1629,32 @@ static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
return CURLE_OK;
}
-static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data)
+static CURLcode ssl_cf_query(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ int query, int *pres1, void *pres2)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+
+ switch(query) {
+ case CF_QUERY_TIMER_APPCONNECT: {
+ struct curltime *when = pres2;
+ if(cf->connected && !Curl_ssl_cf_is_proxy(cf))
+ *when = connssl->handshake_done;
+ return CURLE_OK;
+ }
+ default:
+ break;
+ }
+ return cf->next?
+ cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+ CURLE_UNKNOWN_OPTION;
+}
+
+static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data,
+ bool *input_pending)
{
struct cf_call_data save;
- bool result;
+ int result;
/*
* This function tries to determine connection status.
*
@@ -1647,9 +1664,20 @@ static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data)
* -1 means the connection status is unknown
*/
CF_DATA_SAVE(save, cf, data);
- result = Curl_ssl->check_cxn(cf, data) != 0;
+ result = Curl_ssl->check_cxn(cf, data);
CF_DATA_RESTORE(cf, save);
- return result;
+ if(result > 0) {
+ *input_pending = TRUE;
+ return TRUE;
+ }
+ if(result == 0) {
+ *input_pending = FALSE;
+ return FALSE;
+ }
+ /* ssl backend does not know */
+ return cf->next?
+ cf->next->cft->is_alive(cf->next, data, input_pending) :
+ FALSE; /* pessimistic in absence of data */
}
struct Curl_cftype Curl_cft_ssl = {
@@ -1667,7 +1695,7 @@ struct Curl_cftype Curl_cft_ssl = {
ssl_cf_cntrl,
cf_ssl_is_alive,
Curl_cf_def_conn_keep_alive,
- Curl_cf_def_query,
+ ssl_cf_query,
};
struct Curl_cftype Curl_cft_ssl_proxy = {
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index 2e57899..ac68eab 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -94,6 +94,7 @@
struct ssl_backend_data {
SSL_CTX* ctx;
SSL* handle;
+ CURLcode io_result; /* result of last BIO cfilter operation */
};
#ifdef OPENSSL_EXTRA
@@ -279,12 +280,16 @@ static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
static int 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 Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ connssl->backend->io_result = result;
+ DEBUGF(LOG_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
+ blen, nwritten, result));
wolfSSL_BIO_clear_retry_flags(bio);
if(nwritten < 0 && CURLE_AGAIN == result)
BIO_set_retry_read(bio);
@@ -294,6 +299,7 @@ static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
static int 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 Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result = CURLE_OK;
@@ -304,6 +310,9 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
return 0;
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ connssl->backend->io_result = result;
+ DEBUGF(LOG_CF(data, cf, "bio_read(len=%d) -> %zd, %d",
+ blen, nread, result));
wolfSSL_BIO_clear_retry_flags(bio);
if(nread < 0 && CURLE_AGAIN == result)
BIO_set_retry_read(bio);
@@ -789,6 +798,9 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
#endif
+ else if(backend->io_result == CURLE_AGAIN) {
+ return CURLE_OK;
+ }
else {
failf(data, "SSL_connect failed with error %d: %s", detail,
ERR_error_string(detail, error_buffer));
@@ -948,7 +960,6 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
ERR_clear_error();
rc = SSL_write(backend->handle, mem, memlen);
-
if(rc <= 0) {
int err = SSL_get_error(backend->handle, rc);
@@ -956,9 +967,17 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
/* there's data pending, re-invoke SSL_write() */
+ DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len));
*curlcode = CURLE_AGAIN;
return -1;
default:
+ if(backend->io_result == CURLE_AGAIN) {
+ DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len));
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ }
+ DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d",
+ len, rc, err));
failf(data, "SSL write: %s, errno %d",
ERR_error_string(err, error_buffer),
SOCKERRNO);
@@ -966,6 +985,7 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
return -1;
}
}
+ DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc));
return rc;
}
@@ -995,19 +1015,19 @@ static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
struct Curl_easy *data,
- char *buf,
- size_t buffersize,
+ char *buf, size_t blen,
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_backend_data *backend = connssl->backend;
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
- int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+ int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
int nread;
DEBUGASSERT(backend);
ERR_clear_error();
+ *curlcode = CURLE_OK;
nread = SSL_read(backend->handle, buf, buffsize);
@@ -1016,22 +1036,31 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
switch(err) {
case SSL_ERROR_ZERO_RETURN: /* no more data */
- break;
+ DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen));
+ *curlcode = CURLE_OK;
+ return 0;
case SSL_ERROR_NONE:
/* FALLTHROUGH */
case SSL_ERROR_WANT_READ:
/* FALLTHROUGH */
case SSL_ERROR_WANT_WRITE:
/* there's data pending, re-invoke SSL_read() */
+ DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen));
*curlcode = CURLE_AGAIN;
return -1;
default:
+ if(backend->io_result == CURLE_AGAIN) {
+ DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen));
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ }
failf(data, "SSL read: %s, errno %d",
ERR_error_string(err, error_buffer), SOCKERRNO);
*curlcode = CURLE_RECV_ERROR;
return -1;
}
}
+ DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread));
return nread;
}
diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c
index 39e4fb3..c298200 100644
--- a/Utilities/cmcurl/lib/vtls/x509asn1.c
+++ b/Utilities/cmcurl/lib/vtls/x509asn1.c
@@ -1118,7 +1118,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
version = (version << 8) | *(const unsigned char *) ccp;
if(data->set.ssl.certinfo) {
- ccp = curl_maprintf("%lx", version);
+ ccp = curl_maprintf("%x", version);
if(!ccp)
return CURLE_OUT_OF_MEMORY;
result = Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
@@ -1127,7 +1127,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
return result;
}
if(!certnum)
- infof(data, " Version: %lu (0x%lx)", version + 1, version);
+ infof(data, " Version: %u (0x%x)", version + 1, version);
/* Serial number. */
ccp = ASN1tostr(&cert.serialNumber, 0);
diff --git a/Utilities/cmcurl/lib/wildcard.c b/Utilities/cmcurl/lib/wildcard.c
deleted file mode 100644
index 3b81c7a..0000000
--- a/Utilities/cmcurl/lib/wildcard.c
+++ /dev/null
@@ -1,75 +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 CURL_DISABLE_FTP
-
-#include "wildcard.h"
-#include "llist.h"
-#include "fileinfo.h"
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-static void fileinfo_dtor(void *user, void *element)
-{
- (void)user;
- Curl_fileinfo_cleanup(element);
-}
-
-CURLcode Curl_wildcard_init(struct WildcardData *wc)
-{
- Curl_llist_init(&wc->filelist, fileinfo_dtor);
- wc->state = CURLWC_INIT;
-
- return CURLE_OK;
-}
-
-void Curl_wildcard_dtor(struct WildcardData *wc)
-{
- if(!wc)
- return;
-
- if(wc->dtor) {
- wc->dtor(wc->protdata);
- wc->dtor = ZERO_NULL;
- wc->protdata = NULL;
- }
- DEBUGASSERT(wc->protdata == NULL);
-
- Curl_llist_destroy(&wc->filelist, NULL);
-
-
- free(wc->path);
- wc->path = NULL;
- free(wc->pattern);
- wc->pattern = NULL;
-
- wc->customptr = NULL;
- wc->state = CURLWC_INIT;
-}
-
-#endif /* if disabled */
diff --git a/Utilities/cmcurl/lib/wildcard.h b/Utilities/cmcurl/lib/wildcard.h
deleted file mode 100644
index 9dccab0..0000000
--- a/Utilities/cmcurl/lib/wildcard.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef HEADER_CURL_WILDCARD_H
-#define HEADER_CURL_WILDCARD_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"
-
-#ifndef CURL_DISABLE_FTP
-#include <curl/curl.h>
-#include "llist.h"
-
-/* list of wildcard process states */
-typedef enum {
- CURLWC_CLEAR = 0,
- CURLWC_INIT = 1,
- CURLWC_MATCHING, /* library is trying to get list of addresses for
- downloading */
- CURLWC_DOWNLOADING,
- CURLWC_CLEAN, /* deallocate resources and reset settings */
- CURLWC_SKIP, /* skip over concrete file */
- CURLWC_ERROR, /* error cases */
- CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop
- will end */
-} wildcard_states;
-
-typedef void (*wildcard_dtor)(void *ptr);
-
-/* struct keeping information about wildcard download process */
-struct WildcardData {
- wildcard_states state;
- char *path; /* path to the directory, where we trying wildcard-match */
- char *pattern; /* wildcard pattern */
- struct Curl_llist filelist; /* llist with struct Curl_fileinfo */
- void *protdata; /* pointer to protocol specific temporary data */
- wildcard_dtor dtor;
- void *customptr; /* for CURLOPT_CHUNK_DATA pointer */
-};
-
-CURLcode Curl_wildcard_init(struct WildcardData *wc);
-void Curl_wildcard_dtor(struct WildcardData *wc);
-
-struct Curl_easy;
-
-#else
-/* FTP is disabled */
-#define Curl_wildcard_dtor(x)
-#endif
-
-#endif /* HEADER_CURL_WILDCARD_H */
diff --git a/Utilities/cmcurl/lib/ws.c b/Utilities/cmcurl/lib/ws.c
index 0fc5e56..e8495dc 100644
--- a/Utilities/cmcurl/lib/ws.c
+++ b/Utilities/cmcurl/lib/ws.c
@@ -166,10 +166,6 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
}
k->upgr101 = UPGR101_RECEIVED;
- if(data->set.connect_only)
- /* switch off non-blocking sockets */
- (void)curlx_nonblock(conn->sock[FIRSTSOCKET], FALSE);
-
return result;
}
@@ -750,9 +746,6 @@ CURLcode Curl_ws_disconnect(struct Curl_easy *data,
(void)data;
(void)dead_connection;
Curl_dyn_free(&wsc->early);
-
- /* make sure this is non-blocking to avoid getting stuck in shutdown */
- (void)curlx_nonblock(conn->sock[FIRSTSOCKET], TRUE);
return CURLE_OK;
}