Merge branch 'upstream-curl' into update-curl

* upstream-curl:
  curl 2024-05-22 (fd567d4f)
This commit is contained in:
Brad King
2024-05-29 14:04:11 -04:00
158 changed files with 6866 additions and 4255 deletions
+1 -1
View File
@@ -228,7 +228,7 @@ int main(void)
#endif
int main(void)
{
int flags = 0;
unsigned long flags = 0;
if(0 != ioctlsocket(0, FIONBIO, &flags))
return 1;
;
+1 -1
View File
@@ -25,7 +25,7 @@ include(FindPackageHandleStandardArgs)
find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h")
find_library(NGHTTP2_LIBRARY NAMES nghttp2)
find_library(NGHTTP2_LIBRARY NAMES nghttp2 nghttp2_static)
find_package_handle_standard_args(NGHTTP2
FOUND_VAR
+5 -1
View File
@@ -25,7 +25,11 @@ include(CheckCCompilerFlag)
unset(WPICKY)
if(CURL_WERROR AND CMAKE_COMPILER_IS_GNUCC AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
if(CURL_WERROR AND
((CMAKE_COMPILER_IS_GNUCC AND
NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0 AND
NOT CMAKE_VERSION VERSION_LESS 3.23.0) OR # check_symbol_exists() incompatible with GCC -pedantic-errors in earlier CMake versions
CMAKE_C_COMPILER_ID MATCHES "Clang"))
set(WPICKY "${WPICKY} -pedantic-errors")
endif()
@@ -137,6 +137,9 @@ set(HAVE_TERMIOS_H 0)
set(HAVE_TERMIO_H 0)
set(HAVE_UTIME_H 0) # mingw-w64 has it (wrapper to sys/utime.h)
set(HAVE_DIRENT_H 0)
set(HAVE_OPENDIR 0)
set(HAVE_FSEEKO 0)
set(HAVE__FSEEKI64 1)
set(HAVE_SOCKET 1)
+106 -25
View File
@@ -196,6 +196,7 @@ endif()
# HAVE_GNUTLS_SRP: `gnutls_srp_verifier` present in GnuTLS
# 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_ECH: ECH API checks for OpenSSL, BoringSSL or wolfSSL
#
# For each of the above variables, if the variable is DEFINED (either
# to ON or OFF), the symbol detection will be skipped. If the
@@ -471,11 +472,15 @@ if(ENABLE_IPV6 AND NOT WIN32)
list(APPEND CURL_LIBS "-framework SystemConfiguration")
endif()
endif()
if(ENABLE_IPV6)
set(USE_IPV6 ON)
endif()
if(0) # This code not needed for building within CMake.
find_package(Perl)
option(BUILD_LIBCURL_DOCS "to build libcurl man pages" ON)
option(BUILD_MISC_DOCS "to build misc man pages (e.g. curl-config and mk-ca-bundle)" ON)
option(ENABLE_CURL_MANUAL "to build the man page for curl and enable its -M/--manual option" ON)
if(ENABLE_CURL_MANUAL OR BUILD_LIBCURL_DOCS)
@@ -545,9 +550,6 @@ check_function_exists(gethostname HAVE_GETHOSTNAME)
if(WIN32)
list(APPEND CURL_LIBS "ws2_32" "bcrypt")
if(USE_LIBRTMP)
list(APPEND CURL_LIBS "winmm")
endif()
endif()
if(0) # This code not needed for building within CMake.
@@ -608,7 +610,7 @@ if(CURL_USE_SECTRANSP)
find_library(SECURITY_FRAMEWORK "Security")
if(NOT SECURITY_FRAMEWORK)
message(FATAL_ERROR "Security framework not found")
message(FATAL_ERROR "Security framework not found")
endif()
set(SSL_ENABLED ON)
@@ -625,10 +627,10 @@ if(use_core_foundation_and_core_services)
find_library(CORESERVICES_FRAMEWORK "CoreServices")
if(NOT COREFOUNDATION_FRAMEWORK)
message(FATAL_ERROR "CoreFoundation framework not found")
message(FATAL_ERROR "CoreFoundation framework not found")
endif()
if(NOT CORESERVICES_FRAMEWORK)
message(FATAL_ERROR "CoreServices framework not found")
message(FATAL_ERROR "CoreServices framework not found")
endif()
list(APPEND CURL_LIBS "-framework CoreFoundation -framework CoreServices")
@@ -780,8 +782,8 @@ if(CURL_ZSTD)
endif()
endif()
# Check symbol in OpenSSL-like TLS backends.
macro(openssl_check_symbol_exists SYMBOL FILES VARIABLE)
# Check symbol in an OpenSSL-like TLS backend, or in EXTRA_LIBS depending on it.
macro(openssl_check_symbol_exists SYMBOL FILES VARIABLE EXTRA_LIBS)
cmake_push_check_state()
if(USE_OPENSSL)
set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}")
@@ -805,6 +807,9 @@ macro(openssl_check_symbol_exists SYMBOL FILES VARIABLE)
endif()
list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_UINTPTR_T) # to pull in stdint.h (as of wolfSSL v5.5.4)
endif()
if(NOT "${EXTRA_LIBS}" STREQUAL "")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${EXTRA_LIBS}")
endif()
check_symbol_exists("${SYMBOL}" "${FILES}" "${VARIABLE}")
cmake_pop_check_state()
endmacro()
@@ -813,9 +818,9 @@ endmacro()
macro(openssl_check_quic)
if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD)
if(USE_OPENSSL)
openssl_check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
openssl_check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD "")
elseif(USE_WOLFSSL)
openssl_check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
openssl_check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD "")
endif()
endif()
if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD)
@@ -825,10 +830,34 @@ endmacro()
if(USE_OPENSSL OR USE_WOLFSSL)
if(NOT DEFINED HAVE_SSL_SET0_WBIO)
openssl_check_symbol_exists(SSL_set0_wbio "openssl/ssl.h" HAVE_SSL_SET0_WBIO)
openssl_check_symbol_exists(SSL_set0_wbio "openssl/ssl.h" HAVE_SSL_SET0_WBIO "")
endif()
if(NOT DEFINED HAVE_OPENSSL_SRP AND NOT CURL_DISABLE_SRP)
openssl_check_symbol_exists(SSL_CTX_set_srp_username "openssl/ssl.h" HAVE_OPENSSL_SRP)
openssl_check_symbol_exists(SSL_CTX_set_srp_username "openssl/ssl.h" HAVE_OPENSSL_SRP "")
endif()
endif()
option(USE_HTTPSRR "Enable HTTPS RR support for ECH (experimental)" OFF)
option(USE_ECH "Enable ECH support" OFF)
if(USE_ECH)
if(USE_OPENSSL OR USE_WOLFSSL)
# Be sure that the TLS library actually supports ECH.
if(NOT DEFINED HAVE_ECH)
if(USE_OPENSSL AND HAVE_BORINGSSL)
openssl_check_symbol_exists(SSL_set1_ech_config_list "openssl/ssl.h" HAVE_ECH "")
elseif(USE_OPENSSL)
openssl_check_symbol_exists(SSL_ech_set1_echconfig "openssl/ech.h" HAVE_ECH "")
elseif(USE_WOLFSSL)
openssl_check_symbol_exists(wolfSSL_CTX_GenerateEchConfig "wolfssl/options.h;wolfssl/ssl.h" HAVE_ECH "")
endif()
endif()
if(NOT HAVE_ECH)
message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/wolfSSL")
else()
message(STATUS "ECH enabled.")
endif()
else()
message(FATAL_ERROR "ECH requires ECH-enablded OpenSSL, BoringSSL or wolfSSL")
endif()
endif()
@@ -1054,6 +1083,21 @@ if(WIN32)
endif()
endif()
if(APPLE)
option(USE_APPLE_IDN "Use Apple built-in IDN support" OFF)
if(USE_APPLE_IDN)
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES "icucore")
check_symbol_exists("uidna_openUTS46" "unicode/uidna.h" HAVE_APPLE_IDN)
cmake_pop_check_state()
if(HAVE_APPLE_IDN)
list(APPEND CURL_LIBS "icucore")
else()
set(USE_APPLE_IDN OFF)
endif()
endif()
endif()
#libpsl
option(CURL_USE_LIBPSL "Use libPSL" ON)
mark_as_advanced(CURL_USE_LIBPSL)
@@ -1150,7 +1194,6 @@ if(CURL_USE_GSSAPI)
string(REPLACE ";" " " GSS_LINKER_FLAGS "${GSS_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
list(APPEND CURL_LIBS ${GSS_LIBRARIES})
else()
@@ -1158,6 +1201,26 @@ if(CURL_USE_GSSAPI)
endif()
endif()
option(USE_LIBRTMP "Enable librtmp from rtmpdump" OFF)
if(USE_LIBRTMP)
cmake_push_check_state()
set(_extra_libs "rtmp")
if(WIN32)
list(APPEND _extra_libs "winmm")
endif()
openssl_check_symbol_exists("RTMP_Init" "librtmp/rtmp.h" HAVE_LIBRTMP "${_extra_libs}")
cmake_pop_check_state()
if(HAVE_LIBRTMP)
list(APPEND CURL_LIBS "rtmp")
if(WIN32)
list(APPEND CURL_LIBS "winmm")
endif()
else()
message(WARNING "librtmp requested, but not found or missing OpenSSL. Skipping.")
set(USE_LIBRTMP OFF)
endif()
endif()
option(ENABLE_UNIX_SOCKETS "Define if you want Unix domain sockets support" ON)
if(ENABLE_UNIX_SOCKETS)
include(CheckStructHasMember)
@@ -1311,6 +1374,7 @@ check_include_file_concat("sys/un.h" HAVE_SYS_UN_H)
check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H)
check_include_file_concat("sys/xattr.h" HAVE_SYS_XATTR_H)
check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H)
check_include_file_concat("dirent.h" HAVE_DIRENT_H)
check_include_file_concat("fcntl.h" HAVE_FCNTL_H)
check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H)
check_include_file_concat("io.h" HAVE_IO_H)
@@ -1359,6 +1423,7 @@ endif()
check_symbol_exists(fnmatch "${CURL_INCLUDES};fnmatch.h" HAVE_FNMATCH)
check_symbol_exists(basename "${CURL_INCLUDES};string.h" HAVE_BASENAME)
check_symbol_exists(opendir "${CURL_INCLUDES};dirent.h" HAVE_OPENDIR)
check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET)
check_symbol_exists(sched_yield "${CURL_INCLUDES};sched.h" HAVE_SCHED_YIELD)
check_symbol_exists(socketpair "${CURL_INCLUDES}" HAVE_SOCKETPAIR)
@@ -1400,7 +1465,6 @@ check_symbol_exists(getifaddrs "${CURL_INCLUDES};stdlib.h" HAVE_GETIFADDRS)
check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE)
check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE)
check_symbol_exists(fseeko "${CURL_INCLUDES};stdio.h" HAVE_FSEEKO)
check_symbol_exists(_fseeki64 "${CURL_INCLUDES};stdio.h" HAVE__FSEEKI64)
check_symbol_exists(getpeername "${CURL_INCLUDES}" HAVE_GETPEERNAME)
check_symbol_exists(getsockname "${CURL_INCLUDES}" HAVE_GETSOCKNAME)
@@ -1410,10 +1474,6 @@ check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE)
check_symbol_exists(setmode "${CURL_INCLUDES}" HAVE_SETMODE)
check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT)
if(HAVE_FSEEKO)
set(HAVE_DECL_FSEEKO 1)
endif()
if(NOT MSVC OR (MSVC_VERSION GREATER_EQUAL 1900))
# earlier MSVC compilers had faulty snprintf implementations
check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF)
@@ -1476,6 +1536,15 @@ if(HAVE_FILE_OFFSET_BITS)
endif()
check_type_size("off_t" SIZEOF_OFF_T)
# fseeko may not exist with _FILE_OFFSET_BITS=64 but can exist with
# _FILE_OFFSET_BITS unset or 32 (e.g. Android ARMv7 with NDK 26b and API level < 24)
# so we need to test fseeko after testing for _FILE_OFFSET_BITS
check_symbol_exists(fseeko "${CURL_INCLUDES};stdio.h" HAVE_FSEEKO)
if(HAVE_FSEEKO)
set(HAVE_DECL_FSEEKO 1)
endif()
# include this header to get the type
set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCE_DIR}/include")
set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h")
@@ -1687,6 +1756,10 @@ set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
cmake_dependent_option(BUILD_TESTING "Build tests"
ON "PERL_FOUND;NOT CURL_DISABLE_TESTS"
OFF)
if(HAVE_MANUAL_TOOLS)
add_subdirectory(docs)
endif()
@@ -1697,15 +1770,24 @@ if(BUILD_CURL_EXE)
add_subdirectory(src)
endif()
cmake_dependent_option(BUILD_TESTING "Build tests"
ON "PERL_FOUND;NOT CURL_DISABLE_TESTS"
OFF)
option(BUILD_EXAMPLES "Build libcurl examples" OFF)
if(BUILD_EXAMPLES)
add_subdirectory(docs/examples)
endif()
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
if(NOT CURL_DISABLE_INSTALL)
install(FILES "${PROJECT_SOURCE_DIR}/scripts/mk-ca-bundle.pl"
DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)
# Helper to populate a list (_items) with a label when conditions (the remaining
# args) are satisfied
macro(_add_if label)
@@ -1730,7 +1812,7 @@ if(NOT CURL_DISABLE_INSTALL)
_add_if("brotli" HAVE_BROTLI)
_add_if("zstd" HAVE_ZSTD)
_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
_add_if("IDN" HAVE_LIBIDN2 OR USE_WIN32_IDN)
_add_if("IDN" HAVE_LIBIDN2 OR USE_WIN32_IDN OR USE_APPLE_IDN)
_add_if("Largefile" (SIZEOF_CURL_OFF_T GREATER 4) AND
((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
_add_if("SSPI" USE_WINDOWS_SSPI)
@@ -1743,9 +1825,6 @@ if(NOT CURL_DISABLE_INSTALL)
(HAVE_GSSAPI OR USE_WINDOWS_SSPI))
_add_if("NTLM" NOT (CURL_DISABLE_NTLM) AND
(use_curl_ntlm_core OR USE_WINDOWS_SSPI))
_add_if("NTLM_WB" NOT (CURL_DISABLE_NTLM) AND
(use_curl_ntlm_core OR USE_WINDOWS_SSPI) AND
NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
_add_if("TLS-SRP" USE_TLS_SRP)
_add_if("HTTP2" USE_NGHTTP2)
_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE OR USE_OPENSSL_QUIC)
@@ -1768,6 +1847,8 @@ if(NOT CURL_DISABLE_INSTALL)
_add_if("IPFS" NOT CURL_DISABLE_HTTP)
_add_if("IPNS" NOT CURL_DISABLE_HTTP)
_add_if("HTTPS" NOT CURL_DISABLE_HTTP AND SSL_ENABLED)
_add_if("ECH" HAVE_ECH)
_add_if("HTTPSRR" HAVE_ECH)
_add_if("FTP" NOT CURL_DISABLE_FTP)
_add_if("FTPS" NOT CURL_DISABLE_FTP AND SSL_ENABLED)
_add_if("FILE" NOT CURL_DISABLE_FILE)
+40 -33
View File
@@ -632,6 +632,7 @@ typedef enum {
CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */
CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */
CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */
CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */
CURL_LAST /* never use! */
} CURLcode;
@@ -811,7 +812,10 @@ typedef enum {
#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE
#define CURLAUTH_NTLM (((unsigned long)1)<<3)
#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
#ifndef CURL_NO_OLDIES
/* functionality removed since 8.8.0 */
#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5)
#endif
#define CURLAUTH_BEARER (((unsigned long)1)<<6)
#define CURLAUTH_AWS_SIGV4 (((unsigned long)1)<<7)
#define CURLAUTH_ONLY (((unsigned long)1)<<31)
@@ -2206,6 +2210,9 @@ typedef enum {
/* millisecond version */
CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),
/* set ECH configuration */
CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 325),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@@ -2311,30 +2318,26 @@ enum CURL_NETRC_OPTION {
CURL_NETRC_LAST
};
enum {
CURL_SSLVERSION_DEFAULT,
CURL_SSLVERSION_TLSv1, /* TLS 1.x */
CURL_SSLVERSION_SSLv2,
CURL_SSLVERSION_SSLv3,
CURL_SSLVERSION_TLSv1_0,
CURL_SSLVERSION_TLSv1_1,
CURL_SSLVERSION_TLSv1_2,
CURL_SSLVERSION_TLSv1_3,
#define CURL_SSLVERSION_DEFAULT 0
#define CURL_SSLVERSION_TLSv1 1 /* TLS 1.x */
#define CURL_SSLVERSION_SSLv2 2
#define CURL_SSLVERSION_SSLv3 3
#define CURL_SSLVERSION_TLSv1_0 4
#define CURL_SSLVERSION_TLSv1_1 5
#define CURL_SSLVERSION_TLSv1_2 6
#define CURL_SSLVERSION_TLSv1_3 7
CURL_SSLVERSION_LAST /* never use, keep last */
};
#define CURL_SSLVERSION_LAST 8 /* never use, keep last */
enum {
CURL_SSLVERSION_MAX_NONE = 0,
CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16),
CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16),
CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16),
CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16),
CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16),
#define CURL_SSLVERSION_MAX_NONE 0
#define CURL_SSLVERSION_MAX_DEFAULT (CURL_SSLVERSION_TLSv1 << 16)
#define CURL_SSLVERSION_MAX_TLSv1_0 (CURL_SSLVERSION_TLSv1_0 << 16)
#define CURL_SSLVERSION_MAX_TLSv1_1 (CURL_SSLVERSION_TLSv1_1 << 16)
#define CURL_SSLVERSION_MAX_TLSv1_2 (CURL_SSLVERSION_TLSv1_2 << 16)
#define CURL_SSLVERSION_MAX_TLSv1_3 (CURL_SSLVERSION_TLSv1_3 << 16)
/* never use, keep last */
CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16)
};
#define CURL_SSLVERSION_MAX_LAST (CURL_SSLVERSION_LAST << 16)
enum CURL_TLSAUTH {
CURL_TLSAUTH_NONE,
@@ -3035,17 +3038,18 @@ CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *share);
*/
typedef enum {
CURLVERSION_FIRST,
CURLVERSION_SECOND,
CURLVERSION_THIRD,
CURLVERSION_FOURTH,
CURLVERSION_FIFTH,
CURLVERSION_SIXTH,
CURLVERSION_SEVENTH,
CURLVERSION_EIGHTH,
CURLVERSION_NINTH,
CURLVERSION_TENTH,
CURLVERSION_ELEVENTH,
CURLVERSION_FIRST, /* 7.10 */
CURLVERSION_SECOND, /* 7.11.1 */
CURLVERSION_THIRD, /* 7.12.0 */
CURLVERSION_FOURTH, /* 7.16.1 */
CURLVERSION_FIFTH, /* 7.57.0 */
CURLVERSION_SIXTH, /* 7.66.0 */
CURLVERSION_SEVENTH, /* 7.70.0 */
CURLVERSION_EIGHTH, /* 7.72.0 */
CURLVERSION_NINTH, /* 7.75.0 */
CURLVERSION_TENTH, /* 7.77.0 */
CURLVERSION_ELEVENTH, /* 7.87.0 */
CURLVERSION_TWELFTH, /* 8.8.0 */
CURLVERSION_LAST /* never actually use this */
} CURLversion;
@@ -3054,7 +3058,7 @@ typedef enum {
meant to be a built-in version number for what kind of struct the caller
expects. If the struct ever changes, we redefine the NOW to another enum
from above. */
#define CURLVERSION_NOW CURLVERSION_ELEVENTH
#define CURLVERSION_NOW CURLVERSION_TWELFTH
struct curl_version_info_data {
CURLversion age; /* age of the returned struct */
@@ -3114,6 +3118,9 @@ struct curl_version_info_data {
/* These fields were added in CURLVERSION_ELEVENTH */
/* feature_names is terminated by an entry with a NULL feature name */
const char * const *feature_names;
/* These fields were added in CURLVERSION_TWELFTH */
const char *rtmp_version; /* human readable string. */
};
typedef struct curl_version_info_data curl_version_info_data;
@@ -3154,7 +3161,7 @@ typedef struct curl_version_info_data curl_version_info_data;
#define CURL_VERSION_GSASL (1<<29) /* libgsasl is supported */
#define CURL_VERSION_THREADSAFE (1<<30) /* libcurl API is thread-safe */
/*
/*
* NAME curl_version_info()
*
* DESCRIPTION
+4 -4
View File
@@ -32,13 +32,13 @@
/* This is the version number of the libcurl package from which this header
file origins: */
#define LIBCURL_VERSION "8.7.1"
#define LIBCURL_VERSION "8.8.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 8
#define LIBCURL_VERSION_MINOR 7
#define LIBCURL_VERSION_PATCH 1
#define LIBCURL_VERSION_MINOR 8
#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -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 0x080701
#define LIBCURL_VERSION_NUM 0x080800
/*
* This is the date and time when the full source package was created. The
+14
View File
@@ -464,6 +464,20 @@ typedef int (*curl_push_callback)(CURL *parent,
struct curl_pushheaders *headers,
void *userp);
/*
* Name: curl_multi_waitfds()
*
* Desc: Ask curl for fds for polling. The app can use these to poll on.
* We want curl_multi_perform() called as soon as one of them are
* ready. Passing zero size allows to get just a number of fds.
*
* Returns: CURLMcode type, general multi error code.
*/
CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi,
struct curl_waitfd *ufds,
unsigned int size,
unsigned int *fd_count);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
@@ -275,6 +275,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_DNS_LOCAL_IP6 || \
(option) == CURLOPT_DNS_SERVERS || \
(option) == CURLOPT_DOH_URL || \
(option) == CURLOPT_ECH || \
(option) == CURLOPT_EGDSOCKET || \
(option) == CURLOPT_FTP_ACCOUNT || \
(option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \
+3
View File
@@ -99,6 +99,9 @@ typedef enum {
#define CURLU_ALLOW_SPACE (1<<11) /* Allow spaces in the URL */
#define CURLU_PUNYCODE (1<<12) /* get the host name in punycode */
#define CURLU_PUNY2IDN (1<<13) /* punycode => IDN conversion */
#define CURLU_GET_EMPTY (1<<14) /* allow empty queries and fragments
when extracting the URL or the
components */
typedef struct Curl_URL CURLU;
+26 -15
View File
@@ -31,9 +31,10 @@ configure_file(curl_config.h.cmake
transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
list(APPEND HHEADERS
${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
)
# DllMain is added later for DLL builds only.
list(REMOVE_ITEM CSOURCES dllmain.c)
list(APPEND HHEADERS ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
# The rest of the build
@@ -93,6 +94,7 @@ if(BUILD_TESTING)
${HHEADERS} ${CSOURCES}
)
target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
target_link_libraries(curlu PRIVATE ${CURL_LIBS})
endif()
if(ENABLE_CURLDEBUG)
@@ -101,10 +103,6 @@ if(ENABLE_CURLDEBUG)
set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
endif()
if(BUILD_TESTING)
target_link_libraries(curlu PRIVATE ${CURL_LIBS})
endif()
transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
@@ -152,17 +150,17 @@ if(NOT DEFINED SHARE_LIB_OBJECT)
endif()
endif()
if(WIN32)
# Define CURL_STATICLIB always, to disable __declspec(dllexport) for exported
# libcurl symbols. We handle exports via libcurl.def instead. Except with
# symbol hiding disabled or debug mode enabled, when we export _all_ symbols
# from libcurl DLL, without using libcurl.def.
add_definitions("-DCURL_STATICLIB")
endif()
if(SHARE_LIB_OBJECT)
set(LIB_OBJECT "libcurl_object")
add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})
if(WIN32)
# Define CURL_STATICLIB always, to disable __declspec(dllexport) for
# exported libcurl symbols. We handle exports via libcurl.def instead.
# Except with symbol hiding disabled or debug mode enabled, when we export
# _all_ symbols from libcurl DLL, without using libcurl.def.
set_property(TARGET ${LIB_OBJECT} APPEND
PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
endif()
target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
set_target_properties(${LIB_OBJECT} PROPERTIES
POSITION_INDEPENDENT_CODE ON)
@@ -190,6 +188,10 @@ if(BUILD_STATIC_LIBS)
list(APPEND libcurl_export ${LIB_STATIC})
add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
if(WIN32)
set_property(TARGET ${LIB_OBJECT} APPEND
PROPERTY COMPILE_DEFINITIONS "CURL_STATICLIB")
endif()
target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
# Remove the "lib" prefix since the library is already named "libcurl".
set_target_properties(${LIB_STATIC} PROPERTIES
@@ -219,6 +221,15 @@ if(BUILD_SHARED_LIBS)
list(APPEND libcurl_export ${LIB_SHARED})
add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
if(WIN32 OR CYGWIN)
if(CYGWIN)
# For cygwin always compile dllmain.c as a separate unit since it
# includes windows.h, which shouldn't be included in other units.
set_source_files_properties(dllmain.c PROPERTIES
SKIP_UNITY_BUILD_INCLUSION ON)
endif()
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES dllmain.c)
endif()
if(WIN32)
set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc)
if(HIDES_CURL_PRIVATE_SYMBOLS)
+3 -2
View File
@@ -44,6 +44,7 @@ LIB_VAUTH_HFILES = \
LIB_VTLS_CFILES = \
vtls/bearssl.c \
vtls/cipher_suite.c \
vtls/gtls.c \
vtls/hostcheck.c \
vtls/keylog.c \
@@ -60,6 +61,7 @@ LIB_VTLS_CFILES = \
LIB_VTLS_HFILES = \
vtls/bearssl.h \
vtls/cipher_suite.h \
vtls/gtls.h \
vtls/hostcheck.h \
vtls/keylog.h \
@@ -129,7 +131,6 @@ LIB_CFILES = \
curl_memrchr.c \
curl_multibyte.c \
curl_ntlm_core.c \
curl_ntlm_wb.c \
curl_path.c \
curl_range.c \
curl_rtmp.c \
@@ -140,6 +141,7 @@ LIB_CFILES = \
curl_trc.c \
cw-out.c \
dict.c \
dllmain.c \
doh.c \
dynbuf.c \
dynhds.c \
@@ -271,7 +273,6 @@ LIB_HFILES = \
curl_memrchr.h \
curl_multibyte.h \
curl_ntlm_core.h \
curl_ntlm_wb.h \
curl_path.h \
curl_printf.h \
curl_range.h \
+4 -4
View File
@@ -191,7 +191,7 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
as->expires = expires;
as->prio = prio;
as->persist = persist ? 1 : 0;
Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
Curl_llist_append(&asi->list, as, &as->node);
}
}
@@ -252,7 +252,7 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
CURLcode result = Curl_gmtime(as->expires, &stamp);
if(result)
return result;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else {
char ipv6_unused[16];
if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
@@ -303,7 +303,7 @@ struct altsvcinfo *Curl_altsvc_init(void)
#ifdef USE_HTTP2
| CURLALTSVC_H2
#endif
#ifdef ENABLE_QUIC
#ifdef USE_HTTP3
| CURLALTSVC_H3
#endif
;
@@ -643,7 +643,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
account. [See RFC 7838 section 3.1] */
as->expires = maxage + time(NULL);
as->persist = persist;
Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
Curl_llist_append(&asi->list, as, &as->node);
infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
Curl_alpnid2str(dstalpnid));
}
+3 -3
View File
@@ -539,7 +539,7 @@ static void compound_results(struct thread_data *res,
if(!ai)
return;
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
#ifdef USE_IPV6 /* CURLRES_IPV6 */
if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
/* We have results already, put the new IPv6 entries at the head of the
list. */
@@ -684,7 +684,7 @@ static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node)
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
@@ -932,7 +932,7 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
const char *local_ip6)
{
#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6)
#if defined(HAVE_CARES_SET_LOCAL) && defined(USE_IPV6)
unsigned char a6[INET6_ADDRSTRLEN];
if((!local_ip6) || (local_ip6[0] == 0)) {
+19 -6
View File
@@ -325,7 +325,7 @@ query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
@@ -444,7 +444,7 @@ query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
/*
* getaddrinfo_thread() resolves a name and then exits.
*
* For builds without ARES, but with ENABLE_IPV6, create a resolver thread
* For builds without ARES, but with USE_IPV6, create a resolver thread
* and wait on it.
*/
static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
@@ -554,11 +554,15 @@ static void destroy_async_data(struct Curl_async *async)
if(!done) {
#ifdef _WIN32
if(td->complete_ev)
if(td->complete_ev) {
CloseHandle(td->complete_ev);
else
td->complete_ev = NULL;
}
#endif
Curl_thread_destroy(td->thread_hnd);
if(td->thread_hnd != curl_thread_t_null) {
Curl_thread_destroy(td->thread_hnd);
td->thread_hnd = curl_thread_t_null;
}
}
else {
#ifdef _WIN32
@@ -566,6 +570,7 @@ static void destroy_async_data(struct Curl_async *async)
Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
WaitForSingleObject(td->complete_ev, INFINITE);
CloseHandle(td->complete_ev);
td->complete_ev = NULL;
}
#endif
if(td->thread_hnd != curl_thread_t_null)
@@ -672,7 +677,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
#endif
if(!td->thread_hnd) {
if(td->thread_hnd == curl_thread_t_null) {
/* The thread never started, so mark it as done here for proper cleanup. */
td->tsd.done = 1;
err = errno;
@@ -713,6 +718,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
if(td->complete_ev) {
WaitForSingleObject(td->complete_ev, INFINITE);
CloseHandle(td->complete_ev);
td->complete_ev = NULL;
if(entry)
result = getaddrinfo_complete(data);
}
@@ -754,6 +760,13 @@ void Curl_resolver_kill(struct Curl_easy *data)
/* If we're still resolving, we must wait for the threads to fully clean up,
unfortunately. Otherwise, we can simply cancel to clean up any resolver
data. */
#ifdef _WIN32
if(td && td->complete_ev) {
Curl_GetAddrInfoExCancel(&td->tsd.w8.cancel_ev);
(void)thread_wait_resolv(data, NULL, FALSE);
}
else
#endif
if(td && td->thread_hnd != curl_thread_t_null
&& (data->set.quick_exit != 1L))
(void)thread_wait_resolv(data, NULL, FALSE);
+1 -1
View File
@@ -243,7 +243,7 @@ static CURLcode base64_encode(const char *table64,
*outptr = base64data;
/* Return the length of the new data */
*outlen = output - base64data;
*outlen = (size_t)(output - base64data);
return CURLE_OK;
}
+1 -1
View File
@@ -85,7 +85,7 @@ void Curl_bufcp_free(struct bufc_pool *pool);
* preferably never fail (except for memory exhaustion).
*
* By default and without a pool, a bufq will keep chunks that read
* read empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will
* empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will
* disable that and free chunks once they become empty.
*
* When providing a pool to a bufq, all chunk creation and spare handling
+5 -1
View File
@@ -171,7 +171,7 @@ static int hyper_each_header(void *userdata,
len = Curl_dyn_len(&data->state.headerb);
headp = Curl_dyn_ptr(&data->state.headerb);
result = Curl_http_header(data, data->conn, headp, len);
result = Curl_http_header(data, headp, len);
if(result) {
data->state.hresult = result;
return HYPER_ITER_BREAK;
@@ -980,11 +980,13 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
goto error;
}
#ifndef CURL_DISABLE_PROXY
if(data->state.aptr.proxyuserpwd) {
result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
if(result)
goto error;
}
#endif
if(data->state.aptr.userpwd) {
result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
@@ -1137,7 +1139,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* clear userpwd and proxyuserpwd to avoid reusing old credentials
* from reused connections */
Curl_safefree(data->state.aptr.userpwd);
#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
#endif
return CURLE_OK;
error:
DEBUGASSERT(result);
+18 -14
View File
@@ -195,14 +195,16 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
static void tunnel_free(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct h1_tunnel_state *ts = cf->ctx;
if(ts) {
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
Curl_dyn_free(&ts->rcvbuf);
Curl_dyn_free(&ts->request_data);
Curl_httpchunk_free(data, &ts->ch);
free(ts);
cf->ctx = NULL;
if(cf) {
struct h1_tunnel_state *ts = cf->ctx;
if(ts) {
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
Curl_dyn_free(&ts->rcvbuf);
Curl_dyn_free(&ts->request_data);
Curl_httpchunk_free(data, &ts->ch);
free(ts);
cf->ctx = NULL;
}
}
}
@@ -1057,18 +1059,20 @@ static void cf_h1_proxy_close(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "close");
cf->connected = FALSE;
if(cf->ctx) {
h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
if(cf) {
cf->connected = FALSE;
if(cf->ctx) {
h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
}
if(cf->next)
cf->next->cft->do_close(cf->next, data);
}
if(cf->next)
cf->next->cft->do_close(cf->next, data);
}
struct Curl_cftype Curl_cft_h1_proxy = {
"H1-PROXY",
CF_TYPE_IP_CONNECT,
CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
0,
cf_h1_proxy_destroy,
cf_h1_proxy_connect,
+1 -1
View File
@@ -1532,7 +1532,7 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_h2_proxy = {
"H2-PROXY",
CF_TYPE_IP_CONNECT,
CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
CURL_LOG_LVL_NONE,
cf_h2_proxy_destroy,
cf_h2_proxy_connect,
+1 -1
View File
@@ -189,7 +189,7 @@ static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_haproxy = {
"HAPROXY",
0,
CF_TYPE_PROXY,
0,
cf_haproxy_destroy,
cf_haproxy_connect,
+2 -2
View File
@@ -102,8 +102,8 @@ struct cf_hc_ctx {
CURLcode result; /* overall result */
struct cf_hc_baller h3_baller;
struct cf_hc_baller h21_baller;
int soft_eyeballs_timeout_ms;
int hard_eyeballs_timeout_ms;
unsigned int soft_eyeballs_timeout_ms;
unsigned int hard_eyeballs_timeout_ms;
};
static void cf_hc_baller_init(struct cf_hc_baller *b,
+19 -28
View File
@@ -81,7 +81,7 @@
#include "memdebug.h"
#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
#if defined(USE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
/* It makes support for IPv4-mapped IPv6 addresses.
* Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
* Windows Vista and later: default is on;
@@ -287,7 +287,7 @@ static CURLcode socket_open(struct Curl_easy *data,
/* no socket, no connection */
return CURLE_COULDNT_CONNECT;
#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
if(data->conn->scope_id && (addr->family == AF_INET6)) {
struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
sa6->sin6_scope_id = data->conn->scope_id;
@@ -405,7 +405,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
#endif
@@ -419,7 +419,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
#ifdef IP_BIND_ADDRESS_NO_PORT
int on = 1;
#endif
#ifndef ENABLE_IPV6
#ifndef USE_IPV6
(void)scope;
#endif
@@ -475,7 +475,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
#endif
switch(Curl_if2ip(af,
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
scope, conn->scope_id,
#endif
dev, myhost, sizeof(myhost))) {
@@ -514,7 +514,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
if(af == AF_INET)
conn->ip_version = CURL_IPRESOLVE_V4;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else if(af == AF_INET6)
conn->ip_version = CURL_IPRESOLVE_V6;
#endif
@@ -547,7 +547,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
}
if(done > 0) {
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
/* IPv6 address */
if(af == AF_INET6) {
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
@@ -596,7 +596,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
}
else {
/* no device was given, prepare sa to match af's needs */
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
if(af == AF_INET6) {
si6->sin6_family = AF_INET6;
si6->sin6_port = htons(port);
@@ -616,16 +616,6 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
for(;;) {
if(bind(sockfd, sock, sizeof_sa) >= 0) {
/* we succeeded to bind */
struct Curl_sockaddr_storage add;
curl_socklen_t size = sizeof(add);
memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
char buffer[STRERROR_LEN];
data->state.os_errno = error = SOCKERRNO;
failf(data, "getsockname() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
return CURLE_INTERFACE_FAILED;
}
infof(data, "Local port: %hu", port);
conn->bits.bound = TRUE;
return CURLE_OK;
@@ -639,7 +629,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
/* We reuse/clobber the port variable here below */
if(sock->sa_family == AF_INET)
si4->sin_port = ntohs(port);
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else
si6->sin6_port = ntohs(port);
#endif
@@ -923,7 +913,8 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
struct cf_socket_ctx *ctx = cf->ctx;
#ifdef HAVE_GETSOCKNAME
if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
if((ctx->sock != CURL_SOCKET_BAD) &&
!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
/* TFTP does not connect, so it cannot get the IP like this */
char buffer[STRERROR_LEN];
@@ -946,8 +937,8 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
}
#else
(void)data;
ctx->l_ip[0] = 0;
ctx->l_port = -1;
ctx->ip.local_ip[0] = 0;
ctx->ip.local_port = -1;
#endif
return CURLE_OK;
}
@@ -991,7 +982,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
if(result)
goto out;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
if(ctx->addr.family == AF_INET6) {
set_ipv6_v6only(ctx->sock, 0);
infof(data, " Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
@@ -1000,7 +991,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
#endif
infof(data, " Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
is_tcp = (ctx->addr.family == AF_INET
|| ctx->addr.family == AF_INET6) &&
ctx->addr.socktype == SOCK_STREAM;
@@ -1037,7 +1028,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
#ifndef CURL_DISABLE_BINDLOCAL
/* possibly bind the local end to an IP, interface or port */
if(ctx->addr.family == AF_INET
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
|| ctx->addr.family == AF_INET6
#endif
) {
@@ -1288,7 +1279,7 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
#ifdef DEBUGBUILD
/* simulate network blocking/partial writes */
if(ctx->wblock_percent > 0) {
unsigned char c;
unsigned char c = 0;
Curl_rand(data, &c, 1);
if(c >= ((100-ctx->wblock_percent)*256/100)) {
CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
@@ -1366,7 +1357,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
#ifdef DEBUGBUILD
/* simulate network blocking/partial reads */
if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
unsigned char c;
unsigned char c = 0;
Curl_rand(data, &c, 1);
if(c >= ((100-ctx->rblock_percent)*256/100)) {
CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
@@ -1449,7 +1440,7 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
/* the first socket info gets some specials */
if(cf->sockindex == FIRSTSOCKET) {
cf->conn->remote_addr = &ctx->addr;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
#endif
Curl_persistconninfo(data, cf->conn, &ctx->ip);
+14 -1
View File
@@ -590,7 +590,7 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
/**
* Notify connection filters that the transfer represented by `data`
* is donw with sending data (e.g. has uploaded everything).
* is done with sending data (e.g. has uploaded everything).
*/
void Curl_conn_ev_data_done_send(struct Curl_easy *data)
{
@@ -670,6 +670,19 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
return (result || n <= 0)? 1 : (size_t)n;
}
int Curl_conn_get_stream_error(struct Curl_easy *data,
struct connectdata *conn,
int sockindex)
{
CURLcode result;
int n = 0;
struct Curl_cfilter *cf = conn->cfilter[sockindex];
result = cf? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
&n, NULL) : CURLE_UNKNOWN_OPTION;
return (result || n < 0)? 0 : n;
}
int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
{
if(data && data->conn &&
+10 -1
View File
@@ -160,6 +160,7 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
#define CF_QUERY_SOCKET 3 /* - curl_socket_t */
#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */
#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */
#define CF_QUERY_STREAM_ERROR 6 /* error code - */
/**
* Query the cfilter for properties. Filters ignorant of a query will
@@ -178,10 +179,12 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
* connection, etc.
* CF_TYPE_SSL: provide SSL/TLS
* CF_TYPE_MULTIPLEX: provides multiplexing of easy handles
* CF_TYPE_PROXY provides proxying
*/
#define CF_TYPE_IP_CONNECT (1 << 0)
#define CF_TYPE_SSL (1 << 1)
#define CF_TYPE_MULTIPLEX (1 << 2)
#define CF_TYPE_PROXY (1 << 3)
/* A connection filter type, e.g. specific implementation. */
struct Curl_cftype {
@@ -449,7 +452,7 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data);
/**
* Notify connection filters that the transfer represented by `data`
* is donw with sending data (e.g. has uploaded everything).
* is done with sending data (e.g. has uploaded everything).
*/
void Curl_conn_ev_data_done_send(struct Curl_easy *data);
@@ -496,6 +499,12 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
/**
* Get the underlying error code for a transfer stream or 0 if not known.
*/
int Curl_conn_get_stream_error(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
/**
* Get the index of the given socket in the connection's sockets.
+3 -4
View File
@@ -68,8 +68,7 @@ static void bundle_destroy(struct connectbundle *bundle)
static void bundle_add_conn(struct connectbundle *bundle,
struct connectdata *conn)
{
Curl_llist_insert_next(&bundle->conn_list, bundle->conn_list.tail, conn,
&conn->bundle_node);
Curl_llist_append(&bundle->conn_list, conn, &conn->bundle_node);
conn->bundle = bundle;
bundle->num_connections++;
}
@@ -101,7 +100,7 @@ static void free_bundle_hash_entry(void *freethis)
bundle_destroy(b);
}
int Curl_conncache_init(struct conncache *connc, int size)
int Curl_conncache_init(struct conncache *connc, size_t size)
{
/* allocate a new easy handle to use when closing cached connections */
connc->closure_handle = curl_easy_init();
@@ -141,7 +140,7 @@ static void hashkey(struct connectdata *conn, char *buf, size_t len)
hostname = conn->host.name;
/* put the numbers first so that the hostname gets cut off if too long */
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname);
#else
msnprintf(buf, len, "%ld/%s", port, hostname);
+1 -1
View File
@@ -85,7 +85,7 @@ struct connectbundle {
};
/* returns 1 on error, 0 is fine */
int Curl_conncache_init(struct conncache *, int size);
int Curl_conncache_init(struct conncache *, size_t size);
void Curl_conncache_destroy(struct conncache *connc);
/* return the correct bundle, to a host or a proxy */
+6 -6
View File
@@ -195,7 +195,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, int *port)
{
struct sockaddr_in *si = NULL;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct sockaddr_in6 *si6 = NULL;
#endif
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
@@ -214,7 +214,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
return TRUE;
}
break;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *) sa;
if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
@@ -401,7 +401,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
return CURLE_OUT_OF_MEMORY;
baller->name = ((ai_family == AF_INET)? "ipv4" : (
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
(ai_family == AF_INET6)? "ipv6" :
#endif
"ip"));
@@ -779,7 +779,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
/* any IP version is allowed */
ai_family0 = remotehost->addr?
remotehost->addr->ai_family : 0;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
ai_family1 = ai_family0 == AF_INET6 ?
AF_INET : AF_INET6;
#else
@@ -790,7 +790,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
/* only one IP version is allowed */
ai_family0 = (conn->ip_version == CURL_IPRESOLVE_V4) ?
AF_INET :
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
AF_INET6;
#else
AF_UNSPEC;
@@ -1117,7 +1117,7 @@ const
#endif
struct transport_provider transport_providers[] = {
{ TRNSPRT_TCP, Curl_cf_tcp_create },
#ifdef ENABLE_QUIC
#ifdef USE_HTTP3
{ TRNSPRT_QUIC, Curl_cf_quic_create },
#endif
#ifndef CURL_DISABLE_TFTP
+34 -7
View File
@@ -300,7 +300,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data,
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
if(!(type & CLIENTWRITE_BODY))
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
/* Set the compressed input when this function is called */
@@ -457,7 +457,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
if(!(type & CLIENTWRITE_BODY))
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(zp->zlib_init == ZLIB_INIT_GZIP) {
@@ -669,7 +669,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
CURLcode result = CURLE_OK;
BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
if(!(type & CLIENTWRITE_BODY))
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!bp->br)
@@ -762,7 +762,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
ZSTD_outBuffer out;
size_t errorCode;
if(!(type & CLIENTWRITE_BODY))
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!zp->decomp) {
@@ -916,7 +916,7 @@ static CURLcode error_do_write(struct Curl_easy *data,
(void) buf;
(void) nbytes;
if(!(type & CLIENTWRITE_BODY))
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
failf(data, "Unrecognized content encoding type. "
@@ -978,6 +978,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
do {
const char *name;
size_t namelen;
bool is_chunked = FALSE;
/* Parse a single encoding name. */
while(ISBLANK(*enclist) || *enclist == ',')
@@ -993,10 +994,11 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const struct Curl_cwtype *cwt;
struct Curl_cwriter *writer;
is_chunked = (is_transfer && (namelen == 7) &&
strncasecompare(name, "chunked", 7));
/* if we skip the decoding in this phase, do not look further.
* Exception is "chunked" transfer-encoding which always must happen */
if((is_transfer && !data->set.http_transfer_encoding &&
(namelen != 7 || !strncasecompare(name, "chunked", 7))) ||
if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
(!is_transfer && data->set.http_ce_skip)) {
/* not requested, ignore */
return CURLE_OK;
@@ -1009,6 +1011,31 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
}
cwt = find_unencode_writer(name, namelen, phase);
if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) {
/* A 'chunked' transfer encoding has already been added.
* Ignore duplicates. See #13451.
* Also RFC 9112, ch. 6.1:
* "A sender MUST NOT apply the chunked transfer coding more than
* once to a message body."
*/
return CURLE_OK;
}
if(is_transfer && !is_chunked &&
Curl_cwriter_get_by_name(data, "chunked")) {
/* RFC 9112, ch. 6.1:
* "If any transfer coding other than chunked is applied to a
* response's content, the sender MUST either apply chunked as the
* final transfer coding or terminate the message by closing the
* connection."
* "chunked" must be the last added to be the first in its phase,
* reject this.
*/
failf(data, "Reject response due to 'chunked' not being the last "
"Transfer-Encoding");
return CURLE_BAD_CONTENT_ENCODING;
}
if(!cwt)
cwt = &error_writer; /* Defer error at use. */
+2 -1
View File
@@ -886,7 +886,8 @@ Curl_cookie_add(struct Curl_easy *data,
* Now loop through the fields and init the struct we already have
* allocated
*/
for(ptr = firstptr, fields = 0; ptr && !badcookie;
fields = 0;
for(ptr = firstptr; ptr && !badcookie;
ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
switch(fields) {
case 0:
+9 -9
View File
@@ -130,7 +130,7 @@ Curl_getaddrinfo_ex(const char *nodename,
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
@@ -259,7 +259,7 @@ Curl_he2ai(const struct hostent *he, int port)
struct Curl_addrinfo *prevai = NULL;
struct Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct sockaddr_in6 *addr6;
#endif
CURLcode result = CURLE_OK;
@@ -275,7 +275,7 @@ Curl_he2ai(const struct hostent *he, int port)
for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
size_t ss_size;
size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
if(he->h_addrtype == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
else
@@ -321,7 +321,7 @@ Curl_he2ai(const struct hostent *he, int port)
addr->sin_port = htons((unsigned short)port);
break;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
case AF_INET6:
addr6 = (void *)ai->ai_addr; /* storage area for this info */
@@ -348,7 +348,7 @@ struct namebuff {
struct hostent hostentry;
union {
struct in_addr ina4;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct in6_addr ina6;
#endif
} addrentry;
@@ -401,7 +401,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
addrentry = (void *)&buf->addrentry.ina4;
memcpy(addrentry, inaddr, sizeof(struct in_addr));
break;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
case AF_INET6:
addrsize = sizeof(struct in6_addr);
addrentry = (void *)&buf->addrentry.ina6;
@@ -447,7 +447,7 @@ struct Curl_addrinfo *Curl_str2addr(char *address, int port)
if(Curl_inet_pton(AF_INET, address, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
return Curl_ip2addr(AF_INET, &in, address, port);
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
{
struct in6_addr in6;
if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
@@ -570,7 +570,7 @@ void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
{
struct Curl_addrinfo *ca;
struct sockaddr_in *addr;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct sockaddr_in6 *addr6;
#endif
for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
@@ -580,7 +580,7 @@ void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
addr->sin_port = htons((unsigned short)port);
break;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
case AF_INET6:
addr6 = (void *)ca->ai_addr; /* storage area for this info */
addr6->sin6_port = htons((unsigned short)port);
+19 -7
View File
@@ -156,7 +156,7 @@
#cmakedefine USE_WIN32_LDAP 1
/* Define if you want to enable IPv6 support */
#cmakedefine ENABLE_IPV6 1
#cmakedefine USE_IPV6 1
/* Define to 1 if you have the alarm function. */
#cmakedefine HAVE_ALARM 1
@@ -192,6 +192,12 @@
/* Define to 1 if you have the `closesocket' function. */
#cmakedefine HAVE_CLOSESOCKET 1
/* Define to 1 if you have the <dirent.h> header file. */
#cmakedefine HAVE_DIRENT_H 1
/* Define to 1 if you have the `opendir' function. */
#cmakedefine HAVE_OPENDIR 1
/* Define to 1 if you have the fcntl function. */
#cmakedefine HAVE_FCNTL 1
@@ -713,6 +719,9 @@ ${SIZEOF_TIME_T_CODE}
/* if OpenSSL is in use */
#cmakedefine USE_OPENSSL 1
/* if librtmp/rtmpdump is in use */
#cmakedefine USE_LIBRTMP 1
/* Define to 1 if you don't want the OpenSSL configuration to be loaded
automatically */
#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1
@@ -773,12 +782,6 @@ ${SIZEOF_TIME_T_CODE}
/* Type to use in place of in_addr_t when system does not provide it. */
#cmakedefine in_addr_t ${in_addr_t}
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to `unsigned int' if <sys/types.h> does not define. */
#cmakedefine size_t ${size_t}
@@ -801,6 +804,9 @@ ${SIZEOF_TIME_T_CODE}
/* to enable Windows IDN */
#cmakedefine USE_WIN32_IDN 1
/* to enable Apple IDN */
#cmakedefine USE_APPLE_IDN 1
/* Define to 1 to enable websocket support. */
#cmakedefine USE_WEBSOCKETS 1
@@ -812,3 +818,9 @@ ${SIZEOF_TIME_T_CODE}
/* Define to 1 to enable TLS-SRP support. */
#cmakedefine USE_TLS_SRP 1
/* Define to 1 to query for HTTPSRR when using DoH */
#cmakedefine USE_HTTPSRR 1
/* if ECH support is available */
#cmakedefine USE_ECH 1
+1 -1
View File
@@ -68,7 +68,7 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
/* Override host name when environment variable CURL_GETHOSTNAME is set */
const char *force_hostname = getenv("CURL_GETHOSTNAME");
if(force_hostname) {
strncpy(name, force_hostname, namelen);
strncpy(name, force_hostname, namelen - 1);
err = 0;
}
else {
-17
View File
@@ -159,21 +159,4 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
#endif
}
int curlx_win32_access(const char *path, int mode)
{
#if defined(_UNICODE)
int result = -1;
wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
if(path_w) {
result = _waccess(path_w, mode);
curlx_unicodefree(path_w);
}
else
errno = EINVAL;
return result;
#else
return _access(path, mode);
#endif
}
#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
-500
View File
@@ -1,500 +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"
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
defined(NTLM_WB_ENABLED)
/*
* NTLM details:
*
* https://davenport.sourceforge.net/ntlm.html
* https://www.innovation.ch/java/ntlm.html
*/
#define DEBUG_ME 0
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <signal.h>
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#include "urldata.h"
#include "sendf.h"
#include "select.h"
#include "vauth/ntlm.h"
#include "curl_ntlm_core.h"
#include "curl_ntlm_wb.h"
#include "url.h"
#include "strerror.h"
#include "strdup.h"
#include "strcase.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
#if DEBUG_ME
# define DEBUG_OUT(x) x
#else
# define DEBUG_OUT(x) Curl_nop_stmt
#endif
/* Portable 'sclose_nolog' used only in child process instead of 'sclose'
to avoid fooling the socket leak detector */
#ifdef HAVE_PIPE
# define sclose_nolog(x) close((x))
#elif defined(HAVE_CLOSESOCKET)
# define sclose_nolog(x) closesocket((x))
#elif defined(HAVE_CLOSESOCKET_CAMEL)
# define sclose_nolog(x) CloseSocket((x))
#else
# define sclose_nolog(x) close((x))
#endif
static void ntlm_wb_cleanup(struct ntlmdata *ntlm)
{
if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
sclose(ntlm->ntlm_auth_hlpr_socket);
ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
}
if(ntlm->ntlm_auth_hlpr_pid) {
int i;
for(i = 0; i < 4; i++) {
pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG);
if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD)
break;
switch(i) {
case 0:
kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM);
break;
case 1:
/* Give the process another moment to shut down cleanly before
bringing down the axe */
Curl_wait_ms(1);
break;
case 2:
kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL);
break;
case 3:
break;
}
}
ntlm->ntlm_auth_hlpr_pid = 0;
}
Curl_safefree(ntlm->challenge);
Curl_safefree(ntlm->response);
}
static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm,
const char *userp)
{
curl_socket_t sockfds[2];
pid_t child_pid;
const char *username;
char *slash, *domain = NULL;
const char *ntlm_auth = NULL;
char *ntlm_auth_alloc = NULL;
#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
struct passwd pw, *pw_res;
char pwbuf[1024];
#endif
char buffer[STRERROR_LEN];
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) data;
#endif
/* Return if communication with ntlm_auth already set up */
if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
ntlm->ntlm_auth_hlpr_pid)
return CURLE_OK;
username = userp;
/* The real ntlm_auth really doesn't like being invoked with an
empty username. It won't make inferences for itself, and expects
the client to do so (mostly because it's really designed for
servers like squid to use for auth, and client support is an
afterthought for it). So try hard to provide a suitable username
if we don't already have one. But if we can't, provide the
empty one anyway. Perhaps they have an implementation of the
ntlm_auth helper which *doesn't* need it so we might as well try */
if(!username || !username[0]) {
username = getenv("NTLMUSER");
if(!username || !username[0])
username = getenv("LOGNAME");
if(!username || !username[0])
username = getenv("USER");
#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
if((!username || !username[0]) &&
!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) &&
pw_res) {
username = pw.pw_name;
}
#endif
if(!username || !username[0])
username = userp;
}
slash = strpbrk(username, "\\/");
if(slash) {
domain = strdup(username);
if(!domain)
return CURLE_OUT_OF_MEMORY;
slash = domain + (slash - username);
*slash = '\0';
username = username + (slash - domain) + 1;
}
/* For testing purposes, when DEBUGBUILD is defined and environment
variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform
NTLM challenge/response which only accepts commands and output
strings pre-written in test case definitions */
#ifdef DEBUGBUILD
ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE");
if(ntlm_auth_alloc)
ntlm_auth = ntlm_auth_alloc;
else
#endif
ntlm_auth = NTLM_WB_FILE;
if(access(ntlm_auth, X_OK) != 0) {
failf(data, "Could not access ntlm_auth: %s errno %d: %s",
ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
if(wakeup_create(sockfds)) {
failf(data, "Could not open socket pair. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
child_pid = fork();
if(child_pid == -1) {
wakeup_close(sockfds[0]);
wakeup_close(sockfds[1]);
failf(data, "Could not fork. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
else if(!child_pid) {
/*
* child process
*/
/* Don't use sclose in the child since it fools the socket leak detector */
sclose_nolog(sockfds[0]);
if(dup2(sockfds[1], STDIN_FILENO) == -1) {
failf(data, "Could not redirect child stdin. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
failf(data, "Could not redirect child stdout. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
if(domain)
execl(ntlm_auth, ntlm_auth,
"--helper-protocol", "ntlmssp-client-1",
"--use-cached-creds",
"--username", username,
"--domain", domain,
NULL);
else
execl(ntlm_auth, ntlm_auth,
"--helper-protocol", "ntlmssp-client-1",
"--use-cached-creds",
"--username", username,
NULL);
sclose_nolog(sockfds[1]);
failf(data, "Could not execl(). errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
sclose(sockfds[1]);
ntlm->ntlm_auth_hlpr_socket = sockfds[0];
ntlm->ntlm_auth_hlpr_pid = child_pid;
free(domain);
free(ntlm_auth_alloc);
return CURLE_OK;
done:
free(domain);
free(ntlm_auth_alloc);
return CURLE_REMOTE_ACCESS_DENIED;
}
/* if larger than this, something is seriously wrong */
#define MAX_NTLM_WB_RESPONSE 100000
static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
const char *input, curlntlm state)
{
size_t len_in = strlen(input), len_out = 0;
struct dynbuf b;
char *ptr = NULL;
unsigned char buf[1024];
Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE);
while(len_in > 0) {
ssize_t written = wakeup_write(ntlm->ntlm_auth_hlpr_socket, input, len_in);
if(written == -1) {
/* Interrupted by a signal, retry it */
if(errno == EINTR)
continue;
/* write failed if other errors happen */
goto done;
}
input += written;
len_in -= written;
}
/* Read one line */
while(1) {
ssize_t size =
wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, sizeof(buf));
if(size == -1) {
if(errno == EINTR)
continue;
goto done;
}
else if(size == 0)
goto done;
if(Curl_dyn_addn(&b, buf, size))
goto done;
len_out = Curl_dyn_len(&b);
ptr = Curl_dyn_ptr(&b);
if(len_out && ptr[len_out - 1] == '\n') {
ptr[len_out - 1] = '\0';
break; /* done! */
}
/* loop */
}
/* Samba/winbind installed but not configured */
if(state == NTLMSTATE_TYPE1 &&
len_out == 3 &&
ptr[0] == 'P' && ptr[1] == 'W')
goto done;
/* invalid response */
if(len_out < 4)
goto done;
if(state == NTLMSTATE_TYPE1 &&
(ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' '))
goto done;
if(state == NTLMSTATE_TYPE2 &&
(ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') &&
(ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' '))
goto done;
ntlm->response = strdup(ptr + 3);
Curl_dyn_free(&b);
if(!ntlm->response)
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
done:
Curl_dyn_free(&b);
return CURLE_REMOTE_ACCESS_DENIED;
}
CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
struct connectdata *conn,
bool proxy,
const char *header)
{
struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
(void) data; /* In case it gets unused by nop log macros. */
if(!checkprefix("NTLM", header))
return CURLE_BAD_CONTENT_ENCODING;
header += strlen("NTLM");
while(*header && ISSPACE(*header))
header++;
if(*header) {
ntlm->challenge = strdup(header);
if(!ntlm->challenge)
return CURLE_OUT_OF_MEMORY;
*state = NTLMSTATE_TYPE2; /* We got a type-2 message */
}
else {
if(*state == NTLMSTATE_LAST) {
infof(data, "NTLM auth restarted");
Curl_http_auth_cleanup_ntlm_wb(conn);
}
else if(*state == NTLMSTATE_TYPE3) {
infof(data, "NTLM handshake rejected");
Curl_http_auth_cleanup_ntlm_wb(conn);
*state = NTLMSTATE_NONE;
return CURLE_REMOTE_ACCESS_DENIED;
}
else if(*state >= NTLMSTATE_TYPE1) {
infof(data, "NTLM handshake failure (internal error)");
return CURLE_REMOTE_ACCESS_DENIED;
}
*state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
}
return CURLE_OK;
}
/*
* This is for creating ntlm header output by delegating challenge/response
* to Samba's winbind daemon helper ntlm_auth.
*/
CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
bool proxy)
{
/* point to the address of the pointer that holds the string to send to the
server, which is for a plain host or for an HTTP proxy */
char **allocuserpwd;
/* point to the name and password for this */
const char *userp;
struct ntlmdata *ntlm;
curlntlm *state;
struct auth *authp;
CURLcode res = CURLE_OK;
DEBUGASSERT(conn);
DEBUGASSERT(data);
if(proxy) {
#ifndef CURL_DISABLE_PROXY
allocuserpwd = &data->state.aptr.proxyuserpwd;
userp = conn->http_proxy.user;
ntlm = &conn->proxyntlm;
state = &conn->proxy_ntlm_state;
authp = &data->state.authproxy;
#else
return CURLE_NOT_BUILT_IN;
#endif
}
else {
allocuserpwd = &data->state.aptr.userpwd;
userp = conn->user;
ntlm = &conn->ntlm;
state = &conn->http_ntlm_state;
authp = &data->state.authhost;
}
authp->done = FALSE;
/* not set means empty */
if(!userp)
userp = "";
switch(*state) {
case NTLMSTATE_TYPE1:
default:
/* Use Samba's 'winbind' daemon to support NTLM authentication,
* by delegating the NTLM challenge/response protocol to a helper
* in ntlm_auth.
* https://web.archive.org/web/20190925164737
* /devel.squid-cache.org/ntlm/squid_helper_protocol.html
* https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
* https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
* Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this
* feature is enabled and 'NTLM_WB_FILE' symbol holds absolute
* filename of ntlm_auth helper.
* If NTLM authentication using winbind fails, go back to original
* request handling process.
*/
/* Create communication with ntlm_auth */
res = ntlm_wb_init(data, ntlm, userp);
if(res)
return res;
res = ntlm_wb_response(data, ntlm, "YR\n", *state);
if(res)
return res;
free(*allocuserpwd);
*allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
proxy ? "Proxy-" : "",
ntlm->response);
DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
Curl_safefree(ntlm->response);
if(!*allocuserpwd)
return CURLE_OUT_OF_MEMORY;
break;
case NTLMSTATE_TYPE2: {
char *input = aprintf("TT %s\n", ntlm->challenge);
if(!input)
return CURLE_OUT_OF_MEMORY;
res = ntlm_wb_response(data, ntlm, input, *state);
free(input);
if(res)
return res;
free(*allocuserpwd);
*allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
proxy ? "Proxy-" : "",
ntlm->response);
DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
*state = NTLMSTATE_TYPE3; /* we sent a type-3 */
authp->done = TRUE;
Curl_http_auth_cleanup_ntlm_wb(conn);
if(!*allocuserpwd)
return CURLE_OUT_OF_MEMORY;
break;
}
case NTLMSTATE_TYPE3:
/* connection is already authenticated,
* don't send a header in future requests */
*state = NTLMSTATE_LAST;
FALLTHROUGH();
case NTLMSTATE_LAST:
Curl_safefree(*allocuserpwd);
authp->done = TRUE;
break;
}
return CURLE_OK;
}
void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn)
{
ntlm_wb_cleanup(&conn->ntlm);
ntlm_wb_cleanup(&conn->proxyntlm);
}
#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
+36 -32
View File
@@ -98,8 +98,8 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
return CURLE_OK;
}
/* The get_pathname() function is being borrowed from OpenSSH sftp.c
version 4.6p1. */
/* The original get_pathname() function came from OpenSSH sftp.c version
4.6p1. */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -115,38 +115,37 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
#define MAX_PATHLENGTH 65535 /* arbitrary long */
CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir)
{
const char *cp = *cpp, *end;
char quot;
unsigned int i, j;
size_t fullPathLength, pathLength;
bool relativePath = false;
unsigned int i;
static const char WHITESPACE[] = " \t\r\n";
struct dynbuf out;
CURLcode result;
DEBUGASSERT(homedir);
if(!*cp || !homedir) {
*cpp = NULL;
*path = NULL;
*path = NULL;
*cpp = NULL;
if(!*cp || !homedir)
return CURLE_QUOTE_ERROR;
}
Curl_dyn_init(&out, MAX_PATHLENGTH);
/* Ignore leading whitespace */
cp += strspn(cp, WHITESPACE);
/* Allocate enough space for home directory and filename + separator */
fullPathLength = strlen(cp) + strlen(homedir) + 2;
*path = malloc(fullPathLength);
if(!*path)
return CURLE_OUT_OF_MEMORY;
/* Check for quoted filenames */
if(*cp == '\"' || *cp == '\'') {
quot = *cp++;
/* Search for terminating quote, unescape some chars */
for(i = j = 0; i <= strlen(cp); i++) {
for(i = 0; i <= strlen(cp); i++) {
if(cp[i] == quot) { /* Found quote */
i++;
(*path)[j] = '\0';
break;
}
if(cp[i] == '\0') { /* End of string */
@@ -159,40 +158,45 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
goto fail;
}
}
(*path)[j++] = cp[i];
result = Curl_dyn_addn(&out, &cp[i], 1);
if(result)
return result;
}
if(j == 0) {
if(!Curl_dyn_len(&out))
goto fail;
}
*cpp = cp + i + strspn(cp + i, WHITESPACE);
/* return pointer to second parameter if it exists */
*cpp = &cp[i] + strspn(&cp[i], WHITESPACE);
}
else {
/* Read to end of filename - either to whitespace or terminator */
end = strpbrk(cp, WHITESPACE);
if(!end)
end = strchr(cp, '\0');
/* return pointer to second parameter if it exists */
*cpp = end + strspn(end, WHITESPACE);
pathLength = 0;
relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/');
/* Handling for relative path - prepend home directory */
if(relativePath) {
strcpy(*path, homedir);
pathLength = strlen(homedir);
(*path)[pathLength++] = '/';
(*path)[pathLength] = '\0';
if(cp[0] == '/' && cp[1] == '~' && cp[2] == '/') {
result = Curl_dyn_add(&out, homedir);
if(!result)
result = Curl_dyn_addn(&out, "/", 1);
if(result)
return result;
cp += 3;
}
/* Copy path name up until first "whitespace" */
memcpy(&(*path)[pathLength], cp, (int)(end - cp));
pathLength += (int)(end - cp);
(*path)[pathLength] = '\0';
result = Curl_dyn_addn(&out, cp, (end - cp));
if(result)
return result;
}
*path = Curl_dyn_ptr(&out);
return CURLE_OK;
fail:
Curl_safefree(*path);
Curl_dyn_free(&out);
return CURLE_QUOTE_ERROR;
}
+1 -1
View File
@@ -45,5 +45,5 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
char *homedir,
char **path);
CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir);
CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir);
#endif /* HEADER_CURL_PATH_H */
+31 -7
View File
@@ -35,8 +35,10 @@
#include "warnless.h"
#include <curl/curl.h>
#include <librtmp/rtmp.h>
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
#if defined(_WIN32) && !defined(USE_LWIPSOCK)
@@ -66,7 +68,7 @@ static Curl_send rtmp_send;
*/
const struct Curl_handler Curl_handler_rtmp = {
"RTMP", /* scheme */
"rtmp", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -80,6 +82,7 @@ const struct Curl_handler Curl_handler_rtmp = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
@@ -89,7 +92,7 @@ const struct Curl_handler Curl_handler_rtmp = {
};
const struct Curl_handler Curl_handler_rtmpt = {
"RTMPT", /* scheme */
"rtmpt", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -103,6 +106,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
@@ -112,7 +116,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
};
const struct Curl_handler Curl_handler_rtmpe = {
"RTMPE", /* scheme */
"rtmpe", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -126,6 +130,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
@@ -135,7 +140,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
};
const struct Curl_handler Curl_handler_rtmpte = {
"RTMPTE", /* scheme */
"rtmpte", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -149,6 +154,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
@@ -158,7 +164,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
};
const struct Curl_handler Curl_handler_rtmps = {
"RTMPS", /* scheme */
"rtmps", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -172,6 +178,7 @@ const struct Curl_handler Curl_handler_rtmps = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
@@ -181,7 +188,7 @@ const struct Curl_handler Curl_handler_rtmps = {
};
const struct Curl_handler Curl_handler_rtmpts = {
"RTMPTS", /* scheme */
"rtmpts", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -195,6 +202,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
@@ -335,4 +343,20 @@ static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
return num;
}
void Curl_rtmp_version(char *version, size_t len)
{
char suff[2];
if(RTMP_LIB_VERSION & 0xff) {
suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
suff[1] = '\0';
}
else
suff[0] = '\0';
msnprintf(version, len, "librtmp/%d.%d%s",
RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
suff);
}
#endif /* USE_LIBRTMP */
+2
View File
@@ -30,6 +30,8 @@ extern const struct Curl_handler Curl_handler_rtmpe;
extern const struct Curl_handler Curl_handler_rtmpte;
extern const struct Curl_handler Curl_handler_rtmps;
extern const struct Curl_handler Curl_handler_rtmpts;
void Curl_rtmp_version(char *version, size_t len);
#endif
#endif /* HEADER_CURL_RTMP_H */
+5 -5
View File
@@ -376,7 +376,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_EXTERNAL;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_external_message(conn->user, &resp);
Curl_auth_create_external_message(conn->user, &resp);
}
else if(data->state.aptr.user) {
#if defined(USE_KERBEROS5)
@@ -498,7 +498,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_LOGIN;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_login_message(conn->user, &resp);
Curl_auth_create_login_message(conn->user, &resp);
}
}
@@ -576,14 +576,14 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
conn->user, conn->passwd, &resp);
break;
case SASL_LOGIN:
result = Curl_auth_create_login_message(conn->user, &resp);
Curl_auth_create_login_message(conn->user, &resp);
newstate = SASL_LOGIN_PASSWD;
break;
case SASL_LOGIN_PASSWD:
result = Curl_auth_create_login_message(conn->passwd, &resp);
Curl_auth_create_login_message(conn->passwd, &resp);
break;
case SASL_EXTERNAL:
result = Curl_auth_create_external_message(conn->user, &resp);
Curl_auth_create_external_message(conn->user, &resp);
break;
#ifdef USE_GSASL
case SASL_GSASL:
+48 -13
View File
@@ -72,6 +72,11 @@
# endif
#endif
/* Compatibility */
#if defined(ENABLE_IPV6)
# define USE_IPV6 1
#endif
/*
* Include configuration script results or hand-crafted
* configuration file for platforms which lack config tool.
@@ -290,7 +295,8 @@
/* based on logic in "curl/mprintf.h" */
#if (defined(__GNUC__) || defined(__clang__)) && \
#if (defined(__GNUC__) || defined(__clang__) || \
defined(__IAR_SYSTEMS_ICC__)) && \
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
!defined(CURL_NO_FMT_CHECKS)
#if defined(__MINGW32__) && !defined(__clang__)
@@ -313,7 +319,7 @@
#include <TargetConditionals.h>
#define USE_RESOLVE_ON_IPS 1
# if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \
defined(ENABLE_IPV6)
defined(USE_IPV6)
# define CURL_MACOS_CALL_COPYPROXIES 1
# endif
#endif
@@ -419,11 +425,9 @@
# define LSEEK_ERROR (__int64)-1
# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
# define access(fname,mode) curlx_win32_access(fname, mode)
int curlx_win32_open(const char *filename, int oflag, ...);
int curlx_win32_stat(const char *path, struct_stat *buffer);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
int curlx_win32_access(const char *path, int mode);
#endif
/*
@@ -442,11 +446,9 @@
# define struct_stat struct _stat
# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
# define access(fname,mode) curlx_win32_access(fname, mode)
int curlx_win32_stat(const char *path, struct_stat *buffer);
int curlx_win32_open(const char *filename, int oflag, ...);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
int curlx_win32_access(const char *path, int mode);
# endif
# define LSEEK_ERROR (long)-1
#endif
@@ -521,11 +523,14 @@
# error "curl_off_t must be exactly 64 bits"
#else
typedef unsigned CURL_TYPEOF_CURL_OFF_T curl_uint64_t;
typedef CURL_TYPEOF_CURL_OFF_T curl_int64_t;
# ifndef CURL_SUFFIX_CURL_OFF_TU
# error "CURL_SUFFIX_CURL_OFF_TU must be defined"
# endif
# define CURL_UINT64_SUFFIX CURL_SUFFIX_CURL_OFF_TU
# define CURL_UINT64_C(val) CURL_CONC_MACROS(val,CURL_UINT64_SUFFIX)
# define CURL_PRId64 CURL_FORMAT_CURL_OFF_T
# define CURL_PRIu64 CURL_FORMAT_CURL_OFF_TU
#endif
#if (SIZEOF_TIME_T == 4)
@@ -632,9 +637,9 @@
* Mutually exclusive CURLRES_* definitions.
*/
#if defined(ENABLE_IPV6) && defined(HAVE_GETADDRINFO)
#if defined(USE_IPV6) && defined(HAVE_GETADDRINFO)
# define CURLRES_IPV6
#elif defined(ENABLE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__))
#elif defined(USE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__))
/* assume on Windows that IPv6 without getaddrinfo is a broken build */
# error "Unexpected build: IPv6 is enabled but getaddrinfo was not found."
#else
@@ -656,13 +661,14 @@
/* ---------------------------------------------------------------- */
#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN)
#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && \
!defined(USE_WIN32_IDN) && !defined(USE_APPLE_IDN)
/* The lib and header are present */
#define USE_LIBIDN2
#endif
#if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN)
#error "Both libidn2 and WinIDN are enabled, choose one."
#if defined(USE_LIBIDN2) && (defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN))
#error "libidn2 cannot be enabled with WinIDN or AppleIDN, choose one."
#endif
#define LIBIDN_REQUIRED_VERSION "0.4.1"
@@ -716,6 +722,13 @@
((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7)))
# define UNUSED_PARAM __attribute__((__unused__))
# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#elif defined(__IAR_SYSTEMS_ICC__)
# define UNUSED_PARAM __attribute__((__unused__))
# if (__VER__ >= 9040001)
# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
# else
# define WARN_UNUSED_RESULT
# endif
#else
# define UNUSED_PARAM /* NOTHING */
# define WARN_UNUSED_RESULT
@@ -724,7 +737,8 @@
/* noreturn attribute */
#if !defined(CURL_NORETURN)
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) || \
defined(__IAR_SYSTEMS_ICC__)
# define CURL_NORETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
# define CURL_NORETURN __declspec(noreturn)
@@ -867,7 +881,6 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#error "Multi-SSL combined with QUIC is not supported"
#endif
#define ENABLE_QUIC
#define USE_HTTP3
#endif
@@ -898,4 +911,26 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#define OPENSSL_SUPPRESS_DEPRECATED
#endif
#if defined(inline)
/* 'inline' is defined as macro and assumed to be correct */
/* No need for 'inline' replacement */
#elif defined(__cplusplus)
/* The code is compiled with C++ compiler.
C++ always supports 'inline'. */
/* No need for 'inline' replacement */
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
/* C99 (and later) supports 'inline' keyword */
/* No need for 'inline' replacement */
#elif defined(__GNUC__) && __GNUC__ >= 3
/* GCC supports '__inline__' as an extension */
# define inline __inline__
#elif defined(_MSC_VER) && _MSC_VER >= 1400
/* MSC supports '__inline' from VS 2005 (or even earlier) */
# define inline __inline
#else
/* Probably 'inline' is not supported by compiler.
Define to the empty string to be on the safe side. */
# define inline /* empty */
#endif
#endif /* HEADER_CURL_SETUP_H */
+2 -6
View File
@@ -164,9 +164,7 @@ struct timeval {
(RECV_TYPE_ARG4)(0))
#else /* HAVE_RECV */
#ifndef sread
/* */
Error Missing_definition_of_macro_sread
/* */
#error "Missing definition of macro sread!"
#endif
#endif /* HAVE_RECV */
@@ -184,9 +182,7 @@ struct timeval {
(SEND_TYPE_ARG4)(SEND_4TH_ARG))
#else /* HAVE_SEND */
#ifndef swrite
/* */
Error Missing_definition_of_macro_swrite
/* */
#error "Missing definition of macro swrite!"
#endif
#endif /* HAVE_SEND */
+29 -23
View File
@@ -44,7 +44,7 @@
# include <openssl/opensslv.h>
# if (!defined(LIBRESSL_VERSION_NUMBER) && \
defined(OPENSSL_VERSION_NUMBER) && \
(OPENSSL_VERSION_NUMBER >= 0x10100010L)) || \
(OPENSSL_VERSION_NUMBER >= 0x10101000L)) || \
(defined(LIBRESSL_VERSION_NUMBER) && \
(LIBRESSL_VERSION_NUMBER >= 0x3080000fL))
# include <openssl/opensslconf.h>
@@ -52,6 +52,27 @@
# include <openssl/evp.h>
# define USE_OPENSSL_SHA512_256 1
# define HAS_SHA512_256_IMPLEMENTATION 1
# ifdef __NetBSD__
/* Some NetBSD versions has a bug in SHA-512/256.
* See https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039
* The problematic versions:
* - NetBSD before 9.4
* - NetBSD 9 all development versions (9.99.x)
* - NetBSD 10 development versions (10.99.x) before 10.99.11
* The bug was fixed in NetBSD 9.4 release, NetBSD 10.0 release,
* NetBSD 10.99.11 development.
* It is safe to apply the workaround even if the bug is not present, as
* the workaround just reduces performance slightly. */
# include <sys/param.h>
# if __NetBSD_Version__ < 904000000 || \
(__NetBSD_Version__ >= 999000000 && \
__NetBSD_Version__ < 1000000000) || \
(__NetBSD_Version__ >= 1099000000 && \
__NetBSD_Version__ < 1099001100)
# define NEED_NETBSD_SHA512_256_WORKAROUND 1
# include <string.h>
# endif
# endif
# endif
# endif
#endif /* USE_OPENSSL */
@@ -153,7 +174,7 @@ Curl_sha512_256_finish(unsigned char *digest,
CURLcode ret;
Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
#ifdef __NetBSD__
#ifdef NEED_NETBSD_SHA512_256_WORKAROUND
/* Use a larger buffer to work around a bug in NetBSD:
https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039 */
unsigned char tmp_digest[SHA512_256_DIGEST_SIZE * 2];
@@ -161,9 +182,10 @@ Curl_sha512_256_finish(unsigned char *digest,
tmp_digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
if(ret == CURLE_OK)
memcpy(digest, tmp_digest, SHA512_256_DIGEST_SIZE);
#else /* ! __NetBSD__ */
explicit_memset(tmp_digest, 0, sizeof(tmp_digest));
#else /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
ret = EVP_DigestFinal_ex(*ctx, digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
#endif /* ! __NetBSD__ */
#endif /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
EVP_MD_CTX_destroy(*ctx);
*ctx = NULL;
@@ -264,29 +286,13 @@ Curl_sha512_256_finish(unsigned char *digest,
defined(_MSC_VER) && !defined(__GNUC__) && !defined(__clang__)
# if _MSC_VER >= 1400
# define MHDX_INLINE __forceinline
# else
# define MHDX_INLINE /* empty */
# endif
#endif
#if !defined(MHDX_INLINE)
# if defined(inline)
/* Assume that 'inline' macro was already defined correctly by
* the build system. */
# define MHDX_INLINE inline
# elif defined(__cplusplus)
/* The code is compiled with C++ compiler.
* C++ always supports 'inline'. */
# define MHDX_INLINE inline
# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
/* C99 (and later) supports 'inline' keyword */
# define MHDX_INLINE inline
# elif defined(__GNUC__) && __GNUC__ >= 3
/* GCC supports '__inline__' as an extension */
# define MHDX_INLINE __inline__
# else
# define MHDX_INLINE /* empty */
# endif
/* Assume that 'inline' keyword works or the
* macro was already defined correctly. */
# define MHDX_INLINE inline
#endif
/* Bits manipulation macros and functions.
+2 -1
View File
@@ -131,7 +131,8 @@ curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
void Curl_thread_destroy(curl_thread_t hnd)
{
CloseHandle(hnd);
if(hnd != curl_thread_t_null)
CloseHandle(hnd);
}
int Curl_thread_join(curl_thread_t *hnd)
+72 -9
View File
@@ -111,21 +111,30 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
/* Curl_infof() is for info message along the way */
#define MAXINFO 2048
static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
const char * const fmt, va_list ap) CURL_PRINTF(3, 0);
static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
const char * const fmt, va_list ap)
{
int len = 0;
char buffer[MAXINFO + 2];
if(feat)
len = msnprintf(buffer, MAXINFO, "[%s] ", feat->name);
len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
buffer[len++] = '\n';
buffer[len] = '\0';
Curl_debug(data, CURLINFO_TEXT, buffer, len);
}
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
if(Curl_trc_is_verbose(data)) {
va_list ap;
int len = 0;
char buffer[MAXINFO + 2];
if(data->state.feat)
len = msnprintf(buffer, MAXINFO, "[%s] ", data->state.feat->name);
va_start(ap, fmt);
len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
trc_infof(data, data->state.feat, fmt, ap);
va_end(ap);
buffer[len++] = '\n';
buffer[len] = '\0';
Curl_debug(data, CURLINFO_TEXT, buffer, len);
}
}
@@ -154,7 +163,61 @@ void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
}
}
struct curl_trc_feat Curl_trc_feat_read = {
"READ",
CURL_LOG_LVL_NONE,
};
struct curl_trc_feat Curl_trc_feat_write = {
"WRITE",
CURL_LOG_LVL_NONE,
};
void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_read, fmt, ap);
va_end(ap);
}
}
void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_write, fmt, ap);
va_end(ap);
}
}
#ifndef CURL_DISABLE_FTP
struct curl_trc_feat Curl_trc_feat_ftp = {
"FTP",
CURL_LOG_LVL_NONE,
};
void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
va_list ap;
va_start(ap, fmt);
trc_infof(data, &Curl_trc_feat_ftp, fmt, ap);
va_end(ap);
}
}
#endif /* !CURL_DISABLE_FTP */
static struct curl_trc_feat *trc_feats[] = {
&Curl_trc_feat_read,
&Curl_trc_feat_write,
#ifndef CURL_DISABLE_FTP
&Curl_trc_feat_ftp,
#endif
#ifndef CURL_DISABLE_DOH
&Curl_doh_trc,
#endif
@@ -188,7 +251,7 @@ static struct Curl_cftype *cf_types[] = {
&Curl_cft_haproxy,
&Curl_cft_socks_proxy,
#endif /* !CURL_DISABLE_PROXY */
#ifdef ENABLE_QUIC
#ifdef USE_HTTP3
&Curl_cft_http3,
#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+68 -7
View File
@@ -77,12 +77,32 @@ void Curl_failf(struct Curl_easy *data,
#define CURL_TRC_CF(data, cf, ...) \
do { if(Curl_trc_cf_is_verbose(cf, data)) \
Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0)
#define CURL_TRC_WRITE(data, ...) \
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) \
Curl_trc_write(data, __VA_ARGS__); } while(0)
#define CURL_TRC_READ(data, ...) \
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) \
Curl_trc_read(data, __VA_ARGS__); } while(0)
#ifndef CURL_DISABLE_FTP
#define CURL_TRC_FTP(data, ...) \
do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) \
Curl_trc_ftp(data, __VA_ARGS__); } while(0)
#endif /* !CURL_DISABLE_FTP */
#else /* CURL_HAVE_C99 */
#else
#define infof Curl_infof
#define CURL_TRC_CF Curl_trc_cf_infof
#define CURL_TRC_WRITE Curl_trc_write
#define CURL_TRC_READ Curl_trc_read
#ifndef CURL_DISABLE_FTP
#define CURL_TRC_FTP Curl_trc_ftp
#endif
#endif /* !CURL_HAVE_C99 */
#ifndef CURL_DISABLE_VERBOSE_STRINGS
/* informational messages enabled */
@@ -90,6 +110,8 @@ struct curl_trc_feat {
const char *name;
int log_level;
};
extern struct curl_trc_feat Curl_trc_feat_read;
extern struct curl_trc_feat Curl_trc_feat_write;
#define Curl_trc_is_verbose(data) \
((data) && (data)->set.verbose && \
@@ -97,10 +119,10 @@ struct curl_trc_feat {
((data)->state.feat->log_level >= CURL_LOG_LVL_INFO)))
#define Curl_trc_cf_is_verbose(cf, data) \
(Curl_trc_is_verbose(data) && \
(cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
(cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
#define Curl_trc_ft_is_verbose(data, ft) \
(Curl_trc_is_verbose(data) && \
(ft)->log_level >= CURL_LOG_LVL_INFO)
(Curl_trc_is_verbose(data) && \
(ft)->log_level >= CURL_LOG_LVL_INFO)
/**
* Output an informational message when transfer's verbose logging is enabled.
@@ -114,13 +136,26 @@ void Curl_infof(struct Curl_easy *data,
*/
void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
const char *fmt, ...) CURL_PRINTF(3, 4);
void Curl_trc_ft_infof(struct Curl_easy *data, struct curl_trc_feat *ft,
const char *fmt, ...) CURL_PRINTF(3, 4);
void Curl_trc_write(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
void Curl_trc_read(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
#ifndef CURL_DISABLE_FTP
extern struct curl_trc_feat Curl_trc_feat_ftp;
void Curl_trc_ftp(struct Curl_easy *data,
const char *fmt, ...) CURL_PRINTF(2, 3);
#endif
#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
/* All informational messages are not compiled in for size savings */
#define Curl_trc_is_verbose(d) ((void)(d), FALSE)
#define Curl_trc_cf_is_verbose(x,y) ((void)(x), (void)(y), FALSE)
#define Curl_trc_ft_is_verbose(x,y) ((void)(x), (void)(y), FALSE)
#define Curl_trc_is_verbose(d) (FALSE)
#define Curl_trc_cf_is_verbose(x,y) (FALSE)
#define Curl_trc_ft_is_verbose(x,y) (FALSE)
static void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
{
@@ -134,6 +169,32 @@ static void Curl_trc_cf_infof(struct Curl_easy *data,
(void)data; (void)cf; (void)fmt;
}
struct curl_trc_feat;
static void Curl_trc_ft_infof(struct Curl_easy *data,
struct curl_trc_feat *ft,
const char *fmt, ...)
{
(void)data; (void)ft; (void)fmt;
}
static void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
{
(void)data; (void)fmt;
}
static void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
{
(void)data; (void)fmt;
}
#ifndef CURL_DISABLE_FTP
static void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
{
(void)data; (void)fmt;
}
#endif
#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
#endif /* HEADER_CURL_TRC_H */
-1
View File
@@ -77,7 +77,6 @@
*/
#define curlx_getenv curl_getenv
#define curlx_mvsnprintf curl_mvsnprintf
#define curlx_msnprintf curl_msnprintf
#define curlx_maprintf curl_maprintf
+52 -15
View File
@@ -102,6 +102,8 @@ static void cw_out_buf_free(struct cw_out_buf *cwbuf)
struct cw_out_ctx {
struct Curl_cwriter super;
struct cw_out_buf *buf;
BIT(paused);
BIT(errored);
};
static CURLcode cw_out_write(struct Curl_easy *data,
@@ -201,7 +203,10 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
size_t max_write, min_write;
size_t wlen, nwritten;
(void)ctx;
/* If we errored once, we do not invoke the client callback again */
if(ctx->errored)
return CURLE_WRITE_ERROR;
/* write callbacks may get NULLed by the client between calls. */
cw_get_writefunc(data, otype, &wcb, &wcb_data, &max_write, &min_write);
if(!wcb) {
@@ -210,13 +215,16 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
}
*pconsumed = 0;
while(blen && !(data->req.keepon & KEEP_RECV_PAUSE)) {
while(blen && !ctx->paused) {
if(!flush_all && blen < min_write)
break;
wlen = max_write? CURLMIN(blen, max_write) : blen;
Curl_set_in_callback(data, TRUE);
nwritten = wcb((char *)buf, 1, wlen, wcb_data);
Curl_set_in_callback(data, FALSE);
CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
wlen, (otype == CW_OUT_BODY)? "body" : "header",
nwritten);
if(CURL_WRITEFUNC_PAUSE == nwritten) {
if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
/* Protocols that work without network cannot be paused. This is
@@ -227,9 +235,15 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
}
/* mark the connection as RECV paused */
data->req.keepon |= KEEP_RECV_PAUSE;
ctx->paused = TRUE;
CURL_TRC_WRITE(data, "cw_out, PAUSE requested by client");
break;
}
if(nwritten != wlen) {
else if(CURL_WRITEFUNC_ERROR == nwritten) {
failf(data, "client returned ERROR on write of %zu bytes", wlen);
return CURLE_WRITE_ERROR;
}
else if(nwritten != wlen) {
failf(data, "Failure writing output to destination, "
"passed %zu returned %zd", wlen, nwritten);
return CURLE_WRITE_ERROR;
@@ -283,7 +297,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
if(!cwbuf)
return CURLE_OK;
if(data->req.keepon & KEEP_RECV_PAUSE)
if(ctx->paused)
return CURLE_OK;
/* write the end of the chain until it blocks or gets empty */
@@ -296,7 +310,7 @@ static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
return result;
if(*plast) {
/* could not write last, paused again? */
DEBUGASSERT(data->req.keepon & KEEP_RECV_PAUSE);
DEBUGASSERT(ctx->paused);
return CURLE_OK;
}
}
@@ -338,14 +352,14 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
bool flush_all,
const char *buf, size_t blen)
{
CURLcode result;
CURLcode result = CURLE_OK;
/* if we have buffered data and it is a different type than what
* we are writing now, try to flush all */
if(ctx->buf && ctx->buf->type != otype) {
result = cw_out_flush_chain(ctx, data, &ctx->buf, TRUE);
if(result)
return result;
goto out;
}
if(ctx->buf) {
@@ -355,7 +369,7 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
return result;
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
if(result)
return result;
goto out;
}
else {
/* nothing buffered, try direct write */
@@ -368,10 +382,18 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
/* did not write all, append the rest */
result = cw_out_append(ctx, otype, buf + consumed, blen - consumed);
if(result)
return result;
goto out;
}
}
return CURLE_OK;
out:
if(result) {
/* We do not want to invoked client callbacks a second time after
* encountering an error. See issue #13337 */
ctx->errored = TRUE;
cw_out_bufs_free(ctx);
}
return result;
}
static CURLcode cw_out_write(struct Curl_easy *data,
@@ -409,10 +431,12 @@ bool Curl_cw_out_is_paused(struct Curl_easy *data)
return FALSE;
ctx = (struct cw_out_ctx *)cw_out;
return cw_out_bufs_len(ctx) > 0;
CURL_TRC_WRITE(data, "cw-out is%spaused", ctx->paused? "" : " not");
return ctx->paused;
}
static CURLcode cw_out_flush(struct Curl_easy *data, bool flush_all)
static CURLcode cw_out_flush(struct Curl_easy *data,
bool unpause, bool flush_all)
{
struct Curl_cwriter *cw_out;
CURLcode result = CURLE_OK;
@@ -420,18 +444,31 @@ static CURLcode cw_out_flush(struct Curl_easy *data, bool flush_all)
cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
if(cw_out) {
struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
if(ctx->errored)
return CURLE_WRITE_ERROR;
if(unpause && ctx->paused)
ctx->paused = FALSE;
if(ctx->paused)
return CURLE_OK; /* not doing it */
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
if(result) {
ctx->errored = TRUE;
cw_out_bufs_free(ctx);
return result;
}
}
return result;
}
CURLcode Curl_cw_out_flush(struct Curl_easy *data)
CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
{
return cw_out_flush(data, FALSE);
CURL_TRC_WRITE(data, "cw-out unpause");
return cw_out_flush(data, TRUE, FALSE);
}
CURLcode Curl_cw_out_done(struct Curl_easy *data)
{
return cw_out_flush(data, TRUE);
CURL_TRC_WRITE(data, "cw-out done");
return cw_out_flush(data, FALSE, TRUE);
}
+1 -1
View File
@@ -43,7 +43,7 @@ bool Curl_cw_out_is_paused(struct Curl_easy *data);
/**
* Flush any buffered date to the client, chunk collation still applies.
*/
CURLcode Curl_cw_out_flush(struct Curl_easy *data);
CURLcode Curl_cw_out_unpause(struct Curl_easy *data);
/**
* Mark EndOfStream reached and flush ALL data to the client.
+2 -1
View File
@@ -76,7 +76,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_dict = {
"DICT", /* scheme */
"dict", /* scheme */
ZERO_NULL, /* setup_connection */
dict_do, /* do_it */
ZERO_NULL, /* done */
@@ -90,6 +90,7 @@ const struct Curl_handler Curl_handler_dict = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_DICT, /* defport */
+81
View File
@@ -0,0 +1,81 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#ifdef USE_OPENSSL
#include <openssl/crypto.h>
#endif
/* The fourth-to-last include */
#ifdef __CYGWIN__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef _WIN32
#undef _WIN32
#endif
#endif
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
/* DllMain() must only be defined for Windows and Cygwin DLL builds. */
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(CURL_STATICLIB)
#if defined(USE_OPENSSL) && \
!defined(OPENSSL_IS_AWSLC) && \
!defined(OPENSSL_IS_BORINGSSL) && \
!defined(LIBRESSL_VERSION_NUMBER) && \
(OPENSSL_VERSION_NUMBER >= 0x10100000L)
#define PREVENT_OPENSSL_MEMLEAK
#endif
#ifdef PREVENT_OPENSSL_MEMLEAK
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
(void)hinstDLL;
(void)lpvReserved;
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
/* Call OPENSSL_thread_stop to prevent a memory leak in case OpenSSL is
linked statically.
https://github.com/curl/curl/issues/12327#issuecomment-1826405944 */
OPENSSL_thread_stop();
break;
}
return TRUE;
}
#endif /* OpenSSL */
#endif /* DLL build */
+403 -6
View File
@@ -42,9 +42,13 @@
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
#include "escape.h"
#define DNS_CLASS_IN 0x01
/* local_print_buf truncates if the hex string will be more than this */
#define LOCAL_PB_HEXMAX 400
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char * const errors[]={
"",
@@ -187,6 +191,26 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
return realsize;
}
#if defined(USE_HTTPSRR) && defined(CURLDEBUG)
static void local_print_buf(struct Curl_easy *data,
const char *prefix,
unsigned char *buf, size_t len)
{
unsigned char hexstr[LOCAL_PB_HEXMAX];
size_t hlen = LOCAL_PB_HEXMAX;
bool truncated = false;
if(len > (LOCAL_PB_HEXMAX / 2))
truncated = true;
Curl_hexencode(buf, len, hexstr, hlen);
if(!truncated)
infof(data, "%s: len=%d, val=%s", prefix, (int)len, hexstr);
else
infof(data, "%s: len=%d (truncated)val=%s", prefix, (int)len, hexstr);
return;
}
#endif
/* called from multi.c when this DoH transfer is complete */
static int doh_done(struct Curl_easy *doh, CURLcode result)
{
@@ -379,6 +403,12 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
int slot;
struct dohdata *dohp;
struct connectdata *conn = data->conn;
#ifdef USE_HTTPSRR
/* for now, this is only used when ECH is enabled */
# ifdef USE_ECH
char *qname = NULL;
# endif
#endif
*waitp = FALSE;
(void)hostname;
(void)port;
@@ -408,7 +438,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
goto error;
dohp->pending++;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
/* create IPv6 DoH request */
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
@@ -418,6 +448,37 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
goto error;
dohp->pending++;
}
#endif
#ifdef USE_HTTPSRR
/*
* TODO: Figure out the conditions under which we want to make
* a request for an HTTPS RR when we are not doing ECH. For now,
* making this request breaks a bunch of DoH tests, e.g. test2100,
* where the additional request doesn't match the pre-cooked data
* files, so there's a bit of work attached to making the request
* in a non-ECH use-case. For the present, we'll only make the
* request when ECH is enabled in the build and is being used for
* the curl operation.
*/
# ifdef USE_ECH
if(data->set.tls_ech & CURLECH_ENABLE
|| data->set.tls_ech & CURLECH_HARD) {
if(port == 443)
qname = strdup(hostname);
else
qname = aprintf("_%d._https.%s", port, hostname);
if(!qname)
goto error;
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_HTTPS],
DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
data->multi, dohp->headers);
free(qname);
if(result)
goto error;
dohp->pending++;
}
# endif
#endif
*waitp = TRUE; /* this never returns synchronously */
return NULL;
@@ -501,6 +562,25 @@ static DOHcode store_aaaa(const unsigned char *doh,
return DOH_OK;
}
#ifdef USE_HTTPSRR
static DOHcode store_https(const unsigned char *doh,
int index,
struct dohentry *d,
uint16_t len)
{
/* silently ignore RRs over the limit */
if(d->numhttps_rrs < DOH_MAX_HTTPS) {
struct dohhttps_rr *h = &d->https_rrs[d->numhttps_rrs];
h->val = Curl_memdup(&doh[index], len);
if(!h->val)
return DOH_OUT_OF_MEM;
h->len = len;
d->numhttps_rrs++;
}
return DOH_OK;
}
#endif
static DOHcode store_cname(const unsigned char *doh,
size_t dohlen,
unsigned int index,
@@ -563,7 +643,8 @@ static DOHcode rdata(const unsigned char *doh,
/* RDATA
- A (TYPE 1): 4 bytes
- AAAA (TYPE 28): 16 bytes
- NS (TYPE 2): N bytes */
- NS (TYPE 2): N bytes
- HTTPS (TYPE 65): N bytes */
DOHcode rc;
switch(type) {
@@ -581,6 +662,13 @@ static DOHcode rdata(const unsigned char *doh,
if(rc)
return rc;
break;
#ifdef USE_HTTPSRR
case DNS_TYPE_HTTPS:
rc = store_https(doh, index, d, rdlength);
if(rc)
return rc;
break;
#endif
case DNS_TYPE_CNAME:
rc = store_cname(doh, dohlen, index, d);
if(rc)
@@ -737,7 +825,11 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
if(index != dohlen)
return DOH_DNS_MALFORMAT; /* something is wrong */
#ifdef USE_HTTTPS
if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr && !d->numhttps_rrs)
#else
if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr)
#endif
/* nothing stored! */
return DOH_NO_CONTENT;
@@ -776,6 +868,16 @@ static void showdoh(struct Curl_easy *data,
infof(data, "%s", buffer);
}
}
#ifdef USE_HTTPSRR
for(i = 0; i < d->numhttps_rrs; i++) {
# ifdef CURLDEBUG
local_print_buf(data, "DoH HTTPS",
d->https_rrs[i].val, d->https_rrs[i].len);
# else
infof(data, "DoH HTTPS RR: length %d", d->https_rrs[i].len);
# endif
}
#endif
for(i = 0; i < d->numcname; i++) {
infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
}
@@ -804,7 +906,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
struct Curl_addrinfo *prevai = NULL;
struct Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct sockaddr_in6 *addr6;
#endif
CURLcode result = CURLE_OK;
@@ -820,7 +922,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
size_t ss_size;
CURL_SA_FAMILY_T addrtype;
if(de->addr[i].type == DNS_TYPE_AAAA) {
#ifndef ENABLE_IPV6
#ifndef USE_IPV6
/* we can't handle IPv6 addresses */
continue;
#else
@@ -869,7 +971,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
addr->sin_port = htons((unsigned short)port);
break;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
case AF_INET6:
addr6 = (void *)ai->ai_addr; /* storage area for this info */
DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
@@ -895,7 +997,18 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char *type2name(DNStype dnstype)
{
return (dnstype == DNS_TYPE_A)?"A":"AAAA";
switch(dnstype) {
case DNS_TYPE_A:
return "A";
case DNS_TYPE_AAAA:
return "AAAA";
#ifdef USE_HTTPSRR
case DNS_TYPE_HTTPS:
return "HTTPS";
#endif
default:
return "unknown";
}
}
#endif
@@ -905,8 +1018,270 @@ UNITTEST void de_cleanup(struct dohentry *d)
for(i = 0; i < d->numcname; i++) {
Curl_dyn_free(&d->cname[i]);
}
#ifdef USE_HTTPSRR
for(i = 0; i < d->numhttps_rrs; i++)
free(d->https_rrs[i].val);
#endif
}
#ifdef USE_HTTPSRR
/*
* @brief decode the DNS name in a binary RRData
* @param buf points to the buffer (in/out)
* @param remaining points to the remaining buffer length (in/out)
* @param dnsname returns the string form name on success
* @return is 1 for success, error otherwise
*
* The encoding here is defined in
* https://tools.ietf.org/html/rfc1035#section-3.1
*
* The input buffer pointer will be modified so it points to
* just after the end of the DNS name encoding on output. (And
* that's why it's an "unsigned char **" :-)
*/
static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
char **dnsname)
{
unsigned char *cp = NULL;
int rem = 0;
unsigned char clen = 0; /* chunk len */
struct dynbuf thename;
DEBUGASSERT(buf && remaining && dnsname);
if(!buf || !remaining || !dnsname)
return CURLE_OUT_OF_MEMORY;
rem = (int)*remaining;
if(rem <= 0) {
Curl_dyn_free(&thename);
return CURLE_OUT_OF_MEMORY;
}
Curl_dyn_init(&thename, CURL_MAXLEN_host_name);
cp = *buf;
clen = *cp++;
if(clen == 0) {
/* special case - return "." as name */
if(Curl_dyn_addn(&thename, ".", 1))
return CURLE_OUT_OF_MEMORY;
}
while(clen) {
if(clen >= rem) {
Curl_dyn_free(&thename);
return CURLE_OUT_OF_MEMORY;
}
if(Curl_dyn_addn(&thename, cp, clen) ||
Curl_dyn_addn(&thename, ".", 1))
return CURLE_TOO_LARGE;
cp += clen;
rem -= (clen + 1);
if(rem <= 0) {
Curl_dyn_free(&thename);
return CURLE_OUT_OF_MEMORY;
}
clen = *cp++;
}
*buf = cp;
*remaining = rem - 1;
*dnsname = Curl_dyn_ptr(&thename);
return CURLE_OK;
}
static CURLcode local_decode_rdata_alpn(unsigned char *rrval, size_t len,
char **alpns)
{
/*
* spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
* encoding is catenated list of strings each preceded by a one
* octet length
* output is comma-sep list of the strings
* implementations may or may not handle quoting of comma within
* string values, so we might see a comma within the wire format
* version of a string, in which case we'll precede that by a
* backslash - same goes for a backslash character, and of course
* we need to use two backslashes in strings when we mean one;-)
*/
int remaining = (int) len;
char *oval;
size_t i;
unsigned char *cp = rrval;
struct dynbuf dval;
if(!alpns)
return CURLE_OUT_OF_MEMORY;
Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
remaining = (int)len;
cp = rrval;
while(remaining > 0) {
size_t tlen = (size_t) *cp++;
/* if not 1st time, add comma */
if(remaining != (int)len && Curl_dyn_addn(&dval, ",", 1))
goto err;
remaining--;
if(tlen > (size_t)remaining)
goto err;
/* add escape char if needed, clunky but easier to read */
for(i = 0; i != tlen; i++) {
if('\\' == *cp || ',' == *cp) {
if(Curl_dyn_addn(&dval, "\\", 1))
goto err;
}
if(Curl_dyn_addn(&dval, cp++, 1))
goto err;
}
remaining -= (int)tlen;
}
/* this string is always null terminated */
oval = Curl_dyn_ptr(&dval);
if(!oval)
goto err;
*alpns = oval;
return CURLE_OK;
err:
Curl_dyn_free(&dval);
return CURLE_BAD_CONTENT_ENCODING;
}
#ifdef CURLDEBUG
static CURLcode test_alpn_escapes(void)
{
/* we'll use an example from draft-ietf-dnsop-svcb, figure 10 */
static unsigned char example[] = {
0x08, /* length 8 */
0x66, 0x5c, 0x6f, 0x6f, 0x2c, 0x62, 0x61, 0x72, /* value "f\\oo,bar" */
0x02, /* length 2 */
0x68, 0x32 /* value "h2" */
};
size_t example_len = sizeof(example);
char *aval = NULL;
static const char *expected = "f\\\\oo\\,bar,h2";
if(local_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
return CURLE_BAD_CONTENT_ENCODING;
if(strlen(aval) != strlen(expected))
return CURLE_BAD_CONTENT_ENCODING;
if(memcmp(aval, expected, strlen(aval)))
return CURLE_BAD_CONTENT_ENCODING;
return CURLE_OK;
}
#endif
static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
struct Curl_https_rrinfo **hrr)
{
size_t remaining = len;
unsigned char *cp = rrval;
uint16_t pcode = 0, plen = 0;
struct Curl_https_rrinfo *lhrr = NULL;
char *dnsname = NULL;
#ifdef CURLDEBUG
/* a few tests of escaping, shouldn't be here but ok for now */
if(test_alpn_escapes() != CURLE_OK)
return CURLE_OUT_OF_MEMORY;
#endif
lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
if(!lhrr)
return CURLE_OUT_OF_MEMORY;
lhrr->val = Curl_memdup(rrval, len);
if(!lhrr->val)
goto err;
lhrr->len = len;
if(remaining <= 2)
goto err;
lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
cp += 2;
remaining -= (uint16_t)2;
if(local_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
goto err;
lhrr->target = dnsname;
while(remaining >= 4) {
pcode = (uint16_t)((*cp << 8) + (*(cp + 1)));
cp += 2;
plen = (uint16_t)((*cp << 8) + (*(cp + 1)));
cp += 2;
remaining -= 4;
if(pcode == HTTPS_RR_CODE_ALPN) {
if(local_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
goto err;
}
if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
lhrr->no_def_alpn = TRUE;
else if(pcode == HTTPS_RR_CODE_IPV4) {
lhrr->ipv4hints = Curl_memdup(cp, plen);
if(!lhrr->ipv4hints)
goto err;
lhrr->ipv4hints_len = (size_t)plen;
}
else if(pcode == HTTPS_RR_CODE_ECH) {
lhrr->echconfiglist = Curl_memdup(cp, plen);
if(!lhrr->echconfiglist)
goto err;
lhrr->echconfiglist_len = (size_t)plen;
}
else if(pcode == HTTPS_RR_CODE_IPV6) {
lhrr->ipv6hints = Curl_memdup(cp, plen);
if(!lhrr->ipv6hints)
goto err;
lhrr->ipv6hints_len = (size_t)plen;
}
if(plen > 0 && plen <= remaining) {
cp += plen;
remaining -= plen;
}
}
DEBUGASSERT(!remaining);
*hrr = lhrr;
return CURLE_OK;
err:
if(lhrr) {
free(lhrr->target);
free(lhrr->echconfiglist);
free(lhrr->val);
free(lhrr);
}
return CURLE_OUT_OF_MEMORY;
}
# ifdef CURLDEBUG
static void local_print_httpsrr(struct Curl_easy *data,
struct Curl_https_rrinfo *hrr)
{
DEBUGASSERT(hrr);
infof(data, "HTTPS RR: priority %d, target: %s",
hrr->priority, hrr->target);
if(hrr->alpns)
infof(data, "HTTPS RR: alpns %s", hrr->alpns);
else
infof(data, "HTTPS RR: no alpns");
if(hrr->no_def_alpn)
infof(data, "HTTPS RR: no_def_alpn set");
else
infof(data, "HTTPS RR: no_def_alpn not set");
if(hrr->ipv4hints) {
local_print_buf(data, "HTTPS RR: ipv4hints",
hrr->ipv4hints, hrr->ipv4hints_len);
}
else
infof(data, "HTTPS RR: no ipv4hints");
if(hrr->echconfiglist) {
local_print_buf(data, "HTTPS RR: ECHConfigList",
hrr->echconfiglist, hrr->echconfiglist_len);
}
else
infof(data, "HTTPS RR: no ECHConfigList");
if(hrr->ipv6hints) {
local_print_buf(data, "HTTPS RR: ipv6hint",
hrr->ipv6hints, hrr->ipv6hints_len);
}
else
infof(data, "HTTPS RR: no ipv6hints");
return;
}
# endif
#endif
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dnsp)
{
@@ -923,9 +1298,15 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
CURLE_COULDNT_RESOLVE_HOST;
}
else if(!dohp->pending) {
#ifndef USE_HTTPSRR
DOHcode rc[DOH_PROBE_SLOTS] = {
DOH_OK, DOH_OK
};
#else
DOHcode rc[DOH_PROBE_SLOTS] = {
DOH_OK, DOH_OK, DOH_OK
};
#endif
struct dohentry de;
int slot;
/* remove DoH handles from multi handle and close them */
@@ -991,6 +1372,22 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
} /* address processing done */
/* Now process any build-specific attributes retrieved from DNS */
#ifdef USE_HTTPSRR
if(de.numhttps_rrs > 0 && result == CURLE_OK && *dnsp) {
struct Curl_https_rrinfo *hrr = NULL;
result = Curl_doh_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
&hrr);
if(result) {
infof(data, "Failed to decode HTTPS RR");
return result;
}
infof(data, "Some HTTPS RR to process");
# ifdef CURLDEBUG
local_print_httpsrr(data, hrr);
# endif
(*dnsp)->hinfo = hrr;
}
#endif
/* All done */
de_cleanup(&de);
+38 -3
View File
@@ -26,6 +26,9 @@
#include "urldata.h"
#include "curl_addrinfo.h"
#ifdef USE_HTTPSRR
# include <stdint.h>
#endif
#ifndef CURL_DISABLE_DOH
@@ -51,7 +54,8 @@ typedef enum {
DNS_TYPE_NS = 2,
DNS_TYPE_CNAME = 5,
DNS_TYPE_AAAA = 28,
DNS_TYPE_DNAME = 39 /* RFC6672 */
DNS_TYPE_DNAME = 39, /* RFC6672 */
DNS_TYPE_HTTPS = 65
} DNStype;
/* one of these for each DoH request */
@@ -84,10 +88,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns);
int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks);
#define DOH_MAX_ADDR 24
#define DOH_MAX_CNAME 4
#define DOH_MAX_HTTPS 4
struct dohaddr {
int type;
@@ -97,12 +100,44 @@ struct dohaddr {
} ip;
};
#ifdef USE_HTTPSRR
/*
* These are the code points for DNS wire format SvcParams as
* per draft-ietf-dnsop-svcb-https
* Not all are supported now, and even those that are may need
* more work in future to fully support the spec.
*/
#define HTTPS_RR_CODE_ALPN 0x01
#define HTTPS_RR_CODE_NO_DEF_ALPN 0x02
#define HTTPS_RR_CODE_PORT 0x03
#define HTTPS_RR_CODE_IPV4 0x04
#define HTTPS_RR_CODE_ECH 0x05
#define HTTPS_RR_CODE_IPV6 0x06
/*
* These may need escaping when found within an alpn string
* value.
*/
#define COMMA_CHAR ','
#define BACKSLASH_CHAR '\\'
struct dohhttps_rr {
uint16_t len; /* raw encoded length */
unsigned char *val; /* raw encoded octets */
};
#endif
struct dohentry {
struct dynbuf cname[DOH_MAX_CNAME];
struct dohaddr addr[DOH_MAX_ADDR];
int numaddr;
unsigned int ttl;
int numcname;
#ifdef USE_HTTPSRR
struct dohhttps_rr https_rrs[DOH_MAX_HTTPS];
int numhttps_rrs;
#endif
};
+1 -1
View File
@@ -213,7 +213,7 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
}
/* If we failed, we cleanup the whole buffer and return error */
Curl_dyn_free(s);
return CURLE_OK;
return CURLE_OUT_OF_MEMORY;
#endif
}
+37 -39
View File
@@ -58,7 +58,6 @@
#include "multiif.h"
#include "select.h"
#include "cfilters.h"
#include "cw-out.h"
#include "sendf.h" /* for failf function prototype */
#include "connect.h" /* for Curl_getconnectinfo */
#include "slist.h"
@@ -729,6 +728,8 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
/* clear this as early as possible */
data->set.errorbuffer[0] = 0;
data->state.os_errno = 0;
if(data->multi) {
failf(data, "easy handle already used in multi handle");
return CURLE_FAILED_INIT;
@@ -1086,6 +1087,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
int oldstate;
int newstate;
bool recursive = FALSE;
bool keep_changed, unpause_read, not_all_paused;
if(!GOOD_EASY_HANDLE(data) || !data->conn)
/* crazy input, don't continue */
@@ -1101,51 +1103,47 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
/* Not changing any pause state, return */
DEBUGF(infof(data, "pause: no change, early return"));
return CURLE_OK;
}
keep_changed = ((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) != oldstate);
not_all_paused = (newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE);
unpause_read = ((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
(data->mstate == MSTATE_PERFORMING ||
data->mstate == MSTATE_RATELIMITING));
/* Unpausing writes is detected on the next run in
* transfer.c:Curl_readwrite(). This is because this may result
* in a transfer error if the application's callbacks fail */
/* Unpause parts in active mime tree. */
if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
(data->mstate == MSTATE_PERFORMING ||
data->mstate == MSTATE_RATELIMITING)) {
result = Curl_creader_unpause(data);
if(result)
return result;
}
/* put it back in the keepon */
/* Set the new keepon state, so it takes effect no matter what error
* may happen afterwards. */
k->keepon = newstate;
if(!(newstate & KEEP_RECV_PAUSE)) {
Curl_conn_ev_data_pause(data, FALSE);
result = Curl_cw_out_flush(data);
if(result)
return result;
}
/* if there's no error and we're not pausing both directions, we want
to have this handle checked soon */
if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
/* If not completely pausing both directions now, run again in any case. */
if(not_all_paused) {
Curl_expire(data, 0, EXPIRE_RUN_NOW);
/* reset the too-slow time keeper */
data->state.keeps_speed.tv_sec = 0;
if(!Curl_cw_out_is_paused(data))
/* if not pausing again, force a recv/send check of this connection as
the data might've been read off the socket already */
data->state.select_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
if(data->multi) {
if(Curl_update_timer(data->multi))
return CURLE_ABORTED_BY_CALLBACK;
/* Simulate socket events on next run for unpaused directions */
if(!(newstate & KEEP_SEND_PAUSE))
data->state.select_bits |= CURL_CSELECT_OUT;
if(!(newstate & KEEP_RECV_PAUSE))
data->state.select_bits |= CURL_CSELECT_IN;
/* On changes, tell application to update its timers. */
if(keep_changed && data->multi) {
if(Curl_update_timer(data->multi)) {
result = CURLE_ABORTED_BY_CALLBACK;
goto out;
}
}
}
if(!data->state.done)
if(unpause_read) {
result = Curl_creader_unpause(data);
if(result)
goto out;
}
out:
if(!result && !data->state.done && keep_changed)
/* This transfer may have been moved in or out of the bundle, update the
corresponding socket callback, if used */
result = Curl_updatesocket(data);
@@ -1305,7 +1303,7 @@ static int conn_upkeep(struct Curl_easy *data,
conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
}
else {
/* Do the generic action on the FIRSTSOCKE filter chain */
/* Do the generic action on the FIRSTSOCKET filter chain */
Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
}
Curl_detach_connection(data);
+2 -1
View File
@@ -86,6 +86,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0},
{"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
{"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0},
{"ECH", CURLOPT_ECH, CURLOT_STRING, 0},
{"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0},
{"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS},
{"ERRORBUFFER", CURLOPT_ERRORBUFFER, CURLOT_OBJECT, 0},
@@ -375,6 +376,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
return ((CURLOPT_LASTENTRY%10000) != (324 + 1));
return ((CURLOPT_LASTENTRY%10000) != (325 + 1));
}
#endif
+82 -40
View File
@@ -50,6 +50,14 @@
#include <fcntl.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#include "strtoofft.h"
#include "urldata.h"
#include <curl/curl.h>
@@ -101,7 +109,7 @@ static CURLcode file_setup_connection(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_file = {
"FILE", /* scheme */
"file", /* scheme */
file_setup_connection, /* setup_connection */
file_do, /* do_it */
file_done, /* done */
@@ -115,6 +123,7 @@ const struct Curl_handler Curl_handler_file = {
ZERO_NULL, /* perform_getsock */
file_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
0, /* defport */
@@ -446,12 +455,9 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
fstated = TRUE;
}
if(fstated && !data->state.range && data->set.timecondition) {
if(!Curl_meets_timecondition(data, data->info.filetime)) {
*done = TRUE;
return CURLE_OK;
}
}
if(fstated && !data->state.range && data->set.timecondition &&
!Curl_meets_timecondition(data, data->info.filetime))
return CURLE_OK;
if(fstated) {
time_t filetime;
@@ -543,49 +549,85 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
Curl_pgrsSetDownloadSize(data, expected_size);
if(data->state.resume_from) {
if(data->state.resume_from !=
lseek(fd, data->state.resume_from, SEEK_SET))
if(!S_ISDIR(statbuf.st_mode)) {
if(data->state.resume_from !=
lseek(fd, data->state.resume_from, SEEK_SET))
return CURLE_BAD_DOWNLOAD_RESUME;
}
else {
return CURLE_BAD_DOWNLOAD_RESUME;
}
}
result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
if(result)
goto out;
while(!result) {
ssize_t nread;
/* Don't fill a whole buffer if we want less than all data */
size_t bytestoread;
if(!S_ISDIR(statbuf.st_mode)) {
while(!result) {
ssize_t nread;
/* Don't fill a whole buffer if we want less than all data */
size_t bytestoread;
if(size_known) {
bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
curlx_sotouz(expected_size) : (xfer_blen-1);
if(size_known) {
bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
curlx_sotouz(expected_size) : (xfer_blen-1);
}
else
bytestoread = xfer_blen-1;
nread = read(fd, xfer_buf, bytestoread);
if(nread > 0)
xfer_buf[nread] = 0;
if(nread <= 0 || (size_known && (expected_size == 0)))
break;
if(size_known)
expected_size -= nread;
result = Curl_client_write(data, CLIENTWRITE_BODY, xfer_buf, nread);
if(result)
goto out;
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else
result = Curl_speedcheck(data, Curl_now());
if(result)
goto out;
}
else
bytestoread = xfer_blen-1;
nread = read(fd, xfer_buf, bytestoread);
if(nread > 0)
xfer_buf[nread] = 0;
if(nread <= 0 || (size_known && (expected_size == 0)))
break;
if(size_known)
expected_size -= nread;
result = Curl_client_write(data, CLIENTWRITE_BODY, xfer_buf, nread);
if(result)
goto out;
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else
result = Curl_speedcheck(data, Curl_now());
if(result)
goto out;
}
else {
#ifdef HAVE_OPENDIR
DIR *dir = opendir(file->path);
struct dirent *entry;
if(!dir) {
result = CURLE_READ_ERROR;
goto out;
}
else {
while((entry = readdir(dir))) {
if(entry->d_name[0] != '.') {
result = Curl_client_write(data, CLIENTWRITE_BODY,
entry->d_name, strlen(entry->d_name));
if(result)
break;
result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
if(result)
break;
}
}
closedir(dir);
}
#else
failf(data, "Directory listing not yet implemented on this platform.");
result = CURLE_READ_ERROR;
#endif
}
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
+121 -102
View File
@@ -95,19 +95,89 @@
#ifdef CURL_DISABLE_VERBOSE_STRINGS
#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
#define FTP_CSTATE(c) ""
#define FTP_DSTATE(d) ""
#else /* CURL_DISABLE_VERBOSE_STRINGS */
/* for tracing purposes */
static const char * const ftp_state_names[]={
"STOP",
"WAIT220",
"AUTH",
"USER",
"PASS",
"ACCT",
"PBSZ",
"PROT",
"CCC",
"PWD",
"SYST",
"NAMEFMT",
"QUOTE",
"RETR_PREQUOTE",
"STOR_PREQUOTE",
"POSTQUOTE",
"CWD",
"MKD",
"MDTM",
"TYPE",
"LIST_TYPE",
"RETR_TYPE",
"STOR_TYPE",
"SIZE",
"RETR_SIZE",
"STOR_SIZE",
"REST",
"RETR_REST",
"PORT",
"PRET",
"PASV",
"LIST",
"RETR",
"STOR",
"QUIT"
};
#define FTP_CSTATE(c) ((c)? ftp_state_names[(c)->proto.ftpc.state] : "???")
#define FTP_DSTATE(d) (((d) && (d)->conn)? \
ftp_state_names[(d)->conn->proto.ftpc.state] : "???")
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
/* This is the ONLY way to change FTP state! */
static void _ftp_state(struct Curl_easy *data,
ftpstate newstate
#ifdef DEBUGBUILD
, int lineno
#endif
)
{
struct connectdata *conn = data->conn;
struct ftp_conn *ftpc = &conn->proto.ftpc;
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
#ifdef DEBUGBUILD
(void)lineno;
#endif
#else /* CURL_DISABLE_VERBOSE_STRINGS */
if(ftpc->state != newstate)
#ifdef DEBUGBUILD
CURL_TRC_FTP(data, "[%s] -> [%s] (line %d)", FTP_DSTATE(data),
ftp_state_names[newstate], lineno);
#else
CURL_TRC_FTP(data, "[%s] -> [%s]", FTP_DSTATE(data),
ftp_state_names[newstate]);
#endif
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
ftpc->state = newstate;
}
/* Local API functions */
#ifndef DEBUGBUILD
static void _ftp_state(struct Curl_easy *data,
ftpstate newstate);
#define ftp_state(x,y) _ftp_state(x,y)
#else
static void _ftp_state(struct Curl_easy *data,
ftpstate newstate,
int lineno);
#else /* !DEBUGBUILD */
#define ftp_state(x,y) _ftp_state(x,y,__LINE__)
#endif
#endif /* DEBUGBUILD */
static CURLcode ftp_sendquote(struct Curl_easy *data,
struct connectdata *conn,
@@ -163,7 +233,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_ftp = {
"FTP", /* scheme */
"ftp", /* scheme */
ftp_setup_connection, /* setup_connection */
ftp_do, /* do_it */
ftp_done, /* done */
@@ -177,6 +247,7 @@ const struct Curl_handler Curl_handler_ftp = {
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTP, /* defport */
@@ -194,7 +265,7 @@ const struct Curl_handler Curl_handler_ftp = {
*/
const struct Curl_handler Curl_handler_ftps = {
"FTPS", /* scheme */
"ftps", /* scheme */
ftp_setup_connection, /* setup_connection */
ftp_do, /* do_it */
ftp_done, /* done */
@@ -208,6 +279,7 @@ const struct Curl_handler Curl_handler_ftps = {
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTPS, /* defport */
@@ -221,6 +293,7 @@ const struct Curl_handler Curl_handler_ftps = {
static void close_secondarysocket(struct Curl_easy *data,
struct connectdata *conn)
{
CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_DSTATE(data));
Curl_conn_close(data, SECONDARYSOCKET);
Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
}
@@ -360,7 +433,7 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
struct connectdata *conn = data->conn;
curl_socket_t sock = conn->sock[SECONDARYSOCKET];
curl_socket_t s = CURL_SOCKET_BAD;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct Curl_sockaddr_storage add;
#else
struct sockaddr_in add;
@@ -386,8 +459,10 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
(void)curlx_nonblock(s, TRUE); /* enable non-blocking */
/* Replace any filter on SECONDARY with one listening on this socket */
result = Curl_conn_tcp_accepted_set(data, conn, SECONDARYSOCKET, &s);
if(result)
if(result) {
sclose(s);
return result;
}
if(data->set.fsockopt) {
int error = 0;
@@ -562,7 +637,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
struct connectdata *conn = data->conn;
bool connected;
DEBUGF(infof(data, "ftp InitiateTransfer()"));
CURL_TRC_FTP(data, "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);
@@ -645,7 +720,7 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
}
out:
DEBUGF(infof(data, "ftp AllowServerConnect() -> %d", result));
CURL_TRC_FTP(data, "AllowServerConnect() -> %d", result);
return result;
}
@@ -827,73 +902,6 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
return result;
}
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char * const ftp_state_names[]={
"STOP",
"WAIT220",
"AUTH",
"USER",
"PASS",
"ACCT",
"PBSZ",
"PROT",
"CCC",
"PWD",
"SYST",
"NAMEFMT",
"QUOTE",
"RETR_PREQUOTE",
"STOR_PREQUOTE",
"POSTQUOTE",
"CWD",
"MKD",
"MDTM",
"TYPE",
"LIST_TYPE",
"RETR_TYPE",
"STOR_TYPE",
"SIZE",
"RETR_SIZE",
"STOR_SIZE",
"REST",
"RETR_REST",
"PORT",
"PRET",
"PASV",
"LIST",
"RETR",
"STOR",
"QUIT"
};
#endif
/* This is the ONLY way to change FTP state! */
static void _ftp_state(struct Curl_easy *data,
ftpstate newstate
#ifdef DEBUGBUILD
, int lineno
#endif
)
{
struct connectdata *conn = data->conn;
struct ftp_conn *ftpc = &conn->proto.ftpc;
#if defined(DEBUGBUILD)
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) lineno;
#else
if(ftpc->state != newstate)
infof(data, "FTP %p (line %d) state change from %s to %s",
(void *)ftpc, lineno, ftp_state_names[ftpc->state],
ftp_state_names[newstate]);
#endif
#endif
ftpc->state = newstate;
}
static CURLcode ftp_state_user(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -937,7 +945,7 @@ static int ftp_domore_getsock(struct Curl_easy *data,
* remote site, or we could wait for that site to connect to us. Or just
* handle ordinary commands.
*/
DEBUGF(infof(data, "ftp_domore_getsock()"));
CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_DSTATE(data));
if(FTP_STOP == ftpc->state) {
/* if stopped and still in this state, then we're also waiting for a
@@ -1027,7 +1035,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
char hbuf[NI_MAXHOST];
struct sockaddr *sa = (struct sockaddr *)&ss;
struct sockaddr_in * const sa4 = (void *)sa;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct sockaddr_in6 * const sa6 = (void *)sa;
#endif
static const char mode[][5] = { "EPRT", "PORT" };
@@ -1054,7 +1062,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
(strlen(data->set.str[STRING_FTPPORT]) > 1)) {
char *ip_end = NULL;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
if(*string_ftpport == '[') {
/* [ipv6]:port(-range) */
char *ip_start = string_ftpport + 1;
@@ -1076,7 +1084,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(ip_end) {
/* either ipv6 or (ipv4|domain|interface):port(-range) */
addrlen = ip_end - string_ftpport;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
/* ipv6 */
port_min = port_max = 0;
@@ -1122,7 +1130,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* attempt to get the address of the given interface name */
switch(Curl_if2ip(conn->remote_addr->family,
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
Curl_ipv6_scope(&conn->remote_addr->sa_addr),
conn->scope_id,
#endif
@@ -1154,7 +1162,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
goto out;
}
switch(sa->sa_family) {
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
case AF_INET6:
r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
break;
@@ -1204,7 +1212,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(error, buffer, sizeof(buffer)));
goto out;
}
DEBUGF(infof(data, "ftp_state_use_port(), opened socket"));
CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), opened socket",
FTP_DSTATE(data));
/* step 3, bind to a suitable local address */
@@ -1214,7 +1223,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
for(port = port_min; port <= port_max;) {
if(sa->sa_family == AF_INET)
sa4->sin_port = htons(port);
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else
sa6->sin6_port = htons(port);
#endif
@@ -1265,7 +1274,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
goto out;
}
DEBUGF(infof(data, "ftp_state_use_port(), socket bound to port %d", port));
CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), socket bound to port %d",
FTP_DSTATE(data), port);
/* step 4, listen on the socket */
@@ -1274,7 +1284,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
goto out;
}
DEBUGF(infof(data, "ftp_state_use_port(), listening on %d", port));
CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), listening on %d",
FTP_DSTATE(data), port);
/* step 5, send the proper FTP command */
@@ -1282,7 +1293,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
below */
Curl_printable_address(ai, myhost, sizeof(myhost));
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
/* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
request and enable EPRT again! */
@@ -1309,7 +1320,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
case AF_INET:
port = ntohs(sa4->sin_port);
break;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
case AF_INET6:
port = ntohs(sa6->sin6_port);
break;
@@ -2349,7 +2360,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct ftp_conn *ftpc = &conn->proto.ftpc;
DEBUGF(infof(data, "ftp_state_retr()"));
CURL_TRC_FTP(data, "[%s] ftp_state_retr()", FTP_DSTATE(data));
if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
failf(data, "Maximum file size exceeded");
return CURLE_FILESIZE_EXCEEDED;
@@ -3064,7 +3075,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
DEBUGF(infof(data, "protocol connect phase DONE"));
CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
break;
case FTP_SYST:
@@ -3109,7 +3120,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
DEBUGF(infof(data, "protocol connect phase DONE"));
CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
break;
case FTP_NAMEFMT:
@@ -3120,7 +3131,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
DEBUGF(infof(data, "protocol connect phase DONE"));
CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
break;
case FTP_QUOTE:
@@ -3549,6 +3560,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
/* Send any post-transfer QUOTE strings? */
if(!status && !result && !premature && data->set.postquote)
result = ftp_sendquote(data, conn, data->set.postquote);
CURL_TRC_FTP(data, "[%s] done, result=%d", FTP_DSTATE(data), result);
Curl_safefree(ftp->pathalloc);
return result;
}
@@ -3817,7 +3829,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(!ftpc->wait_data_conn) {
/* no waiting for the data connection so this is now complete */
*completep = 1;
DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result));
CURL_TRC_FTP(data, "[%s] DO-MORE phase ends with %d", FTP_DSTATE(data),
(int)result);
}
return result;
@@ -3841,7 +3854,7 @@ CURLcode ftp_perform(struct Curl_easy *data,
/* this is FTP and no proxy */
CURLcode result = CURLE_OK;
DEBUGF(infof(data, "DO phase starts"));
CURL_TRC_FTP(data, "[%s] DO phase starts", FTP_DSTATE(data));
if(data->req.no_body) {
/* requested no body means no transfer... */
@@ -3861,10 +3874,15 @@ CURLcode ftp_perform(struct Curl_easy *data,
*connected = Curl_conn_is_connected(data->conn, SECONDARYSOCKET);
infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
if(*connected)
infof(data, "[FTP] [%s] perform, DATA connection established",
FTP_DSTATE(data));
else
CURL_TRC_FTP(data, "[%s] perform, awaiting DATA connect",
FTP_DSTATE(data));
if(*dophase_done) {
DEBUGF(infof(data, "DO phase is complete1"));
CURL_TRC_FTP(data, "[%s] DO phase is complete1", FTP_DSTATE(data));
}
return result;
@@ -4432,11 +4450,11 @@ static CURLcode ftp_doing(struct Curl_easy *data,
CURLcode result = ftp_multi_statemach(data, dophase_done);
if(result)
DEBUGF(infof(data, "DO phase failed"));
CURL_TRC_FTP(data, "[%s] DO phase failed", FTP_DSTATE(data));
else if(*dophase_done) {
result = ftp_dophase_done(data, FALSE /* not connected */);
DEBUGF(infof(data, "DO phase is complete2"));
CURL_TRC_FTP(data, "[%s] DO phase is complete2", FTP_DSTATE(data));
}
return result;
}
@@ -4560,6 +4578,7 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
ftpc->use_ssl = data->set.use_ssl;
ftpc->ccc = data->set.ftp_ccc;
CURL_TRC_FTP(data, "[%s] setup connection -> %d", FTP_CSTATE(conn), result);
return result;
}
+1 -1
View File
@@ -349,7 +349,7 @@ static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
Curl_set_in_callback(data, false);
if(add) {
Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
Curl_llist_append(llist, finfo, &infop->list);
}
else {
Curl_fileinfo_cleanup(infop);
+4
View File
@@ -161,7 +161,11 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
*param_charp = data->info.primary.local_ip;
break;
case CURLINFO_RTSP_SESSION_ID:
#ifndef CURL_DISABLE_RTSP
*param_charp = data->set.str[STRING_RTSP_SESSION_ID];
#else
*param_charp = NULL;
#endif
break;
case CURLINFO_SCHEME:
*param_charp = data->info.conn_scheme;
+4 -2
View File
@@ -62,7 +62,7 @@ static CURLcode gopher_connecting(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_gopher = {
"GOPHER", /* scheme */
"gopher", /* scheme */
ZERO_NULL, /* setup_connection */
gopher_do, /* do_it */
ZERO_NULL, /* done */
@@ -76,6 +76,7 @@ const struct Curl_handler Curl_handler_gopher = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
@@ -86,7 +87,7 @@ const struct Curl_handler Curl_handler_gopher = {
#ifdef USE_SSL
const struct Curl_handler Curl_handler_gophers = {
"GOPHERS", /* scheme */
"gophers", /* scheme */
ZERO_NULL, /* setup_connection */
gopher_do, /* do_it */
ZERO_NULL, /* done */
@@ -100,6 +101,7 @@ const struct Curl_handler Curl_handler_gophers = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
+30 -27
View File
@@ -57,7 +57,7 @@ hash_element_dtor(void *user, void *element)
*/
void
Curl_hash_init(struct Curl_hash *h,
int slots,
size_t slots,
hash_function hfunc,
comp_function comparator,
Curl_hash_dtor dtor)
@@ -111,7 +111,7 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
DEBUGASSERT(h);
DEBUGASSERT(h->slots);
if(!h->table) {
int i;
size_t i;
h->table = malloc(h->slots * sizeof(struct Curl_llist));
if(!h->table)
return NULL; /* OOM */
@@ -132,7 +132,7 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
he = mk_hash_element(key, key_len, p);
if(he) {
Curl_llist_insert_next(l, l->tail, he, &he->list);
Curl_llist_append(l, he, &he->list);
++h->size;
return p; /* return the new entry */
}
@@ -192,25 +192,6 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
return NULL;
}
#if defined(DEBUGBUILD) && defined(AGGRESSIVE_TEST)
void
Curl_hash_apply(Curl_hash *h, void *user,
void (*cb)(void *user, void *ptr))
{
struct Curl_llist_element *le;
int i;
for(i = 0; i < h->slots; ++i) {
for(le = (h->table[i])->head;
le;
le = le->next) {
Curl_hash_element *el = le->ptr;
cb(user, el->ptr);
}
}
}
#endif
/* Destroys all the entries in the given hash and resets its attributes,
* prepping the given hash for [static|dynamic] deallocation.
*
@@ -222,7 +203,7 @@ void
Curl_hash_destroy(struct Curl_hash *h)
{
if(h->table) {
int i;
size_t i;
for(i = 0; i < h->slots; ++i) {
Curl_llist_destroy(&h->table[i], (void *) h);
}
@@ -250,7 +231,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
struct Curl_llist_element *le;
struct Curl_llist_element *lnext;
struct Curl_llist *list;
int i;
size_t i;
if(!h || !h->table)
return;
@@ -316,7 +297,7 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
/* If we have reached the end of the list, find the next one */
if(!iter->current_element) {
int i;
size_t i;
for(i = iter->slot_index; i < h->slots; i++) {
if(h->table[i].head) {
iter->current_element = h->table[i].head;
@@ -339,7 +320,7 @@ void Curl_hash_print(struct Curl_hash *h,
{
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
int last_index = -1;
size_t last_index = ~0;
if(!h)
return;
@@ -352,7 +333,7 @@ void Curl_hash_print(struct Curl_hash *h,
while(he) {
if(iter.slot_index != last_index) {
fprintf(stderr, "index %d:", iter.slot_index);
if(last_index >= 0) {
if(last_index != ~0) {
fprintf(stderr, "\n");
}
last_index = iter.slot_index;
@@ -368,3 +349,25 @@ void Curl_hash_print(struct Curl_hash *h,
fprintf(stderr, "\n");
}
#endif
void Curl_hash_offt_init(struct Curl_hash *h,
size_t slots,
Curl_hash_dtor dtor)
{
Curl_hash_init(h, slots, Curl_hash_str, Curl_str_key_compare, dtor);
}
void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem)
{
return Curl_hash_add(h, &id, sizeof(id), elem);
}
int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id)
{
return Curl_hash_delete(h, &id, sizeof(id));
}
void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id)
{
return Curl_hash_pick(h, &id, sizeof(id));
}
+11 -5
View File
@@ -54,7 +54,7 @@ struct Curl_hash {
/* Comparator function to compare keys */
comp_function comp_func;
Curl_hash_dtor dtor;
int slots;
size_t slots;
size_t size;
};
@@ -67,12 +67,12 @@ struct Curl_hash_element {
struct Curl_hash_iterator {
struct Curl_hash *hash;
int slot_index;
size_t slot_index;
struct Curl_llist_element *current_element;
};
void Curl_hash_init(struct Curl_hash *h,
int slots,
size_t slots,
hash_function hfunc,
comp_function comparator,
Curl_hash_dtor dtor);
@@ -80,8 +80,6 @@ void Curl_hash_init(struct Curl_hash *h,
void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
void Curl_hash_apply(struct Curl_hash *h, void *user,
void (*cb)(void *user, void *ptr));
#define Curl_hash_count(h) ((h)->size)
void Curl_hash_destroy(struct Curl_hash *h);
void Curl_hash_clean(struct Curl_hash *h);
@@ -98,5 +96,13 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter);
void Curl_hash_print(struct Curl_hash *h,
void (*func)(void *));
/* Hash for `curl_off_t` as key */
void Curl_hash_offt_init(struct Curl_hash *h, size_t slots,
Curl_hash_dtor dtor);
void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem);
int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id);
void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id);
#endif /* HEADER_CURL_HASH_H */
+5 -5
View File
@@ -253,7 +253,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1);
if(!newhs)
return CURLE_OUT_OF_MEMORY;
/* ->name' and ->value point into ->buffer (to keep the header allocation
/* ->name and ->value point into ->buffer (to keep the header allocation
in a single memory block), which now potentially have moved. Adjust
them. */
newhs->name = newhs->buffer;
@@ -264,8 +264,7 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
newhs->value[olen + vlen] = 0; /* null-terminate at newline */
/* insert this node into the list of headers */
Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
newhs, &newhs->node);
Curl_llist_append(&data->state.httphdrs, newhs, &newhs->node);
data->state.prevhead = newhs;
return CURLE_OK;
}
@@ -328,8 +327,7 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
hs->request = data->state.requests;
/* insert this node into the list of headers */
Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
hs, &hs->node);
Curl_llist_append(&data->state.httphdrs, hs, &hs->node);
data->state.prevhead = hs;
}
else
@@ -361,6 +359,8 @@ static CURLcode hds_cw_collect_write(struct Curl_easy *data,
(type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
CURLH_HEADER)));
CURLcode result = Curl_headers_push(data, buf, htype);
CURL_TRC_WRITE(data, "header_collect pushed(type=%x, len=%zu) -> %d",
htype, blen, result);
if(result)
return result;
}
+33 -21
View File
@@ -144,7 +144,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
(void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
break;
}
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
case AF_INET6: {
const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr;
const struct in6_addr *ipaddr6 = &sa6->sin6_addr;
@@ -167,17 +167,12 @@ create_hostcache_id(const char *name,
int port, char *ptr, size_t buflen)
{
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--) {
*ptr++ = Curl_raw_tolower(*name++);
olen++;
}
olen += msnprintf(ptr, 7, ":%u", port);
return olen;
Curl_strntolower(ptr, name, len);
return msnprintf(&ptr[len], 7, ":%u", port) + len;
}
struct hostcache_prune_data {
@@ -249,7 +244,7 @@ void Curl_hostcache_prune(struct Curl_easy *data)
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
time(&now);
now = time(NULL);
do {
/* Remove outdated and unused entries from the hostcache */
@@ -303,7 +298,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
/* See whether the returned entry is stale. Done before we release lock */
struct hostcache_prune_data user;
time(&user.now);
user.now = time(NULL);
user.cache_timeout = data->set.dns_cache_timeout;
user.oldest = 0;
@@ -523,7 +518,7 @@ Curl_cache_addr(struct Curl_easy *data,
return dns;
}
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
/* return a static IPv6 ::1 for the name */
static struct Curl_addrinfo *get_localhost6(int port, const char *name)
{
@@ -600,7 +595,7 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name)
return ca6;
}
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
/*
* Curl_ipv6works() returns TRUE if IPv6 seems to work.
*/
@@ -632,7 +627,7 @@ bool Curl_ipv6works(struct Curl_easy *data)
return (ipv6_works>0)?TRUE:FALSE;
}
}
#endif /* ENABLE_IPV6 */
#endif /* USE_IPV6 */
/*
* Curl_host_is_ipnum() returns TRUE if the given string is a numerical IPv4
@@ -641,11 +636,11 @@ bool Curl_ipv6works(struct Curl_easy *data)
bool Curl_host_is_ipnum(const char *hostname)
{
struct in_addr in;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
struct in6_addr in6;
#endif
if(Curl_inet_pton(AF_INET, hostname, &in) > 0
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
|| Curl_inet_pton(AF_INET6, hostname, &in6) > 0
#endif
)
@@ -760,7 +755,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(!addr)
return CURLRESOLV_ERROR;
}
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else {
struct in6_addr in6;
/* check if this is an IPv6 address string */
@@ -771,7 +766,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
return CURLRESOLV_ERROR;
}
}
#endif /* ENABLE_IPV6 */
#endif /* USE_IPV6 */
#else /* if USE_RESOLVE_ON_IPS */
#ifndef CURL_DISABLE_DOH
@@ -779,7 +774,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
ipnum = TRUE;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
else {
struct in6_addr in6;
/* check if this is an IPv6 address string */
@@ -787,7 +782,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
/* This is an IPv6 address literal */
ipnum = TRUE;
}
#endif /* ENABLE_IPV6 */
#endif /* USE_IPV6 */
#endif /* CURL_DISABLE_DOH */
#endif /* !USE_RESOLVE_ON_IPS */
@@ -1070,6 +1065,23 @@ static void freednsentry(void *freethis)
dns->inuse--;
if(dns->inuse == 0) {
Curl_freeaddrinfo(dns->addr);
#ifdef USE_HTTPSRR
if(dns->hinfo) {
if(dns->hinfo->target)
free(dns->hinfo->target);
if(dns->hinfo->alpns)
free(dns->hinfo->alpns);
if(dns->hinfo->ipv4hints)
free(dns->hinfo->ipv4hints);
if(dns->hinfo->echconfiglist)
free(dns->hinfo->echconfiglist);
if(dns->hinfo->ipv6hints)
free(dns->hinfo->ipv6hints);
if(dns->hinfo->val)
free(dns->hinfo->val);
free(dns->hinfo);
}
#endif
free(dns);
}
}
@@ -1077,7 +1089,7 @@ static void freednsentry(void *freethis)
/*
* Curl_init_dnscache() inits a new DNS cache.
*/
void Curl_init_dnscache(struct Curl_hash *hash, int size)
void Curl_init_dnscache(struct Curl_hash *hash, size_t size)
{
Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare,
freednsentry);
@@ -1210,7 +1222,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
memcpy(address, addr_begin, alen);
address[alen] = '\0';
#ifndef ENABLE_IPV6
#ifndef USE_IPV6
if(strchr(address, ':')) {
infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
address);
+39 -2
View File
@@ -32,6 +32,10 @@
#include <setjmp.h>
#ifdef USE_HTTPSRR
# include <stdint.h>
#endif
/* Allocate enough memory to hold the full name information structs and
* everything. OSF1 is known to require at least 8872 bytes. The buffer
* required for storing all possible aliases and IP numbers is according to
@@ -58,8 +62,41 @@ struct connectdata;
*/
struct Curl_hash *Curl_global_host_cache_init(void);
#ifdef USE_HTTPSRR
#define CURL_MAXLEN_host_name 253
struct Curl_https_rrinfo {
size_t len; /* raw encoded length */
unsigned char *val; /* raw encoded octets */
/*
* fields from HTTPS RR, with the mandatory fields
* first (priority, target), then the others in the
* order of the keytag numbers defined at
* https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
*/
uint16_t priority;
char *target;
char *alpns; /* keytag = 1 */
bool no_def_alpn; /* keytag = 2 */
/*
* we don't support ports (keytag = 3) as we don't support
* port-switching yet
*/
unsigned char *ipv4hints; /* keytag = 4 */
size_t ipv4hints_len;
unsigned char *echconfiglist; /* keytag = 5 */
size_t echconfiglist_len;
unsigned char *ipv6hints; /* keytag = 6 */
size_t ipv6hints_len;
};
#endif
struct Curl_dns_entry {
struct Curl_addrinfo *addr;
#ifdef USE_HTTPSRR
struct Curl_https_rrinfo *hinfo;
#endif
/* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
time_t timestamp;
/* use-counter, use Curl_resolv_unlock to release reference */
@@ -96,7 +133,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
struct Curl_dns_entry **dnsentry,
timediff_t timeoutms);
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
/*
* Curl_ipv6works() returns TRUE if IPv6 seems to work.
*/
@@ -129,7 +166,7 @@ void Curl_resolv_unlock(struct Curl_easy *data,
struct Curl_dns_entry *dns);
/* init a new dns cache */
void Curl_init_dnscache(struct Curl_hash *hash, int hashsize);
void Curl_init_dnscache(struct Curl_hash *hash, size_t hashsize);
/* prune old entries from the DNS cache */
void Curl_hostcache_prune(struct Curl_easy *data);
+7 -9
View File
@@ -107,11 +107,6 @@ void Curl_hsts_cleanup(struct hsts **hp)
}
}
static struct stsentry *hsts_entry(void)
{
return calloc(1, sizeof(struct stsentry));
}
static CURLcode hsts_create(struct hsts *h,
const char *hostname,
bool subdomains,
@@ -127,7 +122,7 @@ static CURLcode hsts_create(struct hsts *h,
--hlen;
if(hlen) {
char *duphost;
struct stsentry *sts = hsts_entry();
struct stsentry *sts = calloc(1, sizeof(struct stsentry));
if(!sts)
return CURLE_OUT_OF_MEMORY;
@@ -140,7 +135,7 @@ static CURLcode hsts_create(struct hsts *h,
sts->host = duphost;
sts->expires = expires;
sts->includeSubDomains = subdomains;
Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node);
Curl_llist_append(&h->list, sts, &sts->node);
}
return CURLE_OK;
}
@@ -528,8 +523,11 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
char *lineptr = Curl_dyn_ptr(&buf);
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
if(*lineptr == '#')
/* skip commented lines */
/*
* Skip empty or commented lines, since we know the line will have a
* trailing newline from Curl_get_line we can treat length 1 as empty.
*/
if((*lineptr == '#') || strlen(lineptr) <= 1)
continue;
hsts_add(h, lineptr);
File diff suppressed because it is too large Load Diff
+7 -8
View File
@@ -44,7 +44,7 @@ typedef enum {
#ifndef CURL_DISABLE_HTTP
#if defined(ENABLE_QUIC)
#if defined(USE_HTTP3)
#include <stdint.h>
#endif
@@ -102,8 +102,8 @@ CURLcode Curl_http_target(struct Curl_easy *data, struct connectdata *conn,
struct dynbuf *req);
CURLcode Curl_http_statusline(struct Curl_easy *data,
struct connectdata *conn);
CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
char *headp, size_t hdlen);
CURLcode Curl_http_header(struct Curl_easy *data,
const char *hd, size_t hdlen);
CURLcode Curl_transferencode(struct Curl_easy *data);
CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
Curl_HttpReq httpreq,
@@ -134,6 +134,9 @@ int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos);
CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
const char *hd, size_t hdlen,
bool is_eos);
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
@@ -185,12 +188,8 @@ void Curl_http_exp100_got100(struct Curl_easy *data);
* HTTP unique setup
***************************************************************************/
struct HTTP {
#ifndef CURL_DISABLE_HTTP
void *h2_ctx; /* HTTP/2 implementation context */
void *h3_ctx; /* HTTP/3 implementation context */
#else
/* TODO: no longer used, we should remove it from SingleRequest */
char unused;
#endif
};
CURLcode Curl_http_size(struct Curl_easy *data);
+181 -100
View File
@@ -29,6 +29,7 @@
#include <nghttp2/nghttp2.h>
#include "urldata.h"
#include "bufq.h"
#include "hash.h"
#include "http1.h"
#include "http2.h"
#include "http.h"
@@ -127,7 +128,9 @@ struct cf_h2_ctx {
struct bufq inbufq; /* network input */
struct bufq outbufq; /* network output */
struct bufc_pool stream_bufcp; /* spares for stream buffers */
struct dynbuf scratch; /* scratch buffer for temp use */
struct Curl_hash streams; /* hash of `data->id` to `h2_stream_ctx` */
size_t drain_total; /* sum of all stream's UrlState drain */
uint32_t max_concurrent_streams;
int32_t goaway_error;
@@ -153,6 +156,9 @@ static void cf_h2_ctx_clear(struct cf_h2_ctx *ctx)
Curl_bufq_free(&ctx->inbufq);
Curl_bufq_free(&ctx->outbufq);
Curl_bufcp_free(&ctx->stream_bufcp);
Curl_dyn_free(&ctx->scratch);
Curl_hash_clean(&ctx->streams);
Curl_hash_destroy(&ctx->streams);
memset(ctx, 0, sizeof(*ctx));
ctx->call_data = save;
}
@@ -187,6 +193,7 @@ struct h2_stream_ctx {
int status_code; /* HTTP response status code */
uint32_t error; /* stream error code */
CURLcode xfer_result; /* Result of writing out response */
uint32_t local_window_size; /* the local recv window size */
int32_t id; /* HTTP/2 protocol identifier for stream */
BIT(resp_hds_complete); /* we have a complete, final response */
@@ -198,13 +205,58 @@ struct h2_stream_ctx {
buffered data in stream->sendbuf to upload. */
};
#define H2_STREAM_CTX(d) ((struct h2_stream_ctx *)(((d) && \
(d)->req.p.http)? \
((struct HTTP *)(d)->req.p.http)->h2_ctx \
: NULL))
#define H2_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h2_ctx
#define H2_STREAM_ID(d) (H2_STREAM_CTX(d)? \
H2_STREAM_CTX(d)->id : -2)
#define H2_STREAM_CTX(ctx,data) ((struct h2_stream_ctx *)(\
data? Curl_hash_offt_get(&(ctx)->streams, (data)->id) : NULL))
static struct h2_stream_ctx *h2_stream_ctx_create(struct cf_h2_ctx *ctx)
{
struct h2_stream_ctx *stream;
(void)ctx;
stream = calloc(1, sizeof(*stream));
if(!stream)
return NULL;
stream->id = -1;
Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
stream->resp_hds_len = 0;
stream->bodystarted = FALSE;
stream->status_code = -1;
stream->closed = FALSE;
stream->close_handled = FALSE;
stream->error = NGHTTP2_NO_ERROR;
stream->local_window_size = H2_STREAM_WINDOW_SIZE;
stream->upload_left = 0;
stream->nrcvd_data = 0;
return stream;
}
static void free_push_headers(struct h2_stream_ctx *stream)
{
size_t i;
for(i = 0; i<stream->push_headers_used; i++)
free(stream->push_headers[i]);
Curl_safefree(stream->push_headers);
stream->push_headers_used = 0;
}
static void h2_stream_ctx_free(struct h2_stream_ctx *stream)
{
Curl_bufq_free(&stream->sendbuf);
Curl_h1_req_parse_free(&stream->h1);
Curl_dynhds_free(&stream->resp_trailers);
free_push_headers(stream);
free(stream);
}
static void h2_stream_hash_free(void *stream)
{
DEBUGASSERT(stream);
h2_stream_ctx_free((struct h2_stream_ctx *)stream);
}
/*
* Mark this transfer to get "drained".
@@ -241,49 +293,29 @@ static CURLcode http2_data_setup(struct Curl_cfilter *cf,
failf(data, "initialization failure, transfer not http initialized");
return CURLE_FAILED_INIT;
}
stream = H2_STREAM_CTX(data);
stream = H2_STREAM_CTX(ctx, data);
if(stream) {
*pstream = stream;
return CURLE_OK;
}
stream = calloc(1, sizeof(*stream));
stream = h2_stream_ctx_create(ctx);
if(!stream)
return CURLE_OUT_OF_MEMORY;
stream->id = -1;
Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
stream->resp_hds_len = 0;
stream->bodystarted = FALSE;
stream->status_code = -1;
stream->closed = FALSE;
stream->close_handled = FALSE;
stream->error = NGHTTP2_NO_ERROR;
stream->local_window_size = H2_STREAM_WINDOW_SIZE;
stream->upload_left = 0;
stream->nrcvd_data = 0;
if(!Curl_hash_offt_set(&ctx->streams, data->id, stream)) {
h2_stream_ctx_free(stream);
return CURLE_OUT_OF_MEMORY;
}
H2_STREAM_LCTX(data) = stream;
*pstream = stream;
return CURLE_OK;
}
static void free_push_headers(struct h2_stream_ctx *stream)
{
size_t i;
for(i = 0; i<stream->push_headers_used; i++)
free(stream->push_headers[i]);
Curl_safefree(stream->push_headers);
stream->push_headers_used = 0;
}
static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
DEBUGASSERT(ctx);
if(!stream)
@@ -310,12 +342,7 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
nghttp2_session_send(ctx->h2);
}
Curl_bufq_free(&stream->sendbuf);
Curl_h1_req_parse_free(&stream->h1);
Curl_dynhds_free(&stream->resp_trailers);
free_push_headers(stream);
free(stream);
H2_STREAM_LCTX(data) = NULL;
Curl_hash_offt_remove(&ctx->streams, data->id);
}
static int h2_client_new(struct Curl_cfilter *cf,
@@ -408,6 +435,8 @@ static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf,
Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free);
ctx->last_stream_id = 2147483647;
rc = nghttp2_session_callbacks_new(&cbs);
@@ -706,6 +735,7 @@ static ssize_t send_callback(nghttp2_session *h2,
the struct are hidden from the user. */
struct curl_pushheaders {
struct Curl_easy *data;
struct h2_stream_ctx *stream;
const nghttp2_push_promise *frame;
};
@@ -719,9 +749,8 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
if(!h || !GOOD_EASY_HANDLE(h->data))
return NULL;
else {
struct h2_stream_ctx *stream = H2_STREAM_CTX(h->data);
if(stream && num < stream->push_headers_used)
return stream->push_headers[num];
if(h->stream && num < h->stream->push_headers_used)
return h->stream->push_headers[num];
}
return NULL;
}
@@ -744,7 +773,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
!strcmp(header, ":") || strchr(header + 1, ':'))
return NULL;
stream = H2_STREAM_CTX(h->data);
stream = h->stream;
if(!stream)
return NULL;
@@ -804,7 +833,7 @@ static int set_transfer_url(struct Curl_easy *data,
v = curl_pushheader_byname(hp, HTTP_PSEUDO_AUTHORITY);
if(v) {
uc = Curl_url_set_authority(u, v, CURLU_DISALLOW_USER);
uc = Curl_url_set_authority(u, v);
if(uc) {
rc = 2;
goto fail;
@@ -867,12 +896,10 @@ static int push_promise(struct Curl_cfilter *cf,
goto fail;
}
heads.data = data;
heads.frame = frame;
/* ask the application */
CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ask application");
stream = H2_STREAM_CTX(data);
stream = H2_STREAM_CTX(ctx, data);
if(!stream) {
failf(data, "Internal NULL stream");
discard_newhandle(cf, newhandle);
@@ -880,6 +907,10 @@ static int push_promise(struct Curl_cfilter *cf,
goto fail;
}
heads.data = data;
heads.stream = stream;
heads.frame = frame;
rv = set_transfer_url(newhandle, &heads);
if(rv) {
discard_newhandle(cf, newhandle);
@@ -945,12 +976,39 @@ fail:
return rv;
}
static CURLcode recvbuf_write_hds(struct Curl_cfilter *cf,
static void h2_xfer_write_resp_hd(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char *buf, size_t blen)
struct h2_stream_ctx *stream,
const char *buf, size_t blen, bool eos)
{
(void)cf;
return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
/* If we already encountered an error, skip further writes */
if(!stream->xfer_result) {
stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
if(stream->xfer_result)
CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of headers",
stream->id, stream->xfer_result, blen);
}
}
static void h2_xfer_write_resp(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct h2_stream_ctx *stream,
const char *buf, size_t blen, bool eos)
{
/* If we already encountered an error, skip further writes */
if(!stream->xfer_result)
stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
/* If the transfer write is errored, we do not want any more data */
if(stream->xfer_result) {
struct cf_h2_ctx *ctx = cf->ctx;
CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of data, "
"RST-ing stream",
stream->id, stream->xfer_result, blen);
nghttp2_submit_rst_stream(ctx->h2, 0, stream->id,
NGHTTP2_ERR_CALLBACK_FAILURE);
}
}
static CURLcode on_stream_frame(struct Curl_cfilter *cf,
@@ -958,9 +1016,8 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
const nghttp2_frame *frame)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
int32_t stream_id = frame->hd.stream_id;
CURLcode result;
int rv;
if(!stream) {
@@ -1008,9 +1065,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
stream->status_code = -1;
}
result = recvbuf_write_hds(cf, data, STRCONST("\r\n"));
if(result)
return result;
h2_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
@@ -1189,7 +1244,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
* servers send an explicit WINDOW_UPDATE, but not all seem to do that.
* To be safe, we UNHOLD a stream in order not to stall. */
if(CURL_WANT_SEND(data)) {
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
if(stream)
drain_stream(cf, data, stream);
}
@@ -1229,7 +1284,6 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
struct Curl_easy *data_s;
CURLcode result;
(void)flags;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
@@ -1248,13 +1302,11 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
return 0;
}
stream = H2_STREAM_CTX(data_s);
stream = H2_STREAM_CTX(ctx, data_s);
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_xfer_write_resp(data_s, (char *)mem, len, FALSE);
if(result && result != CURLE_AGAIN)
return NGHTTP2_ERR_CALLBACK_FAILURE;
h2_xfer_write_resp(cf, data_s, stream, (char *)mem, len, FALSE);
nghttp2_session_consume(ctx->h2, stream_id, len);
stream->nrcvd_data += (curl_off_t)len;
@@ -1268,6 +1320,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *userp)
{
struct Curl_cfilter *cf = userp;
struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf);
struct h2_stream_ctx *stream;
int rv;
@@ -1292,7 +1345,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
(void)nghttp2_session_set_stream_user_data(session, stream_id, 0);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
stream = H2_STREAM_CTX(data_s);
stream = H2_STREAM_CTX(ctx, data_s);
if(!stream) {
CURL_TRC_CF(data_s, cf,
"[%d] on_stream_close, GOOD easy but no stream", stream_id);
@@ -1327,6 +1380,7 @@ static int on_begin_headers(nghttp2_session *session,
const nghttp2_frame *frame, void *userp)
{
struct Curl_cfilter *cf = userp;
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
struct Curl_easy *data_s = NULL;
@@ -1340,7 +1394,7 @@ static int on_begin_headers(nghttp2_session *session,
return 0;
}
stream = H2_STREAM_CTX(data_s);
stream = H2_STREAM_CTX(ctx, data_s);
if(!stream || !stream->bodystarted) {
return 0;
}
@@ -1356,6 +1410,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
void *userp)
{
struct Curl_cfilter *cf = userp;
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
struct Curl_easy *data_s;
int32_t stream_id = frame->hd.stream_id;
@@ -1371,7 +1426,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
internal error more than anything else! */
return NGHTTP2_ERR_CALLBACK_FAILURE;
stream = H2_STREAM_CTX(data_s);
stream = H2_STREAM_CTX(ctx, data_s);
if(!stream) {
failf(data_s, "Internal NULL stream");
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1465,14 +1520,15 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = recvbuf_write_hds(cf, data_s, STRCONST("HTTP/2 "));
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* the space character after the status code is mandatory */
result = recvbuf_write_hds(cf, data_s, STRCONST(" \r\n"));
Curl_dyn_reset(&ctx->scratch);
result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 "));
if(!result)
result = Curl_dyn_addn(&ctx->scratch, value, valuelen);
if(!result)
result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
if(!result)
h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
Curl_dyn_len(&ctx->scratch), FALSE);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
@@ -1487,16 +1543,17 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* nghttp2 guarantees that namelen > 0, and :status was already
received, and this is not pseudo-header field . */
/* convert to an HTTP1-style header */
result = recvbuf_write_hds(cf, data_s, (const char *)name, namelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = recvbuf_write_hds(cf, data_s, STRCONST(": "));
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = recvbuf_write_hds(cf, data_s, STRCONST("\r\n"));
Curl_dyn_reset(&ctx->scratch);
result = Curl_dyn_addn(&ctx->scratch, (const char *)name, namelen);
if(!result)
result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
if(!result)
result = Curl_dyn_addn(&ctx->scratch, (const char *)value, valuelen);
if(!result)
result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
if(!result)
h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
Curl_dyn_len(&ctx->scratch), FALSE);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
@@ -1517,6 +1574,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
void *userp)
{
struct Curl_cfilter *cf = userp;
struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data_s;
struct h2_stream_ctx *stream = NULL;
CURLcode result;
@@ -1533,7 +1591,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
internal error more than anything else! */
return NGHTTP2_ERR_CALLBACK_FAILURE;
stream = H2_STREAM_CTX(data_s);
stream = H2_STREAM_CTX(ctx, data_s);
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@@ -1620,7 +1678,7 @@ static CURLcode http2_data_done_send(struct Curl_cfilter *cf,
{
struct cf_h2_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
if(!ctx || !ctx->h2 || !stream)
goto out;
@@ -1658,6 +1716,15 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
return -1;
}
else if(stream->error != NGHTTP2_NO_ERROR) {
if(stream->resp_hds_complete && data->req.no_body) {
CURL_TRC_CF(data, cf, "[%d] error after response headers, but we did "
"not want a body anyway, ignore: %s (err %u)",
stream->id, nghttp2_http2_strerror(stream->error),
stream->error);
stream->close_handled = TRUE;
*err = CURLE_OK;
goto out;
}
failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
stream->id, nghttp2_http2_strerror(stream->error),
stream->error);
@@ -1736,11 +1803,12 @@ static int sweight_in_effect(const struct Curl_easy *data)
* struct.
*/
static void h2_pri_spec(struct Curl_easy *data,
static void h2_pri_spec(struct cf_h2_ctx *ctx,
struct Curl_easy *data,
nghttp2_priority_spec *pri_spec)
{
struct Curl_data_priority *prio = &data->set.priority;
struct h2_stream_ctx *depstream = H2_STREAM_CTX(prio->parent);
struct h2_stream_ctx *depstream = H2_STREAM_CTX(ctx, prio->parent);
int32_t depstream_id = depstream? depstream->id:0;
nghttp2_priority_spec_init(pri_spec, depstream_id,
sweight_wanted(data),
@@ -1758,7 +1826,7 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
int rv = 0;
if(stream && stream->id > 0 &&
@@ -1768,7 +1836,7 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
/* send new weight and/or dependency */
nghttp2_priority_spec pri_spec;
h2_pri_spec(data, &pri_spec);
h2_pri_spec(ctx, data, &pri_spec);
CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id);
DEBUGASSERT(stream->id != -1);
rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE,
@@ -1799,7 +1867,12 @@ static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
(void)buf;
*err = CURLE_AGAIN;
if(stream->closed) {
if(stream->xfer_result) {
CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id);
*err = stream->xfer_result;
nread = -1;
}
else if(stream->closed) {
CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
nread = http2_handle_stream_close(cf, data, stream, err);
}
@@ -1838,7 +1911,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
* it is time to stop due to connection close or us not processing
* all network input */
while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
stream = H2_STREAM_CTX(data);
stream = H2_STREAM_CTX(ctx, data);
if(stream && (stream->closed || !data_max_bytes)) {
/* We would like to abort here and stop processing, so that
* the transfer loop can handle the data/close here. However,
@@ -1884,7 +1957,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
ssize_t nread = -1;
CURLcode result;
struct cf_call_data save;
@@ -2016,7 +2089,7 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream,
goto out;
}
h2_pri_spec(data, &pri_spec);
h2_pri_spec(ctx, data, &pri_spec);
if(!nghttp2_session_check_request_allowed(ctx->h2))
CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)");
@@ -2113,7 +2186,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
struct cf_call_data save;
int rv;
ssize_t nwritten;
@@ -2294,7 +2367,7 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
sock = Curl_conn_cf_get_socket(cf, data);
Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
if(want_recv || want_send) {
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
struct cf_call_data save;
bool c_exhaust, s_exhaust;
@@ -2395,7 +2468,7 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf,
{
#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
DEBUGASSERT(data);
if(ctx && ctx->h2 && stream) {
@@ -2480,7 +2553,7 @@ static bool cf_h2_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq)
|| (stream && !Curl_bufq_is_empty(&stream->sendbuf))))
@@ -2539,6 +2612,11 @@ static CURLcode cf_h2_query(struct Curl_cfilter *cf,
*pres1 = (effective_max > INT_MAX)? INT_MAX : (int)effective_max;
CF_DATA_RESTORE(cf, save);
return CURLE_OK;
case CF_QUERY_STREAM_ERROR: {
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
*pres1 = stream? (int)stream->error : 0;
return CURLE_OK;
}
default:
break;
}
@@ -2768,8 +2846,11 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
CURLE_HTTP2_STREAM error! */
bool Curl_h2_http_1_1_error(struct Curl_easy *data)
{
struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
return (stream && stream->error == NGHTTP2_HTTP_1_1_REQUIRED);
if(Curl_conn_is_http2(data, data->conn, FIRSTSOCKET)) {
int err = Curl_conn_get_stream_error(data, data->conn, FIRSTSOCKET);
return (err == NGHTTP2_HTTP_1_1_REQUIRED);
}
return FALSE;
}
#else /* !USE_NGHTTP2 */
+1 -4
View File
@@ -158,10 +158,7 @@ static CURLcode make_headers(struct Curl_easy *data,
msnprintf(date_full_hdr, DATE_FULL_HDR_LEN,
"x-%s-date:%s", provider1, timestamp);
if(Curl_checkheaders(data, STRCONST("Host"))) {
head = NULL;
}
else {
if(!Curl_checkheaders(data, STRCONST("Host"))) {
char full_host[FULL_HOST_LEN + 1];
if(data->state.aptr.host) {
+16 -1
View File
@@ -28,6 +28,7 @@
#include "urldata.h" /* it includes http_chunks.h */
#include "curl_printf.h"
#include "curl_trc.h"
#include "sendf.h" /* for the client write stuff */
#include "dynbuf.h"
#include "content_encoding.h"
@@ -185,8 +186,11 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
if(0 == ch->datasize) {
ch->state = CHUNK_TRAILER; /* now check for trailers */
}
else
else {
ch->state = CHUNK_DATA;
CURL_TRC_WRITE(data, "http_chunked, chunk start of %"
CURL_FORMAT_CURL_OFF_T " bytes", ch->datasize);
}
}
buf++;
@@ -221,6 +225,9 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
ch->datasize -= piece; /* decrease amount left to expect */
buf += piece; /* move read pointer forward */
blen -= piece; /* decrease space left in this round */
CURL_TRC_WRITE(data, "http_chunked, write %zu body bytes, %"
CURL_FORMAT_CURL_OFF_T " bytes in chunk remain",
piece, ch->datasize);
if(0 == ch->datasize)
/* end of data this round, we now expect a trailing CRLF */
@@ -340,11 +347,14 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
even if there's no more chunks to read */
ch->datasize = blen;
ch->state = CHUNK_DONE;
CURL_TRC_WRITE(data, "http_chunk, response complete");
return CURLE_OK;
}
else {
ch->state = CHUNK_FAILED;
ch->last_code = CHUNKE_BAD_CHUNK;
CURL_TRC_WRITE(data, "http_chunk error, expected 0x0a, seeing 0x%ux",
(unsigned int)*buf);
return CURLE_RECV_ERROR;
}
case CHUNK_DONE:
@@ -498,6 +508,7 @@ static CURLcode add_last_chunk(struct Curl_easy *data,
int rc;
if(!data->set.trailer_callback) {
CURL_TRC_READ(data, "http_chunk, added last, empty chunk");
return Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("0\r\n\r\n"), &n);
}
@@ -535,6 +546,8 @@ static CURLcode add_last_chunk(struct Curl_easy *data,
out:
curl_slist_free_all(trailers);
CURL_TRC_READ(data, "http_chunk, added last chunk with trailers "
"from client -> %d", result);
return result;
}
@@ -581,6 +594,8 @@ static CURLcode add_chunk(struct Curl_easy *data,
result = Curl_bufq_cwrite(&ctx->chunkbuf, buf, nread, &n);
if(!result)
result = Curl_bufq_cwrite(&ctx->chunkbuf, "\r\n", 2, &n);
CURL_TRC_READ(data, "http_chunk, made chunk of %zu bytes -> %d",
nread, result);
if(result)
return result;
}
+20 -5
View File
@@ -120,16 +120,29 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
CURLcode Curl_output_negotiate(struct Curl_easy *data,
struct connectdata *conn, bool proxy)
{
struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg :
&conn->negotiate;
struct auth *authp = proxy ? &data->state.authproxy : &data->state.authhost;
curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
&conn->http_negotiate_state;
struct negotiatedata *neg_ctx;
struct auth *authp;
curlnegotiate *state;
char *base64 = NULL;
size_t len = 0;
char *userp;
CURLcode result;
if(proxy) {
#ifndef CURL_DISABLE_PROXY
neg_ctx = &conn->proxyneg;
authp = &data->state.authproxy;
state = &conn->proxy_negotiate_state;
#else
return CURLE_NOT_BUILT_IN;
#endif
}
else {
neg_ctx = &conn->negotiate;
authp = &data->state.authhost;
state = &conn->http_negotiate_state;
}
authp->done = FALSE;
if(*state == GSS_AUTHRECV) {
@@ -171,8 +184,10 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
base64);
if(proxy) {
#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
data->state.aptr.proxyuserpwd = userp;
#endif
}
else {
Curl_safefree(data->state.aptr.userpwd);
-5
View File
@@ -40,7 +40,6 @@
#include "strcase.h"
#include "http_ntlm.h"
#include "curl_ntlm_core.h"
#include "curl_ntlm_wb.h"
#include "curl_base64.h"
#include "vauth/vauth.h"
#include "url.h"
@@ -266,10 +265,6 @@ void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
{
Curl_auth_cleanup_ntlm(&conn->ntlm);
Curl_auth_cleanup_ntlm(&conn->proxyntlm);
#if defined(NTLM_WB_ENABLED)
Curl_http_auth_cleanup_ntlm_wb(conn);
#endif
}
#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
+1 -1
View File
@@ -293,7 +293,7 @@ static void http_proxy_cf_close(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_http_proxy = {
"HTTP-PROXY",
CF_TYPE_IP_CONNECT,
CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
0,
http_proxy_cf_destroy,
http_proxy_cf_connect,
+68 -18
View File
@@ -50,6 +50,63 @@
#include "curl_memory.h"
#include "memdebug.h"
/* for macOS and iOS targets */
#if defined(USE_APPLE_IDN)
#include <unicode/uidna.h>
static CURLcode mac_idn_to_ascii(const char *in, char **out)
{
UErrorCode err = U_ZERO_ERROR;
UIDNA* idna = uidna_openUTS46(UIDNA_CHECK_BIDI, &err);
if(U_FAILURE(err)) {
return CURLE_OUT_OF_MEMORY;
}
else {
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
char buffer[256] = {0};
(void)uidna_nameToASCII_UTF8(idna, in, -1, buffer,
sizeof(buffer), &info, &err);
uidna_close(idna);
if(U_FAILURE(err)) {
return CURLE_URL_MALFORMAT;
}
else {
*out = strdup(buffer);
if(*out)
return CURLE_OK;
else
return CURLE_OUT_OF_MEMORY;
}
}
}
static CURLcode mac_ascii_to_idn(const char *in, char **out)
{
UErrorCode err = U_ZERO_ERROR;
UIDNA* idna = uidna_openUTS46(UIDNA_CHECK_BIDI, &err);
if(U_FAILURE(err)) {
return CURLE_OUT_OF_MEMORY;
}
else {
UIDNAInfo info = UIDNA_INFO_INITIALIZER;
char buffer[256] = {0};
(void)uidna_nameToUnicodeUTF8(idna, in, -1, buffer,
sizeof(buffer), &info, &err);
uidna_close(idna);
if(U_FAILURE(err)) {
return CURLE_URL_MALFORMAT;
}
else {
*out = strdup(buffer);
if(*out)
return CURLE_OK;
else
return CURLE_OUT_OF_MEMORY;
}
}
}
#endif
#ifdef USE_WIN32_IDN
/* using Windows kernel32 and normaliz libraries. */
@@ -181,6 +238,8 @@ static CURLcode idn_decode(const char *input, char **output)
result = CURLE_NOT_BUILT_IN;
#elif defined(USE_WIN32_IDN)
result = win32_idn_to_ascii(input, &decoded);
#elif defined(USE_APPLE_IDN)
result = mac_idn_to_ascii(input, &decoded);
#endif
if(!result)
*output = decoded;
@@ -198,6 +257,10 @@ static CURLcode idn_encode(const char *puny, char **output)
CURLcode result = win32_ascii_to_idn(puny, &enc);
if(result)
return result;
#elif defined(USE_APPLE_IDN)
CURLcode result = mac_ascii_to_idn(puny, &enc);
if(result)
return result;
#endif
*output = enc;
return CURLE_OK;
@@ -246,11 +309,7 @@ CURLcode Curl_idn_encode(const char *puny, char **output)
*/
void Curl_free_idnconverted_hostname(struct hostname *host)
{
if(host->encalloc) {
/* must be freed with idn2_free() if allocated by libidn */
Curl_idn_free(host->encalloc);
host->encalloc = NULL;
}
Curl_safefree(host->encalloc);
}
#endif /* USE_IDN */
@@ -267,20 +326,11 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host)
/* Check name for non-ASCII and convert hostname if we can */
if(!Curl_is_ASCII_name(host->name)) {
char *decoded;
CURLcode result = idn_decode(host->name, &decoded);
if(!result) {
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 */
host->name = host->encalloc;
}
else
CURLcode result = Curl_idn_decode(host->name, &decoded);
if(result)
return result;
/* successful */
host->name = host->encalloc = decoded;
}
#endif
return CURLE_OK;
+1 -6
View File
@@ -26,16 +26,11 @@
bool Curl_is_ASCII_name(const char *hostname);
CURLcode Curl_idnconvert_hostname(struct hostname *host);
#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
#define USE_IDN
void Curl_free_idnconverted_hostname(struct hostname *host);
CURLcode Curl_idn_decode(const char *input, char **output);
CURLcode Curl_idn_encode(const char *input, char **output);
#ifdef USE_LIBIDN2
#define Curl_idn_free(x) idn2_free(x)
#else
#define Curl_idn_free(x) free(x)
#endif
#else
#define Curl_free_idnconverted_hostname(x)
+11 -11
View File
@@ -62,7 +62,7 @@
/* ------------------------------------------------------------------ */
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
/* Return the scope of the given address. */
unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
{
@@ -97,17 +97,17 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
#if defined(HAVE_GETIFADDRS)
if2ip_result_t Curl_if2ip(int af,
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
char *buf, int buf_size)
char *buf, size_t buf_size)
{
struct ifaddrs *iface, *head;
if2ip_result_t res = IF2IP_NOT_FOUND;
#if defined(ENABLE_IPV6) && \
#if defined(USE_IPV6) && \
!defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
(void) local_scope_id;
#endif
@@ -121,7 +121,7 @@ if2ip_result_t Curl_if2ip(int af,
const char *ip;
char scope[12] = "";
char ipstr[64];
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
if(af == AF_INET6) {
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
unsigned int scopeid = 0;
@@ -182,12 +182,12 @@ if2ip_result_t Curl_if2ip(int af,
#elif defined(HAVE_IOCTL_SIOCGIFADDR)
if2ip_result_t Curl_if2ip(int af,
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
char *buf, int buf_size)
char *buf, size_t buf_size)
{
struct ifreq req;
struct in_addr in;
@@ -196,7 +196,7 @@ if2ip_result_t Curl_if2ip(int af,
size_t len;
const char *r;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
(void)remote_scope;
(void)local_scope_id;
#endif
@@ -237,15 +237,15 @@ if2ip_result_t Curl_if2ip(int af,
#else
if2ip_result_t Curl_if2ip(int af,
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
char *buf, int buf_size)
char *buf, size_t buf_size)
{
(void) af;
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
(void) remote_scope;
(void) local_scope_id;
#endif
+3 -3
View File
@@ -32,7 +32,7 @@
#define IPV6_SCOPE_UNIQUELOCAL 3 /* Unique local */
#define IPV6_SCOPE_NODELOCAL 4 /* Loopback. */
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
#else
#define Curl_ipv6_scope(x) 0
@@ -45,12 +45,12 @@ typedef enum {
} if2ip_result_t;
if2ip_result_t Curl_if2ip(int af,
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
char *buf, int buf_size);
char *buf, size_t buf_size);
#ifdef __INTERIX
+4 -2
View File
@@ -117,7 +117,7 @@ static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
*/
const struct Curl_handler Curl_handler_imap = {
"IMAP", /* scheme */
"imap", /* scheme */
imap_setup_connection, /* setup_connection */
imap_do, /* do_it */
imap_done, /* done */
@@ -131,6 +131,7 @@ const struct Curl_handler Curl_handler_imap = {
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_IMAP, /* defport */
@@ -146,7 +147,7 @@ const struct Curl_handler Curl_handler_imap = {
*/
const struct Curl_handler Curl_handler_imaps = {
"IMAPS", /* scheme */
"imaps", /* scheme */
imap_setup_connection, /* setup_connection */
imap_do, /* do_it */
imap_done, /* done */
@@ -160,6 +161,7 @@ const struct Curl_handler Curl_handler_imaps = {
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_IMAPS, /* defport */
+2 -2
View File
@@ -42,11 +42,11 @@
#define INT16SZ 2
/*
* If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* If USE_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)
#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
+2 -2
View File
@@ -39,11 +39,11 @@
#define INT16SZ 2
/*
* If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* If USE_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)
#if !defined(USE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
+32 -26
View File
@@ -524,24 +524,33 @@ static CURLcode read_data(struct Curl_easy *data, int sockindex,
return result;
if(len) {
/* only realloc if there was a length */
len = ntohl(len);
if(len > CURL_MAX_INPUT_LENGTH)
len = 0;
else
buf->data = Curl_saferealloc(buf->data, len);
}
if(!len || !buf->data)
return CURLE_OUT_OF_MEMORY;
return CURLE_TOO_LARGE;
result = socket_read(data, sockindex, buf->data, len);
if(result)
return result;
nread = conn->mech->decode(conn->app_data, buf->data, len,
conn->data_prot, conn);
Curl_dyn_reset(&buf->buf);
}
else
return CURLE_RECV_ERROR;
do {
char buffer[1024];
nread = CURLMIN(len, (int)sizeof(buffer));
result = socket_read(data, sockindex, buffer, nread);
if(result)
return result;
result = Curl_dyn_addn(&buf->buf, buffer, nread);
if(result)
return result;
len -= nread;
} while(len);
/* this decodes the dynbuf *in place* */
nread = conn->mech->decode(conn->app_data,
Curl_dyn_ptr(&buf->buf),
len, conn->data_prot, conn);
if(nread < 0)
return CURLE_RECV_ERROR;
buf->size = (size_t)nread;
Curl_dyn_setlen(&buf->buf, nread);
buf->index = 0;
return CURLE_OK;
}
@@ -549,9 +558,10 @@ static CURLcode read_data(struct Curl_easy *data, int sockindex,
static size_t
buffer_read(struct krb5buffer *buf, void *data, size_t len)
{
if(buf->size - buf->index < len)
len = buf->size - buf->index;
memcpy(data, (char *)buf->data + buf->index, len);
size_t size = Curl_dyn_len(&buf->buf);
if(size - buf->index < len)
len = size - buf->index;
memcpy(data, Curl_dyn_ptr(&buf->buf) + buf->index, len);
buf->index += len;
return len;
}
@@ -586,7 +596,7 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
while(len > 0) {
if(read_data(data, sockindex, &conn->in_buffer))
return -1;
if(conn->in_buffer.size == 0) {
if(Curl_dyn_len(&conn->in_buffer.buf) == 0) {
if(bytes_read > 0)
conn->in_buffer.eof_flag = 1;
return bytes_read;
@@ -835,6 +845,7 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
mech->name);
return CURLE_FAILED_INIT;
}
Curl_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH);
}
infof(data, "Trying mechanism %s...", mech->name);
@@ -899,15 +910,10 @@ Curl_sec_end(struct connectdata *conn)
{
if(conn->mech && conn->mech->end)
conn->mech->end(conn->app_data);
free(conn->app_data);
conn->app_data = NULL;
if(conn->in_buffer.data) {
free(conn->in_buffer.data);
conn->in_buffer.data = NULL;
conn->in_buffer.size = 0;
conn->in_buffer.index = 0;
conn->in_buffer.eof_flag = 0;
}
Curl_safefree(conn->app_data);
Curl_dyn_free(&conn->in_buffer.buf);
conn->in_buffer.index = 0;
conn->in_buffer.eof_flag = 0;
conn->sec_complete = 0;
conn->data_prot = PROT_CLEAR;
conn->mech = NULL;
+8 -3
View File
@@ -164,7 +164,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_ldap = {
"LDAP", /* scheme */
"ldap", /* scheme */
ZERO_NULL, /* setup_connection */
ldap_do, /* do_it */
ZERO_NULL, /* done */
@@ -178,6 +178,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
@@ -192,7 +193,7 @@ const struct Curl_handler Curl_handler_ldap = {
*/
const struct Curl_handler Curl_handler_ldaps = {
"LDAPS", /* scheme */
"ldaps", /* scheme */
ZERO_NULL, /* setup_connection */
ldap_do, /* do_it */
ZERO_NULL, /* done */
@@ -206,6 +207,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
@@ -483,6 +485,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
}
*/
#else
(void)ldap_option;
(void)ldap_ca;
/* we should probably never come up to here since configure
should check in first place if we can support LDAP SSL/TLS */
failf(data, "LDAP local: SSL/TLS not supported with this version "
@@ -544,7 +548,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
num = 0;
for(entryIterator = ldap_first_entry(server, ldapmsg);
entryIterator;
entryIterator = ldap_next_entry(server, entryIterator), num++) {
BerElement *ber = NULL;
+16
View File
@@ -88,6 +88,22 @@ Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e,
++list->size;
}
/*
* Curl_llist_append()
*
* Adds a new list element to the end of the list.
*
* The 'ne' argument should be a pointer into the object to store.
*
* @unittest: 1300
*/
void
Curl_llist_append(struct Curl_llist *list, const void *p,
struct Curl_llist_element *ne)
{
Curl_llist_insert_next(list, list->tail, p, ne);
}
/*
* @unittest: 1300
*/
+2
View File
@@ -45,6 +45,8 @@ struct Curl_llist {
void Curl_llist_init(struct Curl_llist *, Curl_llist_dtor);
void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_element *,
const void *, struct Curl_llist_element *node);
void Curl_llist_append(struct Curl_llist *,
const void *, struct Curl_llist_element *node);
void Curl_llist_remove(struct Curl_llist *, struct Curl_llist_element *,
void *);
size_t Curl_llist_count(struct Curl_llist *);
+2 -1
View File
@@ -55,7 +55,8 @@
#else
#include <mbedtls/config.h>
#endif
#if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
(MBEDTLS_VERSION_NUMBER < 0x03000000)
#define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
#endif
#endif /* USE_MBEDTLS */
+27 -28
View File
@@ -1413,36 +1413,35 @@ CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
char *base;
struct_stat sbuf;
if(stat(filename, &sbuf) || access(filename, R_OK))
if(stat(filename, &sbuf))
result = CURLE_READ_ERROR;
part->data = strdup(filename);
if(!part->data)
result = CURLE_OUT_OF_MEMORY;
part->datasize = -1;
if(!result && S_ISREG(sbuf.st_mode)) {
part->datasize = filesize(filename, sbuf);
part->seekfunc = mime_file_seek;
}
part->readfunc = mime_file_read;
part->freefunc = mime_file_free;
part->kind = MIMEKIND_FILE;
/* As a side effect, set the filename to the current file's base name.
It is possible to withdraw this by explicitly calling
curl_mime_filename() with a NULL filename argument after the current
call. */
base = strippath(filename);
if(!base)
result = CURLE_OUT_OF_MEMORY;
else {
CURLcode res = curl_mime_filename(part, base);
part->data = strdup(filename);
if(!part->data)
result = CURLE_OUT_OF_MEMORY;
else {
part->datasize = -1;
if(S_ISREG(sbuf.st_mode)) {
part->datasize = filesize(filename, sbuf);
part->seekfunc = mime_file_seek;
}
if(res)
result = res;
free(base);
part->readfunc = mime_file_read;
part->freefunc = mime_file_free;
part->kind = MIMEKIND_FILE;
/* As a side effect, set the filename to the current file's base name.
It is possible to withdraw this by explicitly calling
curl_mime_filename() with a NULL filename argument after the current
call. */
base = strippath(filename);
if(!base)
result = CURLE_OUT_OF_MEMORY;
else {
result = curl_mime_filename(part, base);
free(base);
}
}
}
}
return result;
@@ -1971,7 +1970,7 @@ static CURLcode cr_mime_read(struct Curl_easy *data,
switch(nread) {
case 0:
if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
failf(data, "client mime read EOF fail, only "
failf(data, "client mime read EOF fail, "
"only %"CURL_FORMAT_CURL_OFF_T"/%"CURL_FORMAT_CURL_OFF_T
" of needed bytes read", ctx->read_len, ctx->total_len);
return CURLE_READ_ERROR;
+20 -20
View File
@@ -77,7 +77,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
#define OUTCHAR(x) \
do { \
if(!stream(x, userp)) \
if(!stream((unsigned char)x, userp)) \
done++; \
else \
return done; /* return on failure */ \
@@ -243,7 +243,7 @@ static int parsefmt(const char *format,
struct va_input *iptr;
bool loopit = TRUE;
fmt++;
outlen = fmt - start - 1;
outlen = (size_t)(fmt - start - 1);
if(*fmt == '%') {
/* this means a %% that should be output only as %. Create an output
segment. */
@@ -261,7 +261,8 @@ static int parsefmt(const char *format,
continue; /* while */
}
flags = width = precision = 0;
flags = 0;
width = precision = 0;
if(use_dollar != DOLLAR_NOPE) {
param = dollarstring(fmt, &fmt);
@@ -291,7 +292,7 @@ static int parsefmt(const char *format,
break;
case '-':
flags |= FLAGS_LEFT;
flags &= ~FLAGS_PAD_NIL;
flags &= ~(unsigned int)FLAGS_PAD_NIL;
break;
case '#':
flags |= FLAGS_ALT;
@@ -549,7 +550,7 @@ static int parsefmt(const char *format,
optr = &out[ocount++];
if(ocount > MAX_SEGMENTS)
return PFMT_MANYSEGS;
optr->input = param;
optr->input = (unsigned int)param;
optr->flags = flags;
optr->width = width;
optr->precision = precision;
@@ -562,7 +563,7 @@ static int parsefmt(const char *format,
}
/* is there a trailing piece */
outlen = fmt - start;
outlen = (size_t)(fmt - start);
if(outlen) {
optr = &out[ocount++];
if(ocount > MAX_SEGMENTS)
@@ -688,7 +689,7 @@ static int formatf(
mp_intmax_t signed_num; /* Used to convert negative in positive. */
char *w;
size_t outlen = optr->outlen;
int flags = optr->flags;
unsigned int flags = optr->flags;
if(outlen) {
char *str = optr->start;
@@ -710,7 +711,7 @@ static int formatf(
else
width = -width;
flags |= FLAGS_LEFT;
flags &= ~FLAGS_PAD_NIL;
flags &= ~(unsigned int)FLAGS_PAD_NIL;
}
}
else
@@ -867,7 +868,7 @@ number:
str = nilstr;
len = sizeof(nilstr) - 1;
/* Disable quotes around (nil) */
flags &= (~FLAGS_ALT);
flags &= ~(unsigned int)FLAGS_ALT;
}
else {
str = "";
@@ -886,13 +887,13 @@ number:
if(flags & FLAGS_ALT)
OUTCHAR('"');
if(!(flags&FLAGS_LEFT))
if(!(flags & FLAGS_LEFT))
while(width-- > 0)
OUTCHAR(' ');
for(; len && *str; len--)
OUTCHAR(*str++);
if(flags&FLAGS_LEFT)
if(flags & FLAGS_LEFT)
while(width-- > 0)
OUTCHAR(' ');
@@ -952,12 +953,13 @@ number:
*fptr = 0;
if(width >= 0) {
size_t dlen;
if(width >= (int)sizeof(work))
width = sizeof(work)-1;
/* RECURSIVE USAGE */
len = curl_msnprintf(fptr, left, "%d", width);
fptr += len;
left -= len;
dlen = (size_t)curl_msnprintf(fptr, left, "%d", width);
fptr += dlen;
left -= dlen;
}
if(prec >= 0) {
/* for each digit in the integer part, we can have one less
@@ -965,7 +967,7 @@ number:
size_t maxprec = sizeof(work) - 2;
double val = iptr->val.dnum;
if(width > 0 && prec <= width)
maxprec -= width;
maxprec -= (size_t)width;
while(val >= 10.0) {
val /= 10;
maxprec--;
@@ -1039,7 +1041,7 @@ static int addbyter(unsigned char outc, void *f)
struct nsprintf *infop = f;
if(infop->length < infop->max) {
/* only do this if we haven't reached max length yet */
*infop->buffer++ = outc; /* store */
*infop->buffer++ = (char)outc; /* store */
infop->length++; /* we are now one byte larger */
return 0; /* fputc() returns like this on success */
}
@@ -1139,7 +1141,7 @@ char *curl_maprintf(const char *format, ...)
static int storebuffer(unsigned char outc, void *f)
{
char **buffer = f;
**buffer = outc;
**buffer = (char)outc;
(*buffer)++;
return 0;
}
@@ -1160,9 +1162,7 @@ static int fputc_wrapper(unsigned char outc, void *f)
int out = outc;
FILE *s = f;
int rc = fputc(out, s);
if(rc == out)
return 0;
return 1;
return rc == EOF;
}
int curl_mprintf(const char *format, ...)
+4 -3
View File
@@ -75,7 +75,7 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_mqtt = {
"MQTT", /* scheme */
"mqtt", /* scheme */
mqtt_setup_conn, /* setup_connection */
mqtt_do, /* do_it */
mqtt_done, /* done */
@@ -89,6 +89,7 @@ const struct Curl_handler Curl_handler_mqtt = {
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_MQTT, /* defport */
@@ -776,12 +777,12 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
case MQTT_REMAINING_LENGTH:
do {
result = Curl_xfer_recv(data, (char *)&byte, 1, &nread);
if(!nread)
if(result || !nread)
break;
Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
mq->pkt_hd[mq->npacket++] = byte;
} while((byte & 0x80) && (mq->npacket < 4));
if(nread && (byte & 0x80))
if(!result && nread && (byte & 0x80))
/* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
127 * 128^3 bytes. server tried to send more */
result = CURLE_WEIRD_SERVER_REPLY;
+250 -176
View File
@@ -86,6 +86,8 @@
((x) && (x)->magic == CURL_MULTI_HANDLE)
#endif
static void move_pending_to_connect(struct Curl_multi *multi,
struct Curl_easy *data);
static CURLMcode singlesocket(struct Curl_multi *multi,
struct Curl_easy *data);
static CURLMcode add_next_timeout(struct curltime now,
@@ -100,6 +102,7 @@ static void multi_xfer_bufs_free(struct Curl_multi *multi);
static const char * const multi_statename[]={
"INIT",
"PENDING",
"SETUP",
"CONNECT",
"RESOLVING",
"CONNECTING",
@@ -149,6 +152,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
static const init_multistate_func finit[MSTATE_LAST] = {
NULL, /* INIT */
NULL, /* PENDING */
NULL, /* SETUP */
Curl_init_CONNECT, /* CONNECT */
NULL, /* RESOLVING */
NULL, /* CONNECTING */
@@ -360,7 +364,7 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
* per call."
*
*/
static void sh_init(struct Curl_hash *hash, int hashsize)
static void sh_init(struct Curl_hash *hash, size_t hashsize)
{
Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
sh_freeentry);
@@ -374,13 +378,12 @@ static void sh_init(struct Curl_hash *hash, int hashsize)
*/
static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg)
{
Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg,
&msg->list);
Curl_llist_append(&multi->msglist, msg, &msg->list);
}
struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
int chashsize, /* connection hash */
int dnssize) /* dns hash */
struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
size_t chashsize, /* connection hash */
size_t dnssize) /* dns hash */
{
struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
@@ -549,6 +552,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
if(data->set.errorbuffer)
data->set.errorbuffer[0] = 0;
data->state.os_errno = 0;
/* make the Curl_easy refer back to this multi handle - before Curl_expire()
is called. */
data->multi = multi;
@@ -1002,8 +1007,7 @@ void Curl_attach_connection(struct Curl_easy *data,
DEBUGASSERT(!data->conn);
DEBUGASSERT(conn);
data->conn = conn;
Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
&data->conn_queue);
Curl_llist_append(&conn->easyq, data, &data->conn_queue);
if(conn->handler && conn->handler->attach)
conn->handler->attach(data, conn);
Curl_conn_ev_data_attach(conn, data);
@@ -1112,6 +1116,7 @@ static void multi_getsock(struct Curl_easy *data,
switch(data->mstate) {
case MSTATE_INIT:
case MSTATE_PENDING:
case MSTATE_SETUP:
case MSTATE_CONNECT:
/* nothing to poll for yet */
break;
@@ -1208,6 +1213,68 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
return CURLM_OK;
}
CURLMcode curl_multi_waitfds(struct Curl_multi *multi,
struct curl_waitfd *ufds,
unsigned int size,
unsigned int *fd_count)
{
struct Curl_easy *data;
unsigned int nfds = 0;
struct easy_pollset ps;
unsigned int i;
CURLMcode result = CURLM_OK;
struct curl_waitfd *ufd;
unsigned int j;
if(!ufds)
return CURLM_BAD_FUNCTION_ARGUMENT;
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
memset(&ps, 0, sizeof(ps));
for(data = multi->easyp; data; data = data->next) {
multi_getsock(data, &ps);
for(i = 0; i < ps.num; i++) {
if(nfds < size) {
curl_socket_t fd = ps.sockets[i];
int fd_idx = -1;
/* Simple linear search to skip an already added descriptor */
for(j = 0; j < nfds; j++) {
if(ufds[j].fd == fd) {
fd_idx = (int)j;
break;
}
}
if(fd_idx < 0) {
ufd = &ufds[nfds++];
ufd->fd = ps.sockets[i];
ufd->events = 0;
}
else
ufd = &ufds[fd_idx];
if(ps.actions[i] & CURL_POLL_IN)
ufd->events |= CURL_WAIT_POLLIN;
if(ps.actions[i] & CURL_POLL_OUT)
ufd->events |= CURL_WAIT_POLLOUT;
}
else
return CURLM_OUT_OF_MEMORY;
}
}
if(fd_count)
*fd_count = nfds;
return result;
}
#ifdef USE_WINSOCK
/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets can't
* be reset this way because an empty datagram would be sent. #9203
@@ -1224,6 +1291,29 @@ static void reset_socket_fdwrite(curl_socket_t s)
}
#endif
static CURLMcode ufds_increase(struct pollfd **pfds, unsigned int *pfds_len,
unsigned int inc, bool *is_malloced)
{
struct pollfd *new_fds, *old_fds = *pfds;
unsigned int new_len = *pfds_len + inc;
new_fds = calloc(new_len, sizeof(struct pollfd));
if(!new_fds) {
if(*is_malloced)
free(old_fds);
*pfds = NULL;
*pfds_len = 0;
return CURLM_OUT_OF_MEMORY;
}
memcpy(new_fds, old_fds, (*pfds_len) * sizeof(struct pollfd));
if(*is_malloced)
free(old_fds);
*pfds = new_fds;
*pfds_len = new_len;
*is_malloced = TRUE;
return CURLM_OK;
}
#define NUM_POLLS_ON_STACK 10
static CURLMcode multi_wait(struct Curl_multi *multi,
@@ -1237,12 +1327,12 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct Curl_easy *data;
struct easy_pollset ps;
size_t i;
unsigned int nfds = 0;
unsigned int curlfds;
long timeout_internal;
int retcode = 0;
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
struct pollfd *ufds = &a_few_on_stack[0];
unsigned int ufds_len = NUM_POLLS_ON_STACK;
unsigned int nfds = 0, curl_nfds = 0; /* how many ufds are in use */
bool ufds_malloc = FALSE;
#ifdef USE_WINSOCK
WSANETWORKEVENTS wsa_events;
@@ -1261,13 +1351,6 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
if(timeout_ms < 0)
return CURLM_BAD_FUNCTION_ARGUMENT;
/* Count up how many fds we have from the multi handle */
memset(&ps, 0, sizeof(ps));
for(data = multi->easyp; data; data = data->next) {
multi_getsock(data, &ps);
nfds += ps.num;
}
/* If the internally desired timeout is actually shorter than requested from
the outside, then use the shorter time! But only if the internal timer
is actually larger than -1! */
@@ -1275,70 +1358,60 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
timeout_ms = (int)timeout_internal;
curlfds = nfds; /* number of internal file descriptors */
nfds += extra_nfds; /* add the externally provided ones */
memset(ufds, 0, ufds_len * sizeof(struct pollfd));
memset(&ps, 0, sizeof(ps));
#ifdef ENABLE_WAKEUP
/* Add the curl handles to our pollfds first */
for(data = multi->easyp; data; data = data->next) {
multi_getsock(data, &ps);
for(i = 0; i < ps.num; i++) {
short events = 0;
#ifdef USE_WINSOCK
if(use_wakeup) {
#else
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
long mask = 0;
#endif
++nfds;
}
#endif
if(nfds > NUM_POLLS_ON_STACK) {
/* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
big, so at 2^29 sockets this value might wrap. When a process gets
the capability to actually handle over 500 million sockets this
calculation needs a integer overflow check. */
ufds = malloc(nfds * sizeof(struct pollfd));
if(!ufds)
return CURLM_OUT_OF_MEMORY;
ufds_malloc = TRUE;
}
nfds = 0;
/* only do the second loop if we found descriptors in the first stage run
above */
if(curlfds) {
/* Add the curl handles to our pollfds first */
for(data = multi->easyp; data; data = data->next) {
multi_getsock(data, &ps);
for(i = 0; i < ps.num; i++) {
struct pollfd *ufd = &ufds[nfds++];
if(ps.actions[i] & CURL_POLL_IN) {
#ifdef USE_WINSOCK
long mask = 0;
mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
#endif
ufd->fd = ps.sockets[i];
ufd->events = 0;
if(ps.actions[i] & CURL_POLL_IN) {
events |= POLLIN;
}
if(ps.actions[i] & CURL_POLL_OUT) {
#ifdef USE_WINSOCK
mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
reset_socket_fdwrite(ps.sockets[i]);
#endif
ufd->events |= POLLIN;
events |= POLLOUT;
}
if(events) {
if(nfds && ps.sockets[i] == ufds[nfds-1].fd) {
ufds[nfds-1].events |= events;
}
if(ps.actions[i] & CURL_POLL_OUT) {
#ifdef USE_WINSOCK
mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
reset_socket_fdwrite(ps.sockets[i]);
#endif
ufd->events |= POLLOUT;
else {
if(nfds >= ufds_len) {
if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
return CURLM_OUT_OF_MEMORY;
}
DEBUGASSERT(nfds < ufds_len);
ufds[nfds].fd = ps.sockets[i];
ufds[nfds].events = events;
++nfds;
}
}
#ifdef USE_WINSOCK
if(mask) {
if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) {
if(ufds_malloc)
free(ufds);
return CURLM_INTERNAL_ERROR;
}
#endif
}
#endif
}
}
curl_nfds = nfds; /* what curl internally used in ufds */
/* Add external file descriptions from poll-like struct curl_waitfd */
for(i = 0; i < extra_nfds; i++) {
#ifdef USE_WINSOCK
@@ -1357,6 +1430,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
#endif
if(nfds >= ufds_len) {
if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
return CURLM_OUT_OF_MEMORY;
}
DEBUGASSERT(nfds < ufds_len);
ufds[nfds].fd = extra_fds[i].fd;
ufds[nfds].events = 0;
if(extra_fds[i].events & CURL_WAIT_POLLIN)
@@ -1371,6 +1449,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#ifdef ENABLE_WAKEUP
#ifndef USE_WINSOCK
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
if(nfds >= ufds_len) {
if(ufds_increase(&ufds, &ufds_len, 100, &ufds_malloc))
return CURLM_OUT_OF_MEMORY;
}
DEBUGASSERT(nfds < ufds_len);
ufds[nfds].fd = multi->wakeup_pair[0];
ufds[nfds].events = POLLIN;
++nfds;
@@ -1410,7 +1493,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct, the bit values of the actual underlying poll() implementation
may not be the same as the ones in the public libcurl API! */
for(i = 0; i < extra_nfds; i++) {
unsigned r = ufds[curlfds + i].revents;
unsigned r = ufds[curl_nfds + i].revents;
unsigned short mask = 0;
#ifdef USE_WINSOCK
curl_socket_t s = extra_fds[i].fd;
@@ -1443,7 +1526,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#ifdef USE_WINSOCK
/* Count up all our own sockets that had activity,
and remove them from the event. */
if(curlfds) {
if(curl_nfds) {
for(data = multi->easyp; data; data = data->next) {
multi_getsock(data, &ps);
@@ -1464,7 +1547,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#else
#ifdef ENABLE_WAKEUP
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
if(ufds[curlfds + extra_nfds].revents & POLLIN) {
if(ufds[curl_nfds + extra_nfds].revents & POLLIN) {
char buf[64];
ssize_t nread;
while(1) {
@@ -1684,47 +1767,47 @@ static bool multi_handle_timeout(struct Curl_easy *data,
CURLcode *result,
bool connect_timeout)
{
timediff_t timeout_ms;
timeout_ms = Curl_timeleft(data, now, connect_timeout);
timediff_t timeout_ms = Curl_timeleft(data, now, connect_timeout);
if(timeout_ms < 0) {
/* Handle timed out */
struct curltime since;
if(connect_timeout)
since = data->progress.t_startsingle;
else
since = data->progress.t_startop;
if(data->mstate == MSTATE_RESOLVING)
failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds",
Curl_timediff(*now, data->progress.t_startsingle));
" milliseconds", Curl_timediff(*now, since));
else if(data->mstate == MSTATE_CONNECTING)
failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds",
Curl_timediff(*now, data->progress.t_startsingle));
" milliseconds", Curl_timediff(*now, since));
else {
struct SingleRequest *k = &data->req;
if(k->size != -1) {
failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
CURL_FORMAT_CURL_OFF_T " bytes received",
Curl_timediff(*now, data->progress.t_startsingle),
k->bytecount, k->size);
Curl_timediff(*now, since), k->bytecount, k->size);
}
else {
failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
" milliseconds with %" CURL_FORMAT_CURL_OFF_T
" bytes received",
Curl_timediff(*now, data->progress.t_startsingle),
k->bytecount);
" bytes received", Curl_timediff(*now, since), k->bytecount);
}
}
/* Force connection closed if the connection has indeed been used */
if(data->mstate > MSTATE_DO) {
streamclose(data->conn, "Disconnected with pending data");
*stream_error = TRUE;
}
*result = CURLE_OPERATION_TIMEDOUT;
(void)multi_done(data, *result, TRUE);
if(data->conn) {
/* Force connection closed if the connection has indeed been used */
if(data->mstate > MSTATE_DO) {
streamclose(data->conn, "Disconnect due to timeout");
*stream_error = TRUE;
}
(void)multi_done(data, *result, TRUE);
}
return TRUE;
}
return (timeout_ms < 0);
return FALSE;
}
/*
@@ -1816,19 +1899,6 @@ static CURLcode protocol_connect(struct Curl_easy *data,
return result; /* pass back status */
}
/*
* Curl_preconnect() is called immediately before a connect starts. When a
* redirect is followed, this is then called multiple times during a single
* transfer.
*/
CURLcode Curl_preconnect(struct Curl_easy *data)
{
/* this used to do data->state.buffer allocation,
maybe remove completely now? */
(void)data;
return CURLE_OK;
}
static void set_in_callback(struct Curl_multi *multi, bool value)
{
multi->in_callback = value;
@@ -1882,51 +1952,44 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
if(data->conn &&
(data->mstate >= MSTATE_CONNECT) &&
(data->mstate < MSTATE_COMPLETED)) {
/* Check for overall operation timeout here but defer handling the
* connection timeout to later, to allow for a connection to be set up
* in the window since we last checked timeout. This prevents us
* tearing down a completed connection in the case where we were slow
* to check the timeout (e.g. process descheduled during this loop).
* We set connect_timeout=FALSE to do this. */
/* we need to wait for the connect state as only then is the start time
stored, but we must not check already completed handles */
if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
}
}
/* Wait for the connect state as only then is the start time stored, but
we must not check already completed handles */
if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
multi_handle_timeout(data, nowp, &stream_error, &result, FALSE))
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
switch(data->mstate) {
case MSTATE_INIT:
/* init this transfer. */
/* Transitional state. init this transfer. A handle never comes
back to this state. */
result = Curl_pretransfer(data);
if(!result) {
/* after init, go CONNECT */
multistate(data, MSTATE_CONNECT);
*nowp = Curl_pgrsTime(data, TIMER_STARTOP);
rc = CURLM_CALL_MULTI_PERFORM;
}
break;
case MSTATE_CONNECT:
/* Connect. We want to get a connection identifier filled in. */
/* init this transfer. */
result = Curl_preconnect(data);
if(result)
break;
/* after init, go SETUP */
multistate(data, MSTATE_SETUP);
(void)Curl_pgrsTime(data, TIMER_STARTOP);
FALLTHROUGH();
case MSTATE_SETUP:
/* Transitional state. Setup things for a new transfer. The handle
can come back to this state on a redirect. */
*nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
if(data->set.timeout)
Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
if(data->set.connecttimeout)
/* Since a connection might go to pending and back to CONNECT several
times before it actually takes off, we need to set the timeout once
in SETUP before we enter CONNECT the first time. */
Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
multistate(data, MSTATE_CONNECT);
FALLTHROUGH();
case MSTATE_CONNECT:
/* Connect. We want to get a connection identifier filled in. This state
can be entered from SETUP and from PENDING. */
result = Curl_connect(data, &async, &connected);
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
@@ -1934,18 +1997,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, MSTATE_PENDING);
/* add this handle to the list of connect-pending handles */
Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
&data->connect_queue);
Curl_llist_append(&multi->pending, data, &data->connect_queue);
/* unlink from the main list */
unlink_easy(multi, data);
result = CURLE_OK;
break;
}
else if(data->state.previouslypending) {
/* this transfer comes from the pending queue so try move another */
infof(data, "Transfer was pending, now try another");
else
process_pending_handles(data->multi);
}
if(!result) {
*nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
@@ -2226,7 +2285,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
follow = FOLLOW_RETRY;
drc = Curl_follow(data, newurl, follow);
if(!drc) {
multistate(data, MSTATE_CONNECT);
multistate(data, MSTATE_SETUP);
rc = CURLM_CALL_MULTI_PERFORM;
result = CURLE_OK;
}
@@ -2463,7 +2522,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_posttransfer(data);
multi_done(data, result, TRUE);
}
else if(data->req.done) {
else if(data->req.done && !Curl_cwriter_is_paused(data)) {
/* call this even if the readwrite function returned error */
Curl_posttransfer(data);
@@ -2486,10 +2545,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* multi_done() might return CURLE_GOT_NOTHING */
result = Curl_follow(data, newurl, follow);
if(!result) {
multistate(data, MSTATE_CONNECT);
multistate(data, MSTATE_SETUP);
rc = CURLM_CALL_MULTI_PERFORM;
}
free(newurl);
}
else {
/* after the transfer is done, go DONE */
@@ -2501,7 +2559,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
newurl = data->req.location;
data->req.location = NULL;
result = Curl_follow(data, newurl, FOLLOW_FAKE);
free(newurl);
if(result) {
stream_error = TRUE;
result = multi_done(data, result, TRUE);
@@ -2520,6 +2577,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
transfers */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
free(newurl);
break;
}
@@ -2570,8 +2628,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
if(data->conn &&
data->mstate >= MSTATE_CONNECT &&
if(data->mstate >= MSTATE_CONNECT &&
data->mstate < MSTATE_DO &&
rc != CURLM_CALL_MULTI_PERFORM &&
!multi_ischanged(multi, false)) {
@@ -2581,7 +2638,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
* declaring the connection timed out as we may almost have a completed
* connection. */
multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
multi_handle_timeout(data, nowp, &stream_error, &result, FALSE);
}
statemachine_end:
@@ -2658,8 +2715,7 @@ statemachine_end:
multistate(data, MSTATE_MSGSENT);
/* add this handle to the list of msgsent handles */
Curl_llist_insert_next(&multi->msgsent, multi->msgsent.tail, data,
&data->connect_queue);
Curl_llist_append(&multi->msgsent, data, &data->connect_queue);
/* unlink from the main list */
unlink_easy(multi, data);
return CURLM_OK;
@@ -2721,10 +2777,20 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
*/
do {
multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
if(t)
if(t) {
/* the removed may have another timeout in queue */
data = t->payload;
if(data->mstate == MSTATE_PENDING) {
bool stream_unused;
CURLcode result_unused;
if(multi_handle_timeout(data, &now, &stream_unused, &result_unused,
FALSE)) {
infof(data, "PENDING handle timeout");
move_pending_to_connect(multi, data);
}
}
(void)add_next_timeout(now, multi, t->payload);
}
} while(t);
*running_handles = multi->num_alive;
@@ -3678,47 +3744,55 @@ void Curl_multiuse_state(struct Curl_easy *data,
process_pending_handles(data->multi);
}
/* process_pending_handles() moves all handles from PENDING
back into the main list and change state to CONNECT */
static void move_pending_to_connect(struct Curl_multi *multi,
struct Curl_easy *data)
{
DEBUGASSERT(data->mstate == MSTATE_PENDING);
/* put it back into the main list */
link_easy(multi, data);
multistate(data, MSTATE_CONNECT);
/* Remove this node from the pending list */
Curl_llist_remove(&multi->pending, &data->connect_queue, NULL);
/* Make sure that the handle will be processed soonish. */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
/* process_pending_handles() moves a handle from PENDING back into the main
list and change state to CONNECT.
We do not move all transfers because that can be a significant amount.
Since this is tried every now and then doing too many too often becomes a
performance problem.
When there is a change for connection limits like max host connections etc,
this likely only allows one new transfer. When there is a pipewait change,
it can potentially allow hundreds of new transfers.
We could consider an improvement where we store the queue reason and allow
more pipewait rechecks than others.
*/
static void process_pending_handles(struct Curl_multi *multi)
{
struct Curl_llist_element *e = multi->pending.head;
if(e) {
struct Curl_easy *data = e->ptr;
DEBUGASSERT(data->mstate == MSTATE_PENDING);
/* put it back into the main list */
link_easy(multi, data);
multistate(data, MSTATE_CONNECT);
/* Remove this node from the list */
Curl_llist_remove(&multi->pending, e, NULL);
/* Make sure that the handle will be processed soonish. */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
/* mark this as having been in the pending queue */
data->state.previouslypending = TRUE;
move_pending_to_connect(multi, data);
}
}
void Curl_set_in_callback(struct Curl_easy *data, bool value)
{
/* might get called when there is no data pointer! */
if(data) {
if(data->multi_easy)
data->multi_easy->in_callback = value;
else if(data->multi)
data->multi->in_callback = value;
}
if(data && data->multi)
data->multi->in_callback = value;
}
bool Curl_is_in_callback(struct Curl_easy *easy)
bool Curl_is_in_callback(struct Curl_easy *data)
{
return ((easy->multi && easy->multi->in_callback) ||
(easy->multi_easy && easy->multi_easy->in_callback));
return (data && data->multi && data->multi->in_callback);
}
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
+19 -18
View File
@@ -44,24 +44,25 @@ struct Curl_message {
typedef enum {
MSTATE_INIT, /* 0 - start in this state */
MSTATE_PENDING, /* 1 - no connections, waiting for one */
MSTATE_CONNECT, /* 2 - resolve/connect has been sent off */
MSTATE_RESOLVING, /* 3 - awaiting the resolve to finalize */
MSTATE_CONNECTING, /* 4 - awaiting the TCP connect to finalize */
MSTATE_TUNNELING, /* 5 - awaiting HTTPS proxy SSL initialization to
MSTATE_SETUP, /* 2 - start a new transfer */
MSTATE_CONNECT, /* 3 - resolve/connect has been sent off */
MSTATE_RESOLVING, /* 4 - awaiting the resolve to finalize */
MSTATE_CONNECTING, /* 5 - awaiting the TCP connect to finalize */
MSTATE_TUNNELING, /* 6 - awaiting HTTPS proxy SSL initialization to
complete and/or proxy CONNECT to finalize */
MSTATE_PROTOCONNECT, /* 6 - initiate protocol connect procedure */
MSTATE_PROTOCONNECTING, /* 7 - completing the protocol-specific connect
MSTATE_PROTOCONNECT, /* 7 - initiate protocol connect procedure */
MSTATE_PROTOCONNECTING, /* 8 - completing the protocol-specific connect
phase */
MSTATE_DO, /* 8 - start send off the request (part 1) */
MSTATE_DOING, /* 9 - sending off the request (part 1) */
MSTATE_DOING_MORE, /* 10 - send off the request (part 2) */
MSTATE_DID, /* 11 - done sending off request */
MSTATE_PERFORMING, /* 12 - transfer data */
MSTATE_RATELIMITING, /* 13 - wait because limit-rate exceeded */
MSTATE_DONE, /* 14 - post data transfer operation */
MSTATE_COMPLETED, /* 15 - operation complete */
MSTATE_MSGSENT, /* 16 - the operation complete message is sent */
MSTATE_LAST /* 17 - not a true state, never use this */
MSTATE_DO, /* 9 - start send off the request (part 1) */
MSTATE_DOING, /* 10 - sending off the request (part 1) */
MSTATE_DOING_MORE, /* 11 - send off the request (part 2) */
MSTATE_DID, /* 12 - done sending off request */
MSTATE_PERFORMING, /* 13 - transfer data */
MSTATE_RATELIMITING, /* 14 - wait because limit-rate exceeded */
MSTATE_DONE, /* 15 - post data transfer operation */
MSTATE_COMPLETED, /* 16 - operation complete */
MSTATE_MSGSENT, /* 17 - the operation complete message is sent */
MSTATE_LAST /* 18 - not a true state, never use this */
} CURLMstate;
/* we support N sockets per easy handle. Set the corresponding bit to what
@@ -158,7 +159,7 @@ struct Curl_multi {
WSAEVENT wsa_event; /* winsock event used for waits */
#else
#ifdef ENABLE_WAKEUP
curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup
curl_socket_t wakeup_pair[2]; /* pipe()/socketpair() used for wakeup
0 is used for read, 1 is used for write */
#endif
#endif
@@ -179,7 +180,7 @@ struct Curl_multi {
BIT(dead); /* a callback returned error, everything needs to crash and
burn */
BIT(xfer_buf_borrowed); /* xfer_buf is currently being borrowed */
BIT(xfer_ulbuf_borrowed); /* xfer_buf is currently being borrowed */
BIT(xfer_ulbuf_borrowed); /* xfer_ulbuf is currently being borrowed */
#ifdef DEBUGBUILD
BIT(warned); /* true after user warned of DEBUGBUILD */
#endif
+4 -3
View File
@@ -38,15 +38,16 @@ void Curl_attach_connection(struct Curl_easy *data,
void Curl_detach_connection(struct Curl_easy *data);
bool Curl_multiplex_wanted(const struct Curl_multi *multi);
void Curl_set_in_callback(struct Curl_easy *data, bool value);
bool Curl_is_in_callback(struct Curl_easy *easy);
bool Curl_is_in_callback(struct Curl_easy *data);
CURLcode Curl_preconnect(struct Curl_easy *data);
void Curl_multi_connchanged(struct Curl_multi *multi);
/* Internal version of curl_multi_init() accepts size parameters for the
socket, connection and dns hashes */
struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize,
int dnssize);
struct Curl_multi *Curl_multi_handle(size_t hashsize,
size_t chashsize,
size_t dnssize);
/* the write bits start at bit 16 for the *getsock() bitmap */
#define GETSOCK_WRITEBITSTART 16
+1 -1
View File
@@ -78,7 +78,7 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
const char *network,
unsigned int bits)
{
#ifdef ENABLE_IPV6
#ifdef USE_IPV6
int bytes;
int rest;
unsigned char address[16];
+10 -5
View File
@@ -117,7 +117,7 @@ static Curl_recv oldap_recv;
*/
const struct Curl_handler Curl_handler_ldap = {
"LDAP", /* scheme */
"ldap", /* scheme */
oldap_setup_connection, /* setup_connection */
oldap_do, /* do_it */
oldap_done, /* done */
@@ -131,6 +131,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* perform_getsock */
oldap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
@@ -145,7 +146,7 @@ const struct Curl_handler Curl_handler_ldap = {
*/
const struct Curl_handler Curl_handler_ldaps = {
"LDAPS", /* scheme */
"ldaps", /* scheme */
oldap_setup_connection, /* setup_connection */
oldap_do, /* do_it */
oldap_done, /* done */
@@ -159,6 +160,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* perform_getsock */
oldap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
@@ -548,9 +550,12 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
return result;
}
hosturl = aprintf("ldap%s://%s:%d",
conn->handler->flags & PROTOPT_SSL? "s": "",
conn->host.name, conn->remote_port);
hosturl = aprintf("%s://%s%s%s:%d",
conn->handler->scheme,
conn->bits.ipv6_ip? "[": "",
conn->host.name,
conn->bits.ipv6_ip? "]": "",
conn->remote_port);
if(!hosturl)
return CURLE_OUT_OF_MEMORY;
+5 -3
View File
@@ -112,7 +112,7 @@ static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
*/
const struct Curl_handler Curl_handler_pop3 = {
"POP3", /* scheme */
"pop3", /* scheme */
pop3_setup_connection, /* setup_connection */
pop3_do, /* do_it */
pop3_done, /* done */
@@ -126,6 +126,7 @@ const struct Curl_handler Curl_handler_pop3 = {
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_POP3, /* defport */
@@ -141,7 +142,7 @@ const struct Curl_handler Curl_handler_pop3 = {
*/
const struct Curl_handler Curl_handler_pop3s = {
"POP3S", /* scheme */
"pop3s", /* scheme */
pop3_setup_connection, /* setup_connection */
pop3_do, /* do_it */
pop3_done, /* done */
@@ -155,6 +156,7 @@ const struct Curl_handler Curl_handler_pop3s = {
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_POP3S, /* defport */
@@ -1450,7 +1452,7 @@ static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
* This function scans the body after the end-of-body and writes everything
* until the end is found.
*/
CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread)
CURLcode Curl_pop3_write(struct Curl_easy *data, const char *str, size_t nread)
{
/* This code could be made into a special function in the handler struct */
CURLcode result = CURLE_OK;
+2 -1
View File
@@ -92,6 +92,7 @@ extern const struct Curl_handler Curl_handler_pop3s;
/* This function scans the body after the end-of-body and writes everything
* until the end is found */
CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread);
CURLcode Curl_pop3_write(struct Curl_easy *data,
const char *str, size_t nread);
#endif /* HEADER_CURL_POP3_H */
+3 -3
View File
@@ -40,10 +40,9 @@
#include "curl_memory.h"
#include "memdebug.h"
CURLcode Curl_req_init(struct SingleRequest *req)
void Curl_req_init(struct SingleRequest *req)
{
memset(req, 0, sizeof(*req));
return CURLE_OK;
}
CURLcode Curl_req_soft_reset(struct SingleRequest *req,
@@ -266,7 +265,7 @@ static CURLcode req_set_upload_done(struct Curl_easy *data)
else if(data->req.writebytecount)
infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
" bytes", data->req.writebytecount);
else
else if(!data->req.download_done)
infof(data, Curl_creader_total_length(data)?
"We are completely uploaded and fine" :
"Request completely sent off");
@@ -395,6 +394,7 @@ CURLcode Curl_req_send_more(struct Curl_easy *data)
result = req_flush(data);
if(result == CURLE_AGAIN)
result = CURLE_OK;
return result;
}
+1 -1
View File
@@ -152,7 +152,7 @@ struct SingleRequest {
/**
* Initialize the state of the request for first use.
*/
CURLcode Curl_req_init(struct SingleRequest *req);
void Curl_req_init(struct SingleRequest *req);
/**
* The request is about to start. Record time and do a soft reset.
+12 -11
View File
@@ -93,14 +93,14 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
static
CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len);
static
CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport);
CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport);
/*
* RTSP handler interface.
*/
const struct Curl_handler Curl_handler_rtsp = {
"RTSP", /* scheme */
"rtsp", /* scheme */
rtsp_setup_connection, /* setup_connection */
rtsp_do, /* do_it */
rtsp_done, /* done */
@@ -114,6 +114,7 @@ const struct Curl_handler Curl_handler_rtsp = {
ZERO_NULL, /* perform_getsock */
rtsp_disconnect, /* disconnect */
rtsp_rtp_write_resp, /* write_resp */
ZERO_NULL, /* write_resp_hd */
rtsp_conncheck, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTSP, /* defport */
@@ -393,7 +394,9 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(result)
goto out;
#ifndef CURL_DISABLE_PROXY
p_proxyuserpwd = data->state.aptr.proxyuserpwd;
#endif
p_userpwd = data->state.aptr.userpwd;
/* Referrer */
@@ -802,7 +805,7 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, eos=%d)",
blen, rtspc->in_header, is_eos));
/* If header parsing is not onging, extract RTP messages */
/* If header parsing is not ongoing, extract RTP messages */
if(!rtspc->in_header) {
result = rtsp_filter_rtp(data, buf, blen, &consumed);
if(result)
@@ -911,12 +914,12 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
return CURLE_OK;
}
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
{
if(checkprefix("CSeq:", header)) {
long CSeq = 0;
char *endp;
char *p = &header[5];
const char *p = &header[5];
while(ISBLANK(*p))
p++;
CSeq = strtol(p, &endp, 10);
@@ -931,8 +934,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
}
}
else if(checkprefix("Session:", header)) {
char *start;
char *end;
const char *start, *end;
size_t idlen;
/* Find the first non-space letter */
@@ -987,14 +989,13 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
}
static
CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport)
{
/* If we receive multiple Transport response-headers, the linterleaved
channels of each response header is recorded and used together for
subsequent data validity checks.*/
/* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */
char *start;
char *end;
const char *start, *end;
start = transport;
while(start && *start) {
while(*start && ISBLANK(*start) )
@@ -1003,7 +1004,7 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
if(checkprefix("interleaved=", start)) {
long chan1, chan2, chan;
char *endp;
char *p = start + 12;
const char *p = start + 12;
chan1 = strtol(p, &endp, 10);
if(p != endp && chan1 >= 0 && chan1 <= 255) {
unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;

Some files were not shown because too many files have changed in this diff Show More