Merge branch 'upstream-curl' into update-curl

* upstream-curl:
  curl 2026-06-24 (68720b48)
This commit is contained in:
Brad King
2026-06-29 17:13:25 -04:00
235 changed files with 16597 additions and 10997 deletions
+2 -2
View File
@@ -283,7 +283,7 @@ static void check(char c)
int main(void)
{
char buffer[1024];
/* This will not compile if strerror_r does not return a char* */
/* This does not compile if strerror_r does not return a char* */
/* !checksrc! disable ERRNOVAR 1 */
check(strerror_r(EACCES, buffer, sizeof(buffer))[0]);
return 0;
@@ -303,7 +303,7 @@ static void check(float f)
int main(void)
{
char buffer[1024];
/* This will not compile if strerror_r does not return an int */
/* This does not compile if strerror_r does not return an int */
/* !checksrc! disable ERRNOVAR 1 */
check(strerror_r(EACCES, buffer, sizeof(buffer)));
return 0;
+23 -30
View File
@@ -25,15 +25,14 @@
#
# Input variables:
#
# - `GSS_ROOT_DIR`: Absolute path to the root installation of GSS. (also supported as environment)
# - `GSS_ROOT_DIR`: Absolute path to the root installation of GSS. (also supported as environment)
#
# Defines:
#
# - `GSS_FOUND`: System has a GSS library.
# - `GSS_VERSION`: This is set to version advertised by pkg-config or read from manifest.
# In case the library is found but no version info available it is set to "unknown"
# - `CURL::gss`: GSS library target.
# - `CURL_GSS_FLAVOUR`: Custom property. "GNU" or "MIT" if detected.
# - `GSS_FOUND`: System has GSS.
# - `GSS_VERSION`: Version of GSS.
# - `CURL::gss`: GSS library target.
# - `INTERFACE_CURL_GSS_FLAVOR`: Custom property. "GNU" or "MIT" if detected.
set(_gnu_modname "gss")
set(_mit_modname "mit-krb5-gssapi")
@@ -51,7 +50,7 @@ set(_gss_LIBRARY_DIRS "")
if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
if(CURL_USE_PKGCONFIG)
find_package(PkgConfig QUIET)
pkg_search_module(_gss ${_gnu_modname} ${_mit_modname})
pkg_search_module(_gss ${_mit_modname} ${_gnu_modname})
list(APPEND _gss_root_hints "${_gss_PREFIX}")
set(_gss_version "${_gss_VERSION}")
endif()
@@ -121,7 +120,7 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Older versions may not have the "--version" parameter. In this case we just do not care.
# Older versions may not have the "--version" parameter. In this case we do not care.
if(_gss_configure_failed)
set(_gss_version 0)
else()
@@ -134,9 +133,9 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr
RESULT_VARIABLE _gss_configure_failed
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Older versions may not have the "--vendor" parameter. In this case we just do not care.
# Older versions may not have the "--vendor" parameter. In this case we do not care.
if(NOT _gss_configure_failed AND NOT _gss_vendor MATCHES "Heimdal|heimdal")
set(_gss_flavour "MIT") # assume a default, should not really matter
set(_gss_flavor "MIT") # assume a default, should not really matter
endif()
else() # Either there is no config script or we are on a platform that does not provide one (Windows?)
@@ -152,7 +151,7 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr
cmake_pop_check_state()
if(_gss_have_mit_headers)
set(_gss_flavour "MIT")
set(_gss_flavor "MIT")
if(WIN32)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND _gss_libdir_suffixes "lib/AMD64")
@@ -170,14 +169,14 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr
find_path(_gss_INCLUDE_DIRS NAMES "gss.h" HINTS ${_gss_root_hints} PATH_SUFFIXES "include")
if(_gss_INCLUDE_DIRS)
set(_gss_flavour "GNU")
set(_gss_flavor "GNU")
set(_gss_pc_requires ${_gnu_modname})
set(_gss_libname "gss")
endif()
endif()
# If we have headers, look up libraries
if(_gss_flavour)
if(_gss_flavor)
set(_gss_libdir_hints ${_gss_root_hints})
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20)
cmake_path(GET _gss_INCLUDE_DIRS PARENT_PATH _gss_calculated_potential_root)
@@ -189,28 +188,26 @@ if(NOT _gss_FOUND) # Not found by pkg-config. Let us take more traditional appr
find_library(_gss_LIBRARIES NAMES ${_gss_libname} HINTS ${_gss_libdir_hints} PATH_SUFFIXES ${_gss_libdir_suffixes})
endif()
endif()
if(NOT _gss_flavour)
if(NOT _gss_flavor)
message(FATAL_ERROR "GNU or MIT GSS is required")
endif()
else()
# _gss_MODULE_NAME set since CMake 3.16.
# _pkg_check_modules_pkg_name is undocumented and used as a fallback for CMake <3.16 versions.
if(_gss_MODULE_NAME STREQUAL _gnu_modname OR _pkg_check_modules_pkg_name STREQUAL _gnu_modname)
set(_gss_flavour "GNU")
if(_gss_MODULE_NAME STREQUAL _gnu_modname)
set(_gss_flavor "GNU")
set(_gss_pc_requires ${_gnu_modname})
elseif(_gss_MODULE_NAME STREQUAL _mit_modname OR _pkg_check_modules_pkg_name STREQUAL _mit_modname)
set(_gss_flavour "MIT")
elseif(_gss_MODULE_NAME STREQUAL _mit_modname)
set(_gss_flavor "MIT")
set(_gss_pc_requires ${_mit_modname})
else()
message(FATAL_ERROR "GNU or MIT GSS is required")
endif()
message(STATUS "Found GSS/${_gss_flavour} (via pkg-config): ${_gss_INCLUDE_DIRS} (found version \"${_gss_version}\")")
message(STATUS "Found GSS/${_gss_flavor} (via pkg-config): ${_gss_INCLUDE_DIRS} (found version \"${_gss_version}\")")
endif()
set(GSS_VERSION ${_gss_version})
if(NOT GSS_VERSION)
if(_gss_flavour STREQUAL "MIT")
if(_gss_flavor STREQUAL "MIT" AND WIN32)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
cmake_host_system_information(RESULT _mit_version QUERY WINDOWS_REGISTRY
"HKLM/SOFTWARE/MIT/Kerberos/SDK/CurrentVersion" VALUE "VersionString")
@@ -218,12 +215,8 @@ if(NOT GSS_VERSION)
get_filename_component(_mit_version
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE)
endif()
if(WIN32 AND _mit_version)
set(GSS_VERSION "${_mit_version}")
else()
set(GSS_VERSION "MIT Unknown")
endif()
else() # GNU
set(GSS_VERSION "${_mit_version}")
elseif(_gss_flavor STREQUAL "GNU")
if(_gss_INCLUDE_DIRS AND EXISTS "${_gss_INCLUDE_DIRS}/gss.h")
set(_version_regex "#[\t ]*define[\t ]+GSS_VERSION[\t ]+\"([^\"]*)\"")
file(STRINGS "${_gss_INCLUDE_DIRS}/gss.h" _version_str REGEX "${_version_regex}")
@@ -238,7 +231,7 @@ endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GSS
REQUIRED_VARS
_gss_flavour
_gss_flavor
_gss_LIBRARIES
VERSION_VAR
GSS_VERSION
@@ -261,7 +254,7 @@ if(GSS_FOUND)
if(NOT TARGET CURL::gss)
add_library(CURL::gss INTERFACE IMPORTED)
set_target_properties(CURL::gss PROPERTIES
INTERFACE_CURL_GSS_FLAVOUR "${_gss_flavour}"
INTERFACE_CURL_GSS_FLAVOR "${_gss_flavor}"
INTERFACE_LIBCURL_PC_MODULES "${_gss_pc_requires}"
INTERFACE_COMPILE_OPTIONS "${_gss_CFLAGS}"
INTERFACE_INCLUDE_DIRECTORIES "${_gss_INCLUDE_DIRS}"
+1 -1
View File
@@ -61,7 +61,7 @@ if(_nghttp2_FOUND)
elseif(nghttp2_CONFIG)
set(NGHTTP2_FOUND TRUE)
set(NGHTTP2_VERSION ${nghttp2_VERSION})
if(NGHTTP2_USE_STATIC_LIBS)
if(NGHTTP2_USE_STATIC_LIBS OR NOT TARGET nghttp2::nghttp2)
set(_nghttp2_LIBRARIES nghttp2::nghttp2_static)
else()
set(_nghttp2_LIBRARIES nghttp2::nghttp2)
+1 -1
View File
@@ -61,7 +61,7 @@ if(_nghttp3_FOUND)
elseif(nghttp3_CONFIG)
set(NGHTTP3_FOUND TRUE)
set(NGHTTP3_VERSION ${nghttp3_VERSION})
if(NGHTTP3_USE_STATIC_LIBS)
if(NGHTTP3_USE_STATIC_LIBS OR NOT TARGET nghttp3::nghttp3)
set(_nghttp3_LIBRARIES nghttp3::nghttp3_static)
else()
set(_nghttp3_LIBRARIES nghttp3::nghttp3)
+12 -11
View File
@@ -49,27 +49,28 @@
#
# - `NGTCP2_FOUND`: System has ngtcp2.
# - `NGTCP2_VERSION`: Version of ngtcp2.
# - `NGTCP2_CRYPTO_BACKEND`: Name of the crypto library component. (Empty if COMPONENTS was not used.)
# - `CURL::ngtcp2`: ngtcp2 library target.
set(NGTCP2_CRYPTO_BACKEND "")
if(NGTCP2_FIND_COMPONENTS)
set(_ngtcp2_crypto_backend "")
foreach(_component IN LISTS NGTCP2_FIND_COMPONENTS)
if(_component MATCHES "^(BoringSSL|GnuTLS|LibreSSL|ossl|quictls|wolfSSL)")
if(_ngtcp2_crypto_backend)
if(NGTCP2_CRYPTO_BACKEND)
message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
endif()
set(_ngtcp2_crypto_backend ${_component})
set(NGTCP2_CRYPTO_BACKEND ${_component})
endif()
endforeach()
if(_ngtcp2_crypto_backend)
string(TOLOWER "ngtcp2_crypto_${_ngtcp2_crypto_backend}" _crypto_library_lower)
string(TOUPPER "ngtcp2_crypto_${_ngtcp2_crypto_backend}" _crypto_library_upper)
if(NGTCP2_CRYPTO_BACKEND)
string(TOLOWER "ngtcp2_crypto_${NGTCP2_CRYPTO_BACKEND}" _crypto_library_lower)
string(TOUPPER "ngtcp2_crypto_${NGTCP2_CRYPTO_BACKEND}" _crypto_library_upper)
endif()
endif()
set(_ngtcp2_pc_requires "libngtcp2")
if(_ngtcp2_crypto_backend)
if(NGTCP2_CRYPTO_BACKEND)
list(APPEND _ngtcp2_pc_requires "lib${_crypto_library_lower}")
endif()
@@ -81,7 +82,7 @@ if(NOT DEFINED NGTCP2_INCLUDE_DIR AND
pkg_check_modules(_ngtcp2 ${_ngtcp2_pc_requires})
set(_tried_pkgconfig TRUE)
endif()
if(NOT _ngtcp2_FOUND AND CURL_USE_CMAKECONFIG)
if(NOT _ngtcp2_FOUND AND CURL_USE_CMAKECONFIG AND NGTCP2_CRYPTO_BACKEND)
find_package(ngtcp2 CONFIG QUIET)
# Skip using it if the crypto library target is not available
if(ngtcp2_CONFIG AND
@@ -105,7 +106,7 @@ if(_ngtcp2_FOUND)
elseif(ngtcp2_CONFIG)
set(NGTCP2_FOUND TRUE)
set(NGTCP2_VERSION ${ngtcp2_VERSION})
if(NGTCP2_USE_STATIC_LIBS)
if(NGTCP2_USE_STATIC_LIBS OR NOT TARGET ngtcp2::ngtcp2)
set(_ngtcp2_LIBRARIES ngtcp2::ngtcp2_static ngtcp2::${_crypto_library_lower}_static)
else()
set(_ngtcp2_LIBRARIES ngtcp2::ngtcp2 ngtcp2::${_crypto_library_lower})
@@ -130,7 +131,7 @@ else()
unset(_version_str)
endif()
if(_ngtcp2_crypto_backend)
if(NGTCP2_CRYPTO_BACKEND)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20)
cmake_path(GET NGTCP2_LIBRARY PARENT_PATH _ngtcp2_library_dir)
else()
@@ -145,7 +146,7 @@ else()
endif()
if(${_crypto_library_upper}_LIBRARY)
set(NGTCP2_${_ngtcp2_crypto_backend}_FOUND TRUE)
set(NGTCP2_${NGTCP2_CRYPTO_BACKEND}_FOUND TRUE)
set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library_upper}_LIBRARY})
endif()
endif()
+7 -6
View File
@@ -53,12 +53,12 @@ if(NOT DEFINED ZSTD_INCLUDE_DIR AND
pkg_check_modules(_zstd ${_zstd_pc_requires})
endif()
if(NOT _zstd_FOUND AND CURL_USE_CMAKECONFIG)
find_package(Zstd CONFIG QUIET)
find_package(zstd CONFIG QUIET)
# Skip using if older than v1.4.5
if(Zstd_CONFIG AND
if(zstd_CONFIG AND
NOT TARGET zstd::libzstd_static AND
NOT TARGET zstd::libzstd_shared)
unset(Zstd_CONFIG)
unset(zstd_CONFIG)
endif()
endif()
endif()
@@ -74,9 +74,10 @@ if(_zstd_FOUND)
set(_zstd_LIBRARIES "${_zstd_STATIC_LIBRARIES}")
endif()
message(STATUS "Found Zstd (via pkg-config): ${_zstd_INCLUDE_DIRS} (found version \"${ZSTD_VERSION}\")")
elseif(Zstd_CONFIG)
elseif(zstd_CONFIG)
set(Zstd_FOUND TRUE)
set(ZSTD_FOUND TRUE)
set(ZSTD_VERSION ${Zstd_VERSION})
set(ZSTD_VERSION ${zstd_VERSION})
if(ZSTD_USE_STATIC_LIBS)
set(_zstd_LIBRARIES zstd::libzstd_static)
elseif(TARGET zstd::libzstd)
@@ -84,7 +85,7 @@ elseif(Zstd_CONFIG)
else()
set(_zstd_LIBRARIES zstd::libzstd_shared)
endif()
message(STATUS "Found Zstd (via CMake Config): ${Zstd_CONFIG} (found version \"${ZSTD_VERSION}\")")
message(STATUS "Found Zstd (via CMake Config): ${zstd_CONFIG} (found version \"${ZSTD_VERSION}\")")
else()
find_path(ZSTD_INCLUDE_DIR NAMES "zstd.h")
if(ZSTD_USE_STATIC_LIBS)
+2
View File
@@ -267,6 +267,8 @@ macro(curl_collect_target_link_options _target)
get_target_property(_val ${_target} INTERFACE_LINK_LIBRARIES)
if(_val)
foreach(_lib IN LISTS _val)
# Extract imported target name from e.g. "$<LINK_ONLY:OpenSSL::Crypto>" set by libssh2
string(REGEX REPLACE "^\\\$<LINK_ONLY:(.*)>\$" "\\1" _lib "${_lib}")
if(TARGET "${_lib}")
curl_collect_target_link_options(${_lib})
else()
+6 -5
View File
@@ -250,7 +250,7 @@ if(PICKY_COMPILER)
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 19.1) OR
(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 17.0))
list(APPEND _picky_enable
-Wno-format-signedness # clang 19.1 gcc 5.1 appleclang 17.0 # In clang-cl enums are signed ints by default
-Wformat-signedness # clang 19.1 gcc 5.1 appleclang 17.0 # In clang-cl enums are signed ints by default
)
endif()
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 21.1) OR
@@ -300,13 +300,14 @@ if(PICKY_COMPILER)
list(APPEND _picky_enable
-Wdouble-promotion # clang 3.6 gcc 4.6 appleclang 6.1
-Wformat=2 # clang 2.7 gcc 4.8
-Wlogical-op # gcc 4.4
-Wtrampolines # gcc 4.6
)
endif()
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0)
list(APPEND _picky_enable
-Warray-bounds=2 # clang 2.9 gcc 5.0 (clang default: -Warray-bounds)
-Wno-format-signedness # clang 19.1 gcc 5.1 appleclang 17.0
-Wformat-signedness # clang 19.1 gcc 5.1 appleclang 17.0
)
endif()
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0)
@@ -391,7 +392,7 @@ if(PICKY_COMPILER)
list(APPEND _picky "-Wno-conversion") # Avoid false positives
endif()
endif()
elseif(MSVC AND MSVC_VERSION LESS_EQUAL 1950) # Skip for untested/unreleased newer versions
elseif(MSVC AND MSVC_VERSION LESS_EQUAL 1951) # Enable for tested versions only
list(APPEND _picky "-Wall")
list(APPEND _picky "-wd4061") # enumerator 'A' in switch of enum 'B' is not explicitly handled by a case label
list(APPEND _picky "-wd4191") # 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)(void)'
@@ -407,7 +408,7 @@ if(PICKY_COMPILER)
list(APPEND _picky "-wd4746")
list(APPEND _picky "-wd4820") # 'A': 'N' bytes padding added after data member 'B'
if(MSVC_VERSION GREATER_EQUAL 1900)
list(APPEND _picky "-wd5045") # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
list(APPEND _picky "-wd5045") # Compiler inserts Spectre mitigation for memory load if /Qspectre switch specified
endif()
endif()
endif()
@@ -437,7 +438,7 @@ if(CMAKE_C_STANDARD STREQUAL 90)
endif()
if((CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 3.9) OR
(CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 8.1))
list(APPEND _picky "-Wno-comma") # Just silly
list(APPEND _picky "-Wno-comma") # Silly
endif()
endif()
+1 -1
View File
@@ -122,7 +122,7 @@ if("@USE_NGHTTP3@")
list(APPEND _curl_libs CURL::nghttp3)
endif()
if("@USE_NGTCP2@")
find_dependency(NGTCP2 MODULE)
find_dependency(NGTCP2 MODULE COMPONENTS "@NGTCP2_CRYPTO_BACKEND@")
list(APPEND _curl_libs CURL::ngtcp2)
endif()
if("@USE_GNUTLS@")
+34 -5
View File
@@ -21,7 +21,7 @@
# SPDX-License-Identifier: curl
#
###########################################################################
# Based on CI runs for Cygwin/MSYS2, Linux, macOS, FreeBSD, NetBSD, OpenBSD
# Based on CI runs for Cygwin/MSYS2, Linux, macOS/iOS, DragonFly BSD, FreeBSD, MidnightBSD, NetBSD, OpenBSD
if(NOT UNIX)
message(FATAL_ERROR "This file should be included on Unix platforms only")
endif()
@@ -30,7 +30,9 @@ if(APPLE OR
CYGWIN)
set(HAVE_ACCEPT4 0)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(HAVE_ACCEPT4 1)
@@ -60,13 +62,26 @@ set(HAVE_DECL_FSEEKO 1)
set(HAVE_DIRENT_H 1)
if(APPLE OR
CYGWIN OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(HAVE_EVENTFD 0)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
set(HAVE_EVENTFD 1)
endif()
if(ANDROID AND ANDROID_PLATFORM_LEVEL GREATER_EQUAL 34)
set(HAVE_MEMSET_EXPLICIT 1)
endif()
if((APPLE AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.9) OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR # v6+
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR # v11.2+
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD") # v1.3+
set(HAVE_MEMSET_S 1)
elseif(NOT APPLE)
set(HAVE_MEMSET_S 0)
endif()
set(HAVE_FCNTL 1)
set(HAVE_FCNTL_H 1)
set(HAVE_FCNTL_O_NONBLOCK 1)
@@ -78,7 +93,9 @@ if(APPLE)
set(HAVE_FSETXATTR 1)
set(HAVE_FSETXATTR_5 0)
set(HAVE_FSETXATTR_6 1)
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
elseif(CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(HAVE_FSETXATTR 0)
set(HAVE_FSETXATTR_5 0)
@@ -95,7 +112,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(HAVE_GETADDRINFO_THREADSAFE 0)
elseif(CYGWIN OR
CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
set(HAVE_GETADDRINFO_THREADSAFE 1)
endif()
@@ -106,14 +125,18 @@ if(APPLE OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(HAVE_GETHOSTBYNAME_R 0)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
set(HAVE_GETHOSTBYNAME_R 1)
endif()
set(HAVE_GETHOSTBYNAME_R_3 0)
set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
set(HAVE_GETHOSTBYNAME_R_5 0)
set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
set(HAVE_GETHOSTBYNAME_R_6 1)
set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 1)
else()
@@ -129,7 +152,9 @@ endif()
if(APPLE OR
CYGWIN OR
CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(HAVE_GETPASS_R 0)
elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
@@ -201,6 +226,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
BSD OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "SunOS")
@@ -221,7 +247,8 @@ set(HAVE_SCHED_YIELD 1)
set(HAVE_SELECT 1)
set(HAVE_SEND 1)
if(APPLE OR
CYGWIN)
CYGWIN OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD")
set(HAVE_SENDMMSG 0)
else()
set(HAVE_SENDMMSG 1)
@@ -259,10 +286,12 @@ if(ANDROID OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
endif()
if(APPLE OR
CYGWIN OR
CMAKE_SYSTEM_NAME STREQUAL "DragonFlyBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(HAVE_SYS_EVENTFD_H 0)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
set(HAVE_SYS_EVENTFD_H 1)
endif()
+73 -39
View File
@@ -535,14 +535,14 @@ elseif(BUILD_STATIC_CURL AND NOT BUILD_STATIC_LIBS)
set(BUILD_STATIC_CURL OFF)
endif()
# Lib flavour selected for curl tool
# Lib flavor selected for curl tool
if(BUILD_STATIC_CURL)
set(LIB_SELECTED_FOR_EXE ${LIB_STATIC})
else()
set(LIB_SELECTED_FOR_EXE ${LIB_SHARED})
endif()
# Lib flavour selected for example and test programs.
# Lib flavor selected for example and test programs.
if(BUILD_SHARED_LIBS)
set(LIB_SELECTED ${LIB_SHARED})
else()
@@ -774,7 +774,7 @@ option(BUILD_MISC_DOCS "Build misc man pages (e.g. curl-config and mk-ca-bundle)
option(ENABLE_CURL_MANUAL "Build the man page for curl and enable its -M/--manual option" ON)
if((ENABLE_CURL_MANUAL OR BUILD_LIBCURL_DOCS) AND NOT Perl_FOUND)
message(WARNING "Perl not found. Will not build manuals.")
message(WARNING "Perl not found. Cannot build manuals.")
endif()
endif() # XXX(cmake): end
@@ -868,6 +868,7 @@ elseif(AMIGA)
set(OPENSSL_CRYPTO_LIBRARY "${AMISSL_AUTO_LIBRARY}")
set(CURL_USE_OPENSSL ON)
set(CURL_CA_FALLBACK ON CACHE BOOL "")
list(PREPEND CURL_NETWORK_AND_TIME_LIBS "${AMISSL_STUBS_LIBRARY}" "${AMISSL_AUTO_LIBRARY}")
endif()
elseif(NOT WIN32 AND NOT APPLE)
check_library_exists("socket" "connect" "" HAVE_LIBSOCKET)
@@ -926,7 +927,7 @@ endif()
cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_USE_WOLFSSL "Enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_USE_GNUTLS "Enable GnuTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_USE_RUSTLS "Enable Rustls for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
cmake_dependent_option(CURL_USE_RUSTLS "Enable Rustls for SSL/TLS (experimental)" OFF CURL_ENABLE_SSL OFF)
if(WIN32 OR
CURL_USE_SCHANNEL OR
@@ -1029,12 +1030,12 @@ if(CURL_USE_OPENSSL)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
if(NOT DEFINED HAVE_BORINGSSL)
check_symbol_exists("OPENSSL_IS_BORINGSSL" "openssl/base.h" HAVE_BORINGSSL)
endif()
if(NOT DEFINED HAVE_AWSLC)
check_symbol_exists("OPENSSL_IS_AWSLC" "openssl/base.h" HAVE_AWSLC)
endif()
if(NOT DEFINED HAVE_BORINGSSL)
check_symbol_exists("OPENSSL_IS_BORINGSSL" "openssl/base.h" HAVE_BORINGSSL)
endif()
if(NOT DEFINED HAVE_LIBRESSL)
check_symbol_exists("LIBRESSL_VERSION_NUMBER" "openssl/opensslv.h" HAVE_LIBRESSL)
endif()
@@ -1049,15 +1050,15 @@ if(CURL_USE_OPENSSL)
add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}")
endif()
if(HAVE_BORINGSSL OR HAVE_AWSLC)
if(NOT MSVC AND NOT ANDROID) # BoringSSL/AWS-LC MSVC builds use native Windows threads
if(HAVE_AWSLC OR HAVE_BORINGSSL)
if(NOT MSVC AND NOT ANDROID) # AWS-LC/BoringSSL MSVC builds use native Windows threads
find_package(Threads)
if(CMAKE_USE_PTHREADS_INIT)
set(HAVE_THREADS_POSIX_BORINGSSL 1)
list(APPEND CURL_NETWORK_AND_TIME_LIBS Threads::Threads)
list(APPEND CMAKE_REQUIRED_LIBRARIES Threads::Threads)
elseif(OPENSSL_USE_STATIC_LIBS)
message(WARNING "BoringSSL/AWS-LC requires POSIX Threads.")
message(WARNING "AWS-LC/BoringSSL requires POSIX Threads.")
endif()
endif()
if(OPENSSL_USE_STATIC_LIBS AND CMAKE_C_COMPILER_ID MATCHES "Clang")
@@ -1066,17 +1067,17 @@ if(CURL_USE_OPENSSL)
endif()
endif()
if(HAVE_BORINGSSL)
if(USE_AMISSL)
set(_openssl "AmiSSL")
elseif(HAVE_AWSLC)
set(_openssl "AWS-LC")
elseif(HAVE_BORINGSSL)
if(BORINGSSL_VERSION)
set(CURL_BORINGSSL_VERSION "\"${BORINGSSL_VERSION}\"")
endif()
set(_openssl "BoringSSL")
elseif(HAVE_AWSLC)
set(_openssl "AWS-LC")
elseif(HAVE_LIBRESSL)
set(_openssl "LibreSSL")
elseif(USE_AMISSL)
set(_openssl "AmiSSL")
else()
set(_openssl "OpenSSL")
endif()
@@ -1291,8 +1292,8 @@ if(USE_OPENSSL)
endif()
endif()
option(USE_HTTPSRR "Enable HTTPS RR support" OFF)
option(USE_ECH "Enable ECH support" OFF)
option(USE_HTTPSRR "Enable HTTPS RR support (experimental)" OFF)
option(USE_ECH "Enable ECH support (experimental)" OFF)
if(USE_ECH)
if(USE_OPENSSL OR USE_WOLFSSL OR USE_RUSTLS)
# Be sure that the TLS library actually supports ECH.
@@ -1308,7 +1309,7 @@ if(USE_ECH)
set(HAVE_ECH 1)
endif()
if(NOT HAVE_ECH)
message(FATAL_ERROR "ECH support missing in OpenSSL/BoringSSL/AWS-LC/wolfSSL/rustls-ffi")
message(FATAL_ERROR "ECH support missing in AWS-LC/BoringSSL/OpenSSL/Rustls/wolfSSL")
else()
message(STATUS "ECH enabled")
# ECH wants HTTPSRR
@@ -1316,11 +1317,11 @@ if(USE_ECH)
message(STATUS "HTTPSRR enabled")
endif()
else()
message(FATAL_ERROR "ECH requires ECH-enabled OpenSSL, BoringSSL, AWS-LC, wolfSSL or rustls-ffi")
message(FATAL_ERROR "ECH requires ECH-enabled AWS-LC, BoringSSL, OpenSSL, Rustls or wolfSSL")
endif()
endif()
option(USE_SSLS_EXPORT "Enable SSL session export support" OFF)
option(USE_SSLS_EXPORT "Enable SSL session import/export (experimental)" OFF)
if(USE_SSLS_EXPORT)
if(_ssl_enabled)
message(STATUS "SSL export enabled.")
@@ -1329,6 +1330,8 @@ if(USE_SSLS_EXPORT)
endif()
endif()
option(USE_PROXY_HTTP3 "Enable HTTP/3 proxy support (experimental)" OFF)
option(USE_NGHTTP2 "Use nghttp2 library" ON)
if(USE_NGHTTP2)
find_package(NGHTTP2 MODULE)
@@ -1376,7 +1379,7 @@ if(USE_NGTCP2)
list(APPEND CURL_LIBS CURL::nghttp3)
endif()
option(USE_QUICHE "Use quiche library for HTTP/3 support" OFF)
option(USE_QUICHE "Use quiche library for HTTP/3 support (experimental)" OFF)
if(USE_QUICHE)
if(USE_NGTCP2)
message(FATAL_ERROR "Only one HTTP/3 backend can be selected")
@@ -1397,6 +1400,20 @@ if(USE_QUICHE)
endif()
endif()
if(USE_PROXY_HTTP3)
if(CURL_DISABLE_PROXY)
message(FATAL_ERROR "USE_PROXY_HTTP3 requires proxy support")
elseif(CURL_DISABLE_HTTP)
message(FATAL_ERROR "USE_PROXY_HTTP3 requires HTTP support")
elseif(NOT USE_NGTCP2 OR NOT USE_NGHTTP3)
message(FATAL_ERROR "USE_PROXY_HTTP3 requires ngtcp2 + nghttp3")
elseif(NOT USE_OPENSSL)
message(FATAL_ERROR "USE_PROXY_HTTP3 currently requires OpenSSL")
else()
message(STATUS "HTTP/3 proxy support enabled (experimental)")
endif()
endif()
if(NOT CURL_DISABLE_SRP AND (HAVE_GNUTLS_SRP OR HAVE_OPENSSL_SRP))
set(USE_TLS_SRP 1)
endif()
@@ -1544,8 +1561,8 @@ if(CURL_USE_GSSAPI)
if(GSS_FOUND)
list(APPEND CURL_LIBS CURL::gss)
get_target_property(_gss_flavour CURL::gss INTERFACE_CURL_GSS_FLAVOUR)
if(_gss_flavour STREQUAL "GNU")
get_target_property(_gss_flavor CURL::gss INTERFACE_CURL_GSS_FLAVOR)
if(_gss_flavor STREQUAL "GNU")
set(HAVE_GSSGNU 1)
elseif(GSS_VERSION) # MIT
set(CURL_KRB5_VERSION "\"${GSS_VERSION}\"")
@@ -1856,7 +1873,9 @@ check_function_exists("getrlimit" HAVE_GETRLIMIT)
check_function_exists("setlocale" HAVE_SETLOCALE)
check_function_exists("setrlimit" HAVE_SETRLIMIT)
if(NOT APPLE)
if(APPLE)
check_function_exists("mach_absolute_time" HAVE_MACH_ABSOLUTE_TIME)
else()
# Apple platforms do not offer pipe2(), but the iPhone Simulator-specific
# /usr/lib/system/libsystem_sim_kernel.dylib exports it. To avoid false
# detection, omit this feature check for Apple targets.
@@ -1867,9 +1886,17 @@ if(NOT WIN32)
check_function_exists("if_nametoindex" HAVE_IF_NAMETOINDEX) # net/if.h
check_function_exists("realpath" HAVE_REALPATH)
check_function_exists("sched_yield" HAVE_SCHED_YIELD)
check_symbol_exists("strcasecmp" "string.h" HAVE_STRCASECMP)
check_symbol_exists("stricmp" "string.h" HAVE_STRICMP)
check_symbol_exists("strcmpi" "string.h" HAVE_STRCMPI)
check_symbol_exists("inet_ntop" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_NTOP) # arpa/inet.h netinet/in.h sys/socket.h
check_symbol_exists("inet_pton" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_PTON) # arpa/inet.h netinet/in.h sys/socket.h
check_symbol_exists("strcasecmp" "string.h" HAVE_STRCASECMP)
check_symbol_exists("stricmp" "string.h" HAVE_STRICMP)
check_symbol_exists("strcmpi" "string.h" HAVE_STRCMPI)
check_symbol_exists("memset_s" "string.h" HAVE_MEMSET_S)
if(NOT HAVE_MEMSET_S)
check_function_exists("memset_explicit" HAVE_MEMSET_EXPLICIT)
endif()
endif()
if(AMIGA)
@@ -1880,14 +1907,6 @@ if(NOT _ssl_enabled)
check_symbol_exists("arc4random" "${CURL_INCLUDES};stdlib.h" HAVE_ARC4RANDOM)
endif()
if(APPLE)
check_function_exists("mach_absolute_time" HAVE_MACH_ABSOLUTE_TIME)
endif()
if(NOT WIN32)
check_symbol_exists("inet_ntop" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_NTOP) # arpa/inet.h netinet/in.h sys/socket.h
check_symbol_exists("inet_pton" "${CURL_INCLUDES};stdlib.h;string.h" HAVE_INET_PTON) # arpa/inet.h netinet/in.h sys/socket.h
endif()
check_symbol_exists("fsetxattr" "sys/xattr.h" HAVE_FSETXATTR)
if(HAVE_FSETXATTR)
curl_internal_test(HAVE_FSETXATTR_5)
@@ -2268,6 +2287,7 @@ curl_add_if("NTLM" CURL_ENABLE_NTLM AND
curl_add_if("TLS-SRP" USE_TLS_SRP)
curl_add_if("HTTP2" USE_NGHTTP2)
curl_add_if("HTTP3" USE_NGTCP2 OR USE_QUICHE)
curl_add_if("proxy-HTTP3" USE_PROXY_HTTP3)
curl_add_if("MultiSSL" CURL_WITH_MULTI_SSL)
curl_add_if("HTTPS-proxy" NOT CURL_DISABLE_PROXY AND _ssl_enabled AND (USE_OPENSSL OR USE_GNUTLS
OR USE_SCHANNEL OR USE_RUSTLS OR USE_MBEDTLS OR
@@ -2385,8 +2405,8 @@ if(NOT CURL_DISABLE_INSTALL)
set(_explicit_libs "")
get_target_property(_imported "${_lib}" IMPORTED)
if(NOT _imported)
# Reading the LOCATION property on non-imported target will error out.
# Assume the user will not need this information in the .pc file.
# Reading the LOCATION property on non-imported target errors out.
# Assume the user does not need this information in the .pc file.
continue()
endif()
set(_libdirs "")
@@ -2399,7 +2419,7 @@ if(NOT CURL_DISABLE_INSTALL)
endif()
if(_lib STREQUAL OpenSSL::SSL AND NOT HAVE_BORINGSSL) # BoringSSL does not provide openssl.pc
set(_modules "openssl")
elseif(_lib STREQUAL ZLIB::ZLIB)
elseif(_lib STREQUAL ZLIB::ZLIB AND NOT ANDROID) # Android does not provide zlib.pc
set(_modules "zlib")
else()
get_target_property(_modules "${_lib}" INTERFACE_LIBCURL_PC_MODULES)
@@ -2433,6 +2453,9 @@ if(NOT CURL_DISABLE_INSTALL)
list(APPEND LIBCURL_PC_LIBS_PRIVATE "${_lib}")
list(APPEND LIBCURL_PC_LIBS_PRIVATE_LIST "${_lib}")
endif()
elseif(_lib MATCHES "^-") # '-option'
list(APPEND _ldflags "${_lib}")
list(APPEND LIBCURL_PC_LIBS_PRIVATE_LIST "${_lib}")
else()
list(APPEND LIBCURL_PC_LIBS_PRIVATE "-l${_lib}")
list(APPEND LIBCURL_PC_LIBS_PRIVATE_LIST "${_lib}")
@@ -2463,6 +2486,17 @@ if(NOT CURL_DISABLE_INSTALL)
string(REPLACE ";" "," LIBCURL_PC_REQUIRES_PRIVATE "${LIBCURL_PC_REQUIRES_PRIVATE}")
endif()
if(LIBCURL_PC_LIBS_PRIVATE)
# Remove duplicates listed next to each other
set(_libs "")
set(_prev "")
foreach(_lib IN LISTS LIBCURL_PC_LIBS_PRIVATE)
if(NOT _prev STREQUAL _lib)
list(APPEND _libs "${_lib}")
set(_prev "${_lib}")
endif()
endforeach()
set(LIBCURL_PC_LIBS_PRIVATE "${_libs}")
string(REPLACE ";" " " LIBCURL_PC_LIBS_PRIVATE "${LIBCURL_PC_LIBS_PRIVATE}")
endif()
if(_ldflags)
@@ -2598,7 +2632,7 @@ if(NOT CURL_DISABLE_INSTALL)
# USE_MBEDTLS
# USE_NGHTTP2
# USE_NGHTTP3
# USE_NGTCP2
# USE_NGTCP2 NGTCP2_CRYPTO_BACKEND
# USE_OPENSSL OPENSSL_VERSION_MAJOR
# USE_QUICHE
# USE_RUSTLS
+32 -28
View File
@@ -252,7 +252,7 @@ typedef int (*curl_xferinfo_callback)(void *clientp,
#ifndef CURL_MAX_READ_SIZE
/* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */
#define CURL_MAX_READ_SIZE (10*1024*1024)
#define CURL_MAX_READ_SIZE (10 * 1024 * 1024)
#endif
#ifndef CURL_MAX_WRITE_SIZE
@@ -269,7 +269,7 @@ typedef int (*curl_xferinfo_callback)(void *clientp,
/* The only reason to have a max limit for this is to avoid the risk of a bad
server feeding libcurl with a never-ending header that causes reallocs
infinitely */
#define CURL_MAX_HTTP_HEADER (100*1024)
#define CURL_MAX_HTTP_HEADER (100 * 1024)
#endif
/* This is a magic return code for the write callback that, when returned,
@@ -593,7 +593,7 @@ typedef enum {
CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */
CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind
that failed */
CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */
CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialize ENGINE */
CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not
accepted and we failed to login */
CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */
@@ -802,9 +802,11 @@ typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */
#define CURLPROXY_SOCKS5_HOSTNAME 7L /* Use the SOCKS5 protocol but pass along
the hostname rather than the IP
address. added in 7.18.0 */
#define CURLPROXY_HTTPS3 8L /* HTTPS and attempt HTTP/3
added in 8.21.0 */
typedef enum {
CURLPROXY_LAST = 8 /* never use */
CURLPROXY_LAST = 9 /* never use */
} curl_proxytype; /* this enum was added in 7.10 */
/*
@@ -816,7 +818,7 @@ typedef enum {
* CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication
* CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated)
* CURLAUTH_NTLM - HTTP NTLM authentication
* CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour
* CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavor
* CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper
* CURLAUTH_BEARER - HTTP Bearer token authentication
* CURLAUTH_ONLY - Use together with a single other type to force no
@@ -902,16 +904,16 @@ enum curl_khmatch {
};
typedef int
(*curl_sshkeycallback) (CURL *easy, /* easy handle */
const struct curl_khkey *knownkey, /* known */
const struct curl_khkey *foundkey, /* found */
enum curl_khmatch, /* libcurl's view on the keys */
void *clientp); /* custom pointer passed with */
/* CURLOPT_SSH_KEYDATA */
(*curl_sshkeycallback)(CURL *easy, /* easy handle */
const struct curl_khkey *knownkey, /* known */
const struct curl_khkey *foundkey, /* found */
enum curl_khmatch, /* libcurl's view on the keys */
void *clientp); /* custom pointer passed with */
/* CURLOPT_SSH_KEYDATA */
typedef int
(*curl_sshhostkeycallback) (void *clientp,/* custom pointer passed */
/* with CURLOPT_SSH_HOSTKEYDATA */
(*curl_sshhostkeycallback)(void *clientp,/* custom pointer passed */
/* with CURLOPT_SSH_HOSTKEYDATA */
int keytype, /* CURLKHTYPE */
const char *key, /* hostkey to check */
size_t keylen); /* length of the key */
@@ -932,7 +934,7 @@ typedef enum {
/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the
name of improving interoperability with older servers. Some SSL libraries
have introduced work-arounds for this flaw but those work-arounds sometimes
have introduced workarounds for this flaw but those workarounds sometimes
make the SSL communication fail. To regain functionality with those broken
servers, a user can this way allow the vulnerability back. */
#define CURLSSLOPT_ALLOW_BEAST (1L << 0)
@@ -1362,7 +1364,7 @@ typedef enum {
CURLOPTDEPRECATED(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63,
8.17.0, "removed"),
/* Set if we should verify the peer in ssl handshake, set 1 to verify. */
/* Set if we should verify the peer in SSL handshake, set 1 to verify. */
CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64),
/* The CApath or CAfile used to validate the peer certificate
@@ -1420,7 +1422,7 @@ typedef enum {
*/
CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80),
/* Set if we should verify the Common name from the peer certificate in ssl
/* Set if we should verify the Common name from the peer certificate in SSL
* handshake, set 1 to check existence, 2 to ensure that it matches the
* provided hostname. */
CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81),
@@ -1494,8 +1496,8 @@ typedef enum {
CURLOPT(CURLOPT_SHARE, CURLOPTTYPE_OBJECTPOINT, 100),
/* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and
CURLPROXY_SOCKS5. */
CURLPROXY_HTTPS, CURLPROXY_HTTPS2, CURLPROXY_HTTPS3, CURLPROXY_SOCKS4,
CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */
CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_VALUES, 101),
/* Set the Accept-Encoding string. Use this to tell a server you would like
@@ -1524,12 +1526,12 @@ typedef enum {
Note that setting multiple bits may cause extra network round-trips. */
CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107),
/* Set the ssl context callback function, currently only for OpenSSL or
/* Set the SSL context callback function, currently only for OpenSSL or
wolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
The function must match the curl_ssl_ctx_callback prototype. */
CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108),
/* Set the userdata for the ssl context callback function's third
/* Set the userdata for the SSL context callback function's third
argument */
CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_CBPOINT, 109),
@@ -1935,11 +1937,11 @@ typedef enum {
/* Set authentication options directly */
CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224),
/* Enable/disable TLS NPN extension (http2 over ssl might fail without) */
/* Enable/disable TLS NPN extension (http2 over SSL might fail without) */
CURLOPTDEPRECATED(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225,
7.86.0, "Has no function"),
/* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */
/* Enable/disable TLS ALPN extension (http2 over SSL might fail without) */
CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226),
/* Time to wait for a response to an HTTP request containing an
@@ -1985,10 +1987,12 @@ typedef enum {
CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239),
/* Set stream dependency on another curl handle */
CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240),
CURLOPTDEPRECATED(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240,
8.21.0, "Has no function"),
/* Set E-xclusive stream dependency on another curl handle */
CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241),
CURLOPTDEPRECATED(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241,
8.21.0, "Has no function"),
/* Do not send any tftp option requests to the server */
CURLOPT(CURLOPT_TFTP_NO_OPTIONS, CURLOPTTYPE_LONG, 242),
@@ -2012,11 +2016,11 @@ typedef enum {
this option is used only if PROXY_SSL_VERIFYPEER is true */
CURLOPT(CURLOPT_PROXY_CAPATH, CURLOPTTYPE_STRINGPOINT, 247),
/* Set if we should verify the proxy in ssl handshake,
/* Set if we should verify the proxy in SSL handshake,
set 1 to verify. */
CURLOPT(CURLOPT_PROXY_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 248),
/* Set if we should verify the Common name from the proxy certificate in ssl
/* Set if we should verify the Common name from the proxy certificate in SSL
* handshake, set 1 to check existence, 2 to ensure that it matches
* the provided hostname. */
CURLOPT(CURLOPT_PROXY_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 249),
@@ -2808,14 +2812,14 @@ struct curl_slist {
* backend can also be specified via the name parameter (passing -1 as id). If
* both id and name are specified, the name is ignored. If neither id nor
* name are specified, the function fails with CURLSSLSET_UNKNOWN_BACKEND
* and set the "avail" pointer to the NULL-terminated list of available
* and set the "avail" pointer to the null-terminated list of available
* backends.
*
* Upon success, the function returns CURLSSLSET_OK.
*
* If the specified SSL backend is not available, the function returns
* CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a
* NULL-terminated list of available SSL backends.
* null-terminated list of available SSL backends.
*
* The SSL backend can be set only once. If it has already been set, a
* subsequent attempt to change it results in a CURLSSLSET_TOO_LATE.
+4 -4
View File
@@ -32,12 +32,12 @@
/* This is the version number of the libcurl package from which this header
file origins: */
#define LIBCURL_VERSION "8.20.0"
#define LIBCURL_VERSION "8.21.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 8
#define LIBCURL_VERSION_MINOR 20
#define LIBCURL_VERSION_MINOR 21
#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 always
@@ -47,7 +47,7 @@
Where XX, YY and ZZ are the main version, release and patch numbers in
hexadecimal (using 8 bits each). All three numbers are always represented
using two digits. 1.2 would appear as "0x010200" while version 9.11.7
using two digits. Version 1.2 would appear as "0x010200" while 9.11.7
appears as "0x090b07".
This 6-digit (24 bits) hexadecimal number does not show pre-release number,
@@ -58,7 +58,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 0x081400
#define LIBCURL_VERSION_NUM 0x081500
/*
* This is the date and time when the full source package was created. The
+1 -1
View File
@@ -297,7 +297,7 @@
/* ===================================== */
#elif defined(_MSC_VER)
# if (_MSC_VER >= 1800)
# if _MSC_VER >= 1800
# include <inttypes.h>
# define CURL_FORMAT_CURL_OFF_T PRId64
# define CURL_FORMAT_CURL_OFF_TU PRIu64
+1 -2
View File
@@ -149,8 +149,7 @@ if(SHARE_LIB_OBJECT)
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)
set_target_properties(${LIB_OBJECT} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAGS}")
if(CURL_HIDES_PRIVATE_SYMBOLS)
set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_OPTIONS "${CURL_CFLAG_SYMBOLS_HIDE}")
+29 -11
View File
@@ -96,6 +96,7 @@ LIB_VTLS_CFILES = \
vtls/schannel.c \
vtls/schannel_verify.c \
vtls/vtls.c \
vtls/vtls_config.c \
vtls/vtls_scache.c \
vtls/vtls_spack.c \
vtls/wolfssl.c \
@@ -113,23 +114,32 @@ LIB_VTLS_HFILES = \
vtls/schannel.h \
vtls/schannel_int.h \
vtls/vtls.h \
vtls/vtls_config.h \
vtls/vtls_int.h \
vtls/vtls_scache.h \
vtls/vtls_spack.h \
vtls/wolfssl.h \
vtls/x509asn1.h
LIB_VQUIC_CFILES = \
vquic/curl_ngtcp2.c \
vquic/curl_quiche.c \
vquic/vquic.c \
LIB_VQUIC_CFILES = \
vquic/capsule.c \
vquic/cf-capsule.c \
vquic/cf-ngtcp2.c \
vquic/cf-ngtcp2-cmn.c \
vquic/cf-ngtcp2-proxy.c \
vquic/cf-quiche.c \
vquic/vquic.c \
vquic/vquic-tls.c
LIB_VQUIC_HFILES = \
vquic/curl_ngtcp2.h \
vquic/curl_quiche.h \
vquic/vquic.h \
vquic/vquic_int.h \
LIB_VQUIC_HFILES = \
vquic/capsule.h \
vquic/cf-capsule.h \
vquic/cf-ngtcp2.h \
vquic/cf-ngtcp2-cmn.h \
vquic/cf-ngtcp2-proxy.h \
vquic/cf-quiche.h \
vquic/vquic.h \
vquic/vquic_int.h \
vquic/vquic-tls.h
LIB_VSSH_CFILES = \
@@ -155,12 +165,15 @@ LIB_CFILES = \
cf-haproxy.c \
cf-https-connect.c \
cf-ip-happy.c \
cf-recvbuf.c \
cf-setup.c \
cf-socket.c \
cfilters.c \
conncache.c \
connect.c \
content_encoding.c \
cookie.c \
creds.c \
cshutdn.c \
curl_addrinfo.c \
curl_endian.c \
@@ -230,13 +243,14 @@ LIB_CFILES = \
multi_ev.c \
multi_ntfy.c \
netrc.c \
noproxy.c \
openldap.c \
parsedate.c \
peer.c \
pingpong.c \
pop3.c \
progress.c \
protocol.c \
proxy.c \
psl.c \
rand.c \
ratelimit.c \
@@ -285,6 +299,8 @@ LIB_HFILES = \
cf-haproxy.h \
cf-https-connect.h \
cf-ip-happy.h \
cf-recvbuf.h \
cf-setup.h \
cf-socket.h \
cfilters.h \
conncache.h \
@@ -292,6 +308,7 @@ LIB_HFILES = \
connect.h \
content_encoding.h \
cookie.h \
creds.h \
curl_addrinfo.h \
curl_ctype.h \
curl_endian.h \
@@ -362,12 +379,13 @@ LIB_HFILES = \
multi_ntfy.h \
multiif.h \
netrc.h \
noproxy.h \
parsedate.h \
peer.h \
pingpong.h \
pop3.h \
progress.h \
protocol.h \
proxy.h \
psl.h \
rand.h \
ratelimit.h \
+3 -3
View File
@@ -113,11 +113,11 @@ static struct altsvc *altsvc_createid(const char *srchost,
return NULL;
as->src.host = (char *)as + sizeof(struct altsvc);
memcpy(as->src.host, srchost, hlen);
/* the null terminator is already there */
/* the null-terminator is already there */
as->dst.host = (char *)as + sizeof(struct altsvc) + hlen + 1;
memcpy(as->dst.host, dsthost, dlen);
/* the null terminator is already there */
/* the null-terminator is already there */
as->src.alpnid = srcalpnid;
as->dst.alpnid = dstalpnid;
@@ -149,7 +149,7 @@ static struct altsvc *altsvc_create(struct Curl_str *srchost,
static void altsvc_append(struct altsvcinfo *asi, struct altsvc *as)
{
while(Curl_llist_count(&asi->list) >= MAX_ALTSVC_ENTRIES) {
/* It's full. Remove the first entry in the list */
/* It is full. Remove the first entry in the list */
struct Curl_llist_node *e = Curl_llist_head(&asi->list);
struct altsvc *oldas = Curl_node_elem(e);
Curl_node_remove(e);
+1
View File
@@ -35,6 +35,7 @@
#define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */
#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */
#define CURL_NEW_ENV_VAR 0
#define CURL_NEW_ENV_VALUE 1
+4 -4
View File
@@ -281,8 +281,8 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
if(ares->ares_status == ARES_SUCCESS && !result) {
struct Curl_dns_entry *dns =
Curl_dnscache_mk_entry2(data, async->dns_queries,
&ares->res_AAAA, &ares->res_A,
async->hostname, async->port);
&ares->res_AAAA, &ares->res_A,
async->hostname, async->port);
if(!dns) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -314,7 +314,7 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
}
CURL_TRC_DNS(data, "ares: is_resolved() result=%d, dns=%sfound",
result, *pdns ? "" : "not ");
(int)result, *pdns ? "" : "not ");
async_ares_cleanup(async);
out:
@@ -489,7 +489,7 @@ static struct Curl_addrinfo *async_ares_node2addr(
struct Curl_addrinfo *calast = NULL;
int error = 0;
for(ai = node; ai != NULL; ai = ai->ai_next) {
for(ai = node; ai; ai = ai->ai_next) {
size_t ss_size;
struct Curl_addrinfo *ca;
/* ignore elements with unsupported address family,
+20 -10
View File
@@ -111,7 +111,7 @@ struct async_thrdd_item {
#ifdef CURLVERBOSE
char description[CURL_ASYN_ITEM_DESC_LEN];
#endif
int sock_error;
int sockerr;
uint32_t mid;
uint32_t resolv_id;
uint16_t port;
@@ -372,9 +372,9 @@ static void async_thrdd_item_process(void *arg)
rc = Curl_getaddrinfo_ex(item->hostname, service, &hints, &item->res);
if(rc) {
item->sock_error = SOCKERRNO ? SOCKERRNO : rc;
if(item->sock_error == 0)
item->sock_error = RESOLVER_ENOMEM;
item->sockerr = SOCKERRNO ? SOCKERRNO : rc;
if(item->sockerr == 0)
item->sockerr = RESOLVER_ENOMEM;
}
else {
Curl_addrinfo_set_port(item->res, item->port);
@@ -399,9 +399,9 @@ static void async_thrdd_item_process(void *arg)
#endif
item->res = Curl_ipv4_resolve_r(item->hostname, item->port);
if(!item->res) {
item->sock_error = SOCKERRNO;
if(item->sock_error == 0)
item->sock_error = RESOLVER_ENOMEM;
item->sockerr = SOCKERRNO;
if(item->sockerr == 0)
item->sockerr = RESOLVER_ENOMEM;
}
}
@@ -481,8 +481,13 @@ static void async_thrdd_report_item(struct Curl_easy *data,
struct dynbuf tmp;
const char *sep = "";
const struct Curl_addrinfo *ai = item->res;
int ai_family = (item->dns_queries & CURL_DNSQ_AAAA) ? AF_INET6 : AF_INET;
CURLcode result;
int ai_family;
#ifdef USE_IPV6
ai_family = (item->dns_queries & CURL_DNSQ_AAAA) ? AF_INET6 : AF_INET;
#else
ai_family = AF_INET;
#endif
if(!CURL_TRC_DNS_is_verbose(data))
return;
@@ -635,7 +640,7 @@ CURLcode Curl_async_getaddrinfo(struct Curl_easy *data,
out:
if(result)
CURL_TRC_DNS(data, "error queueing query %s:%d -> %d",
async->hostname, async->port, result);
async->hostname, async->port, (int)result);
return result;
}
@@ -701,6 +706,9 @@ CURLcode Curl_async_take_result(struct Curl_easy *data,
if(thrdd->rr.channel)
(void)Curl_ares_perform(thrdd->rr.channel, 0);
#endif
#ifndef ENABLE_WAKEUP
Curl_async_thrdd_multi_process(data->multi);
#endif
if(!async->done)
return CURLE_AGAIN;
@@ -756,7 +764,7 @@ out:
(result != CURLE_COULDNT_RESOLVE_HOST) &&
(result != CURLE_COULDNT_RESOLVE_PROXY)) {
CURL_TRC_DNS(data, "Error %d resolving %s:%d",
result, async->hostname, async->port);
(int)result, async->hostname, async->port);
}
return result;
}
@@ -789,10 +797,12 @@ const struct Curl_addrinfo *Curl_async_get_ai(struct Curl_easy *data,
if(thrdd->res_A)
return async_thrdd_get_ai(thrdd->res_A->res, ai_family, index);
break;
#ifdef USE_IPV6
case AF_INET6:
if(thrdd->res_AAAA)
return async_thrdd_get_ai(thrdd->res_AAAA->res, ai_family, index);
break;
#endif
default:
break;
}
+1
View File
@@ -204,6 +204,7 @@ void Curl_bufq_skip(struct bufq *q, size_t amount);
typedef CURLcode Curl_bufq_writer(void *writer_ctx,
const uint8_t *buf, size_t len,
size_t *pwritten);
/**
* Passes the chunks in the buffer queue to the writer and returns
* the amount of buf written. A writer may return -1 and CURLE_AGAIN
+92 -163
View File
@@ -37,48 +37,38 @@
struct cf_dns_ctx {
struct Curl_dns_entry *dns;
struct Curl_peer *peer;
CURLcode resolv_result;
uint32_t resolv_id;
uint16_t port;
uint8_t dns_queries;
uint8_t transport;
BIT(started);
BIT(announced);
BIT(abstract_unix_socket);
BIT(complete_resolve);
BIT(for_proxy);
char hostname[1];
};
static struct cf_dns_ctx *cf_dns_ctx_create(struct Curl_easy *data,
struct Curl_peer *peer,
uint8_t dns_queries,
const char *hostname,
uint16_t port, uint8_t transport,
bool abstract_unix_socket,
uint8_t transport,
bool for_proxy,
bool complete_resolve,
struct Curl_dns_entry *dns)
bool complete_resolve)
{
struct cf_dns_ctx *ctx;
size_t hlen = strlen(hostname);
ctx = curlx_calloc(1, sizeof(*ctx) + hlen);
ctx = curlx_calloc(1, sizeof(*ctx));
if(!ctx)
return NULL;
ctx->port = port;
Curl_peer_link(&ctx->peer, peer);
ctx->dns_queries = dns_queries;
ctx->transport = transport;
ctx->abstract_unix_socket = abstract_unix_socket;
ctx->for_proxy = for_proxy;
ctx->complete_resolve = complete_resolve;
ctx->dns = Curl_dns_entry_link(data, dns);
ctx->started = !!ctx->dns;
if(hlen)
memcpy(ctx->hostname, hostname, hlen);
CURL_TRC_DNS(data, "created DNS filter for %s:%u, transport=%x, queries=%x",
ctx->hostname, ctx->port, ctx->transport, ctx->dns_queries);
peer->hostname, peer->port, ctx->transport, ctx->dns_queries);
return ctx;
}
@@ -86,6 +76,7 @@ static void cf_dns_ctx_destroy(struct Curl_easy *data,
struct cf_dns_ctx *ctx)
{
if(ctx) {
Curl_peer_unlink(&ctx->peer);
Curl_dns_entry_unlink(data, &ctx->dns);
curlx_free(ctx);
}
@@ -131,16 +122,14 @@ static void cf_dns_report(struct Curl_cfilter *cf,
!dns->hostname[0] || Curl_host_is_ipnum(dns->hostname))
return;
switch(ctx->transport) {
case TRNSPRT_UNIX:
if(ctx->peer->unix_socket) {
#ifdef USE_UNIX_SOCKETS
CURL_TRC_CF(data, cf, "resolved unix domain %s",
Curl_conn_get_unix_path(data->conn));
CURL_TRC_CF(data, cf, "resolved unix://%s", ctx->peer->hostname);
#else
DEBUGASSERT(0);
#endif
break;
default:
}
else {
curlx_dyn_init(&tmp, 1024);
infof(data, "Host %s:%u was resolved.", dns->hostname, dns->port);
#ifdef CURLRES_IPV6
@@ -161,7 +150,6 @@ static void cf_dns_report(struct Curl_cfilter *cf,
}
#endif
curlx_dyn_free(&tmp);
break;
}
}
#else
@@ -181,24 +169,19 @@ static CURLcode cf_dns_start(struct Curl_cfilter *cf,
*pdns = NULL;
#ifdef USE_UNIX_SOCKETS
if(ctx->transport == TRNSPRT_UNIX) {
CURL_TRC_CF(data, cf, "resolve unix socket %s", ctx->hostname);
return Curl_resolv_unix(data, ctx->hostname,
(bool)cf->conn->bits.abstract_unix_socket, pdns);
}
#endif
/* Resolve target host right on */
CURL_TRC_CF(data, cf, "cf_dns_start host %s:%u", ctx->hostname, ctx->port);
if(Curl_is_ipv4addr(ctx->hostname))
CURL_TRC_CF(data, cf, "cf_dns_start %s %s:%u",
ctx->peer->unix_socket ? "unix-domain-socket" : "host",
ctx->peer->hostname, ctx->peer->port);
if(ctx->peer->unix_socket)
ctx->dns_queries = 0;
else if(Curl_is_ipv4addr(ctx->peer->hostname))
ctx->dns_queries |= CURL_DNSQ_A;
#ifdef USE_IPV6
else if(Curl_is_ipaddr(ctx->hostname)) /* not ipv4, must be ipv6 then */
else if(ctx->peer->ipv6)
ctx->dns_queries |= CURL_DNSQ_AAAA;
#endif
result = Curl_resolv(data, ctx->dns_queries,
ctx->hostname, ctx->port, ctx->transport,
result = Curl_resolv(data, ctx->peer, ctx->dns_queries, ctx->transport,
(bool)ctx->for_proxy, timeout_ms,
&ctx->resolv_id, pdns);
DEBUGASSERT(!result || !*pdns);
@@ -211,14 +194,14 @@ static CURLcode cf_dns_start(struct Curl_cfilter *cf,
}
else if(result == CURLE_OPERATION_TIMEDOUT) { /* took too long */
failf(data, "Failed to resolve '%s' with timeout after %"
FMT_TIMEDIFF_T " ms", ctx->hostname,
FMT_TIMEDIFF_T " ms", ctx->peer->hostname,
curlx_ptimediff_ms(Curl_pgrs_now(data),
&data->progress.t_startsingle));
return CURLE_OPERATION_TIMEDOUT;
}
else {
DEBUGASSERT(result);
failf(data, "Could not resolve: %s", ctx->hostname);
failf(data, "Could not resolve: %s", ctx->peer->hostname);
return result;
}
}
@@ -281,7 +264,7 @@ static CURLcode cf_dns_connect(struct Curl_cfilter *cf,
}
if(ctx->resolv_result) {
CURL_TRC_CF(data, cf, "error resolving: %d", ctx->resolv_result);
CURL_TRC_CF(data, cf, "error resolving: %d", (int)ctx->resolv_result);
return ctx->resolv_result;
}
@@ -327,13 +310,6 @@ static void cf_dns_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
cf_dns_ctx_destroy(data, ctx);
}
static void cf_dns_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
cf->connected = FALSE;
if(cf->next)
cf->next->cft->do_close(cf->next, data);
}
static CURLcode cf_dns_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
@@ -379,7 +355,6 @@ struct Curl_cftype Curl_cft_dns = {
CURL_LOG_LVL_NONE,
cf_dns_destroy,
cf_dns_connect,
cf_dns_close,
Curl_cf_def_shutdown,
cf_dns_adjust_pollset,
Curl_cf_def_data_pending,
@@ -393,23 +368,19 @@ struct Curl_cftype Curl_cft_dns = {
static CURLcode cf_dns_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *peer,
uint8_t dns_queries,
const char *hostname,
uint16_t port,
uint8_t transport,
bool abstract_unix_socket,
bool for_proxy,
bool complete_resolve,
struct Curl_dns_entry *dns)
bool complete_resolve)
{
struct Curl_cfilter *cf = NULL;
struct cf_dns_ctx *ctx;
CURLcode result = CURLE_OK;
(void)data;
ctx = cf_dns_ctx_create(data, dns_queries, hostname, port, transport,
abstract_unix_socket, for_proxy,
complete_resolve, dns);
ctx = cf_dns_ctx_create(data, peer, dns_queries, transport,
for_proxy, complete_resolve);
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -424,88 +395,28 @@ out:
return result;
}
/* Create a "resolv" filter for the transfer's connection. Figures
* out the hostname/path and port where to connect to. */
static CURLcode cf_dns_conn_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
uint8_t dns_queries,
uint8_t transport,
bool complete_resolve,
struct Curl_dns_entry *dns)
{
struct connectdata *conn = data->conn;
const char *hostname = NULL;
uint16_t port = 0;
bool abstract_unix_socket = FALSE, for_proxy = FALSE;
#ifdef USE_UNIX_SOCKETS
{
const char *unix_path = Curl_conn_get_unix_path(conn);
if(unix_path) {
DEBUGASSERT(transport == TRNSPRT_UNIX);
hostname = unix_path;
abstract_unix_socket = (bool)conn->bits.abstract_unix_socket;
}
}
#endif
#ifndef CURL_DISABLE_PROXY
if(!hostname && conn->bits.proxy) {
for_proxy = TRUE;
hostname = conn->bits.socksproxy ?
conn->socks_proxy.host.name : conn->http_proxy.host.name;
port = conn->bits.socksproxy ?
conn->socks_proxy.port : conn->http_proxy.port;
}
#endif
if(!hostname) {
struct hostname *ehost;
ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
/* If not connecting via a proxy, extract the port from the URL, if it is
* there, thus overriding any defaults that might have been set above. */
hostname = ehost->name;
port = conn->bits.conn_to_port ?
conn->conn_to_port : (uint16_t)conn->remote_port;
}
if(!hostname) {
DEBUGASSERT(0);
return CURLE_FAILED_INIT;
}
return cf_dns_create(pcf, data, dns_queries,
hostname, port, transport,
abstract_unix_socket, for_proxy,
complete_resolve, dns);
}
/* Adds a "resolv" filter at the top of the connection's filter chain.
* For FIRSTSOCKET, the `dns` parameter may be NULL. The filter will
* figure out hostname and port to connect to and start the DNS resolve
* on the first connect attempt.
* For SECONDARYSOCKET, the `dns` parameter must be given.
*/
* The filter will resolve the peer on the first connect attempt. */
CURLcode Curl_cf_dns_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
struct Curl_peer *peer,
uint8_t dns_queries,
uint8_t transport,
struct Curl_dns_entry *dns)
uint8_t transport)
{
struct Curl_cfilter *cf = NULL;
bool for_proxy = FALSE;
CURLcode result;
DEBUGASSERT(data);
if(sockindex == FIRSTSOCKET)
result = cf_dns_conn_create(&cf, data, dns_queries, transport, FALSE, dns);
else if(dns) {
result = cf_dns_create(&cf, data, dns_queries,
dns->hostname, dns->port, transport,
FALSE, FALSE, FALSE, dns);
}
else {
DEBUGASSERT(0);
result = CURLE_FAILED_INIT;
}
if(!peer)
return CURLE_FAILED_INIT;
#ifndef CURL_DISABLE_PROXY
for_proxy = (peer == conn->socks_proxy.peer) ||
(peer == conn->http_proxy.peer);
#endif
result = cf_dns_create(&cf, data, peer, dns_queries, transport,
for_proxy, FALSE);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -514,7 +425,7 @@ out:
}
/* Insert a new "resolv" filter directly after `cf`. It will
* start a DNS resolve for the given hostnmae and port on the
* start a DNS resolve for the given peer on the
* first connect attempt.
* See socks.c on how this is used to make a non-blocking DNS
* resolve during connect.
@@ -522,17 +433,15 @@ out:
CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
uint8_t dns_queries,
const char *hostname,
uint16_t port,
struct Curl_peer *peer,
uint8_t transport,
bool complete_resolve)
{
struct Curl_cfilter *cf;
CURLcode result;
result = cf_dns_create(&cf, data, dns_queries,
hostname, port, transport,
FALSE, FALSE, complete_resolve, NULL);
result = cf_dns_create(&cf, data, peer, dns_queries, transport,
FALSE, complete_resolve);
if(result)
return result;
@@ -543,29 +452,35 @@ CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
/* Return the resolv result from the first "resolv" filter, starting
* the given filter `cf` downwards.
*/
static CURLcode cf_dns_result(struct Curl_cfilter *cf)
static CURLcode cf_dns_result(struct Curl_cfilter *cf,
struct Curl_peer *peer)
{
for(; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_dns) {
struct cf_dns_ctx *ctx = cf->ctx;
if(ctx->dns || ctx->resolv_result)
return ctx->resolv_result;
return CURLE_AGAIN;
if(Curl_peer_same_destination(ctx->peer, peer)) {
if(ctx->dns || ctx->resolv_result)
return ctx->resolv_result;
return CURLE_AGAIN;
}
return CURLE_OK; /* ok, but no results */
}
}
return CURLE_FAILED_INIT;
}
/* Return the result of the DNS resolution. Searches for a "resolv"
/* Return the result of the DNS resolution for peer. Searches for a "resolv"
* filter from the top of the filter chain down. Returns
* - CURLE_AGAIN when not done yet
* - CURLE_OK when DNS was successfully resolved
* - CURLR_FAILED_INIT when no resolv filter was found
* - error returned by the DNS resolv
*/
CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex)
CURLcode Curl_conn_dns_result(struct connectdata *conn,
int sockindex,
struct Curl_peer *peer)
{
return cf_dns_result(conn->cfilter[sockindex]);
return cf_dns_result(conn->cfilter[sockindex], peer);
}
static const struct Curl_addrinfo *cf_dns_get_nth_ai(
@@ -598,6 +513,7 @@ static const struct Curl_addrinfo *cf_dns_get_nth_ai(
*/
const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct Curl_peer *peer,
int ai_family,
unsigned int index)
{
@@ -605,12 +521,14 @@ const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
for(; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_dns) {
struct cf_dns_ctx *ctx = cf->ctx;
if(ctx->resolv_result)
return NULL;
else if(ctx->dns)
return cf_dns_get_nth_ai(cf, ctx->dns->addr, ai_family, index);
else
return Curl_resolv_get_ai(data, ctx->resolv_id, ai_family, index);
if(Curl_peer_same_destination(ctx->peer, peer)) {
if(ctx->resolv_result)
return NULL;
else if(ctx->dns)
return cf_dns_get_nth_ai(cf, ctx->dns->addr, ai_family, index);
else
return Curl_resolv_get_ai(data, ctx->resolv_id, ai_family, index);
}
}
}
return NULL;
@@ -621,11 +539,14 @@ const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
* not done yet or if no address for the family exists, returns NULL.
*/
const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
int sockindex, int ai_family,
struct Curl_peer *peer,
int sockindex,
int ai_family,
unsigned int index)
{
struct connectdata *conn = data->conn;
return Curl_cf_dns_get_ai(conn->cfilter[sockindex], data, ai_family, index);
return Curl_cf_dns_get_ai(conn->cfilter[sockindex], data, peer,
ai_family, index);
}
#ifdef USE_HTTPSRR
@@ -633,35 +554,43 @@ const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
* connection. If the DNS resolving is not done yet or if there
* is no HTTPS-RR info, returns NULL.
*/
const struct Curl_https_rrinfo *Curl_conn_dns_get_https(struct Curl_easy *data,
int sockindex)
const struct Curl_https_rrinfo *
Curl_conn_dns_get_https(struct Curl_easy *data,
int sockindex,
struct Curl_peer *peer)
{
struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
for(; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_dns) {
struct cf_dns_ctx *ctx = cf->ctx;
if(ctx->dns)
return ctx->dns->hinfo;
else
return Curl_resolv_get_https(data, ctx->resolv_id);
if(Curl_peer_same_destination(ctx->peer, peer)) {
if(ctx->dns)
return ctx->dns->hinfo;
else
return Curl_resolv_get_https(data, ctx->resolv_id);
}
}
}
return NULL;
}
bool Curl_conn_dns_resolved_https(struct Curl_easy *data, int sockindex)
bool Curl_conn_dns_resolved_https(struct Curl_easy *data,
int sockindex,
struct Curl_peer *peer)
{
struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
for(; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_dns) {
struct cf_dns_ctx *ctx = cf->ctx;
if(ctx->dns)
return TRUE;
else
return Curl_resolv_knows_https(data, ctx->resolv_id);
if(Curl_peer_same_destination(ctx->peer, peer)) {
if(ctx->dns)
return TRUE;
else
return Curl_resolv_knows_https(data, ctx->resolv_id);
}
}
}
return FALSE;
return TRUE;
}
#endif /* USE_HTTPSRR */
+18 -10
View File
@@ -29,41 +29,49 @@ struct Curl_easy;
struct connectdata;
struct Curl_dns_entry;
struct Curl_addrinfo;
struct Curl_peer;
CURLcode Curl_cf_dns_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
struct Curl_peer *peer,
uint8_t dns_queries,
uint8_t transport,
struct Curl_dns_entry *dns);
uint8_t transport);
CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
uint8_t dns_queries,
const char *hostname,
uint16_t port,
struct Curl_peer *peer,
uint8_t transport,
bool complete_resolve);
CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex);
CURLcode Curl_conn_dns_result(struct connectdata *conn,
int sockindex,
struct Curl_peer *peer);
const struct Curl_addrinfo *Curl_conn_dns_get_ai(struct Curl_easy *data,
struct Curl_peer *peer,
int sockindex,
int ai_family,
unsigned int index);
const struct Curl_addrinfo *Curl_cf_dns_get_ai(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct Curl_peer *peer,
int ai_family,
unsigned int index);
#ifdef USE_HTTPSRR
const struct Curl_https_rrinfo *Curl_conn_dns_get_https(struct Curl_easy *data,
int sockindex);
bool Curl_conn_dns_resolved_https(struct Curl_easy *data, int sockindex);
const struct Curl_https_rrinfo *
Curl_conn_dns_get_https(struct Curl_easy *data,
int sockindex,
struct Curl_peer *peer);
bool Curl_conn_dns_resolved_https(struct Curl_easy *data,
int sockindex,
struct Curl_peer *peer);
#else
#define Curl_conn_dns_get_https(a, b) NULL
#define Curl_conn_dns_resolved_https(a, b) TRUE
#define Curl_conn_dns_get_https(a, b, c) NULL
#define Curl_conn_dns_resolved_https(a, b, c) TRUE
#endif
extern struct Curl_cftype Curl_cft_dns;
+271 -54
View File
@@ -25,6 +25,8 @@
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
#include <curl/curl.h>
#include "urldata.h"
#include "curlx/dynbuf.h"
#include "sendf.h"
@@ -33,6 +35,7 @@
#include "http_proxy.h"
#include "select.h"
#include "progress.h"
#include "multiif.h"
#include "cfilters.h"
#include "cf-h1-proxy.h"
#include "connect.h"
@@ -40,7 +43,6 @@
#include "strcase.h"
#include "curlx/strparse.h"
typedef enum {
H1_TUNNEL_INIT, /* init/default/no tunnel state */
H1_TUNNEL_CONNECT, /* CONNECT request is being send */
@@ -52,11 +54,13 @@ typedef enum {
/* struct for HTTP CONNECT tunneling */
struct h1_tunnel_state {
struct Curl_peer *dest;
struct dynbuf rcvbuf;
struct dynbuf request_data;
size_t nsent;
size_t headerlines;
struct Curl_chunker ch;
int httpversion;
enum keeponval {
KEEPON_DONE,
KEEPON_CONNECT,
@@ -70,6 +74,12 @@ struct h1_tunnel_state {
BIT(leading_unfold);
};
/* Persistent context for the H1-PROXY filter */
struct cf_h1_proxy_ctx {
struct h1_tunnel_state *ts;
BIT(udp_tunnel);
};
static bool tunnel_is_established(struct h1_tunnel_state *ts)
{
return ts && (ts->tunnel_state == H1_TUNNEL_ESTABLISHED);
@@ -80,6 +90,12 @@ static bool tunnel_is_failed(struct h1_tunnel_state *ts)
return ts && (ts->tunnel_state == H1_TUNNEL_FAILED);
}
static bool h1_proxy_is_udp(struct Curl_cfilter *cf)
{
struct cf_h1_proxy_ctx *pctx = cf->ctx;
return (pctx->udp_tunnel ? TRUE : FALSE);
}
static CURLcode tunnel_reinit(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct h1_tunnel_state *ts)
@@ -95,6 +111,8 @@ static CURLcode tunnel_reinit(struct Curl_cfilter *cf,
ts->close_connection = FALSE;
ts->maybe_folded = FALSE;
ts->leading_unfold = FALSE;
ts->nsent = 0;
ts->headerlines = 0;
return CURLE_OK;
}
@@ -156,7 +174,9 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
case H1_TUNNEL_ESTABLISHED:
CURL_TRC_CF(data, cf, "new tunnel state 'established'");
infof(data, "CONNECT phase completed");
infof(data, "CONNECT%s phase completed for HTTP proxy",
h1_proxy_is_udp(cf) ? "-UDP" : "");
data->state.authproxy.done = TRUE;
data->state.authproxy.multipass = FALSE;
FALLTHROUGH();
@@ -172,23 +192,33 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
/* If a proxy-authorization header was used for the proxy, then we should
make sure that it is not accidentally used for the document request
after we have connected. Let's thus free and clear it here. */
curlx_safefree(data->req.proxyuserpwd);
curlx_safefree(data->req.hd_proxy_auth);
break;
}
}
static void tunnel_free(struct Curl_cfilter *cf,
static void tunnel_free(struct h1_tunnel_state *ts,
struct Curl_easy *data)
{
if(ts) {
Curl_peer_unlink(&ts->dest);
curlx_dyn_free(&ts->rcvbuf);
curlx_dyn_free(&ts->request_data);
Curl_httpchunk_free(data, &ts->ch);
curlx_free(ts);
}
}
static void cf_tunnel_free(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
if(cf) {
struct h1_tunnel_state *ts = cf->ctx;
struct cf_h1_proxy_ctx *pctx = cf->ctx;
struct h1_tunnel_state *ts = pctx ? pctx->ts : NULL;
if(ts) {
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
curlx_dyn_free(&ts->rcvbuf);
curlx_dyn_free(&ts->request_data);
Curl_httpchunk_free(data, &ts->ch);
curlx_free(ts);
cf->ctx = NULL;
tunnel_free(ts, data);
pctx->ts = NULL;
}
}
}
@@ -206,20 +236,21 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
int http_minor;
CURLcode result;
DEBUGASSERT(data);
/* This only happens if we have looped here due to authentication reasons,
and we do not really use the newly cloned URL here then. Free it. */
curlx_safefree(data->req.newurl);
result = Curl_http_proxy_create_CONNECT(&req, cf, data, 1);
result = Curl_http_proxy_create_tunnel_request(&req, cf, data, ts->dest,
PROXY_HTTP_V1,
h1_proxy_is_udp(cf));
if(result)
goto out;
infof(data, "Establish HTTP proxy tunnel to %s", req->authority);
curlx_dyn_reset(&ts->request_data);
ts->nsent = 0;
ts->headerlines = 0;
http_minor = (cf->conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? 0 : 1;
http_minor = ts->httpversion % 10;
result = Curl_h1_req_write_head(req, http_minor, &ts->request_data);
if(!result)
@@ -268,6 +299,92 @@ out:
return result;
}
static CURLcode on_resp_header_udp(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct h1_tunnel_state *ts,
const char *header)
{
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
if((checkprefix("WWW-Authenticate:", header) && (401 == k->httpcode)) ||
(checkprefix("Proxy-authenticate:", header) && (407 == k->httpcode))) {
bool proxy = (k->httpcode == 407);
char *auth = Curl_copy_header_value(header);
if(!auth)
return CURLE_OUT_OF_MEMORY;
CURL_TRC_CF(data, cf, "CONNECT-UDP: fwd auth header '%s'", header);
result = Curl_http_input_auth(data, proxy, auth);
curlx_free(auth);
if(result)
return result;
}
else if(checkprefix("Content-Length:", header)) {
if(k->httpcode / 100 == 2 || k->httpcode == 101) {
infof(data, "Ignoring Content-Length in CONNECT-UDP %03d response",
k->httpcode);
}
else {
const char *p = header + strlen("Content-Length:");
if(curlx_str_numblanks(&p, &ts->cl)) {
failf(data, "Unsupported Content-Length value");
return CURLE_WEIRD_SERVER_REPLY;
}
}
}
else if(checkprefix("Transfer-Encoding:", header)) {
if(k->httpcode / 100 == 2 || k->httpcode == 101) {
infof(data, "Ignoring Transfer-Encoding in "
"CONNECT-UDP %03d response", k->httpcode);
}
else if(Curl_compareheader(header,
STRCONST("Transfer-Encoding:"),
STRCONST("chunked"))) {
CURL_TRC_CF(data, cf, "CONNECT-UDP Response --> "
"Transfer-Encoding: chunked");
ts->chunked_encoding = TRUE;
/* reset our chunky engine */
Curl_httpchunk_reset(data, &ts->ch, TRUE);
}
}
else if(checkprefix("Capsule-protocol:", header)) {
if(Curl_compareheader(header,
STRCONST("Capsule-protocol:"),
STRCONST("?1"))) {
CURL_TRC_CF(data, cf, "CONNECT-UDP Response --> Capsule-protocol: ?1");
}
}
else if(Curl_compareheader(header,
STRCONST("Connection:"), STRCONST("close"))) {
ts->close_connection = TRUE;
CURL_TRC_CF(data, cf, "CONNECT-UDP Response --> Connection: close");
}
else if(Curl_compareheader(header,
STRCONST("Proxy-Connection:"),
STRCONST("close"))) {
ts->close_connection = TRUE;
CURL_TRC_CF(data, cf,
"CONNECT-UDP Response --> Proxy-Connection: close");
}
else if(!strncmp(header, "HTTP/1.", 7) &&
((header[7] == '0') || (header[7] == '1')) &&
(header[8] == ' ') &&
ISDIGIT(header[9]) && ISDIGIT(header[10]) && ISDIGIT(header[11]) &&
!ISDIGIT(header[12])) {
/* store the HTTP code from the proxy */
data->info.httpproxycode = k->httpcode =
((header[9] - '0') * 100) +
((header[10] - '0') * 10) +
(header[11] - '0');
CURL_TRC_CF(data, cf, "CONNECT-UDP Response --> %d", k->httpcode);
}
return result;
}
static CURLcode on_resp_header(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct h1_tunnel_state *ts,
@@ -359,6 +476,12 @@ static CURLcode single_header(struct Curl_cfilter *cf,
/* output debug if that is requested */
Curl_debug(data, CURLINFO_HEADER_IN, linep, line_len);
/* a CONNECT response line is handed to the client as a header, so it must
pass the same checks as a regular response header before delivery */
result = Curl_verify_header(data, linep, line_len);
if(result)
return result;
/* send the header to the callback */
writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
(ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
@@ -406,7 +529,13 @@ static CURLcode single_header(struct Curl_cfilter *cf,
return result;
}
result = on_resp_header(cf, data, ts, linep);
if(h1_proxy_is_udp(cf)) {
result = on_resp_header_udp(cf, data, ts, linep);
}
else {
result = on_resp_header(cf, data, ts, linep);
}
if(result)
return result;
@@ -448,8 +577,15 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
}
if(!nread) {
if(ts->maybe_folded) {
/* EOF right after LF: finalize the pending header line. */
result = single_header(cf, data, ts);
if(result)
return result;
ts->maybe_folded = FALSE;
}
if(data->set.proxyauth && data->state.authproxy.avail &&
data->req.proxyuserpwd) {
data->req.hd_proxy_auth) {
/* proxy auth was requested and there was proxy auth available,
then deem this as "mere" proxy disconnect */
ts->close_connection = TRUE;
@@ -539,12 +675,16 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
ts->maybe_folded = TRUE;
}
if(result)
return result;
} /* while there is buffer left and loop is requested */
if(error)
result = CURLE_RECV_ERROR;
*done = (ts->keepon == KEEPON_DONE);
if(!result && *done && data->info.httpproxycode / 100 != 2) {
if(!result && *done &&
data->info.httpproxycode / 100 != 2 &&
!(h1_proxy_is_udp(cf) && data->info.httpproxycode == 101)) {
/* Deal with the possibly already received authenticate
headers. 'newurl' is set to a new URL if we must loop. */
result = Curl_http_auth_act(data);
@@ -597,7 +737,8 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "CONNECT receive");
result = recv_CONNECT_resp(cf, data, ts, &done);
if(result)
CURL_TRC_CF(data, cf, "error receiving CONNECT response: %d", result);
CURL_TRC_CF(data, cf, "error receiving CONNECT response: %d",
(int)result);
if(!result)
result = Curl_pgrsUpdate(data);
/* error or not complete yet. return for more multi-multi */
@@ -623,9 +764,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
*/
CURL_TRC_CF(data, cf, "CONNECT need to close+open");
infof(data, "Connect me again please");
Curl_conn_cf_close(cf, data);
result = Curl_conn_cf_connect(cf->next, data, &done);
goto out;
return CURLE_AGAIN;
}
else {
/* staying on this connection, reset state */
@@ -641,17 +780,36 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
} while(data->req.newurl);
DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE);
if(data->info.httpproxycode / 100 != 2) {
/* a non-2xx response and we have no next URL to try. */
curlx_safefree(data->req.newurl);
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
return CURLE_COULDNT_CONNECT;
if(h1_proxy_is_udp(cf)) {
/* RFC 9298: Accept 101 Upgrade for HTTP/1.1 and
* 2xx responses for HTTP/2 and HTTP/3 proxies. */
if(data->info.httpproxycode / 100 != 2 &&
data->info.httpproxycode != 101) {
curlx_safefree(data->req.newurl);
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
failf(data, "CONNECT-UDP tunnel failed, response %d",
data->req.httpcode);
return CURLE_COULDNT_CONNECT;
}
}
else {
if(data->info.httpproxycode / 100 != 2) {
/* a non-2xx response and we have no next URL to try. */
curlx_safefree(data->req.newurl);
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
return CURLE_COULDNT_CONNECT;
}
}
/* 2xx response, SUCCESS! */
/* 101 Switching Protocol for CONNECT-UDP */
h1_tunnel_go_state(cf, ts, H1_TUNNEL_ESTABLISHED, data);
infof(data, "CONNECT tunnel established, response %d",
data->info.httpproxycode);
if(h1_proxy_is_udp(cf))
infof(data, "CONNECT-UDP tunnel established, response %d",
data->info.httpproxycode);
else
infof(data, "CONNECT tunnel established, response %d",
data->info.httpproxycode);
result = CURLE_OK;
out:
@@ -665,7 +823,8 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
bool *done)
{
CURLcode result;
struct h1_tunnel_state *ts = cf->ctx;
struct cf_h1_proxy_ctx *pctx = cf->ctx;
struct h1_tunnel_state *ts = pctx->ts;
if(cf->connected) {
*done = TRUE;
@@ -682,7 +841,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
result = tunnel_init(cf, data, &ts);
if(result)
return result;
cf->ctx = ts;
pctx->ts = ts;
}
/* We want "seamless" operations through HTTP proxy tunnel */
@@ -690,18 +849,17 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
result = H1_CONNECT(cf, data, ts);
if(result)
goto out;
curlx_safefree(data->req.proxyuserpwd);
curlx_safefree(data->req.hd_proxy_auth);
out:
*done = (result == CURLE_OK) && tunnel_is_established(cf->ctx);
*done = (result == CURLE_OK) && tunnel_is_established(pctx->ts);
if(*done) {
cf->connected = TRUE;
/* The real request will follow the CONNECT, reset request partially */
Curl_req_soft_reset(&data->req, data);
Curl_client_reset(data);
Curl_pgrsReset(data);
tunnel_free(cf, data);
cf_tunnel_free(cf, data);
}
return result;
}
@@ -710,7 +868,8 @@ static CURLcode cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct h1_tunnel_state *ts = cf->ctx;
struct cf_h1_proxy_ctx *pctx = cf->ctx;
struct h1_tunnel_state *ts = pctx->ts;
CURLcode result = CURLE_OK;
if(!cf->connected) {
@@ -730,28 +889,52 @@ static CURLcode cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
else
result = Curl_pollset_set_out_only(data, ps, sock);
}
else {
if(cf->next)
result = cf->next->cft->adjust_pollset(cf->next, data, ps);
}
return result;
}
static bool cf_h1_proxy_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
return cf->next ? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
}
static void cf_h1_proxy_destroy(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "destroy");
tunnel_free(cf, data);
cf_tunnel_free(cf, data);
curlx_safefree(cf->ctx);
}
static void cf_h1_proxy_close(struct Curl_cfilter *cf,
struct Curl_easy *data)
static CURLcode cf_h1_proxy_query(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query, int *pres1, void *pres2)
{
CURL_TRC_CF(data, cf, "close");
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);
struct cf_h1_proxy_ctx *pctx = cf->ctx;
struct h1_tunnel_state *ts = pctx ? pctx->ts : NULL;
switch(query) {
case CF_QUERY_HOST_PORT:
if(!ts || !ts->dest)
break;
*pres1 = (int)ts->dest->port;
*((const char **)pres2) = ts->dest->hostname;
return CURLE_OK;
case CF_QUERY_ALPN_NEGOTIATED: {
const char **palpn = pres2;
DEBUGASSERT(palpn);
*palpn = NULL;
return CURLE_OK;
}
default:
break;
}
return cf->next ?
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
CURLE_UNKNOWN_OPTION;
}
struct Curl_cftype Curl_cft_h1_proxy = {
@@ -760,28 +943,62 @@ struct Curl_cftype Curl_cft_h1_proxy = {
0,
cf_h1_proxy_destroy,
cf_h1_proxy_connect,
cf_h1_proxy_close,
Curl_cf_def_shutdown,
cf_h1_proxy_adjust_pollset,
Curl_cf_def_data_pending,
cf_h1_proxy_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
Curl_cf_def_cntrl,
Curl_cf_def_conn_is_alive,
Curl_cf_def_conn_keep_alive,
Curl_cf_http_proxy_query,
cf_h1_proxy_query,
};
CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data)
struct Curl_easy *data,
struct Curl_peer *dest,
int httpversion,
bool udp_tunnel)
{
struct Curl_cfilter *cf;
struct cf_h1_proxy_ctx *pctx;
struct h1_tunnel_state *ts;
CURLcode result;
(void)data;
result = Curl_cf_create(&cf, &Curl_cft_h1_proxy, NULL);
if(!result)
Curl_conn_cf_insert_after(cf_at, cf);
if(!dest)
return CURLE_FAILED_INIT;
if((httpversion < 10) || (httpversion >= 20))
return CURLE_FAILED_INIT;
ts = curlx_calloc(1, sizeof(*ts));
if(!ts) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
Curl_peer_link(&ts->dest, dest);
ts->httpversion = httpversion;
curlx_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
curlx_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
Curl_httpchunk_init(data, &ts->ch, TRUE);
pctx = curlx_calloc(1, sizeof(*pctx));
if(!pctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
pctx->udp_tunnel = udp_tunnel;
pctx->ts = ts;
result = Curl_cf_create(&cf, &Curl_cft_h1_proxy, pctx);
if(result) {
curlx_free(pctx);
goto out;
}
ts = NULL;
Curl_conn_cf_insert_after(cf_at, cf);
out:
tunnel_free(ts, data);
return result;
}
+6 -1
View File
@@ -27,8 +27,13 @@
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
struct Curl_peer;
CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data);
struct Curl_easy *data,
struct Curl_peer *dest,
int httpversion,
bool udp_tunnel);
extern struct Curl_cftype Curl_cft_h1_proxy;
+101 -96
View File
@@ -76,30 +76,40 @@ struct tunnel_stream {
BIT(reset);
};
static CURLcode tunnel_stream_init(struct Curl_cfilter *cf,
struct tunnel_stream *ts)
static CURLcode tunnel_stream_init(struct tunnel_stream *ts,
struct Curl_peer *dest)
{
const char *hostname;
uint16_t port;
bool ipv6_ip;
ts->state = H2_TUNNEL_INIT;
ts->stream_id = -1;
Curl_bufq_init2(&ts->recvbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS,
BUFQ_OPT_SOFT_LIMIT);
Curl_bufq_init(&ts->sendbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS);
Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip);
/* host:port with IPv6 support */
ts->authority = curl_maprintf("%s%s%s:%u", ipv6_ip ? "[" : "", hostname,
ipv6_ip ? "]" : "", port);
ts->authority = curl_maprintf("%s%s%s:%u", dest->ipv6 ? "[" : "",
dest->hostname,
dest->ipv6 ? "]" : "",
dest->port);
if(!ts->authority)
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
}
static void tunnel_stream_reset(struct tunnel_stream *ts)
{
Curl_http_resp_free(ts->resp);
ts->resp = NULL;
Curl_bufq_reset(&ts->recvbuf);
Curl_bufq_reset(&ts->sendbuf);
ts->stream_id = -1;
ts->error = 0;
ts->has_final_response = FALSE;
ts->closed = FALSE;
ts->reset = FALSE;
ts->state = H2_TUNNEL_INIT;
}
static void tunnel_stream_clear(struct tunnel_stream *ts)
{
Curl_http_resp_free(ts->resp);
@@ -113,9 +123,11 @@ static void tunnel_stream_clear(struct tunnel_stream *ts)
static void h2_tunnel_go_state(struct Curl_cfilter *cf,
struct tunnel_stream *ts,
h2_tunnel_state new_state,
struct Curl_easy *data)
struct Curl_easy *data,
bool udp_tunnel)
{
(void)cf;
(void)udp_tunnel;
if(ts->state == new_state)
return;
@@ -131,7 +143,7 @@ static void h2_tunnel_go_state(struct Curl_cfilter *cf,
switch(new_state) {
case H2_TUNNEL_INIT:
CURL_TRC_CF(data, cf, "[%d] new tunnel state 'init'", ts->stream_id);
tunnel_stream_clear(ts);
tunnel_stream_reset(ts);
break;
case H2_TUNNEL_CONNECT:
@@ -147,7 +159,8 @@ static void h2_tunnel_go_state(struct Curl_cfilter *cf,
case H2_TUNNEL_ESTABLISHED:
CURL_TRC_CF(data, cf, "[%d] new tunnel state 'established'",
ts->stream_id);
infof(data, "CONNECT phase completed");
infof(data, "CONNECT%s phase completed for HTTP/2 proxy",
udp_tunnel ? "-UDP" : "");
data->state.authproxy.done = TRUE;
data->state.authproxy.multipass = FALSE;
FALLTHROUGH();
@@ -158,7 +171,7 @@ static void h2_tunnel_go_state(struct Curl_cfilter *cf,
/* If a proxy-authorization header was used for the proxy, then we should
make sure that it is not accidentally used for the document request
after we have connected. Let's thus free and clear it here. */
curlx_safefree(data->req.proxyuserpwd);
curlx_safefree(data->req.hd_proxy_auth);
break;
}
}
@@ -171,6 +184,7 @@ struct cf_h2_proxy_ctx {
struct bufq inbufq; /* network receive buffer */
struct bufq outbufq; /* network send buffer */
struct Curl_peer *dest; /* where to tunnel to */
struct tunnel_stream tunnel; /* our tunnel CONNECT stream */
int32_t goaway_error;
int32_t last_stream_id;
@@ -178,6 +192,7 @@ struct cf_h2_proxy_ctx {
BIT(rcvd_goaway);
BIT(sent_goaway);
BIT(nw_out_blocked);
BIT(udp_tunnel);
};
/* How to access `call_data` from a cf_h2 filter */
@@ -193,6 +208,7 @@ static void cf_h2_proxy_ctx_clear(struct cf_h2_proxy_ctx *ctx)
}
Curl_bufq_free(&ctx->inbufq);
Curl_bufq_free(&ctx->outbufq);
Curl_peer_unlink(&ctx->dest);
tunnel_stream_clear(&ctx->tunnel);
memset(ctx, 0, sizeof(*ctx));
ctx->call_data = save;
@@ -213,7 +229,8 @@ static void drain_tunnel(struct Curl_cfilter *cf,
struct cf_h2_proxy_ctx *ctx = cf->ctx;
(void)cf;
if(!tunnel->closed && !tunnel->reset &&
!Curl_bufq_is_empty(&ctx->tunnel.sendbuf))
(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf) ||
!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)))
Curl_multi_mark_dirty(data);
}
@@ -228,7 +245,7 @@ static CURLcode proxy_h2_nw_out_writer(void *writer_ctx,
CURLcode result;
result = Curl_conn_cf_send(cf->next, data, buf, buflen, FALSE, pnwritten);
CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %d, %zu",
buflen, result, *pnwritten);
buflen, (int)result, *pnwritten);
return result;
}
return CURLE_FAILED_INIT;
@@ -247,8 +264,7 @@ static int proxy_h2_client_new(struct Curl_cfilter *cf,
return rc;
/* We handle window updates ourself to enforce buffer limits */
nghttp2_option_set_no_auto_window_update(o, 1);
#if NGHTTP2_VERSION_NUM >= 0x013200
/* with 1.50.0 */
#if NGHTTP2_VERSION_NUM >= 0x013200 /* with 1.50.0 */
/* turn off RFC 9113 leading and trailing white spaces validation against
HTTP field value. */
nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1);
@@ -354,7 +370,7 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %d, %zu",
Curl_bufq_len(&ctx->inbufq), result, nread);
Curl_bufq_len(&ctx->inbufq), (int)result, nread);
if(result) {
if(result != CURLE_AGAIN) {
failf(data, "Failed receiving HTTP2 proxy data");
@@ -363,6 +379,7 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
break;
}
else if(nread == 0) {
CURL_TRC_CF(data, cf, "server closed connection");
ctx->conn_closed = TRUE;
break;
}
@@ -558,12 +575,12 @@ static int proxy_h2_on_header(nghttp2_session *session,
}
if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 &&
memcmp(HTTP_PSEUDO_STATUS, name, namelen) == 0) {
!memcmp(HTTP_PSEUDO_STATUS, name, namelen)) {
int http_status;
struct http_resp *resp;
/* status: always comes first, we might get more than one response,
* link the previous ones for keepers */
* discard previous, interim responses */
result = Curl_http_decode_status(&http_status,
(const char *)value, valuelen);
if(result)
@@ -571,7 +588,8 @@ static int proxy_h2_on_header(nghttp2_session *session,
result = Curl_http_resp_make(&resp, http_status, NULL);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
resp->prev = ctx->tunnel.resp;
if(ctx->tunnel.resp)
Curl_http_resp_free(ctx->tunnel.resp);
ctx->tunnel.resp = resp;
CURL_TRC_CF(data, cf, "[%d] status: HTTP/2 %03d",
stream_id, ctx->tunnel.resp->status);
@@ -750,15 +768,15 @@ static CURLcode submit_CONNECT(struct Curl_cfilter *cf,
CURLcode result;
struct httpreq *req = NULL;
result = Curl_http_proxy_create_CONNECT(&req, cf, data, 2);
result = Curl_http_proxy_create_tunnel_request(&req, cf, data, ctx->dest,
PROXY_HTTP_V2,
(bool)ctx->udp_tunnel);
if(result)
goto out;
result = Curl_creader_set_null(data);
if(result)
goto out;
infof(data, "Establish HTTP/2 proxy tunnel to %s", req->authority);
result = proxy_h2_submit(&ts->stream_id, cf, data, ctx->h2, req,
NULL, ts, tunnel_send_callback, cf);
if(result) {
@@ -778,41 +796,30 @@ static CURLcode inspect_response(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct tunnel_stream *ts)
{
CURLcode result = CURLE_OK;
struct dynhds_entry *auth_reply = NULL;
(void)cf;
struct cf_h2_proxy_ctx *ctx = cf->ctx;
proxy_inspect_result res;
CURLcode result;
DEBUGASSERT(ts->resp);
if(ts->resp->status / 100 == 2) {
infof(data, "CONNECT tunnel established, response %d", ts->resp->status);
h2_tunnel_go_state(cf, ts, H2_TUNNEL_ESTABLISHED, data);
return CURLE_OK;
result = Curl_http_proxy_inspect_tunnel_response(
cf, data, ts->resp, (bool)ctx->udp_tunnel, &res);
if(result)
return result;
switch(res) {
case PROXY_INSPECT_OK:
h2_tunnel_go_state(cf, ts, H2_TUNNEL_ESTABLISHED, data,
(bool)ctx->udp_tunnel);
break;
case PROXY_INSPECT_FAILED:
h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data,
(bool)ctx->udp_tunnel);
result = CURLE_COULDNT_CONNECT;
break;
case PROXY_INSPECT_AUTH_RETRY:
h2_tunnel_go_state(cf, ts, H2_TUNNEL_INIT, data,
(bool)ctx->udp_tunnel);
break;
}
if(ts->resp->status == 401) {
auth_reply = Curl_dynhds_cget(&ts->resp->headers, "WWW-Authenticate");
}
else if(ts->resp->status == 407) {
auth_reply = Curl_dynhds_cget(&ts->resp->headers, "Proxy-Authenticate");
}
if(auth_reply) {
CURL_TRC_CF(data, cf, "[0] CONNECT: fwd auth header '%s'",
auth_reply->value);
result = Curl_http_input_auth(data, ts->resp->status == 407,
auth_reply->value);
if(result)
return result;
if(data->req.newurl) {
/* Indicator that we should try again */
curlx_safefree(data->req.newurl);
h2_tunnel_go_state(cf, ts, H2_TUNNEL_INIT, data);
return CURLE_OK;
}
}
/* Seems to have failed */
return CURLE_COULDNT_CONNECT;
return result;
}
static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
@@ -824,6 +831,11 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
DEBUGASSERT(ts);
DEBUGASSERT(ts->authority);
if(ctx->conn_closed) {
failf(data, "proxy closed connection");
return CURLE_COULDNT_CONNECT;
}
do {
switch(ts->state) {
case H2_TUNNEL_INIT:
@@ -832,7 +844,8 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
result = submit_CONNECT(cf, data, ts);
if(result)
goto out;
h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data);
h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data,
(bool)ctx->udp_tunnel);
FALLTHROUGH();
case H2_TUNNEL_CONNECT:
@@ -841,12 +854,14 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
if(!result)
result = proxy_h2_progress_egress(cf, data);
if(result && result != CURLE_AGAIN) {
h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data);
h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data,
(bool)ctx->udp_tunnel);
break;
}
if(ts->has_final_response) {
h2_tunnel_go_state(cf, ts, H2_TUNNEL_RESPONSE, data);
h2_tunnel_go_state(cf, ts, H2_TUNNEL_RESPONSE, data,
(bool)ctx->udp_tunnel);
}
else {
result = CURLE_OK;
@@ -875,7 +890,8 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
out:
if((result && (result != CURLE_AGAIN)) || ctx->tunnel.closed)
h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data);
h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data,
(bool)ctx->udp_tunnel);
return result;
}
@@ -896,7 +912,7 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
Curl_bufq_init(&ctx->inbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
Curl_bufq_init(&ctx->outbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
if(tunnel_stream_init(cf, &ctx->tunnel))
if(tunnel_stream_init(&ctx->tunnel, ctx->dest))
goto out;
rc = nghttp2_session_callbacks_new(&cbs);
@@ -958,7 +974,7 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
out:
if(cbs)
nghttp2_session_callbacks_del(cbs);
CURL_TRC_CF(data, cf, "[0] init proxy ctx -> %d", result);
CURL_TRC_CF(data, cf, "[0] init proxy ctx -> %d", (int)result);
return result;
}
@@ -1016,21 +1032,6 @@ out:
return result;
}
static void cf_h2_proxy_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
if(ctx) {
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
cf_h2_proxy_ctx_clear(ctx);
CF_DATA_RESTORE(cf, save);
}
if(cf->next)
cf->next->cft->do_close(cf->next, data);
}
static void cf_h2_proxy_destroy(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -1133,7 +1134,7 @@ static CURLcode cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
result = Curl_pollset_set(data, ps, sock, want_recv, want_send);
CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d -> %d",
want_recv, want_send, result);
want_recv, want_send, (int)result);
CF_DATA_RESTORE(cf, save);
}
else if(ctx->sent_goaway && !cf->shutdown) {
@@ -1145,7 +1146,7 @@ static CURLcode cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
want_recv = nghttp2_session_want_read(ctx->h2);
result = Curl_pollset_set(data, ps, sock, want_recv, want_send);
CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d -> %d",
want_recv, want_send, result);
want_recv, want_send, (int)result);
CF_DATA_RESTORE(cf, save);
}
return result;
@@ -1194,7 +1195,7 @@ static CURLcode tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %d, %zu",
ctx->tunnel.stream_id, len, result, *pnread);
ctx->tunnel.stream_id, len, (int)result, *pnread);
return result;
}
@@ -1232,14 +1233,15 @@ static CURLcode cf_h2_proxy_recv(struct Curl_cfilter *cf,
result = Curl_1st_fatal(result, proxy_h2_progress_egress(cf, data));
out:
if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
if((!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) ||
!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) &&
(!result || (result == CURLE_AGAIN))) {
/* data pending and no fatal error to report. Need to trigger
* draining to avoid stalling when no socket events happen. */
drain_tunnel(cf, data, &ctx->tunnel);
}
CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu",
ctx->tunnel.stream_id, len, result, *pnread);
ctx->tunnel.stream_id, len, (int)result, *pnread);
CF_DATA_RESTORE(cf, save);
return result;
}
@@ -1269,7 +1271,8 @@ static CURLcode cf_h2_proxy_send(struct Curl_cfilter *cf,
}
result = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, pnwritten);
CURL_TRC_CF(data, cf, "cf_send(), bufq_write %d, %zu", result, *pnwritten);
CURL_TRC_CF(data, cf, "cf_send(), bufq_write %d, %zu", (int)result,
*pnwritten);
if(result && (result != CURLE_AGAIN))
goto out;
@@ -1298,7 +1301,8 @@ static CURLcode cf_h2_proxy_send(struct Curl_cfilter *cf,
}
out:
if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
if((!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) ||
!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) &&
(!result || (result == CURLE_AGAIN))) {
/* data pending and no fatal error to report. Need to trigger
* draining to avoid stalling when no socket events happen. */
@@ -1306,7 +1310,7 @@ out:
}
CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, "
"h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)",
ctx->tunnel.stream_id, len, result, *pnwritten,
ctx->tunnel.stream_id, len, (int)result, *pnwritten,
nghttp2_session_get_stream_remote_window_size(
ctx->h2, ctx->tunnel.stream_id),
nghttp2_session_get_remote_window_size(ctx->h2),
@@ -1338,7 +1342,7 @@ static CURLcode cf_h2_proxy_flush(struct Curl_cfilter *cf,
out:
CURL_TRC_CF(data, cf, "[%d] flush -> %d, "
"h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)",
ctx->tunnel.stream_id, result,
ctx->tunnel.stream_id, (int)result,
nghttp2_session_get_stream_remote_window_size(
ctx->h2, ctx->tunnel.stream_id),
nghttp2_session_get_remote_window_size(ctx->h2),
@@ -1410,8 +1414,8 @@ static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf,
switch(query) {
case CF_QUERY_HOST_PORT:
*pres1 = (int)cf->conn->http_proxy.port;
*((const char **)pres2) = cf->conn->http_proxy.host.name;
*pres1 = (int)ctx->dest->port;
*((const char **)pres2) = ctx->dest->hostname;
return CURLE_OK;
case CF_QUERY_NEED_FLUSH: {
if(!Curl_bufq_is_empty(&ctx->outbufq) ||
@@ -1464,7 +1468,6 @@ struct Curl_cftype Curl_cft_h2_proxy = {
CURL_LOG_LVL_NONE,
cf_h2_proxy_destroy,
cf_h2_proxy_connect,
cf_h2_proxy_close,
cf_h2_proxy_shutdown,
cf_h2_proxy_adjust_pollset,
cf_h2_proxy_data_pending,
@@ -1477,7 +1480,9 @@ struct Curl_cftype Curl_cft_h2_proxy = {
};
CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
struct Curl_easy *data)
struct Curl_easy *data,
struct Curl_peer *dest,
bool udp_tunnel)
{
struct Curl_cfilter *cf_h2_proxy = NULL;
struct cf_h2_proxy_ctx *ctx;
@@ -1487,17 +1492,17 @@ CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
ctx = curlx_calloc(1, sizeof(*ctx));
if(!ctx)
goto out;
Curl_peer_link(&ctx->dest, dest);
ctx->udp_tunnel = udp_tunnel;
result = Curl_cf_create(&cf_h2_proxy, &Curl_cft_h2_proxy, ctx);
if(result)
goto out;
ctx = NULL;
Curl_conn_cf_insert_after(cf, cf_h2_proxy);
result = CURLE_OK;
out:
if(result)
cf_h2_proxy_ctx_free(ctx);
cf_h2_proxy_ctx_free(ctx);
return result;
}
+3 -1
View File
@@ -28,7 +28,9 @@
#if defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY)
CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
struct Curl_easy *data);
struct Curl_easy *data,
struct Curl_peer *dest,
bool udp_tunnel);
extern struct Curl_cftype Curl_cft_h2_proxy;
+3 -20
View File
@@ -28,6 +28,7 @@
#include "urldata.h"
#include "cfilters.h"
#include "cf-haproxy.h"
#include "connect.h"
#include "curl_addrinfo.h"
#include "curl_trc.h"
#include "select.h"
@@ -44,13 +45,6 @@ struct cf_haproxy_ctx {
struct dynbuf data_out;
};
static void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx)
{
DEBUGASSERT(ctx);
ctx->state = HAPROXY_INIT;
curlx_dyn_reset(&ctx->data_out);
}
static void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx)
{
if(ctx) {
@@ -78,7 +72,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter *cf,
DEBUGASSERT(ctx);
DEBUGASSERT(ctx->state == HAPROXY_INIT);
#ifdef USE_UNIX_SOCKETS
if(cf->conn->unix_domain_socket)
if(Curl_conn_get_first_peer(cf->conn, cf->sockindex)->unix_socket)
/* the buffer is large enough to hold this! */
result = curlx_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
else {
@@ -97,7 +91,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter *cf,
client_dest_ip = ipquad.remote_ip;
}
result = curlx_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
result = curlx_dyn_addf(&ctx->data_out, "PROXY %s %s %s %d %d\r\n",
is_ipv6 ? "TCP6" : "TCP4",
client_source_ip, client_dest_ip,
ipquad.local_port, ipquad.remote_port);
@@ -172,16 +166,6 @@ static void cf_haproxy_destroy(struct Curl_cfilter *cf,
cf_haproxy_ctx_free(cf->ctx);
}
static void cf_haproxy_close(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "close");
cf->connected = FALSE;
cf_haproxy_ctx_reset(cf->ctx);
if(cf->next)
cf->next->cft->do_close(cf->next, data);
}
static CURLcode cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
@@ -201,7 +185,6 @@ struct Curl_cftype Curl_cft_haproxy = {
0,
cf_haproxy_destroy,
cf_haproxy_connect,
cf_haproxy_close,
Curl_cf_def_shutdown,
cf_haproxy_adjust_pollset,
Curl_cf_def_data_pending,
+16 -21
View File
@@ -29,6 +29,7 @@
#include "curl_trc.h"
#include "cfilters.h"
#include "cf-dns.h"
#include "cf-setup.h"
#include "connect.h"
#include "hostip.h"
#include "httpsrr.h"
@@ -62,7 +63,6 @@ static void cf_hc_baller_discard(struct cf_hc_baller *b,
struct Curl_easy *data)
{
if(b->cf) {
Curl_conn_cf_close(b->cf, data);
Curl_conn_cf_discard_chain(&b->cf, data);
b->cf = NULL;
}
@@ -304,13 +304,14 @@ static enum alpnid cf_hc_get_httpsrr_alpn(struct Curl_cfilter *cf,
size_t i;
/* Do we have HTTPS-RR information? */
rr = Curl_conn_dns_get_https(data, cf->sockindex);
rr = Curl_conn_dns_get_https(
data, cf->sockindex, Curl_conn_get_destination(cf->conn, cf->sockindex));
/* We do not support `rr->no_def_alpn`. */
if(Curl_httpsrr_applicable(data, rr) && !rr->no_def_alpn) {
for(i = 0; i < CURL_ARRAYSIZE(rr->alpns); ++i) {
enum alpnid alpn_rr = (enum alpnid)rr->alpns[i];
if(alpn_rr == not_this_one) /* don't want this one */
if(alpn_rr == not_this_one) /* do not want this one */
continue;
switch(alpn_rr) {
case ALPN_h3:
@@ -493,7 +494,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
*done = FALSE;
if(!ctx->httpsrr_resolved) {
ctx->httpsrr_resolved = Curl_conn_dns_resolved_https(data, cf->sockindex);
ctx->httpsrr_resolved = Curl_conn_dns_resolved_https(
data, cf->sockindex, Curl_conn_get_destination(cf->conn, cf->sockindex));
#ifdef DEBUGBUILD
if(!ctx->httpsrr_resolved && getenv("CURL_DBG_AWAIT_HTTPSRR")) {
CURL_TRC_CF(data, cf, "awaiting HTTPS-RR");
@@ -576,7 +578,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
}
out:
CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
CURL_TRC_CF(data, cf, "connect -> %d, done=%d", (int)result, *done);
return result;
}
@@ -616,7 +618,7 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
result = ctx->ballers[i].result;
}
}
CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", (int)result, *done);
return result;
}
@@ -635,7 +637,8 @@ static CURLcode cf_hc_adjust_pollset(struct Curl_cfilter *cf,
continue;
result = Curl_conn_cf_adjust_pollset(b->cf, data, ps);
}
CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %u socks", result, ps->n);
CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %u socks", (int)result,
ps->n);
}
return result;
}
@@ -731,18 +734,6 @@ out:
return result;
}
static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "close");
cf_hc_ctx_close(data, cf->ctx);
cf->connected = FALSE;
if(cf->next) {
cf->next->cft->do_close(cf->next, data);
Curl_conn_cf_discard_chain(&cf->next, data);
}
}
static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_hc_ctx *ctx = cf->ctx;
@@ -757,7 +748,6 @@ struct Curl_cftype Curl_cft_http_connect = {
CURL_LOG_LVL_NONE,
cf_hc_destroy,
cf_hc_connect,
cf_hc_close,
cf_hc_shutdown,
cf_hc_adjust_pollset,
cf_hc_data_pending,
@@ -822,9 +812,14 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
DEBUGASSERT(conn->scheme->protocol == CURLPROTO_HTTPS);
/* This filter is intended for HTTPS using ALPN and does
* not support HTTPS Eyeballing to a proxy. */
if((conn->scheme->protocol != CURLPROTO_HTTPS) ||
#ifndef CURL_DISABLE_PROXY
conn->bits.origin_is_proxy ||
#endif
!conn->bits.tls_enable_alpn)
goto out;
goto out;
result = cf_hc_add(data, conn, sockindex, conn->transport_wanted);
+159 -132
View File
@@ -56,12 +56,14 @@
#include "multiif.h"
#include "progress.h"
#include "select.h"
#include "sockaddr.h"
#include "vquic/vquic.h" /* for quic cfilters */
struct transport_provider {
uint8_t transport;
cf_ip_connect_create *cf_create;
uint8_t transport;
bool tunnel;
};
static
@@ -69,23 +71,30 @@ static
const
#endif
struct transport_provider transport_providers[] = {
{ TRNSPRT_TCP, Curl_cf_tcp_create },
{ Curl_cf_tcp_create, TRNSPRT_TCP, FALSE },
{ Curl_cf_tcp_create, TRNSPRT_TCP, TRUE },
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3)
{ TRNSPRT_QUIC, Curl_cf_quic_create },
{ Curl_cf_quic_create, TRNSPRT_QUIC, FALSE },
#endif
#if !defined(CURL_DISABLE_HTTP) && defined(USE_PROXY_HTTP3)
{ Curl_cf_h3_proxy_create, TRNSPRT_QUIC, TRUE },
#endif
#ifndef CURL_DISABLE_TFTP
{ TRNSPRT_UDP, Curl_cf_udp_create },
{ Curl_cf_udp_create, TRNSPRT_UDP, FALSE },
#endif
#ifdef USE_UNIX_SOCKETS
{ TRNSPRT_UNIX, Curl_cf_unix_create },
{ Curl_cf_unix_create, TRNSPRT_UNIX, FALSE },
{ Curl_cf_unix_create, TRNSPRT_UNIX, TRUE },
#endif
};
static cf_ip_connect_create *get_cf_create(uint8_t transport)
static cf_ip_connect_create *get_cf_create(uint8_t transport,
bool tunnel)
{
size_t i;
for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) {
if(transport == transport_providers[i].transport)
if((transport == transport_providers[i].transport) &&
(tunnel == transport_providers[i].tunnel))
return transport_providers[i].cf_create;
}
return NULL;
@@ -102,7 +111,6 @@ UNITTEST void debug_set_transport_provider(
for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) {
if(transport == transport_providers[i].transport) {
transport_providers[i].cf_create = cf_create;
return;
}
}
}
@@ -110,15 +118,18 @@ UNITTEST void debug_set_transport_provider(
struct cf_ai_iter {
struct Curl_cfilter *cf;
struct Curl_peer *peer;
int ai_family;
unsigned int n;
};
static void cf_ai_iter_init(struct cf_ai_iter *iter,
struct Curl_cfilter *cf,
struct Curl_peer *peer,
int ai_family)
{
iter->cf = cf;
iter->peer = peer; /* not linked, ctx->ballers owns and has same lifetime */
iter->ai_family = ai_family;
iter->n = 0;
}
@@ -131,7 +142,7 @@ static const struct Curl_addrinfo *cf_ai_iter_next(struct cf_ai_iter *iter,
if(!iter->cf)
return NULL;
addr = Curl_conn_dns_get_ai(data, iter->cf->sockindex,
addr = Curl_conn_dns_get_ai(data, iter->peer, iter->cf->sockindex,
iter->ai_family, iter->n);
if(addr)
iter->n++;
@@ -142,19 +153,23 @@ static bool cf_ai_iter_has_more(struct cf_ai_iter *iter,
struct Curl_easy *data)
{
return (iter->cf &&
!!Curl_conn_dns_get_ai(data, iter->cf->sockindex,
!!Curl_conn_dns_get_ai(data, iter->peer, iter->cf->sockindex,
iter->ai_family, iter->n));
}
struct cf_ip_attempt {
struct cf_ip_attempt *next;
struct Curl_peer *origin;
struct Curl_peer *peer;
struct Curl_peer *tunnel_peer;
struct Curl_sockaddr_ex addr;
struct Curl_cfilter *cf; /* current sub-cfilter connecting */
cf_ip_connect_create *cf_create;
struct curltime started; /* start of current attempt */
CURLcode result;
int ai_family;
uint8_t transport;
uint8_t transport_peer;
uint8_t tunnel_transport;
int error;
BIT(connected); /* cf has connected */
BIT(shutdown); /* cf has shutdown */
@@ -168,16 +183,23 @@ static void cf_ip_attempt_free(struct cf_ip_attempt *a,
if(a) {
if(a->cf)
Curl_conn_cf_discard_chain(&a->cf, data);
Curl_peer_unlink(&a->origin);
Curl_peer_unlink(&a->peer);
Curl_peer_unlink(&a->tunnel_peer);
curlx_free(a);
}
}
static CURLcode cf_ip_attempt_new(struct cf_ip_attempt **pa,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct Curl_cfilter *cf,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct Curl_sockaddr_ex *addr,
int ai_family,
uint8_t transport,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport,
cf_ip_connect_create *cf_create)
{
struct Curl_cfilter *wcf;
@@ -189,14 +211,20 @@ static CURLcode cf_ip_attempt_new(struct cf_ip_attempt **pa,
if(!a)
return CURLE_OUT_OF_MEMORY;
Curl_peer_link(&a->origin, origin);
Curl_peer_link(&a->peer, peer);
a->transport_peer = transport_peer;
Curl_peer_link(&a->tunnel_peer, tunnel_peer);
a->tunnel_transport = tunnel_transport;
a->addr = *addr;
a->ai_family = ai_family;
a->transport = transport;
a->result = CURLE_OK;
a->cf_create = cf_create;
*pa = a;
result = a->cf_create(&a->cf, data, cf->conn, &a->addr, a->transport);
result = a->cf_create(&a->cf, data, a->origin, a->peer, a->transport_peer,
cf->conn, &a->addr, a->tunnel_peer,
a->tunnel_transport);
if(result)
goto out;
@@ -245,13 +273,17 @@ struct cf_ip_ballers {
#ifdef USE_IPV6
struct cf_ai_iter ipv6_iter;
#endif
struct Curl_peer *origin;
struct Curl_peer *peer;
struct Curl_peer *tunnel_peer;
cf_ip_connect_create *cf_create; /* for creating cf */
struct curltime started;
struct curltime last_attempt_started;
timediff_t attempt_delay_ms;
int last_attempt_ai_family;
uint32_t max_concurrent;
uint8_t transport;
uint8_t transport_peer;
uint8_t tunnel_transport;
};
static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
@@ -269,7 +301,9 @@ static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
a->inconclusive = FALSE;
a->cf = NULL;
result = a->cf_create(&a->cf, data, cf->conn, &a->addr, a->transport);
result = a->cf_create(&a->cf, data, a->origin, a->peer, a->transport_peer,
cf->conn, &a->addr,
a->tunnel_peer, a->tunnel_transport);
if(!result) {
bool dummy;
/* the new filter might have sub-filters */
@@ -282,11 +316,9 @@ static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
return result;
}
static void cf_ip_ballers_clear(struct Curl_cfilter *cf,
struct Curl_easy *data,
static void cf_ip_ballers_clear(struct Curl_easy *data,
struct cf_ip_ballers *bs)
{
(void)cf;
while(bs->running) {
struct cf_ip_attempt *a = bs->running;
bs->running = a->next;
@@ -294,35 +326,36 @@ static void cf_ip_ballers_clear(struct Curl_cfilter *cf,
}
cf_ip_attempt_free(bs->winner, data);
bs->winner = NULL;
Curl_peer_unlink(&bs->origin);
Curl_peer_unlink(&bs->peer);
Curl_peer_unlink(&bs->tunnel_peer);
}
static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs,
struct Curl_cfilter *cf,
cf_ip_connect_create *cf_create,
uint8_t transport,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport,
timediff_t attempt_delay_ms,
uint32_t max_concurrent)
{
memset(bs, 0, sizeof(*bs));
bs->cf_create = cf_create;
bs->transport = transport;
bs->cf_create = get_cf_create(transport_peer, !!tunnel_peer);
if(!bs->cf_create) {
failf(data, "unsupported transport type %u%s",
transport_peer, tunnel_peer ? " to proxy" : "");
return CURLE_UNSUPPORTED_PROTOCOL;
}
Curl_peer_link(&bs->origin, origin);
Curl_peer_link(&bs->peer, peer);
bs->transport_peer = transport_peer;
Curl_peer_link(&bs->tunnel_peer, tunnel_peer);
bs->tunnel_transport = tunnel_transport;
bs->attempt_delay_ms = attempt_delay_ms;
bs->max_concurrent = max_concurrent;
bs->last_attempt_ai_family = AF_INET; /* so AF_INET6 is next */
if(transport == TRNSPRT_UNIX) {
#ifdef USE_UNIX_SOCKETS
cf_ai_iter_init(&bs->addr_iter, cf, AF_UNIX);
#else
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
else { /* TCP/UDP/QUIC */
#ifdef USE_IPV6
cf_ai_iter_init(&bs->ipv6_iter, cf, AF_INET6);
#endif
cf_ai_iter_init(&bs->addr_iter, cf, AF_INET);
}
return CURLE_OK;
}
@@ -458,15 +491,17 @@ evaluate:
if(bs->max_concurrent)
cf_ip_ballers_prune(bs, cf, data, bs->max_concurrent - 1);
result = Curl_socket_addr_from_ai(&addr, ai, bs->transport);
result = Curl_socket_addr_from_ai(&addr, ai, bs->transport_peer);
if(result)
goto out;
result = cf_ip_attempt_new(&a, cf, data, &addr, ai_family,
bs->transport, bs->cf_create);
result = cf_ip_attempt_new(&a, data, cf, bs->origin, bs->peer,
bs->transport_peer, &addr, ai_family,
bs->tunnel_peer, bs->tunnel_transport,
bs->cf_create);
CURL_TRC_CF(data, cf, "starting %s attempt for ipv%s -> %d",
bs->running ? "next" : "first",
(ai_family == AF_INET) ? "4" : "6", result);
(ai_family == AF_INET) ? "4" : "6", (int)result);
if(result)
goto out;
DEBUGASSERT(a);
@@ -495,7 +530,7 @@ evaluate:
if(!a->inconclusive)
continue;
result = cf_ip_attempt_restart(a, cf, data);
CURL_TRC_CF(data, cf, "restarted baller %d -> %d", i, result);
CURL_TRC_CF(data, cf, "restarted baller %d -> %d", i, (int)result);
if(result) /* serious failure */
goto out;
bs->last_attempt_started = *Curl_pgrs_now(data);
@@ -518,7 +553,7 @@ evaluate:
result = CURLE_COULDNT_CONNECT;
VERBOSE(i = 0);
for(a = bs->running; a; a = a->next) {
CURL_TRC_CF(data, cf, "baller %d: result=%d", i, a->result);
CURL_TRC_CF(data, cf, "baller %d: result=%d", i, (int)a->result);
if(a->result)
result = a->result;
}
@@ -652,7 +687,6 @@ typedef enum {
} cf_connect_state;
struct cf_ip_happy_ctx {
uint8_t transport;
cf_ip_connect_create *cf_create;
cf_connect_state state;
struct cf_ip_ballers ballers;
@@ -674,40 +708,39 @@ static CURLcode is_connected(struct Curl_cfilter *cf,
if(!result)
return CURLE_OK;
else {
const char *hostname, *proxy_name = NULL;
struct Curl_peer *peer = NULL, *proxy_peer = NULL;
char viamsg[160];
#ifndef CURL_DISABLE_PROXY
if(conn->bits.socksproxy)
proxy_name = conn->socks_proxy.host.name;
else if(conn->bits.httpproxy)
proxy_name = conn->http_proxy.host.name;
#endif
hostname = conn->bits.conn_to_host ? conn->conn_to_host.name :
conn->host.name;
#ifdef USE_UNIX_SOCKETS
if(conn->unix_domain_socket)
curl_msnprintf(viamsg, sizeof(viamsg), "over %s",
conn->unix_domain_socket);
else
peer = Curl_conn_get_first_peer(conn, cf->sockindex);
if(!conn->origin || !peer)
return CURLE_FAILED_INIT;
#ifndef CURL_DISABLE_PROXY
if(conn->socks_proxy.peer)
proxy_peer = conn->socks_proxy.peer;
else if(conn->http_proxy.peer)
proxy_peer = conn->http_proxy.peer;
#endif
{
uint16_t port;
if(cf->sockindex == SECONDARYSOCKET)
port = conn->secondary_port;
else if(cf->conn->bits.conn_to_port)
port = conn->conn_to_port;
viamsg[0] = 0;
if(!Curl_peer_equal(peer, conn->origin) &&
!Curl_peer_equal(peer, proxy_peer)) {
#ifdef USE_UNIX_SOCKETS
if(peer->unix_socket)
curl_msnprintf(viamsg, sizeof(viamsg), " over unix://%s",
peer->hostname);
else
port = conn->remote_port;
curl_msnprintf(viamsg, sizeof(viamsg), "port %d", port);
#endif
curl_msnprintf(viamsg, sizeof(viamsg), " via %s:%u",
peer->hostname, peer->port);
}
failf(data, "Failed to connect to %s %s %s%s%safter "
failf(data, "Failed to connect to %s:%u%s %s%s%safter "
"%" FMT_TIMEDIFF_T " ms: %s",
hostname, viamsg,
proxy_name ? "via " : "",
proxy_name ? proxy_name : "",
proxy_name ? " " : "",
conn->origin->hostname, conn->origin->port, viamsg,
proxy_peer ? "over proxy " : "",
proxy_peer ? proxy_peer->hostname : "",
proxy_peer ? " " : "",
curlx_ptimediff_ms(Curl_pgrs_now(data),
&data->progress.t_startsingle),
curl_easy_strerror(result));
@@ -734,28 +767,41 @@ static CURLcode cf_ip_happy_init(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
CURL_TRC_CF(data, cf, "init ip ballers for transport %u", ctx->transport);
if(ctx->ballers.transport_peer == TRNSPRT_UNIX) {
#ifdef USE_UNIX_SOCKETS
cf_ai_iter_init(&ctx->ballers.addr_iter, cf, ctx->ballers.peer, AF_UNIX);
#else
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
}
else { /* TCP/UDP/QUIC */
#ifdef USE_IPV6
cf_ai_iter_init(&ctx->ballers.ipv6_iter, cf, ctx->ballers.peer, AF_INET6);
#endif
cf_ai_iter_init(&ctx->ballers.addr_iter, cf, ctx->ballers.peer, AF_INET);
}
CURL_TRC_CF(data, cf, "init ip ballers for transport %u",
ctx->ballers.transport_peer);
ctx->started = *Curl_pgrs_now(data);
return cf_ip_ballers_init(&ctx->ballers, cf,
ctx->cf_create, ctx->transport,
data->set.happy_eyeballs_timeout,
IP_HE_MAX_CONCURRENT_ATTEMPTS);
return CURLE_OK;
}
static void cf_ip_happy_ctx_clear(struct Curl_cfilter *cf,
static void cf_ip_happy_ctx_clear(struct cf_ip_happy_ctx *ctx,
struct Curl_easy *data)
{
struct cf_ip_happy_ctx *ctx = cf->ctx;
DEBUGASSERT(ctx);
DEBUGASSERT(data);
cf_ip_ballers_clear(cf, data, &ctx->ballers);
if(ctx)
cf_ip_ballers_clear(data, &ctx->ballers);
}
static void cf_ip_happy_ctx_destroy(struct cf_ip_happy_ctx *ctx)
static void cf_ip_happy_ctx_destroy(struct cf_ip_happy_ctx *ctx,
struct Curl_easy *data)
{
if(ctx)
if(ctx) {
cf_ip_happy_ctx_clear(ctx, data);
curlx_free(ctx);
}
}
static CURLcode cf_ip_happy_shutdown(struct Curl_cfilter *cf,
@@ -772,7 +818,7 @@ static CURLcode cf_ip_happy_shutdown(struct Curl_cfilter *cf,
}
result = cf_ip_ballers_shutdown(&ctx->ballers, data, done);
CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", (int)result, *done);
return result;
}
@@ -785,7 +831,8 @@ static CURLcode cf_ip_happy_adjust_pollset(struct Curl_cfilter *cf,
if(!cf->connected) {
result = cf_ip_ballers_pollset(&ctx->ballers, data, ps);
CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %u socks", result, ps->n);
CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %u socks", (int)result,
ps->n);
}
return result;
}
@@ -810,7 +857,7 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
*done = FALSE;
if(!ctx->dns_resolved) {
result = Curl_conn_dns_result(cf->conn, cf->sockindex);
result = Curl_conn_dns_result(cf->conn, cf->sockindex, ctx->ballers.peer);
if(!result)
ctx->dns_resolved = TRUE;
else if(result == CURLE_AGAIN) {
@@ -841,9 +888,9 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
cf->connected = TRUE;
cf->next = ctx->ballers.winner->cf;
ctx->ballers.winner->cf = NULL;
cf_ip_happy_ctx_clear(cf, data);
cf_ip_happy_ctx_clear(ctx, data);
Curl_expire_done(data, EXPIRE_HAPPY_EYEBALLS);
/* whatever errors where reported by ballers, clear our errorbuf */
/* whatever errors were reported by ballers, clear our errorbuf */
Curl_reset_fail(data);
if(cf->conn->scheme->protocol & PROTO_FAMILY_SSH)
@@ -871,22 +918,6 @@ out:
return result;
}
static void cf_ip_happy_close(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_ip_happy_ctx *ctx = cf->ctx;
CURL_TRC_CF(data, cf, "close");
cf_ip_happy_ctx_clear(cf, data);
cf->connected = FALSE;
ctx->state = SCFST_INIT;
if(cf->next) {
cf->next->cft->do_close(cf->next, data);
Curl_conn_cf_discard_chain(&cf->next, data);
}
}
static bool cf_ip_happy_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
@@ -940,8 +971,8 @@ static void cf_ip_happy_destroy(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "destroy");
if(ctx) {
cf_ip_happy_ctx_clear(cf, data);
cf_ip_happy_ctx_destroy(ctx);
cf_ip_happy_ctx_clear(ctx, data);
cf_ip_happy_ctx_destroy(ctx, data);
}
}
@@ -951,7 +982,6 @@ struct Curl_cftype Curl_cft_ip_happy = {
CURL_LOG_LVL_NONE,
cf_ip_happy_destroy,
cf_ip_happy_connect,
cf_ip_happy_close,
cf_ip_happy_shutdown,
cf_ip_happy_adjust_pollset,
cf_ip_happy_data_pending,
@@ -963,21 +993,14 @@ struct Curl_cftype Curl_cft_ip_happy = {
cf_ip_happy_query,
};
/**
* Create an IP happy eyeball connection filter that uses the, once resolved,
* address information to connect on ip families based on connection
* configuration.
* @param pcf output, the created cfilter
* @param data easy handle used in creation
* @param conn connection the filter is created for
* @param cf_create method to create the sub-filters performing the
* actual connects.
*/
static CURLcode cf_ip_happy_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct connectdata *conn,
cf_ip_connect_create *cf_create,
uint8_t transport)
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport)
{
struct cf_ip_happy_ctx *ctx = NULL;
CURLcode result;
@@ -990,35 +1013,39 @@ static CURLcode cf_ip_happy_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
ctx->transport = transport;
ctx->cf_create = cf_create;
result = cf_ip_ballers_init(&ctx->ballers, data,
origin, peer, transport_peer,
tunnel_peer, tunnel_transport,
data->set.happy_eyeballs_timeout,
IP_HE_MAX_CONCURRENT_ATTEMPTS);
if(result)
goto out;
result = Curl_cf_create(pcf, &Curl_cft_ip_happy, ctx);
out:
if(result) {
curlx_safefree(*pcf);
cf_ip_happy_ctx_destroy(ctx);
cf_ip_happy_ctx_destroy(ctx, data);
}
return result;
}
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
uint8_t transport)
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport)
{
cf_ip_connect_create *cf_create;
struct Curl_cfilter *cf;
CURLcode result;
/* Need to be first */
DEBUGASSERT(cf_at);
cf_create = get_cf_create(transport);
if(!cf_create) {
CURL_TRC_CF(data, cf_at, "unsupported transport type %u", transport);
return CURLE_UNSUPPORTED_PROTOCOL;
}
result = cf_ip_happy_create(&cf, data, cf_at->conn, cf_create, transport);
result = cf_ip_happy_create(&cf, data, origin, peer, transport_peer,
cf_at->conn, tunnel_peer, tunnel_transport);
if(result)
return result;
+25 -9
View File
@@ -29,28 +29,44 @@ struct connectdata;
struct Curl_addrinfo;
struct Curl_cfilter;
struct Curl_easy;
struct Curl_peer;
struct Curl_sockaddr_ex;
/**
* Create a cfilter for making an "ip" connection to the
* given address, using parameters from `conn`. The "ip" connection
* can be a TCP socket, a UDP socket or even a QUIC connection.
* Create a cfilter to connect to `origin` via an optional `peer`
* using `transport_peer` and `addr`.
* With a `tunnel_peer` present, the filter will be used to proxy tunnel
* to it and the tunnel will use `tunnel_transport`.
* `pcf`: the filter created on success
* `data`: the transfer initiating the connect
* `conn`: the connection that gets connected
*
* It MUST use only the supplied `ai` for its connection attempt.
*
* Such a filter may be used in "happy eyeball" scenarios, and its
* `connect` implementation needs to support non-blocking. Once connected,
* The filter is used in "happy eyeball" scenarios. Once connected,
* it MAY be installed in the connection filter chain to serve transfers.
*/
typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
uint8_t transport);
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport);
/**
* Create an IP happy eyeball connection filter that connects to `origin`
* via an optional `peer` using `transport_peer`.
* With a `tunnel_peer` present, the filter will be used to proxy tunnel
* to it and the tunnel will use `tunnel_transport`.
*/
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
uint8_t transport);
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport);
extern struct Curl_cftype Curl_cft_ip_happy;
+157
View File
@@ -0,0 +1,157 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#ifndef CURL_DISABLE_WEBSOCKETS
/* only used for this protocol, so far */
#include "urldata.h"
#include "bufq.h"
#include "cfilters.h"
#include "cf-recvbuf.h"
#include "curl_trc.h"
#define CURL_CF_RECVBUF_CHUNK (16 * 1024)
struct cf_recvbuf_ctx {
struct bufq recvbuf;
};
static void cf_recvbuf_destroy(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_recvbuf_ctx *ctx = cf->ctx;
(void)data;
if(ctx) {
Curl_bufq_free(&ctx->recvbuf);
curlx_free(ctx);
}
}
static CURLcode cf_recvbuf_recv(struct Curl_cfilter *cf,
struct Curl_easy *data,
char *buf, size_t len,
size_t *pnread)
{
struct cf_recvbuf_ctx *ctx = cf->ctx;
if(!Curl_bufq_is_empty(&ctx->recvbuf)) {
return Curl_bufq_cread(&ctx->recvbuf, buf, len, pnread);
}
if(cf->next)
return cf->next->cft->do_recv(cf->next, data, buf, len, pnread);
*pnread = 0;
return CURLE_RECV_ERROR;
}
static bool cf_recvbuf_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct cf_recvbuf_ctx *ctx = cf->ctx;
if(!Curl_bufq_is_empty(&ctx->recvbuf))
return TRUE;
return cf->next ?
cf->next->cft->has_data_pending(cf->next, data) : FALSE;
}
struct Curl_cftype Curl_cft_recvbuf = {
"RECVBUF",
0,
CURL_LOG_LVL_NONE,
cf_recvbuf_destroy,
Curl_cf_def_connect,
Curl_cf_def_shutdown,
Curl_cf_def_adjust_pollset,
cf_recvbuf_data_pending,
Curl_cf_def_send,
cf_recvbuf_recv,
Curl_cf_def_cntrl,
Curl_cf_def_conn_is_alive,
Curl_cf_def_conn_keep_alive,
Curl_cf_def_query,
};
static CURLcode cf_recvbuf_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
const uint8_t *buf, size_t blen)
{
struct Curl_cfilter *cf = NULL;
struct cf_recvbuf_ctx *ctx;
CURLcode result = CURLE_OK;
size_t nwritten = 0;
(void)data;
ctx = curlx_calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
Curl_bufq_init2(&ctx->recvbuf, CURL_CF_RECVBUF_CHUNK,
(blen / CURL_CF_RECVBUF_CHUNK) + 1,
(BUFQ_OPT_SOFT_LIMIT | BUFQ_OPT_NO_SPARES));
result = Curl_bufq_write(&ctx->recvbuf, buf, blen, &nwritten);
if(result)
goto out;
if(nwritten != blen) {
result = CURLE_FAILED_INIT;
goto out;
}
result = Curl_cf_create(&cf, &Curl_cft_recvbuf, ctx);
if(result)
goto out;
ctx = NULL;
out:
*pcf = result ? NULL : cf;
if(ctx) {
Curl_bufq_free(&ctx->recvbuf);
curlx_free(ctx);
}
return result;
}
CURLcode Curl_cf_recvbuf_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
const uint8_t *buf, size_t blen)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
result = cf_recvbuf_create(&cf, data, buf, blen);
if(result)
goto out;
cf->connected = Curl_conn_is_connected(conn, sockindex);
Curl_conn_cf_add(data, conn, sockindex, cf);
out:
return result;
}
#endif /* !CURL_DISABLE_WEBSOCKETS */
@@ -1,5 +1,5 @@
#ifndef HEADER_CURL_NOPROXY_H
#define HEADER_CURL_NOPROXY_H
#ifndef HEADER_CURL_CF_RECVBUF_H
#define HEADER_CURL_CF_RECVBUF_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -25,8 +25,16 @@
***************************************************************************/
#include "curl_setup.h"
#ifndef CURL_DISABLE_PROXY
bool Curl_check_noproxy(const char *name, const char *no_proxy);
#endif
#ifndef CURL_DISABLE_WEBSOCKETS
/* only used for this protocol, so far */
#endif /* HEADER_CURL_NOPROXY_H */
CURLcode Curl_cf_recvbuf_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
const uint8_t *buf, size_t blen);
extern struct Curl_cftype Curl_cft_recvbuf;
#endif /* !CURL_DISABLE_WEBSOCKETS */
#endif /* HEADER_CURL_CF_RECVBUF_H */
+476
View File
@@ -0,0 +1,476 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#include "urldata.h"
#include "cfilters.h"
#include "cf-haproxy.h"
#include "cf-ip-happy.h"
#include "cf-setup.h"
#include "curl_trc.h"
#include "connect.h"
#include "http_proxy.h"
#include "socks.h"
#include "vquic/cf-capsule.h"
#include "vquic/vquic.h"
#include "vtls/vtls.h"
typedef enum {
CF_SETUP_INIT,
CF_SETUP_CNNCT_EYEBALLS,
CF_SETUP_CNNCT_SOCKS,
CF_SETUP_CNNCT_HTTP_PROXY,
CF_SETUP_CNNCT_HAPROXY,
CF_SETUP_CNNCT_SSL,
CF_SETUP_DONE
} cf_setup_state;
struct cf_setup_ctx {
cf_setup_state state;
int ssl_mode;
uint8_t transport;
uint8_t retry_count;
};
#ifndef CURL_DISABLE_PROXY
static CURLcode cf_setup_add_haproxy(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(ctx->state < CF_SETUP_CNNCT_HAPROXY) {
if(data->set.haproxyprotocol) {
if(ctx->transport == TRNSPRT_QUIC) {
failf(data, "haproxy protocol does not support QUIC");
return CURLE_UNSUPPORTED_PROTOCOL;
}
result = Curl_cf_haproxy_insert_after(cf, data);
if(result) {
CURL_TRC_CF(data, cf, "adding HAPROXY filter failed -> %d",
(int)result);
return result;
}
CURL_TRC_CF(data, cf, "added HAPROXY filter");
}
ctx->state = CF_SETUP_CNNCT_HAPROXY;
}
return result;
}
static CURLcode cf_setup_add_socks(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->socks_proxy.peer) {
/* Add a SOCKS proxy to go through `first_peer` to `second_peer`*/
struct Curl_peer *second_peer;
if(cf->conn->http_proxy.peer)
second_peer = cf->conn->http_proxy.peer;
else
second_peer = Curl_conn_get_destination(cf->conn, cf->sockindex);
if(!second_peer)
return CURLE_FAILED_INIT;
result = Curl_cf_socks_proxy_insert_after(
cf, data, second_peer, cf->conn->ip_version,
cf->conn->socks_proxy.proxytype,
cf->conn->socks_proxy.creds);
if(result) {
CURL_TRC_CF(data, cf, "adding SOCKS filter failed -> %d", (int)result);
return result;
}
CURL_TRC_CF(data, cf, "added SOCKS filter to %s:%u",
second_peer->hostname, second_peer->port);
ctx->state = CF_SETUP_CNNCT_SOCKS;
}
return result;
}
#ifndef CURL_DISABLE_HTTP
static CURLcode cf_setup_add_http_proxy(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY &&
cf->conn->http_proxy.peer && !cf->conn->bits.origin_is_proxy) {
struct Curl_peer *peer = cf->conn->http_proxy.peer;
struct Curl_peer *tunnel_peer =
Curl_conn_get_destination(cf->conn, cf->sockindex);
#ifdef USE_SSL
if(CURL_PROXY_IS_HTTPS(cf->conn->http_proxy.proxytype) &&
!Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
result = Curl_cf_ssl_proxy_insert_after(
cf, data, cf->conn->http_proxy.peer);
if(result) {
CURL_TRC_CF(data, cf, "adding SSL filter for HTTP proxy failed -> %d",
(int)result);
return result;
}
CURL_TRC_CF(data, cf, "added SSL filter for HTTP proxy");
}
#endif /* USE_SSL */
result = Curl_cf_http_proxy_insert_after(
cf, data, peer, tunnel_peer,
ctx->transport, cf->conn->http_proxy.proxytype);
if(result) {
CURL_TRC_CF(data, cf, "adding HTTP proxy tunnel filter failed -> %d",
(int)result);
return result;
}
CURL_TRC_CF(data, cf, "added HTTP proxy tunnel filter");
ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
}
return result;
}
#endif /* !CURL_DISABLE_HTTP */
#endif /* CURL_DISABLE_PROXY */
/* Get the origin curl connects its socket to.
* Can be origin or the first proxy. */
static struct Curl_peer *conn_get_first_origin(struct connectdata *conn,
int sockindex)
{
#ifndef CURL_DISABLE_PROXY
if(conn->socks_proxy.peer)
return conn->socks_proxy.peer;
if(conn->http_proxy.peer)
return conn->http_proxy.peer;
#endif
return (sockindex == SECONDARYSOCKET) ? conn->origin2 : conn->origin;
}
static CURLcode cf_setup_add_ip_happy(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
/* What is the first hop we directly connect to and what transport
* do we use for it? Only on the first hop we can do Happy Eyeballs.
* first_origin and first_peer differ on --connect-to. */
struct Curl_peer *first_origin =
conn_get_first_origin(cf->conn, cf->sockindex);
struct Curl_peer *first_peer =
Curl_conn_get_first_peer(cf->conn, cf->sockindex);
struct Curl_peer *tunnel_peer = NULL;
uint8_t first_transport = ctx->transport;
if(!first_peer)
return CURLE_FAILED_INIT;
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
if(cf->conn->http_proxy.peer && !cf->conn->bits.origin_is_proxy) {
first_transport =
Curl_http_proxy_transport(cf->conn->http_proxy.proxytype);
tunnel_peer = Curl_conn_get_destination(cf->conn, cf->sockindex);
if((first_transport == TRNSPRT_QUIC) && cf->conn->socks_proxy.peer) {
failf(data, "HTTP/3 proxy not possible via SOCKS");
return CURLE_UNSUPPORTED_PROTOCOL;
}
}
#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
result = cf_ip_happy_insert_after(cf, data, first_origin, first_peer,
first_transport,
tunnel_peer, ctx->transport);
if(result) {
CURL_TRC_CF(data, cf, "adding happy eyeballs failed -> %d", (int)result);
return result;
}
if(tunnel_peer && (first_transport == TRNSPRT_QUIC)) {
CURL_TRC_CF(data, cf, "happy eyeballing to HTTP/3 proxy %s:%u",
first_peer->hostname, first_peer->port);
ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
}
else {
CURL_TRC_CF(data, cf, "happy eyeballing to %s %s:%u",
tunnel_peer ? "proxy" : "origin",
first_peer->hostname, first_peer->port);
ctx->state = CF_SETUP_CNNCT_EYEBALLS;
}
}
return result;
}
static CURLcode cf_setup_add_origin_filters(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
(void)data; /* not used in all builds */
if(ctx->state < CF_SETUP_CNNCT_SSL) {
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) && \
!defined(CURL_DISABLE_PROXY)
/* Wanting QUIC with an HTTP tunneling filter, we now need to add
* the QUIC filter on top. Without tunneling, this has already
* happened in the Happy Eyeball filter. */
if(ctx->transport == TRNSPRT_QUIC &&
cf->conn->http_proxy.peer && !cf->conn->bits.origin_is_proxy) {
struct Curl_peer *origin = Curl_conn_get_origin(cf->conn, cf->sockindex);
struct Curl_peer *peer =
Curl_conn_get_destination(cf->conn, cf->sockindex);
result = Curl_cf_capsule_insert_after(cf, data);
if(result) {
CURL_TRC_CF(data, cf, "adding capsule filter failed -> %d",
(int)result);
return result;
}
result = Curl_cf_quic_insert_after(cf, origin, peer);
if(result) {
CURL_TRC_CF(data, cf, "adding QUIC filter failed -> %d", (int)result);
return result;
}
CURL_TRC_CF(data, cf, "added QUIC filter for origin");
}
else
#endif /* !CURL_DISABLE_HTTP && USE_HTTP3 && CURL_DISABLE_PROXY */
#ifdef USE_SSL
if((ctx->ssl_mode == CURL_CF_SSL_ENABLE ||
(ctx->ssl_mode != CURL_CF_SSL_DISABLE &&
cf->conn->scheme->flags & PROTOPT_SSL)) && /* we want SSL */
!Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
#ifndef CURL_DISABLE_PROXY
if(cf->conn->bits.origin_is_proxy) {
result = Curl_cf_ssl_proxy_insert_after(cf, data, cf->conn->origin);
}
else
#endif
{
/* Another FTP quirk: when adding SSL verification, to a DATA
* connection, always verify against the control's origin */
struct Curl_peer *origin = Curl_conn_get_origin(cf->conn, FIRSTSOCKET);
struct Curl_peer *peer =
Curl_conn_get_destination(cf->conn, cf->sockindex);
result = Curl_cf_ssl_insert_after(cf, data, origin, peer);
}
if(result) {
CURL_TRC_CF(data, cf, "adding SSL filter for origin failed -> %d",
(int)result);
return result;
}
CURL_TRC_CF(data, cf, "added SSL filter for origin");
}
#endif /* USE_SSL */
ctx->state = CF_SETUP_CNNCT_SSL;
}
return result;
}
static CURLcode cf_setup_connect_steps(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
}
/* connect current sub-chain */
connect_sub_chain:
VERBOSE(Curl_conn_trc_filters(data, cf->sockindex, "cf_setup_connect"));
if(cf->next && !cf->next->connected) {
result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
return result;
}
result = cf_setup_add_ip_happy(cf, data);
if(result)
return result;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
#ifndef CURL_DISABLE_PROXY
result = cf_setup_add_socks(cf, data);
if(result)
return result;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
#ifndef CURL_DISABLE_HTTP
result = cf_setup_add_http_proxy(cf, data);
if(result)
return result;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
#endif /* !CURL_DISABLE_HTTP */
result = cf_setup_add_haproxy(cf, data);
if(result)
return result;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
#endif /* !CURL_DISABLE_PROXY */
result = cf_setup_add_origin_filters(cf, data);
if(result)
return result;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
ctx->state = CF_SETUP_DONE;
cf->connected = TRUE;
*done = TRUE;
return CURLE_OK;
}
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result;
/* In some situations, a server/proxy may close the connection and
* we need to connect again (HTTP/1.x proxy auth, for example).
* We used to close the filters and reuse them for another attempt,
* however that complicates filter code and it is simpler to tear them
* all down and start over. */
retry:
result = cf_setup_connect_steps(cf, data, done);
if(result == CURLE_AGAIN) {
++ctx->retry_count;
if(ctx->retry_count > 5) /* arbitrary limit, better just timeout? */
return CURLE_COULDNT_CONNECT;
CURL_TRC_CF(data, cf, "retrying connect, %d. time", ctx->retry_count);
Curl_conn_cf_discard_chain(&cf->next, data);
ctx->state = CF_SETUP_INIT;
goto retry;
}
return result;
}
static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURL_TRC_CF(data, cf, "destroy");
curlx_safefree(ctx);
}
struct Curl_cftype Curl_cft_setup = {
"SETUP",
CF_TYPE_SETUP,
CURL_LOG_LVL_NONE,
cf_setup_destroy,
cf_setup_connect,
Curl_cf_def_shutdown,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
Curl_cf_def_cntrl,
Curl_cf_def_conn_is_alive,
Curl_cf_def_conn_keep_alive,
Curl_cf_def_query,
};
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf = NULL;
struct cf_setup_ctx *ctx;
CURLcode result = CURLE_OK;
(void)data;
ctx = curlx_calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
ctx->state = CF_SETUP_INIT;
ctx->ssl_mode = ssl_mode;
ctx->transport = transport;
result = Curl_cf_create(&cf, &Curl_cft_setup, ctx);
if(result)
goto out;
ctx = NULL;
out:
*pcf = result ? NULL : cf;
if(ctx) {
curlx_free(ctx);
}
return result;
}
CURLcode Curl_cf_setup_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
result = cf_setup_create(&cf, data, transport, ssl_mode);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
out:
return result;
}
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf;
CURLcode result;
DEBUGASSERT(data);
result = cf_setup_create(&cf, data, transport, ssl_mode);
if(result)
goto out;
Curl_conn_cf_insert_after(cf_at, cf);
out:
return result;
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef HEADER_CURL_CF_SETUP_H
#define HEADER_CURL_CF_SETUP_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
struct Curl_dns_entry;
struct ip_quadruple;
struct Curl_peer;
struct Curl_str;
CURLcode Curl_cf_setup_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
uint8_t transport,
int ssl_mode);
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
uint8_t transport,
int ssl_mode);
extern struct Curl_cftype Curl_cft_setup;
#endif /* HEADER_CURL_CF_SETUP_H */
+265 -160
View File
@@ -26,6 +26,9 @@
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> /* <netinet/tcp.h> may need it */
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h> /* for sockaddr_un */
#endif
#ifdef HAVE_LINUX_TCP_H
#include <linux/tcp.h>
#elif defined(HAVE_NETINET_TCP_H)
@@ -44,16 +47,17 @@
#include <arpa/inet.h>
#endif
#ifdef HAVE_IFADDRS_H
#include <ifaddrs.h>
#endif
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
#ifdef __VMS
#include <in.h>
#include <inet.h>
#endif
#ifdef __DragonFly__
/* Required for __DragonFly_version */
#include <sys/param.h>
#endif
#include "urldata.h"
#include "curl_trc.h"
#include "if2ip.h"
@@ -63,11 +67,13 @@
#include "curl_addrinfo.h"
#include "select.h"
#include "multiif.h"
#include "curlx/inet_ntop.h"
#include "curlx/inet_pton.h"
#include "progress.h"
#include "conncache.h"
#include "multihandle.h"
#include "rand.h"
#include "sockaddr.h"
#include "curlx/strdup.h"
#include "system_win32.h"
#include "curlx/nonblock.h"
@@ -77,6 +83,63 @@
#include "curlx/strparse.h"
/* retrieves ip address and port from a sockaddr structure. note it calls
* curlx_inet_ntop which sets errno on fail, not SOCKERRNO.
* @unittest 1607
*/
UNITTEST bool sockaddr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, uint16_t *port);
UNITTEST bool sockaddr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, uint16_t *port)
{
struct sockaddr_in *si = NULL;
#ifdef USE_IPV6
struct sockaddr_in6 *si6 = NULL;
#endif
#ifdef USE_UNIX_SOCKETS
struct sockaddr_un *su = NULL;
#else
(void)salen;
#endif
switch(sa->sa_family) {
case AF_INET:
si = (struct sockaddr_in *)(void *)sa;
if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
*port = ntohs(si->sin_port);
return TRUE;
}
break;
#ifdef USE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *)sa;
if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) {
*port = ntohs(si6->sin6_port);
return TRUE;
}
break;
#endif
#ifdef USE_UNIX_SOCKETS
case AF_UNIX:
if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
su = (struct sockaddr_un *)sa;
curl_msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
}
else
addr[0] = 0; /* socket with no name */
*port = 0;
return TRUE;
#endif
default:
break;
}
addr[0] = '\0';
*port = 0;
errno = SOCKEAFNOSUPPORT;
return FALSE;
}
static void tcpnodelay(struct Curl_cfilter *cf,
struct Curl_easy *data,
curl_socket_t sockfd)
@@ -86,8 +149,7 @@ static void tcpnodelay(struct Curl_cfilter *cf,
int level = IPPROTO_TCP;
VERBOSE(char buffer[STRERROR_LEN]);
if(setsockopt(sockfd, level, TCP_NODELAY,
(void *)&onoff, sizeof(onoff)) < 0)
if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, sizeof(onoff)) < 0)
CURL_TRC_CF(data, cf, "Could not set TCP_NODELAY: %s",
curlx_strerror(SOCKERRNO, buffer, sizeof(buffer)));
#else
@@ -97,8 +159,8 @@ static void tcpnodelay(struct Curl_cfilter *cf,
#endif
}
#if defined(USE_WINSOCK) || defined(TCP_KEEPIDLE) || \
defined(TCP_KEEPALIVE) || defined(TCP_KEEPALIVE_THRESHOLD) || \
#if defined(USE_WINSOCK) || defined(TCP_KEEPIDLE) || \
defined(TCP_KEEPALIVE) || defined(TCP_KEEPALIVE_THRESHOLD) || \
defined(TCP_KEEPINTVL) || defined(TCP_KEEPALIVE_ABORT_THRESHOLD)
#if defined(USE_WINSOCK) || \
(defined(__sun) && !defined(TCP_KEEPIDLE)) || \
@@ -132,14 +194,15 @@ static void tcpkeepalive(struct Curl_cfilter *cf,
VERSION_GREATER_THAN_EQUAL)) {
CURL_TRC_CF(data, cf, "Set TCP_KEEP* on fd=%" FMT_SOCKET_T, sockfd);
optval = curlx_sltosi(data->set.tcp_keepidle);
/* Offered by mingw-w64 v12+. MS SDK 6.0A+. */
/* Offered by mingw-w64 v12+, MS SDK 6.0A/VS2008+ */
#ifndef TCP_KEEPALIVE
#define TCP_KEEPALIVE 3
#endif
/* Offered by mingw-w64 v12+. MS SDK ~10+/~VS2017+. */
/* Offered by mingw-w64 v12+, MS SDK 10.0.15063.0/VS2017 15.1+ */
#ifndef TCP_KEEPCNT
#define TCP_KEEPCNT 16
#endif
/* Offered by mingw-w64 v12+, MS SDK 10.0.16299.0/VS2017 15.4+ */
#ifndef TCP_KEEPIDLE
#define TCP_KEEPIDLE TCP_KEEPALIVE
#endif
@@ -302,6 +365,49 @@ int Curl_sock_nosigpipe(curl_socket_t sockfd)
}
#endif /* USE_SO_NOSIGPIPE */
#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
static uint32_t get_scope_id(struct Curl_easy *data,
struct sockaddr_in6 *sa6)
{
uint32_t scope_id = 0;
if(data->conn->scope_id)
return data->conn->scope_id;
/* NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Assign) */
scope_id = sa6->sin6_scope_id;
if(!scope_id && IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) {
/* The resolver did not set scope_id for this link-local address.
* Try to determine it from the system's network interfaces.
* Without a scope_id, connect() to a link-local address fails
* with EINVAL on Linux.
* NOTE: On multi-homed hosts with several interfaces having
* link-local addresses, this picks the first one found, which
* may not be the correct outgoing interface. */
#if defined(HAVE_GETIFADDRS) && defined(HAVE_NET_IF_H)
struct ifaddrs *ifa, *ifa_list;
if(getifaddrs(&ifa_list) == 0) {
for(ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
if(ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6 &&
(ifa->ifa_flags & IFF_UP) &&
!(ifa->ifa_flags & IFF_LOOPBACK)) {
struct sockaddr_in6 *s6 = (void *)ifa->ifa_addr;
if(IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) && s6->sin6_scope_id) {
scope_id = s6->sin6_scope_id;
infof(data,
"determined scope_id=%lu for link-local address "
"from local interface",
(unsigned long)scope_id);
break;
}
}
}
freeifaddrs(ifa_list);
}
#endif /* HAVE_GETIFADDRS && HAVE_NET_IF_H */
}
return scope_id;
}
#endif
static CURLcode socket_open(struct Curl_easy *data,
struct Curl_sockaddr_ex *addr,
curl_socket_t *sockfd)
@@ -371,9 +477,9 @@ static CURLcode socket_open(struct Curl_easy *data,
#endif
#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
if(data->conn->scope_id && (addr->family == AF_INET6)) {
if(addr->family == AF_INET6) {
struct sockaddr_in6 * const sa6 = (void *)&addr->curl_sa_addr;
sa6->sin6_scope_id = data->conn->scope_id;
sa6->sin6_scope_id = get_scope_id(data, sa6);
}
#endif
return CURLE_OK;
@@ -511,8 +617,7 @@ CURLcode Curl_parse_interface(const char *input,
++host_part;
*host = curlx_memdup0(host_part, len - (host_part - input));
if(!*host) {
curlx_free(*iface);
*iface = NULL;
curlx_safefree(*iface);
return CURLE_OUT_OF_MEMORY;
}
return CURLE_OK;
@@ -547,7 +652,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
const char *host_input = data->set.str[STRING_BINDHOST];
const char *iface = iface_input ? iface_input : dev;
const char *host = host_input ? host_input : dev;
int error;
int sockerr;
#ifdef IP_BIND_ADDRESS_NO_PORT
int on = 1;
#endif
@@ -610,9 +715,9 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
if(iface_input && !host_input) {
/* Do not fall back to treating it as a hostname */
char buffer[STRERROR_LEN];
data->state.os_errno = error = SOCKERRNO;
data->state.os_errno = sockerr = SOCKERRNO;
failf(data, "Could not bind to interface '%s' with errno %d: %s",
iface, error, curlx_strerror(error, buffer, sizeof(buffer)));
iface, sockerr, curlx_strerror(sockerr, buffer, sizeof(buffer)));
return CURLE_INTERFACE_FAILED;
}
break;
@@ -624,7 +729,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
* We now have the numerical IP address in the 'myhost' buffer
*/
host = myhost;
infof(data, "Local Interface %s is ip %s using address family %i",
infof(data, "Local Interface %s is ip %s using address family %d",
iface, host, af);
done = 1;
break;
@@ -650,7 +755,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
int h_af = h->addr->ai_family;
/* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
Curl_printable_address(h->addr, myhost, sizeof(myhost));
infof(data, "Name '%s' family %i resolved to '%s' family %i",
infof(data, "Name '%s' family %d resolved to '%s' family %d",
host, af, myhost, h_af);
Curl_dns_entry_unlink(data, &h); /* this will NULL, potential free h */
if(af != h_af) {
@@ -714,9 +819,9 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
generic resolve error. */
char buffer[STRERROR_LEN];
data->state.errorbuf = FALSE;
data->state.os_errno = error = SOCKERRNO;
data->state.os_errno = sockerr = SOCKERRNO;
failf(data, "Could not bind to '%s' with errno %d: %s", host,
error, curlx_strerror(error, buffer, sizeof(buffer)));
sockerr, curlx_strerror(sockerr, buffer, sizeof(buffer)));
return CURLE_INTERFACE_FAILED;
}
}
@@ -765,9 +870,9 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
}
{
char buffer[STRERROR_LEN];
data->state.os_errno = error = SOCKERRNO;
data->state.os_errno = sockerr = SOCKERRNO;
failf(data, "bind failed with errno %d: %s",
error, curlx_strerror(error, buffer, sizeof(buffer)));
sockerr, curlx_strerror(sockerr, buffer, sizeof(buffer)));
}
return CURLE_INTERFACE_FAILED;
@@ -777,12 +882,12 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
/*
* verifyconnect() returns TRUE if the connect really has happened.
*/
static bool verifyconnect(curl_socket_t sockfd, int *error)
static bool verifyconnect(curl_socket_t sockfd, int *psockerr)
{
bool rc = TRUE;
#ifdef SO_ERROR
int err = 0;
curl_socklen_t errSize = sizeof(err);
int sockerr = 0;
curl_socklen_t errSize = sizeof(sockerr);
#ifdef _WIN32
/*
@@ -803,27 +908,27 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
SleepEx(0, FALSE);
#endif
if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
err = SOCKERRNO;
if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&sockerr, &errSize))
sockerr = SOCKERRNO;
#if defined(EBADIOCTL) && defined(__minix)
/* Minix 3.1.x does not support getsockopt on UDP sockets */
if(EBADIOCTL == err) {
if(EBADIOCTL == sockerr) {
SET_SOCKERRNO(0);
err = 0;
sockerr = 0;
}
#endif
if((err == 0) || (SOCKEISCONN == err))
if((sockerr == 0) || (SOCKEISCONN == sockerr))
/* we are connected, awesome! */
rc = TRUE;
else
/* This was not a successful connect */
rc = FALSE;
if(error)
*error = err;
if(psockerr)
*psockerr = sockerr;
#else
(void)sockfd;
if(error)
*error = SOCKERRNO;
if(psockerr)
*psockerr = SOCKERRNO;
#endif
return rc;
}
@@ -832,38 +937,25 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
* Determine the curl code for a socket connect() == -1 with errno.
*/
static CURLcode socket_connect_result(struct Curl_easy *data,
const char *ipaddress, int error)
const char *ipaddress, int sockerr)
{
switch(error) {
case SOCKEINPROGRESS:
case SOCKEWOULDBLOCK:
#ifdef EAGAIN
#if (EAGAIN) != (SOCKEWOULDBLOCK)
/* On some platforms EAGAIN and EWOULDBLOCK are the
* same value, and on others they are different, hence
* the odd #if
*/
case EAGAIN:
#endif
#endif
if(sockerr == SOCKEINPROGRESS || SOCK_EAGAIN(sockerr))
return CURLE_OK;
default:
/* unknown error, fallthrough and try another address! */
{
VERBOSE(char buffer[STRERROR_LEN]);
infof(data, "Immediate connect fail for %s: %s", ipaddress,
curlx_strerror(error, buffer, sizeof(buffer)));
NOVERBOSE((void)ipaddress);
}
data->state.os_errno = error;
/* connect failed */
return CURLE_COULDNT_CONNECT;
/* unknown error, fallthrough and try another address! */
{
VERBOSE(char buffer[STRERROR_LEN]);
infof(data, "Immediate connect fail for %s: %s", ipaddress,
curlx_strerror(sockerr, buffer, sizeof(buffer)));
NOVERBOSE((void)ipaddress);
}
data->state.os_errno = sockerr;
/* connect failed */
return CURLE_COULDNT_CONNECT;
}
struct cf_socket_ctx {
uint8_t transport;
struct Curl_peer *peer;
struct Curl_sockaddr_ex addr; /* address to connect to */
curl_socket_t sock; /* current attempt socket */
struct ip_quadruple ip; /* The IP quadruple 2x(addr+port) */
@@ -874,13 +966,14 @@ struct cf_socket_ctx {
struct curltime last_sndbuf_query_at; /* when SO_SNDBUF last queried */
ULONG sndbuf_size; /* the last set SO_SNDBUF size */
#endif
int error; /* errno of last failure or 0 */
int sockerr; /* socket error of last failure or 0 */
#ifdef DEBUGBUILD
int wblock_percent; /* percent of writes doing EAGAIN */
int wpartial_percent; /* percent of bytes written in send */
int rblock_percent; /* percent of reads doing EAGAIN */
size_t recv_max; /* max enforced read size */
#endif
uint8_t transport;
BIT(got_first_byte); /* if first byte was received */
BIT(listening); /* socket is listening */
BIT(accepted); /* socket was accepted, not connected */
@@ -889,10 +982,12 @@ struct cf_socket_ctx {
};
static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
struct Curl_peer *peer,
struct Curl_sockaddr_ex *addr,
uint8_t transport)
{
memset(ctx, 0, sizeof(*ctx));
Curl_peer_link(&ctx->peer, peer);
ctx->sock = CURL_SOCKET_BAD;
ctx->transport = transport;
ctx->addr = *addr;
@@ -929,22 +1024,12 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
return CURLE_OK;
}
static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
static void cf_socket_ctx_free(struct cf_socket_ctx *ctx)
{
struct cf_socket_ctx *ctx = cf->ctx;
if(ctx && ctx->sock != CURL_SOCKET_BAD) {
CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_SOCKET_T, ctx->sock);
if(ctx->sock == cf->conn->sock[cf->sockindex])
cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
ctx->sock = CURL_SOCKET_BAD;
ctx->active = FALSE;
memset(&ctx->started_at, 0, sizeof(ctx->started_at));
memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
if(ctx) {
Curl_peer_unlink(&ctx->peer);
curlx_free(ctx);
}
cf->connected = FALSE;
}
static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
@@ -973,10 +1058,16 @@ static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
cf_socket_close(cf, data);
CURL_TRC_CF(data, cf, "destroy");
curlx_free(ctx);
cf->ctx = NULL;
if(ctx) {
if(ctx->sock != CURL_SOCKET_BAD) {
CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_SOCKET_T, ctx->sock);
if(ctx->sock == cf->conn->sock[cf->sockindex])
cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
}
cf_socket_ctx_free(ctx);
}
}
static void set_local_ip(struct Curl_cfilter *cf,
@@ -996,12 +1087,12 @@ static void set_local_ip(struct Curl_cfilter *cf,
memset(&ssloc, 0, sizeof(ssloc));
if(getsockname(ctx->sock, (struct sockaddr *)&ssloc, &slen)) {
VERBOSE(int error = SOCKERRNO);
VERBOSE(int sockerr = SOCKERRNO);
infof(data, "getsockname() failed with errno %d: %s",
error, curlx_strerror(error, buffer, sizeof(buffer)));
sockerr, curlx_strerror(sockerr, buffer, sizeof(buffer)));
}
else if(!Curl_addr2string((struct sockaddr *)&ssloc, slen,
ctx->ip.local_ip, &ctx->ip.local_port)) {
else if(!sockaddr2string((struct sockaddr *)&ssloc, slen,
ctx->ip.local_ip, &ctx->ip.local_port)) {
infof(data, "ssloc inet_ntop() failed with errno %d: %s",
errno, curlx_strerror(errno, buffer, sizeof(buffer)));
}
@@ -1018,12 +1109,15 @@ static CURLcode set_remote_ip(struct Curl_cfilter *cf,
/* store remote address and port used in this connection attempt */
ctx->ip.transport = ctx->transport;
if(!Curl_addr2string(&ctx->addr.curl_sa_addr,
(curl_socklen_t)ctx->addr.addrlen,
ctx->ip.remote_ip, &ctx->ip.remote_port)) {
if(!sockaddr2string(&ctx->addr.curl_sa_addr,
(curl_socklen_t)ctx->addr.addrlen,
ctx->ip.remote_ip, &ctx->ip.remote_port)) {
char buffer[STRERROR_LEN];
ctx->error = errno;
/* using bare errno instead of SOCKERRNO is safe here, because
sockaddr2string() calls curlx_inet_ntop(), and they both report failures
via errno (even on Windows builds). */
ctx->sockerr = errno;
/* malformed address or bug in inet_ntop, try next address */
failf(data, "curl_sa_addr inet_ntop() failed with errno %d: %s",
errno, curlx_strerror(errno, buffer, sizeof(buffer)));
@@ -1091,7 +1185,20 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
(void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_V6ONLY,
(void *)&on, sizeof(on));
#endif
infof(data, " Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
{
struct sockaddr_in6 *sa6 = (void *)&ctx->addr.curl_sa_addr;
if(sa6->sin6_scope_id)
infof(data, " Trying [%s]:%d scope_id=%lu...",
ctx->ip.remote_ip, ctx->ip.remote_port,
(unsigned long)sa6->sin6_scope_id);
else
#endif
infof(data, " Trying [%s]:%d...",
ctx->ip.remote_ip, ctx->ip.remote_port);
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
}
#endif
}
else
#endif
@@ -1154,7 +1261,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
error = curlx_nonblock(ctx->sock, TRUE);
if(error < 0) {
result = CURLE_UNSUPPORTED_PROTOCOL;
ctx->error = SOCKERRNO;
ctx->sockerr = SOCKERRNO;
goto out;
}
#else
@@ -1164,7 +1271,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
error = curlx_nonblock(ctx->sock, TRUE);
if(error < 0) {
result = CURLE_UNSUPPORTED_PROTOCOL;
ctx->error = SOCKERRNO;
ctx->sockerr = SOCKERRNO;
goto out;
}
}
@@ -1183,7 +1290,7 @@ out:
cf->connected = TRUE;
}
CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
result, ctx->sock);
(int)result, ctx->sock);
return result;
}
@@ -1257,7 +1364,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
*done = FALSE; /* a negative world view is best */
if(ctx->sock == CURL_SOCKET_BAD) {
int error;
int sockerr;
result = cf_socket_open(cf, data);
if(result)
@@ -1270,12 +1377,13 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
/* Connect TCP socket */
rc = do_connect(cf, data, (bool)cf->conn->bits.tcp_fastopen);
error = SOCKERRNO;
sockerr = SOCKERRNO;
set_local_ip(cf, data);
CURL_TRC_CF(data, cf, "local address %s port %d...",
ctx->ip.local_ip, ctx->ip.local_port);
if(rc == -1) {
result = socket_connect_result(data, ctx->ip.remote_ip, error);
ctx->sockerr = sockerr;
result = socket_connect_result(data, ctx->ip.remote_ip, sockerr);
goto out;
}
}
@@ -1295,7 +1403,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
if(verifyconnect(ctx->sock, &ctx->error)) {
if(verifyconnect(ctx->sock, &ctx->sockerr)) {
/* we are connected with TCP, awesome! */
ctx->connected_at = *Curl_pgrs_now(data);
set_local_ip(cf, data);
@@ -1307,7 +1415,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
}
else if(rc & CURL_CSELECT_ERR) {
CURL_TRC_CF(data, cf, "poll/select error on fd=%" FMT_SOCKET_T, ctx->sock);
(void)verifyconnect(ctx->sock, &ctx->error);
(void)verifyconnect(ctx->sock, &ctx->sockerr);
result = CURLE_COULDNT_CONNECT;
}
@@ -1315,10 +1423,10 @@ out:
if(result) {
VERBOSE(char buffer[STRERROR_LEN]);
set_local_ip(cf, data);
if(ctx->error) {
data->state.os_errno = ctx->error;
SET_SOCKERRNO(ctx->error);
VERBOSE(curlx_strerror(ctx->error, buffer, sizeof(buffer)));
if(ctx->sockerr) {
data->state.os_errno = ctx->sockerr;
SET_SOCKERRNO(ctx->sockerr);
VERBOSE(curlx_strerror(ctx->sockerr, buffer, sizeof(buffer)));
}
else {
VERBOSE(curlx_strcopy(buffer, sizeof(buffer), STRCONST("peer closed")));
@@ -1330,7 +1438,7 @@ out:
infof(data, "connect to %s port %u from %s port %d failed: %s",
ctx->ip.remote_ip, ctx->ip.remote_port,
ctx->ip.local_ip, ctx->ip.local_port,
curlx_strerror(ctx->error, buffer, sizeof(buffer)));
curlx_strerror(ctx->sockerr, buffer, sizeof(buffer)));
*done = FALSE;
}
return result;
@@ -1369,7 +1477,7 @@ static CURLcode cf_socket_adjust_pollset(struct Curl_cfilter *cf,
#ifdef USE_WINSOCK
/* Offered by mingw-w64 v13+. MS SDK 7.0A+. */
/* Offered by mingw-w64 v13+, MS SDK 7.0A/VS2010+ */
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
#endif
@@ -1442,22 +1550,12 @@ static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!curlx_sztouz(rv, pnwritten)) {
int sockerr = SOCKERRNO;
if(
#ifdef USE_WINSOCK
/* This is how Windows does it */
(SOCKEWOULDBLOCK == sockerr)
#else
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
due to its inability to send off data without blocking. We therefore
treat both error codes the same here */
(SOCKEWOULDBLOCK == sockerr) ||
(EAGAIN == sockerr) || (SOCKEINTR == sockerr) ||
(SOCKEINPROGRESS == sockerr)
if(SOCK_EAGAIN(sockerr)
#ifndef USE_WINSOCK
|| (sockerr == SOCKEINTR) || (sockerr == SOCKEINPROGRESS)
#endif
) {
/* EWOULDBLOCK */
result = CURLE_AGAIN;
result = CURLE_AGAIN; /* EWOULDBLOCK */
}
else {
char buffer[STRERROR_LEN];
@@ -1474,7 +1572,7 @@ static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
#endif
CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, %zu",
orig_len, result, *pnwritten);
orig_len, (int)result, *pnwritten);
cf->conn->sock[cf->sockindex] = fdsave;
return result;
}
@@ -1508,21 +1606,12 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!curlx_sztouz(rv, pnread)) {
int sockerr = SOCKERRNO;
if(
#ifdef USE_WINSOCK
/* This is how Windows does it */
(SOCKEWOULDBLOCK == sockerr)
#else
/* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
due to its inability to send off data without blocking. We therefore
treat both error codes the same here */
(SOCKEWOULDBLOCK == sockerr) ||
(EAGAIN == sockerr) || (SOCKEINTR == sockerr)
if(SOCK_EAGAIN(sockerr)
#ifndef USE_WINSOCK
|| (sockerr == SOCKEINTR)
#endif
) {
/* EWOULDBLOCK */
result = CURLE_AGAIN;
result = CURLE_AGAIN; /* EWOULDBLOCK */
}
else {
char buffer[STRERROR_LEN];
@@ -1533,7 +1622,7 @@ static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
}
CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread);
CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, (int)result, *pnread);
if(!result && !ctx->got_first_byte) {
ctx->first_byte_at = *Curl_pgrs_now(data);
ctx->got_first_byte = TRUE;
@@ -1548,8 +1637,6 @@ static void cf_socket_update_data(struct Curl_cfilter *cf,
if(cf->connected && (cf->sockindex == FIRSTSOCKET)) {
struct cf_socket_ctx *ctx = cf->ctx;
data->info.primary = ctx->ip;
/* not sure if this is redundant... */
data->info.conn_remote_port = cf->conn->remote_port;
}
}
@@ -1696,7 +1783,6 @@ struct Curl_cftype Curl_cft_tcp = {
CURL_LOG_LVL_NONE,
cf_socket_destroy,
cf_tcp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_adjust_pollset,
Curl_cf_def_data_pending,
@@ -1710,17 +1796,24 @@ struct Curl_cftype Curl_cft_tcp = {
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
uint8_t transport)
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport)
{
struct cf_socket_ctx *ctx = NULL;
struct Curl_cfilter *cf = NULL;
CURLcode result;
(void)data;
(void)origin;
(void)conn;
DEBUGASSERT(transport == TRNSPRT_TCP);
(void)tunnel_peer;
(void)tunnel_transport;
DEBUGASSERT(transport_peer == TRNSPRT_TCP);
if(!addr) {
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
@@ -1732,7 +1825,7 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
goto out;
}
result = cf_socket_ctx_init(ctx, addr, transport);
result = cf_socket_ctx_init(ctx, peer, addr, transport_peer);
if(result)
goto out;
@@ -1742,7 +1835,7 @@ out:
*pcf = (!result) ? cf : NULL;
if(result) {
curlx_safefree(cf);
curlx_safefree(ctx);
cf_socket_ctx_free(ctx);
}
return result;
@@ -1837,7 +1930,8 @@ static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
if(ctx->sock == CURL_SOCKET_BAD) {
result = cf_socket_open(cf, data);
if(result) {
CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d",
(int)result);
goto out;
}
@@ -1862,7 +1956,6 @@ struct Curl_cftype Curl_cft_udp = {
CURL_LOG_LVL_NONE,
cf_socket_destroy,
cf_udp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_adjust_pollset,
Curl_cf_def_data_pending,
@@ -1876,24 +1969,31 @@ struct Curl_cftype Curl_cft_udp = {
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
uint8_t transport)
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport)
{
struct cf_socket_ctx *ctx = NULL;
struct Curl_cfilter *cf = NULL;
CURLcode result;
(void)data;
(void)origin;
(void)conn;
DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
(void)tunnel_peer;
(void)tunnel_transport;
DEBUGASSERT(transport_peer == TRNSPRT_UDP || transport_peer == TRNSPRT_QUIC);
ctx = curlx_calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
result = cf_socket_ctx_init(ctx, addr, transport);
result = cf_socket_ctx_init(ctx, peer, addr, transport_peer);
if(result)
goto out;
@@ -1903,7 +2003,7 @@ out:
*pcf = (!result) ? cf : NULL;
if(result) {
curlx_safefree(cf);
curlx_safefree(ctx);
cf_socket_ctx_free(ctx);
}
return result;
@@ -1916,7 +2016,6 @@ struct Curl_cftype Curl_cft_unix = {
CURL_LOG_LVL_NONE,
cf_socket_destroy,
cf_tcp_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_adjust_pollset,
Curl_cf_def_data_pending,
@@ -1929,25 +2028,32 @@ struct Curl_cftype Curl_cft_unix = {
};
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
uint8_t transport)
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport)
{
struct cf_socket_ctx *ctx = NULL;
struct Curl_cfilter *cf = NULL;
CURLcode result;
(void)data;
(void)origin;
(void)conn;
DEBUGASSERT(transport == TRNSPRT_UNIX);
(void)tunnel_peer;
(void)tunnel_transport;
DEBUGASSERT(transport_peer == TRNSPRT_UNIX);
ctx = curlx_calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
result = cf_socket_ctx_init(ctx, addr, transport);
result = cf_socket_ctx_init(ctx, peer, addr, transport_peer);
if(result)
goto out;
@@ -1957,7 +2063,7 @@ out:
*pcf = (!result) ? cf : NULL;
if(result) {
curlx_safefree(cf);
curlx_safefree(ctx);
cf_socket_ctx_free(ctx);
}
return result;
@@ -2005,13 +2111,13 @@ static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf,
plen = sizeof(ssrem);
memset(&ssrem, 0, plen);
if(getpeername(ctx->sock, (struct sockaddr *)&ssrem, &plen)) {
int error = SOCKERRNO;
int sockerr = SOCKERRNO;
failf(data, "getpeername() failed with errno %d: %s",
error, curlx_strerror(error, buffer, sizeof(buffer)));
sockerr, curlx_strerror(sockerr, buffer, sizeof(buffer)));
return;
}
if(!Curl_addr2string((struct sockaddr *)&ssrem, plen,
ctx->ip.remote_ip, &ctx->ip.remote_port)) {
if(!sockaddr2string((struct sockaddr *)&ssrem, plen,
ctx->ip.remote_ip, &ctx->ip.remote_port)) {
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
errno, curlx_strerror(errno, buffer, sizeof(buffer)));
return;
@@ -2058,7 +2164,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "Checking for incoming on fd=%" FMT_SOCKET_T
" ip=%s:%d", ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
socketstate = SOCKET_READABLE(ctx->sock, 0);
CURL_TRC_CF(data, cf, "socket_check -> %x", socketstate);
CURL_TRC_CF(data, cf, "socket_check -> %x", (unsigned int)socketstate);
switch(socketstate) {
case -1: /* error */
/* let's die here */
@@ -2128,10 +2234,10 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
int error = 0;
/* activate callback for setting socket options */
Curl_set_in_callback(data, true);
Curl_set_in_callback(data, TRUE);
error = data->set.fsockopt(data->set.sockopt_client,
ctx->sock, CURLSOCKTYPE_ACCEPT);
Curl_set_in_callback(data, false);
Curl_set_in_callback(data, FALSE);
if(error)
return CURLE_ABORTED_BY_CALLBACK;
@@ -2146,7 +2252,6 @@ struct Curl_cftype Curl_cft_tcp_accept = {
CURL_LOG_LVL_NONE,
cf_socket_destroy,
cf_tcp_accept_connect,
cf_socket_close,
cf_socket_shutdown,
cf_socket_adjust_pollset,
Curl_cf_def_data_pending,
+15 -22
View File
@@ -25,8 +25,6 @@
***************************************************************************/
#include "curl_setup.h"
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
struct Curl_addrinfo;
struct Curl_cfilter;
struct Curl_easy;
@@ -34,23 +32,6 @@ struct connectdata;
struct Curl_sockaddr_ex;
struct ip_quadruple;
/*
* The Curl_sockaddr_ex structure is libcurl's external API curl_sockaddr
* structure with enough space available to directly hold any
* protocol-specific address structures. The variable declared here will be
* used to pass / receive data to/from the fopensocket callback if this has
* been set, before that, it is initialized from parameters.
*/
struct Curl_sockaddr_ex {
int family;
int socktype;
int protocol;
unsigned int addrlen;
union {
struct sockaddr sa;
struct Curl_sockaddr_storage buf;
} addr;
};
#define curl_sa_addr addr.sa
#define curl_sa_addrbuf addr.buf
@@ -94,9 +75,13 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
*/
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
uint8_t transport);
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport);
/**
* Creates a cfilter that opens a UDP socket to the given address
@@ -107,9 +92,13 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
*/
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
uint8_t transport);
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport);
/**
* Creates a cfilter that opens a UNIX socket to the given address
@@ -120,9 +109,13 @@ CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
*/
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct Curl_peer *origin,
struct Curl_peer *peer,
uint8_t transport_peer,
struct connectdata *conn,
struct Curl_sockaddr_ex *addr,
uint8_t transport);
struct Curl_peer *tunnel_peer,
uint8_t tunnel_transport);
/**
* Creates a cfilter that keeps a listening socket.
+88 -215
View File
@@ -33,16 +33,26 @@
#include "select.h"
#include "curlx/strparse.h"
#ifdef UNITTESTS
/* @unittest 2600 */
UNITTEST void cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
UNITTEST void cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
CURLcode Curl_cf_def_connect(struct Curl_cfilter *cf,
struct Curl_easy *data, bool *done)
{
cf->connected = FALSE;
if(cf->next)
cf->next->cft->do_close(cf->next, data);
CURLcode result;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
}
if(cf->next) {
result = cf->next->cft->do_connect(cf->next, data, done);
if(result || !*done)
return result;
}
cf->connected = TRUE;
*done = TRUE;
return CURLE_OK;
}
#endif
CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data, bool *done)
@@ -117,29 +127,28 @@ CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
}
#ifdef CURLVERBOSE
static void conn_trc_filters(struct Curl_easy *data,
int sockindex,
const char *info)
void Curl_conn_trc_filters(struct Curl_easy *data,
int sockindex, const char *info)
{
if(CURL_TRC_M_is_verbose(data) && data->conn) {
struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
if(cf) {
struct dynbuf msg;
CURLcode result = CURLE_OK;
char msg[256], *buf;
int blen, n;
curlx_dyn_init(&msg, 1024);
result = curlx_dyn_addf(&msg, "%s [%d]", info, sockindex);
for(; cf && !result; cf = cf->next) {
result = curlx_dyn_addf(&msg, "[%s%s]",
cf->connected ? "" : "!", cf->cft->name);
buf = msg;
blen = sizeof(msg) - 1;
n = curl_msnprintf(buf, blen, "%s [%d]", info, sockindex);
buf += n;
blen -= n;
for(; cf && blen; cf = cf->next) {
n = curl_msnprintf(buf, blen, "[%s%s]",
cf->connected ? "" : "!", cf->cft->name);
buf += n;
blen -= n;
}
if(!result)
CURL_TRC_M(data, "%s", curlx_dyn_ptr(&msg));
else
CURL_TRC_M(data, "%s [%d] error %d tracing chain",
info, sockindex, result);
curlx_dyn_free(&msg);
CURL_TRC_M(data, "%s%s", msg, blen ? "" : "...");
}
else
CURL_TRC_M(data, "%s [%d][-]", info, sockindex);
@@ -170,22 +179,11 @@ void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
void Curl_conn_cf_discard_all(struct Curl_easy *data,
struct connectdata *conn, int sockindex)
{
struct curltime *pt = &conn->shutdown.start[sockindex];
memset(pt, 0, sizeof(*pt));
Curl_conn_cf_discard_chain(&conn->cfilter[sockindex], data);
}
void Curl_conn_close(struct Curl_easy *data, int sockindex)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data->conn);
/* it is valid to call that without filters being present */
cf = data->conn->cfilter[sockindex];
if(cf) {
cf->cft->do_close(cf, data);
}
Curl_shutdown_clear(data, sockindex);
}
CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
{
struct Curl_cfilter *cf;
@@ -225,7 +223,7 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
bool cfdone = FALSE;
result = cf->cft->do_shutdown(cf, data, &cfdone);
if(result) {
CURL_TRC_CF(data, cf, "shut down failed with %d", result);
CURL_TRC_CF(data, cf, "shut down failed with %d", (int)result);
return result;
}
else if(!cfdone) {
@@ -427,12 +425,6 @@ CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
return CURLE_FAILED_INIT;
}
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
if(cf)
cf->cft->do_close(cf, data);
}
CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const uint8_t *buf, size_t len, bool eos,
size_t *pnwritten)
@@ -452,29 +444,6 @@ CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return CURLE_RECV_ERROR;
}
#ifdef CURLVERBOSE
static CURLcode cf_verboseconnect(struct Curl_easy *data,
struct Curl_cfilter *cf)
{
if(Curl_trc_is_verbose(data)) {
struct ip_quadruple ipquad;
bool is_ipv6;
CURLcode result;
result = Curl_conn_cf_get_ip_info(cf, data, &is_ipv6, &ipquad);
if(result)
return result;
infof(data, "Established %sconnection to %s (%s port %u) from %s port %u ",
(cf->sockindex == SECONDARYSOCKET) ? "2nd " : "",
CURL_CONN_HOST_DISPNAME(data->conn),
ipquad.remote_ip, ipquad.remote_port,
ipquad.local_ip, ipquad.local_port);
}
return CURLE_OK;
}
#endif
static CURLcode cf_cntrl_all(struct connectdata *conn,
struct Curl_easy *data,
bool ignore_result,
@@ -492,36 +461,14 @@ static CURLcode cf_cntrl_all(struct connectdata *conn,
return result;
}
static void cf_cntrl_update_info(struct Curl_easy *data,
struct connectdata *conn)
void Curl_conn_cntrl_update_info(struct Curl_easy *data,
struct connectdata *conn)
{
cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
}
/**
* Update connection statistics
*/
static void conn_report_connect_stats(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
if(cf) {
struct curltime connected;
struct curltime appconnected;
memset(&connected, 0, sizeof(connected));
cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
if(connected.tv_sec || connected.tv_usec)
Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
memset(&appconnected, 0, sizeof(appconnected));
cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
if(appconnected.tv_sec || appconnected.tv_usec)
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
}
}
static void conn_remove_setup_filters(struct Curl_easy *data,
int sockindex)
void Curl_conn_remove_setup_filters(struct Curl_easy *data,
int sockindex)
{
struct Curl_cfilter **anchor = &data->conn->cfilter[sockindex];
while(*anchor) {
@@ -538,123 +485,11 @@ static void conn_remove_setup_filters(struct Curl_easy *data,
}
}
CURLcode Curl_conn_connect(struct Curl_easy *data,
int sockindex,
bool blocking,
bool *done)
{
#define CF_CONN_NUM_POLLS_ON_STACK 5
struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
struct easy_pollset ps;
struct curl_pollfds cpfds;
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
if(!CONN_SOCK_IDX_VALID(sockindex))
return CURLE_BAD_FUNCTION_ARGUMENT;
if(data->conn->scheme->flags & PROTOPT_NONETWORK) {
*done = TRUE;
return CURLE_OK;
}
cf = data->conn->cfilter[sockindex];
if(!cf) {
*done = FALSE;
return CURLE_FAILED_INIT;
}
*done = (bool)cf->connected;
if(*done)
return CURLE_OK;
Curl_pollset_init(&ps);
Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
while(!*done) {
if(Curl_conn_needs_flush(data, sockindex)) {
DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
result = Curl_conn_flush(data, sockindex);
if(result && (result != CURLE_AGAIN))
return result;
}
result = cf->cft->do_connect(cf, data, done);
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d",
blocking, result, *done);
if(!result && *done) {
/* Now that the complete filter chain is connected, let all filters
* persist information at the connection. E.g. cf-socket sets the
* socket and ip related information. */
cf_cntrl_update_info(data, data->conn);
conn_report_connect_stats(cf, data);
data->conn->keepalive = *Curl_pgrs_now(data);
VERBOSE(result = cf_verboseconnect(data, cf));
VERBOSE(conn_trc_filters(data, sockindex, "connected"));
conn_remove_setup_filters(data, sockindex);
VERBOSE(conn_trc_filters(data, sockindex, "reduced to"));
goto out;
}
else if(result) {
CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d", result);
VERBOSE(conn_trc_filters(data, sockindex, "failed to connect"));
conn_report_connect_stats(cf, data);
goto out;
}
if(!blocking)
goto out;
else {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft_ms(data);
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
int rc;
if(timeout_ms < 0) {
/* no need to continue if time already is up */
failf(data, "connect timeout");
result = CURLE_OPERATION_TIMEDOUT;
goto out;
}
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
Curl_pollset_reset(&ps);
Curl_pollfds_reset(&cpfds);
/* In general, we want to send after connect, wait on that. */
if(sockfd != CURL_SOCKET_BAD)
result = Curl_pollset_set_out_only(data, &ps, sockfd);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, &ps);
if(result)
goto out;
result = Curl_pollfds_add_ps(&cpfds, &ps);
if(result)
goto out;
rc = Curl_poll(cpfds.pfds, cpfds.n,
CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10)));
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d",
rc);
if(rc < 0) {
result = CURLE_COULDNT_CONNECT;
goto out;
}
/* continue iterating */
}
}
out:
Curl_pollset_cleanup(&ps);
Curl_pollfds_cleanup(&cpfds);
return result;
}
bool Curl_conn_is_setup(struct connectdata *conn, int sockindex)
{
if(!CONN_SOCK_IDX_VALID(sockindex))
return FALSE;
return (conn->cfilter[sockindex] != NULL);
return !!conn->cfilter[sockindex];
}
bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
@@ -688,10 +523,37 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
return FALSE;
}
#ifndef CURL_DISABLE_PROXY
static bool cf_is_tunneling(struct Curl_cfilter *cf)
{
for(; cf; cf = cf->next) {
if((cf->cft->flags & CF_TYPE_PROXY))
return TRUE;
}
return FALSE;
}
bool Curl_conn_is_tunneling(struct connectdata *conn, int sockindex)
{
if(!CONN_SOCK_IDX_VALID(sockindex))
return FALSE;
return conn ? cf_is_tunneling(conn->cfilter[sockindex]) : FALSE;
}
#else
bool Curl_conn_is_tunneling(struct connectdata *conn, int sockindex)
{
(void)conn;
(void)sockindex;
return FALSE;
}
#endif /* CURL_DISABLE_PROXY */
static bool cf_is_ssl(struct Curl_cfilter *cf)
{
for(; cf; cf = cf->next) {
if(cf->cft->flags & CF_TYPE_SSL)
/* A tunneling proxy does not offer end2end encryption, even if
* it does SSL itself (e.g. QUIC H3 proxy) */
if((cf->cft->flags & CF_TYPE_SSL) && !(cf->cft->flags & CF_TYPE_PROXY))
return TRUE;
if(cf->cft->flags & CF_TYPE_IP_CONNECT)
return FALSE;
@@ -890,8 +752,19 @@ CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data,
DEBUGASSERT(data);
DEBUGASSERT(conn);
for(i = 0; (i < 2) && !result; ++i) {
result = Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
/* During connect time, connection filters may add sockets to the pollset
* even when the transfer neither wants to send nor receive. And those
* sockets, when having events, are served.
* Once connected however, a transfer that neither wants to send nor receive
* will never call the connection filters. Any sockets added by the filters
* will not change state and POLLIN/POLLOUT events will trigger forever,
* making us busy loop. See #21671 */
if(ps->n || !Curl_conn_is_connected(conn, FIRSTSOCKET) ||
(conn->cfilter[SECONDARYSOCKET] &&
!Curl_conn_is_connected(conn, SECONDARYSOCKET))) {
for(i = 0; (i < 2) && !result && conn; ++i) {
result = Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
}
}
return result;
}
@@ -953,8 +826,8 @@ void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
&portarg, CURL_UNCONST(phost))) {
/* Everything connected or query unsuccessful, the overall
* connection's destination is the answer */
*phost = data->conn->host.name;
portarg = data->conn->remote_port;
*phost = data->conn->origin->hostname;
portarg = data->conn->origin->port;
}
if(pport)
*pport = portarg;
@@ -1018,8 +891,8 @@ const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf,
return NULL;
}
static const struct Curl_sockaddr_ex *
cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data)
static const struct Curl_sockaddr_ex *cf_get_remote_addr(
struct Curl_cfilter *cf, struct Curl_easy *data)
{
const struct Curl_sockaddr_ex *remote_addr = NULL;
if(cf &&
@@ -1057,8 +930,8 @@ curl_socket_t Curl_conn_get_first_socket(struct Curl_easy *data)
return data->conn->sock[FIRSTSOCKET];
}
const struct Curl_sockaddr_ex *
Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex)
const struct Curl_sockaddr_ex *Curl_conn_get_remote_addr(
struct Curl_easy *data, int sockindex)
{
struct Curl_cfilter *cf =
(data->conn && CONN_SOCK_IDX_VALID(sockindex)) ?
+19 -24
View File
@@ -39,10 +39,6 @@ struct curl_tlssessioninfo;
typedef void Curl_cft_destroy_this(struct Curl_cfilter *cf,
struct Curl_easy *data);
/* Callback to close the connection immediately. */
typedef void Curl_cft_close(struct Curl_cfilter *cf,
struct Curl_easy *data);
/* Callback to close the connection filter gracefully, non-blocking.
* Implementations MUST NOT chain calls to cf->next.
*/
@@ -218,7 +214,6 @@ struct Curl_cftype {
int log_level; /* log level for such filters */
Curl_cft_destroy_this *destroy; /* destroy resources of this cf */
Curl_cft_connect *do_connect; /* establish connection */
Curl_cft_close *do_close; /* close conn */
Curl_cft_shutdown *do_shutdown; /* shutdown conn */
Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
Curl_cft_data_pending *has_data_pending; /* conn has data pending */
@@ -270,6 +265,8 @@ CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
int query, int *pres1, void *pres2);
CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data, bool *done);
CURLcode Curl_cf_def_connect(struct Curl_cfilter *cf,
struct Curl_easy *data, bool *done);
/**
* Create a new filter instance, unattached to the filter chain.
@@ -322,7 +319,6 @@ void Curl_conn_cf_discard_all(struct Curl_easy *data,
CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done);
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const uint8_t *buf, size_t len, bool eos,
size_t *pnwritten);
@@ -364,16 +360,6 @@ bool Curl_conn_cf_wants_httpsrr(struct Curl_cfilter *cf,
#define CURL_CF_SSL_DISABLE 0
#define CURL_CF_SSL_ENABLE 1
/**
* Bring the filter chain at `sockindex` for connection `data->conn` into
* connected state. Which will set `*done` to TRUE.
* This can be called on an already connected chain with no side effects.
* When not `blocking`, calls may return without error and `*done != TRUE`,
* while the individual filters negotiated the connection.
*/
CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex,
bool blocking, bool *done);
/**
* Check if a filter chain at `sockindex` for connection `conn` exists.
*/
@@ -399,6 +385,10 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex);
*/
bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
/* Determine if the connection has one or more proxy filters.
* e.g. is tunneling. */
bool Curl_conn_is_tunneling(struct connectdata *conn, int sockindex);
/*
* Fill `info` with information about the TLS instance securing the connection
* when available, otherwise e.g. when Curl_conn_is_ssl() is FALSE, return
@@ -433,11 +423,11 @@ unsigned char Curl_conn_get_transport(struct Curl_easy *data,
const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data,
struct connectdata *conn);
/**
* Close the filter chain at `sockindex` for connection `data->conn`.
* Filters remain in place and may be connected again afterwards.
*/
void Curl_conn_close(struct Curl_easy *data, int sockindex);
void Curl_conn_cntrl_update_info(struct Curl_easy *data,
struct connectdata *conn);
void Curl_conn_remove_setup_filters(struct Curl_easy *data,
int sockindex);
/**
* Shutdown the connection at `sockindex` non-blocking, using timeout
@@ -582,7 +572,7 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
* Get the remote hostname and port that the connection is currently
* talking to (or will talk to).
* Once connected or before connect starts,
* it is `conn->host.name` and `conn->remote_port`.
* it is `conn->origin->hostname` and `conn->origin->port`.
* During connect, when tunneling proxies are involved (http or socks),
* it will be the name and port the proxy currently negotiates with.
*/
@@ -604,6 +594,11 @@ int Curl_conn_get_stream_error(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
#ifdef CURLVERBOSE
void Curl_conn_trc_filters(struct Curl_easy *data,
int sockindex, const char *info);
#endif
/**
* Get the index of the given socket in the connection's sockets.
* Useful in calling `Curl_conn_send()/Curl_conn_recv()` with the
@@ -664,7 +659,7 @@ struct cf_call_data {
#define CF_DATA_SAVE(save, cf, data) \
do { \
(save) = CF_CTX_CALL_DATA(cf); \
DEBUGASSERT((save).data == NULL || (save).depth > 0); \
DEBUGASSERT(!(save).data || (save).depth > 0); \
CF_CTX_CALL_DATA(cf).depth++; \
CF_CTX_CALL_DATA(cf).data = (struct Curl_easy *)CURL_UNCONST(data); \
} while(0)
@@ -672,7 +667,7 @@ struct cf_call_data {
#define CF_DATA_RESTORE(cf, save) \
do { \
DEBUGASSERT(CF_CTX_CALL_DATA(cf).depth == (save).depth + 1); \
DEBUGASSERT((save).data == NULL || (save).depth > 0); \
DEBUGASSERT(!(save).data || (save).depth > 0); \
CF_CTX_CALL_DATA(cf) = (save); \
} while(0)
+5 -5
View File
@@ -122,7 +122,7 @@ void Curl_cpool_init(struct cpool *cpool,
cpool->idata = idata;
cpool->share = share;
cpool->initialised = TRUE;
cpool->initialized = TRUE;
}
/* Return the "first" connection in the pool or NULL. */
@@ -230,7 +230,7 @@ static void cpool_discard_conn(struct cpool *cpool,
void Curl_cpool_destroy(struct cpool *cpool)
{
if(cpool && cpool->initialised && cpool->idata) {
if(cpool && cpool->initialized && cpool->idata) {
struct connectdata *conn;
struct Curl_sigpipe_ctx pipe_ctx;
@@ -305,9 +305,9 @@ static struct cpool_bundle *cpool_add_bundle(struct cpool *cpool,
return bundle;
}
static struct connectdata *
cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle,
const struct curltime *pnow)
static struct connectdata *cpool_bundle_get_oldest_idle(
struct cpool_bundle *bundle,
const struct curltime *pnow)
{
struct Curl_llist_node *curr;
timediff_t highscore = -1;
+1 -1
View File
@@ -56,7 +56,7 @@ struct cpool {
struct Curl_easy *idata; /* internal handle for maintenance */
struct Curl_share *share; /* != NULL if pool belongs to share */
BIT(locked);
BIT(initialised);
BIT(initialized);
};
/* Init the pool, pass multi only if pool is owned by it.
+201 -350
View File
@@ -23,51 +23,20 @@
***************************************************************************/
#include "curl_setup.h"
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h> /* <netinet/tcp.h> may need it */
#endif
#ifdef HAVE_SYS_UN_H
#include <sys/un.h> /* for sockaddr_un */
#endif
#ifdef HAVE_LINUX_TCP_H
#include <linux/tcp.h>
#elif defined(HAVE_NETINET_TCP_H)
#include <netinet/tcp.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef __VMS
#include <in.h>
#include <inet.h>
#endif
#include "urldata.h"
#include "curl_trc.h"
#include "strerror.h"
#include "cfilters.h"
#include "connect.h"
#include "cf-dns.h"
#include "cf-haproxy.h"
#include "cf-https-connect.h"
#include "cf-ip-happy.h"
#include "cf-socket.h"
#include "cf-setup.h"
#include "multiif.h"
#include "curlx/inet_ntop.h"
#include "curlx/strparse.h"
#include "vtls/vtls.h" /* for vtls cfilters */
#include "progress.h"
#include "conncache.h"
#include "multihandle.h"
#include "http_proxy.h"
#include "socks.h"
#include "select.h"
#include "curlx/strparse.h"
#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
@@ -210,59 +179,6 @@ bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
return FALSE;
}
/* retrieves ip address and port from a sockaddr structure. note it calls
curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, uint16_t *port)
{
struct sockaddr_in *si = NULL;
#ifdef USE_IPV6
struct sockaddr_in6 *si6 = NULL;
#endif
#ifdef USE_UNIX_SOCKETS
struct sockaddr_un *su = NULL;
#else
(void)salen;
#endif
switch(sa->sa_family) {
case AF_INET:
si = (struct sockaddr_in *)(void *)sa;
if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) {
*port = ntohs(si->sin_port);
return TRUE;
}
break;
#ifdef USE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *)sa;
if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) {
*port = ntohs(si6->sin6_port);
return TRUE;
}
break;
#endif
#ifdef USE_UNIX_SOCKETS
case AF_UNIX:
if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
su = (struct sockaddr_un *)sa;
curl_msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
}
else
addr[0] = 0; /* socket with no name */
*port = 0;
return TRUE;
#endif
default:
break;
}
addr[0] = '\0';
*port = 0;
errno = SOCKEAFNOSUPPORT;
return FALSE;
}
/*
* Used to extract socket and connectdata struct for the most recent
* transfer on the given Curl_easy.
@@ -325,267 +241,22 @@ void Curl_conncontrol(struct connectdata *conn,
}
}
typedef enum {
CF_SETUP_INIT,
CF_SETUP_CNNCT_EYEBALLS,
CF_SETUP_CNNCT_SOCKS,
CF_SETUP_CNNCT_HTTP_PROXY,
CF_SETUP_CNNCT_HAPROXY,
CF_SETUP_CNNCT_SSL,
CF_SETUP_DONE
} cf_setup_state;
struct cf_setup_ctx {
cf_setup_state state;
int ssl_mode;
uint8_t transport;
};
static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(cf->connected) {
*done = TRUE;
return CURLE_OK;
}
/* connect current sub-chain */
connect_sub_chain:
if(cf->next && !cf->next->connected) {
result = Curl_conn_cf_connect(cf->next, data, done);
if(result || !*done)
return result;
}
if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
result = cf_ip_happy_insert_after(cf, data, ctx->transport);
if(result)
return result;
ctx->state = CF_SETUP_CNNCT_EYEBALLS;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
}
/* sub-chain connected, do we need to add more? */
#ifndef CURL_DISABLE_PROXY
if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
/* for the secondary socket (FTP), use the "connect to host"
* but ignore the "connect to port" (use the secondary port)
*/
const char *hostname =
cf->conn->bits.httpproxy ?
cf->conn->http_proxy.host.name :
cf->conn->bits.conn_to_host ?
cf->conn->conn_to_host.name :
cf->sockindex == SECONDARYSOCKET ?
cf->conn->secondaryhostname : cf->conn->host.name;
uint16_t port =
cf->conn->bits.httpproxy ? cf->conn->http_proxy.port :
cf->sockindex == SECONDARYSOCKET ? cf->conn->secondary_port :
cf->conn->bits.conn_to_port ? cf->conn->conn_to_port :
cf->conn->remote_port;
const char *user = cf->conn->socks_proxy.user;
const char *passwd = cf->conn->socks_proxy.passwd;
result = Curl_cf_socks_proxy_insert_after(
cf, data, hostname, port, cf->conn->ip_version,
cf->conn->socks_proxy.proxytype, user, passwd);
if(result)
return result;
ctx->state = CF_SETUP_CNNCT_SOCKS;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
}
if(ctx->state < CF_SETUP_CNNCT_HTTP_PROXY && cf->conn->bits.httpproxy) {
#ifdef USE_SSL
if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype) &&
!Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
result = Curl_cf_ssl_proxy_insert_after(cf, data);
if(result)
return result;
}
#endif /* USE_SSL */
#ifndef CURL_DISABLE_HTTP
if(cf->conn->bits.tunnel_proxy) {
result = Curl_cf_http_proxy_insert_after(cf, data);
if(result)
return result;
}
#endif /* !CURL_DISABLE_HTTP */
ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
}
#endif /* !CURL_DISABLE_PROXY */
if(ctx->state < CF_SETUP_CNNCT_HAPROXY) {
#ifndef CURL_DISABLE_PROXY
if(data->set.haproxyprotocol) {
if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
failf(data, "haproxy protocol not supported with SSL "
"encryption in place (QUIC?)");
return CURLE_UNSUPPORTED_PROTOCOL;
}
result = Curl_cf_haproxy_insert_after(cf, data);
if(result)
return result;
}
#endif /* !CURL_DISABLE_PROXY */
ctx->state = CF_SETUP_CNNCT_HAPROXY;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
}
if(ctx->state < CF_SETUP_CNNCT_SSL) {
#ifdef USE_SSL
if((ctx->ssl_mode == CURL_CF_SSL_ENABLE ||
(ctx->ssl_mode != CURL_CF_SSL_DISABLE &&
cf->conn->scheme->flags & PROTOPT_SSL)) && /* we want SSL */
!Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
result = Curl_cf_ssl_insert_after(cf, data);
if(result)
return result;
}
#endif /* USE_SSL */
ctx->state = CF_SETUP_CNNCT_SSL;
if(!cf->next || !cf->next->connected)
goto connect_sub_chain;
}
ctx->state = CF_SETUP_DONE;
cf->connected = TRUE;
*done = TRUE;
return CURLE_OK;
}
static void cf_setup_close(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURL_TRC_CF(data, cf, "close");
cf->connected = FALSE;
ctx->state = CF_SETUP_INIT;
if(cf->next) {
cf->next->cft->do_close(cf->next, data);
Curl_conn_cf_discard_chain(&cf->next, data);
}
}
static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURL_TRC_CF(data, cf, "destroy");
curlx_safefree(ctx);
}
struct Curl_cftype Curl_cft_setup = {
"SETUP",
CF_TYPE_SETUP,
CURL_LOG_LVL_NONE,
cf_setup_destroy,
cf_setup_connect,
cf_setup_close,
Curl_cf_def_shutdown,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
Curl_cf_def_cntrl,
Curl_cf_def_conn_is_alive,
Curl_cf_def_conn_keep_alive,
Curl_cf_def_query,
};
static CURLcode cf_setup_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf = NULL;
struct cf_setup_ctx *ctx;
CURLcode result = CURLE_OK;
(void)data;
ctx = curlx_calloc(1, sizeof(*ctx));
if(!ctx) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
ctx->state = CF_SETUP_INIT;
ctx->ssl_mode = ssl_mode;
ctx->transport = transport;
result = Curl_cf_create(&cf, &Curl_cft_setup, ctx);
if(result)
goto out;
ctx = NULL;
out:
*pcf = result ? NULL : cf;
if(ctx) {
curlx_free(ctx);
}
return result;
}
static CURLcode cf_setup_add(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
result = cf_setup_create(&cf, data, transport, ssl_mode);
if(result)
goto out;
Curl_conn_cf_add(data, conn, sockindex, cf);
out:
return result;
}
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
uint8_t transport,
int ssl_mode)
{
struct Curl_cfilter *cf;
CURLcode result;
DEBUGASSERT(data);
result = cf_setup_create(&cf, data, transport, ssl_mode);
if(result)
goto out;
Curl_conn_cf_insert_after(cf_at, cf);
out:
return result;
}
CURLcode Curl_conn_setup(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
struct Curl_dns_entry *dns,
int ssl_mode)
{
CURLcode result = CURLE_OK;
struct Curl_peer *peer = Curl_conn_get_first_peer(conn, sockindex);
uint8_t dns_queries;
DEBUGASSERT(data);
DEBUGASSERT(conn->scheme);
DEBUGASSERT(!conn->cfilter[sockindex]);
if(!peer)
return CURLE_FAILED_INIT;
#ifndef CURL_DISABLE_HTTP
if(!conn->cfilter[sockindex] &&
conn->scheme->protocol == CURLPROTO_HTTPS) {
@@ -598,8 +269,8 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
/* Still no cfilter set, apply default. */
if(!conn->cfilter[sockindex]) {
result = cf_setup_add(data, conn, sockindex,
conn->transport_wanted, ssl_mode);
result = Curl_cf_setup_add(data, conn, sockindex,
conn->transport_wanted, ssl_mode);
if(result)
goto out;
}
@@ -609,28 +280,179 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
if(sockindex == FIRSTSOCKET)
dns_queries |= CURL_DNSQ_HTTPS;
#endif
result = Curl_cf_dns_add(data, conn, sockindex, dns_queries,
conn->transport_wanted, dns);
result = Curl_cf_dns_add(data, conn, sockindex, peer, dns_queries,
conn->transport_wanted);
DEBUGASSERT(conn->cfilter[sockindex]);
out:
return result;
}
#ifdef USE_UNIX_SOCKETS
const char *Curl_conn_get_unix_path(struct connectdata *conn)
#ifdef CURLVERBOSE
static CURLcode conn_connect_trace(struct Curl_easy *data,
struct Curl_cfilter *cf)
{
const char *unix_path = conn->unix_domain_socket;
if(Curl_trc_is_verbose(data)) {
struct ip_quadruple ipquad;
bool is_ipv6;
CURLcode result;
#ifndef CURL_DISABLE_PROXY
if(!unix_path && conn->bits.proxy && conn->socks_proxy.host.name &&
!strncmp(UNIX_SOCKET_PREFIX "/",
conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
result = Curl_conn_cf_get_ip_info(cf, data, &is_ipv6, &ipquad);
if(result)
return result;
infof(data, "Established %sconnection to %s (%s port %u) from %s port %u ",
(cf->sockindex == SECONDARYSOCKET) ? "2nd " : "",
CURL_CONN_HOST_DISPNAME(data->conn),
ipquad.remote_ip, ipquad.remote_port,
ipquad.local_ip, ipquad.local_port);
}
return CURLE_OK;
}
#endif
return unix_path;
/**
* Update connection statistics
*/
static void conn_report_connect_stats(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
if(cf) {
struct curltime connected;
struct curltime appconnected;
memset(&connected, 0, sizeof(connected));
cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
if(connected.tv_sec || connected.tv_usec)
Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
memset(&appconnected, 0, sizeof(appconnected));
cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
if(appconnected.tv_sec || appconnected.tv_usec)
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
}
}
CURLcode Curl_conn_connect(struct Curl_easy *data,
int sockindex,
bool blocking,
bool *done)
{
#define CF_CONN_NUM_POLLS_ON_STACK 5
struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
struct easy_pollset ps;
struct curl_pollfds cpfds;
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
if(!CONN_SOCK_IDX_VALID(sockindex))
return CURLE_BAD_FUNCTION_ARGUMENT;
if(data->conn->scheme->flags & PROTOPT_NONETWORK) {
*done = TRUE;
return CURLE_OK;
}
cf = data->conn->cfilter[sockindex];
if(!cf) {
*done = FALSE;
return CURLE_FAILED_INIT;
}
*done = (bool)cf->connected;
if(*done)
return CURLE_OK;
Curl_pollset_init(&ps);
Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
while(!*done) {
if(Curl_conn_needs_flush(data, sockindex)) {
DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
result = Curl_conn_flush(data, sockindex);
if(result && (result != CURLE_AGAIN))
goto out;
}
result = cf->cft->do_connect(cf, data, done);
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d",
blocking, (int)result, *done);
if(!result && *done) {
/* A final sanity check on connection security */
if((data->state.origin->scheme->flags & PROTOPT_SSL) &&
(sockindex == FIRSTSOCKET) &&
!Curl_conn_is_ssl(data->conn, FIRSTSOCKET)) {
DEBUGASSERT(0);
failf(data, "transfer requires SSL, but not connected via SSL");
result = CURLE_FAILED_INIT;
goto out;
}
/* Now that the complete filter chain is connected, let all filters
* persist information at the connection. E.g. cf-socket sets the
* socket and ip related information. */
Curl_conn_cntrl_update_info(data, data->conn);
conn_report_connect_stats(cf, data);
data->conn->keepalive = *Curl_pgrs_now(data);
VERBOSE(result = conn_connect_trace(data, cf));
VERBOSE(Curl_conn_trc_filters(data, sockindex, "connected"));
Curl_conn_remove_setup_filters(data, sockindex);
VERBOSE(Curl_conn_trc_filters(data, sockindex, "reduced to"));
goto out;
}
else if(result) {
CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d",
(int)result);
VERBOSE(Curl_conn_trc_filters(data, sockindex, "failed to connect"));
conn_report_connect_stats(cf, data);
goto out;
}
if(!blocking)
goto out;
else {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft_ms(data);
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
int rc;
if(timeout_ms < 0) {
/* no need to continue if time already is up */
failf(data, "connect timeout");
result = CURLE_OPERATION_TIMEDOUT;
goto out;
}
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
Curl_pollset_reset(&ps);
Curl_pollfds_reset(&cpfds);
/* In general, we want to send after connect, wait on that. */
if(sockfd != CURL_SOCKET_BAD)
result = Curl_pollset_set_out_only(data, &ps, sockfd);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, &ps);
if(result)
goto out;
result = Curl_pollfds_add_ps(&cpfds, &ps);
if(result)
goto out;
rc = Curl_poll(cpfds.pfds, cpfds.n,
CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10)));
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d",
rc);
if(rc < 0) {
result = CURLE_COULDNT_CONNECT;
goto out;
}
/* continue iterating */
}
}
out:
Curl_pollset_cleanup(&ps);
Curl_pollfds_cleanup(&cpfds);
return result;
}
#endif /* USE_UNIX_SOCKETS */
void Curl_conn_set_multiplex(struct connectdata *conn)
{
@@ -641,3 +463,32 @@ void Curl_conn_set_multiplex(struct connectdata *conn)
}
}
}
struct Curl_peer *Curl_conn_get_origin(struct connectdata *conn,
int sockindex)
{
return (sockindex == SECONDARYSOCKET) ?
conn->origin2 : conn->origin;
}
struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
int sockindex)
{
return (sockindex == SECONDARYSOCKET) ?
(conn->via_peer2 ? conn->via_peer2 : conn->origin2) :
(conn->via_peer ? conn->via_peer : conn->origin);
}
struct Curl_peer *Curl_conn_get_first_peer(struct connectdata *conn,
int sockindex)
{
#ifndef CURL_DISABLE_PROXY
if(conn->socks_proxy.peer)
return conn->socks_proxy.peer;
if(conn->http_proxy.peer)
return conn->http_proxy.peer;
#endif
return (sockindex == SECONDARYSOCKET) ?
(conn->via_peer2 ? conn->via_peer2 : conn->origin2) :
(conn->via_peer ? conn->via_peer : conn->origin);
}
+31 -27
View File
@@ -28,8 +28,7 @@
#include "hostip.h"
#include "curlx/timeval.h"
struct Curl_dns_entry;
struct ip_quadruple;
struct Curl_peer;
struct Curl_str;
enum alpnid Curl_alpn2alpnid(const unsigned char *name, size_t len);
@@ -71,9 +70,6 @@ bool Curl_shutdown_started(struct Curl_easy *data, int sockindex);
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
struct connectdata **connp);
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, uint16_t *port);
/*
* Curl_conncontrol() marks the end of a connection/stream. The 'ctrl'
* argument specifies if it is the end of a connection or a stream.
@@ -86,9 +82,9 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
* when the connection will close.
*/
#define CONNCTRL_KEEP 0 /* undo a marked closure */
#define CONNCTRL_KEEP 0 /* undo a marked closure */
#define CONNCTRL_CONNECTION 1
#define CONNCTRL_STREAM 2
#define CONNCTRL_STREAM 2
void Curl_conncontrol(struct connectdata *conn,
int ctrl
@@ -99,42 +95,50 @@ void Curl_conncontrol(struct connectdata *conn,
#if defined(DEBUGBUILD) && defined(CURLVERBOSE)
#define streamclose(x, y) Curl_conncontrol(x, CONNCTRL_STREAM, y)
#define connclose(x, y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y)
#define connkeep(x, y) Curl_conncontrol(x, CONNCTRL_KEEP, y)
#define connclose(x, y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y)
#define connkeep(x, y) Curl_conncontrol(x, CONNCTRL_KEEP, y)
#else /* !DEBUGBUILD || !CURLVERBOSE */
#define streamclose(x, y) Curl_conncontrol(x, CONNCTRL_STREAM)
#define connclose(x, y) Curl_conncontrol(x, CONNCTRL_CONNECTION)
#define connkeep(x, y) Curl_conncontrol(x, CONNCTRL_KEEP)
#define connclose(x, y) Curl_conncontrol(x, CONNCTRL_CONNECTION)
#define connkeep(x, y) Curl_conncontrol(x, CONNCTRL_KEEP)
#endif
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
uint8_t transport,
int ssl_mode);
/**
* Setup the cfilters at `sockindex` in connection `conn`.
* If no filter chain is installed yet, inspects the configuration
* in `data` and `conn? to install a suitable filter chain.
* in `data` and `conn` to install a suitable filter chain.
*/
CURLcode Curl_conn_setup(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
struct Curl_dns_entry *dns,
int ssl_mode);
/**
* Bring the filter chain at `sockindex` for connection `data->conn` into
* connected state. Which will set `*done` to TRUE.
* This can be called on an already connected chain with no side effects.
* When not `blocking`, calls may return without error and `*done != TRUE`,
* while the individual filters negotiated the connection.
*/
CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex,
bool blocking, bool *done);
/* Set conn to allow multiplexing. */
void Curl_conn_set_multiplex(struct connectdata *conn);
#ifdef USE_UNIX_SOCKETS
#ifndef CURL_DISABLE_PROXY
#define UNIX_SOCKET_PREFIX "localhost"
#endif
const char *Curl_conn_get_unix_path(struct connectdata *conn);
#else
#define Curl_conn_get_unix_path(c) NULL
#endif
/* Get the origin peer at sockindex. */
struct Curl_peer *Curl_conn_get_origin(struct connectdata *conn,
int sockindex);
extern struct Curl_cftype Curl_cft_setup;
/* Get the peer the connection actually connects to at sockindex.
* Often the same as "origin", but can be redirected via "connect-to"
* or "alt-svc". May tunnel through proxies. */
struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
int sockindex);
/* Get the peer curl connects its socket to.
* Can be origin, "connect-to" or the first proxy. */
struct Curl_peer *Curl_conn_get_first_peer(struct connectdata *conn,
int sockindex);
#endif /* HEADER_CURL_CONNECT_H */
+74 -42
View File
@@ -46,6 +46,7 @@
#include <zstd.h>
#endif
#include "connect.h"
#include "sendf.h"
#include "curl_trc.h"
#include "content_encoding.h"
@@ -88,7 +89,7 @@ static voidpf zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
{
(void)opaque;
/* not a typo, keep it curlx_calloc() */
return (voidpf)curlx_calloc(items, size);
return curlx_calloc(items, size);
}
static void zfree_cb(voidpf opaque, voidpf ptr)
@@ -100,8 +101,7 @@ static void zfree_cb(voidpf opaque, voidpf ptr)
static CURLcode process_zlib_error(struct Curl_easy *data, z_stream *z)
{
if(z->msg)
failf(data, "Error while processing content unencoding: %s",
z->msg);
failf(data, "Error while processing content unencoding: %s", z->msg);
else
failf(data, "Error while processing content unencoding: "
"Unknown failure within decompression software.");
@@ -154,6 +154,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
z_const Bytef *orig_in = z->next_in;
bool done = FALSE;
CURLcode result = CURLE_OK; /* Curl_client_write status */
int i = 0;
/* Check state. */
if(zp->zlib_init != ZLIB_INIT &&
@@ -164,9 +165,18 @@ static CURLcode inflate_stream(struct Curl_easy *data,
/* because the buffer size is fixed, iteratively decompress and transfer to
the client via next_write function. */
while(!done) {
int status; /* zlib status */
int status; /* zlib status */
done = TRUE;
if(++i > (1024 * 1024 / DECOMPRESS_BUFFER_SIZE)) {
/* check every MB of output if we are not exceeding time limit */
i = 0;
if(Curl_timeleft_ms(data) < 0) {
failf(data, "Operation timed out while decoding payload");
return exit_zlib(data, z, &zp->zlib_init, CURLE_OPERATION_TIMEDOUT);
}
}
/* (re)set buffer for decompressed output for every iteration */
z->next_out = (Bytef *)zp->buffer;
z->avail_out = DECOMPRESS_BUFFER_SIZE;
@@ -176,7 +186,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
/* Flush output data if some. */
if(z->avail_out != DECOMPRESS_BUFFER_SIZE) {
if(status == Z_OK || status == Z_STREAM_END) {
zp->zlib_init = started; /* Data started. */
zp->zlib_init = started; /* Data started. */
result = Curl_cwriter_write(data, writer->next, type, zp->buffer,
DECOMPRESS_BUFFER_SIZE - z->avail_out);
if(result) {
@@ -210,7 +220,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
done = FALSE;
break;
}
zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */
zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */
}
result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
break;
@@ -224,7 +234,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
again. If we are in a state that would wrongly allow restart in raw mode
at the next call, assume output has already started. */
if(nread && zp->zlib_init == ZLIB_INIT)
zp->zlib_init = started; /* Cannot restart anymore. */
zp->zlib_init = started; /* Cannot restart anymore. */
return result;
}
@@ -234,7 +244,7 @@ static CURLcode deflate_do_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *)writer;
z_stream *z = &zp->z; /* zlib state structure */
z_stream *z = &zp->z; /* zlib state structure */
/* Initialize zlib */
z->zalloc = (alloc_func)zalloc_cb;
@@ -251,7 +261,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data,
const char *buf, size_t nbytes)
{
struct zlib_writer *zp = (struct zlib_writer *)writer;
z_stream *z = &zp->z; /* zlib state structure */
z_stream *z = &zp->z; /* zlib state structure */
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
@@ -271,7 +281,7 @@ static void deflate_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *)writer;
z_stream *z = &zp->z; /* zlib state structure */
z_stream *z = &zp->z; /* zlib state structure */
exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
}
@@ -293,7 +303,7 @@ static CURLcode gzip_do_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *)writer;
z_stream *z = &zp->z; /* zlib state structure */
z_stream *z = &zp->z; /* zlib state structure */
/* Initialize zlib */
z->zalloc = (alloc_func)zalloc_cb;
@@ -311,7 +321,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
const char *buf, size_t nbytes)
{
struct zlib_writer *zp = (struct zlib_writer *)writer;
z_stream *z = &zp->z; /* zlib state structure */
z_stream *z = &zp->z; /* zlib state structure */
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
@@ -332,7 +342,7 @@ static void gzip_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *)writer;
z_stream *z = &zp->z; /* zlib state structure */
z_stream *z = &zp->z; /* zlib state structure */
exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
}
@@ -353,7 +363,7 @@ static const struct Curl_cwtype gzip_encoding = {
struct brotli_writer {
struct Curl_cwriter super;
char buffer[DECOMPRESS_BUFFER_SIZE];
BrotliDecoderState *br; /* State structure for brotli. */
BrotliDecoderState *br; /* State structure for brotli. */
};
static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
@@ -412,15 +422,26 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
size_t dstleft;
CURLcode result = CURLE_OK;
BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
int i = 0;
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!bp->br)
return CURLE_WRITE_ERROR; /* Stream already ended. */
return CURLE_WRITE_ERROR; /* Stream already ended. */
while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) &&
result == CURLE_OK) {
if(++i > (1024 * 1024 / DECOMPRESS_BUFFER_SIZE)) {
/* check every MB of output if we are not exceeding time limit */
i = 0;
if(Curl_timeleft_ms(data) < 0) {
failf(data, "Operation timed out while decoding payload");
return CURLE_OPERATION_TIMEDOUT;
}
}
dst = (uint8_t *)bp->buffer;
dstleft = DECOMPRESS_BUFFER_SIZE;
r = BrotliDecoderDecompressStream(bp->br,
@@ -473,7 +494,7 @@ static const struct Curl_cwtype brotli_encoding = {
/* Zstd writer. */
struct zstd_writer {
struct Curl_cwriter super;
ZSTD_DStream *zds; /* State structure for zstd. */
ZSTD_DStream *zds; /* State structure for zstd. */
char buffer[DECOMPRESS_BUFFER_SIZE];
};
@@ -520,6 +541,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
ZSTD_inBuffer in;
ZSTD_outBuffer out;
size_t errorCode;
int i = 0;
if(!(type & CLIENTWRITE_BODY) || !nbytes)
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
@@ -529,6 +551,15 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
in.size = nbytes;
for(;;) {
if(++i > (1024 * 1024 / DECOMPRESS_BUFFER_SIZE)) {
/* check every MB of output if we are not exceeding time limit */
i = 0;
if(Curl_timeleft_ms(data) < 0) {
failf(data, "Operation timed out while decoding payload");
return CURLE_OPERATION_TIMEDOUT;
}
}
out.pos = 0;
out.dst = zp->buffer;
out.size = DECOMPRESS_BUFFER_SIZE;
@@ -750,24 +781,14 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
return CURLE_OK;
}
if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) {
failf(data, "Reject response due to more than %d content encodings",
MAX_ENCODE_STACK);
if(Curl_cwriter_count(data, phase) >= MAX_ENCODE_STACK) {
failf(data, "Reject response exceeding limit of %d %s encodings",
MAX_ENCODE_STACK,
is_transfer ? "transfer" : "content");
return CURLE_BAD_CONTENT_ENCODING;
}
cwt = find_unencode_writer(name, namelen, phase);
if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) {
/* A 'chunked' transfer encoding has already been added.
* Ignore duplicates. See #13451.
* Also RFC 9112, ch. 6.1:
* "A sender MUST NOT apply the chunked transfer coding more than
* once to a message body."
*/
CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder");
return CURLE_OK;
}
if(is_transfer && !is_chunked &&
Curl_cwriter_get_by_name(data, "chunked")) {
/* RFC 9112, ch. 6.1:
@@ -782,20 +803,31 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
"Transfer-Encoding");
return CURLE_BAD_CONTENT_ENCODING;
}
if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) {
/* A 'chunked' transfer encoding has already been added.
* Ignore duplicates. See #13451.
* Also RFC 9112, ch. 6.1:
* "A sender MUST NOT apply the chunked transfer coding more than
* once to a message body."
*/
CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder");
}
else {
if(!cwt)
cwt = &error_writer; /* Defer error at use. */
if(!cwt)
cwt = &error_writer; /* Defer error at use. */
result = Curl_cwriter_create(&writer, data, cwt, phase);
CURL_TRC_WRITE(data, "added %s decoder %s -> %d",
is_transfer ? "transfer" : "content", cwt->name,
(int)result);
if(result)
return result;
result = Curl_cwriter_create(&writer, data, cwt, phase);
CURL_TRC_WRITE(data, "added %s decoder %s -> %d",
is_transfer ? "transfer" : "content", cwt->name, result);
if(result)
return result;
result = Curl_cwriter_add(data, writer);
if(result) {
Curl_cwriter_free(data, writer);
return result;
result = Curl_cwriter_add(data, writer);
if(result) {
Curl_cwriter_free(data, writer);
return result;
}
}
if(is_chunked)
has_chunked = TRUE;
+250 -210
View File
@@ -29,6 +29,7 @@
#include "cookie.h"
#include "psl.h"
#include "curl_trc.h"
#include "transfer.h"
#include "slist.h"
#include "curl_share.h"
#include "strcase.h"
@@ -71,7 +72,7 @@ static void freecookie(struct Cookie *co, bool maintoo)
}
static bool cookie_tailmatch(const char *cookie_domain,
size_t cookie_domain_len,
const size_t cookie_domain_len,
const char *hostname)
{
size_t hostname_len = strlen(hostname);
@@ -250,19 +251,11 @@ static char *sanitize_cookie_path(const char *cookie_path, size_t len)
/*
* strstore
*
* A thin wrapper around strdup which ensures that any memory allocated at
* *str will be freed before the string allocated by strdup is stored there.
* The intended usecase is repeated assignments to the same variable during
* parsing in a last-wins scenario. The caller is responsible for checking
* for OOM errors.
* A thin wrapper around curlx_memdup0().
*/
static CURLcode strstore(char **str, const char *newstr, size_t len)
{
DEBUGASSERT(str);
if(!len) {
len++;
newstr = "";
}
*str = curlx_memdup0(newstr, len);
if(!*str)
return CURLE_OUT_OF_MEMORY;
@@ -354,9 +347,9 @@ static bool bad_domain(const char *domain, size_t len)
static bool invalid_octets(const char *ptr, size_t len)
{
const unsigned char *p = (const unsigned char *)ptr;
/* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */
/* Reject all bytes \x01 - \x1f + \x7f */
while(len && *p) {
if(((*p != 9) && (*p < 0x20)) || (*p == 0x7f))
if((*p < 0x20) || (*p == 0x7f))
return TRUE;
p++;
len--;
@@ -377,7 +370,7 @@ static bool invalid_octets(const char *ptr, size_t len)
#define COOKIE_PIECES 4 /* the list above */
static CURLcode storecookie(struct Cookie *co, struct Curl_str *cp,
static CURLcode storecookie(struct Cookie *co, const struct Curl_str *cp,
const char *path, const char *domain)
{
CURLcode result;
@@ -421,19 +414,189 @@ static CURLcode storecookie(struct Cookie *co, struct Curl_str *cp,
return result;
}
/* this function return errors on OOM etc, not on plain cookie format
problems */
static CURLcode parse_cookie_header(
struct Curl_easy *data,
struct Cookie *co,
struct CookieInfo *ci,
bool *okay, /* if the cookie was fine */
const char *ptr,
const char *domain, /* default domain */
const char *path, /* full path used when this cookie is
set, used to get default path for
the cookie unless set */
bool secure) /* TRUE if connection is over secure origin */
/*
* Parse the first name/value pair of the cookie header, which is the actual
* cookie name and value.
*/
static bool parse_first_pair(struct Curl_easy *data, struct Cookie *co,
struct Curl_str *cookie,
struct Curl_str *name,
struct Curl_str *val,
bool sep)
{
/* The first name/value pair is the actual cookie name */
if(!sep || !curlx_strlen(name)) {
infof(data, "invalid cookie, dropped");
return FALSE;
}
/*
* Check for too long individual name or contents. Chrome and Firefox
* support 4095 or 4096 bytes combo
*/
if((curlx_strlen(name) + curlx_strlen(val)) > MAX_NAME) {
infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
curlx_strlen(name), curlx_strlen(val));
return FALSE;
}
/* Check if we have a reserved prefix set. */
if(!strncmp("__Secure-", curlx_str(name), 9))
co->prefix_secure = TRUE;
else if(!strncmp("__Host-", curlx_str(name), 7))
co->prefix_host = TRUE;
cookie[COOKIE_NAME] = *name;
cookie[COOKIE_VALUE] = *val;
return TRUE;
}
static bool parse_flag(struct Curl_easy *data, struct Cookie *co,
const struct CookieInfo *ci,
struct Curl_str *name, bool secure)
{
/*
* secure cookies are only allowed to be set when the connection is
* using a secure protocol, or when the cookie is being set by
* reading from file
*/
if(curlx_str_casecompare(name, "secure")) {
if(secure || !ci->running)
co->secure = TRUE;
else {
infof(data, "skipped cookie because not 'secure'");
return FALSE;
}
}
else if(curlx_str_casecompare(name, "httponly"))
co->httponly = TRUE;
return TRUE;
}
static bool parse_domain(struct Curl_easy *data, struct Cookie *co,
struct Curl_str *cookie_domain,
struct Curl_str *val,
const char **domainp)
{
bool is_ip;
const char *domain = *domainp;
const char *v = curlx_str(val);
/*
* Now, we make sure that our host is within the given domain, or
* the given domain is not valid and thus cannot be set.
*/
if('.' == *v)
curlx_str_nudge(val, 1);
#ifndef USE_LIBPSL
/*
* Without PSL we do not know when the incoming cookie is set on a
* TLD or otherwise "protected" suffix. To reduce risk, we require a
* dot OR the exact hostname being "localhost".
*/
if(bad_domain(curlx_str(val), curlx_strlen(val))) {
*domainp = ":";
domain = ":";
}
#endif
is_ip = Curl_host_is_ipnum(domain ? domain : curlx_str(val));
if(!domain ||
(is_ip &&
!strncmp(curlx_str(val), domain, curlx_strlen(val)) &&
(curlx_strlen(val) == strlen(domain))) ||
(!is_ip && cookie_tailmatch(curlx_str(val),
curlx_strlen(val), domain))) {
*cookie_domain = *val;
if(!is_ip)
co->tailmatch = TRUE; /* we always do that if the domain name was
given */
}
else {
/*
* We did not get a tailmatch and then the attempted set domain is
* not a domain to which the current host belongs. Mark as bad.
*/
infof(data, "skipped cookie with bad tailmatch domain: %s",
curlx_str(val));
return FALSE;
}
return TRUE;
}
static void parse_maxage(struct Cookie *co, struct Curl_str *val,
time_t *nowp)
{
int rc;
const char *maxage = curlx_str(val);
if(*maxage == '\"')
maxage++;
rc = curlx_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
if(!*nowp)
*nowp = time(NULL);
switch(rc) {
case STRE_OVERFLOW:
/* overflow, used max value */
co->expires = CURL_OFF_T_MAX;
break;
default:
/* negative or otherwise bad, expire */
co->expires = 1;
break;
case STRE_OK:
if(!co->expires)
co->expires = 1; /* expire now */
else if(CURL_OFF_T_MAX - *nowp < co->expires)
/* would overflow */
co->expires = CURL_OFF_T_MAX;
else
co->expires += *nowp;
break;
}
cap_expires(*nowp, co);
}
static void parse_expires(struct Cookie *co, struct Curl_str *val,
time_t *nowp)
{
/*
* Let max-age have priority.
*
* If the date cannot get parsed for whatever reason, the cookie
* will be treated as a session cookie
*/
if(!co->expires && (curlx_strlen(val) < MAX_DATE_LENGTH)) {
char dbuf[MAX_DATE_LENGTH + 1];
time_t date = 0;
memcpy(dbuf, curlx_str(val), curlx_strlen(val));
dbuf[curlx_strlen(val)] = 0;
if(!Curl_getdate_capped(dbuf, &date)) {
if(!date)
date++;
co->expires = (curl_off_t)date;
}
else
co->expires = 0;
if(!*nowp)
*nowp = time(NULL);
cap_expires(*nowp, co);
}
}
/* this function returns errors on OOM etc, not for cookie format problems */
static CURLcode
parse_cookie_header(struct Curl_easy *data,
struct Cookie *co,
const struct CookieInfo *ci,
bool *okay, /* if the cookie was fine */
const char *ptr, /* the header */
const char *domain, /* default domain */
/* full path used when this cookie is set */
const char *path,
bool secure_origin)
{
/* This line was read off an HTTP-header */
time_t now = 0;
@@ -449,22 +612,25 @@ static CURLcode parse_cookie_header(
memset(cookie, 0, sizeof(cookie));
do {
struct Curl_str name;
struct Curl_str val;
/* we have a <name>=<value> pair or a stand-alone word here */
if(!curlx_str_cspn(&ptr, &name, ";\t\r\n=")) {
struct Curl_str val;
bool sep = FALSE;
curlx_str_trimblanks(&name);
if(invalid_octets(curlx_str(&name), curlx_strlen(&name))) {
infof(data, "invalid octets in name, cookie dropped");
return CURLE_OK;
}
if(!curlx_str_single(&ptr, '=')) {
sep = TRUE; /* a '=' was used */
if(!curlx_str_cspn(&ptr, &val, ";\r\n"))
curlx_str_trimblanks(&val);
/* Reject cookies with a TAB inside the value */
if(curlx_strlen(&val) &&
memchr(curlx_str(&val), '\t', curlx_strlen(&val))) {
infof(data, "cookie contains TAB, dropping");
if(invalid_octets(curlx_str(&val), curlx_strlen(&val))) {
infof(data, "invalid octets in value, cookie dropped");
return CURLE_OK;
}
}
@@ -472,167 +638,23 @@ static CURLcode parse_cookie_header(
curlx_str_init(&val);
if(!curlx_strlen(&cookie[COOKIE_NAME])) {
/* The first name/value pair is the actual cookie name */
if(!sep ||
/* Bad name/value pair. */
invalid_octets(curlx_str(&name), curlx_strlen(&name)) ||
invalid_octets(curlx_str(&val), curlx_strlen(&val)) ||
!curlx_strlen(&name)) {
infof(data, "invalid octets in name/value, cookie dropped");
if(!parse_first_pair(data, co, cookie, &name, &val, sep))
return CURLE_OK;
}
/*
* Check for too long individual name or contents, or too long
* combination of name + contents. Chrome and Firefox support 4095 or
* 4096 bytes combo
*/
if(curlx_strlen(&name) >= (MAX_NAME - 1) ||
curlx_strlen(&val) >= (MAX_NAME - 1) ||
((curlx_strlen(&name) + curlx_strlen(&val)) > MAX_NAME)) {
infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
curlx_strlen(&name), curlx_strlen(&val));
return CURLE_OK;
}
/* Check if we have a reserved prefix set. */
if(!strncmp("__Secure-", curlx_str(&name), 9))
co->prefix_secure = TRUE;
else if(!strncmp("__Host-", curlx_str(&name), 7))
co->prefix_host = TRUE;
cookie[COOKIE_NAME] = name;
cookie[COOKIE_VALUE] = val;
}
else if(!sep) {
/*
* this is a "<name>" with no content
*/
/*
* secure cookies are only allowed to be set when the connection is
* using a secure protocol, or when the cookie is being set by
* reading from file
*/
if(curlx_str_casecompare(&name, "secure")) {
if(secure || !ci->running)
co->secure = TRUE;
else {
infof(data, "skipped cookie because not 'secure'");
return CURLE_OK;
}
}
else if(curlx_str_casecompare(&name, "httponly"))
co->httponly = TRUE;
}
else if(curlx_str_casecompare(&name, "path")) {
cookie[COOKIE_PATH] = val;
}
else if(curlx_str_casecompare(&name, "domain") && curlx_strlen(&val)) {
bool is_ip;
const char *v = curlx_str(&val);
/*
* Now, we make sure that our host is within the given domain, or
* the given domain is not valid and thus cannot be set.
*/
if('.' == *v)
curlx_str_nudge(&val, 1);
#ifndef USE_LIBPSL
/*
* Without PSL we do not know when the incoming cookie is set on a
* TLD or otherwise "protected" suffix. To reduce risk, we require a
* dot OR the exact hostname being "localhost".
*/
if(bad_domain(curlx_str(&val), curlx_strlen(&val)))
domain = ":";
#endif
is_ip = Curl_host_is_ipnum(domain ? domain : curlx_str(&val));
if(!domain ||
(is_ip &&
!strncmp(curlx_str(&val), domain, curlx_strlen(&val)) &&
(curlx_strlen(&val) == strlen(domain))) ||
(!is_ip && cookie_tailmatch(curlx_str(&val),
curlx_strlen(&val), domain))) {
cookie[COOKIE_DOMAIN] = val;
if(!is_ip)
co->tailmatch = TRUE; /* we always do that if the domain name was
given */
}
else {
/*
* We did not get a tailmatch and then the attempted set domain is
* not a domain to which the current host belongs. Mark as bad.
*/
infof(data, "skipped cookie with bad tailmatch domain: %s",
curlx_str(&val));
if(!parse_flag(data, co, ci, &name, secure_origin))
return CURLE_OK;
}
}
else if(curlx_str_casecompare(&name, "max-age") && curlx_strlen(&val)) {
/*
* Defined in RFC2109:
*
* Optional. The Max-Age attribute defines the lifetime of the
* cookie, in seconds. The delta-seconds value is a decimal non-
* negative integer. After delta-seconds seconds elapse, the
* client should discard the cookie. A value of zero means the
* cookie should be discarded immediately.
*/
int rc;
const char *maxage = curlx_str(&val);
if(*maxage == '\"')
maxage++;
rc = curlx_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
if(!now)
now = time(NULL);
switch(rc) {
case STRE_OVERFLOW:
/* overflow, used max value */
co->expires = CURL_OFF_T_MAX;
break;
default:
/* negative or otherwise bad, expire */
co->expires = 1;
break;
case STRE_OK:
if(!co->expires)
co->expires = 1; /* expire now */
else if(CURL_OFF_T_MAX - now < co->expires)
/* would overflow */
co->expires = CURL_OFF_T_MAX;
else
co->expires += now;
break;
}
cap_expires(now, co);
}
else if(curlx_str_casecompare(&name, "expires") && curlx_strlen(&val) &&
!co->expires && (curlx_strlen(&val) < MAX_DATE_LENGTH)) {
/*
* Let max-age have priority.
*
* If the date cannot get parsed for whatever reason, the cookie
* will be treated as a session cookie
*/
char dbuf[MAX_DATE_LENGTH + 1];
time_t date = 0;
memcpy(dbuf, curlx_str(&val), curlx_strlen(&val));
dbuf[curlx_strlen(&val)] = 0;
if(!Curl_getdate_capped(dbuf, &date)) {
if(!date)
date++;
co->expires = (curl_off_t)date;
}
else
co->expires = 0;
if(!now)
now = time(NULL);
cap_expires(now, co);
else if(curlx_str_casecompare(&name, "path"))
cookie[COOKIE_PATH] = val;
else if(curlx_str_casecompare(&name, "domain") && curlx_strlen(&val)) {
if(!parse_domain(data, co, &cookie[COOKIE_DOMAIN], &val, &domain))
return CURLE_OK;
}
else if(curlx_str_casecompare(&name, "max-age") && curlx_strlen(&val))
parse_maxage(co, &val, &now);
else if(curlx_str_casecompare(&name, "expires") && curlx_strlen(&val))
parse_expires(co, &val, &now);
}
} while(!curlx_str_single(&ptr, ';'));
@@ -646,11 +668,10 @@ static CURLcode parse_cookie_header(
}
static CURLcode parse_netscape(struct Cookie *co,
struct CookieInfo *ci,
const struct CookieInfo *ci,
bool *okay,
const char *lineptr,
bool secure) /* TRUE if connection is over
secure origin */
bool secure_origin)
{
/*
* This line is NOT an HTTP header style line, we do offer support for
@@ -667,7 +688,7 @@ static CURLcode parse_netscape(struct Cookie *co,
* Firefox's cookie files, they are prefixed #HttpOnly_ and the rest
* remains as usual, so we skip 10 characters of the line.
*/
if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
if(!strncmp(lineptr, "#HttpOnly_", 10)) {
lineptr += 10;
co->httponly = TRUE;
}
@@ -723,7 +744,7 @@ static CURLcode parse_netscape(struct Cookie *co,
case 3:
co->secure = FALSE;
if(curl_strnequal(ptr, "TRUE", len)) {
if(secure || ci->running)
if(secure_origin || ci->running)
co->secure = TRUE;
else
return CURLE_OK;
@@ -738,10 +759,12 @@ static CURLcode parse_netscape(struct Cookie *co,
if(!co->name)
return CURLE_OUT_OF_MEMORY;
else {
/* For Netscape file format cookies we check prefix on the name */
if(curl_strnequal("__Secure-", co->name, 9))
/* For Netscape file format cookies we check prefix on the name.
These prefixes are matched case sensitively, same as on the
header path and as the 6265bis document specifies. */
if(!strncmp("__Secure-", co->name, 9))
co->prefix_secure = TRUE;
else if(curl_strnequal("__Host-", co->name, 7))
else if(!strncmp("__Host-", co->name, 7))
co->prefix_host = TRUE;
}
break;
@@ -765,12 +788,20 @@ static CURLcode parse_netscape(struct Cookie *co,
/* we did not find the sufficient number of fields */
return CURLE_OK;
/* Reject control octets in the name or value, matching the filtering done
for cookies set over HTTP. A cookie loaded from a file is later sent in
request headers, so the same bytes that make a server reject a request
must not slip in through the file. */
if(invalid_octets(co->name, strlen(co->name)) ||
invalid_octets(co->value, strlen(co->value)))
return CURLE_OK;
*okay = TRUE;
return CURLE_OK;
}
static bool is_public_suffix(struct Curl_easy *data,
struct Cookie *co,
const struct Cookie *co,
const char *domain)
{
#ifdef USE_LIBPSL
@@ -787,12 +818,21 @@ static bool is_public_suffix(struct Curl_easy *data,
char lcookie[256];
size_t dlen = strlen(domain);
size_t clen = strlen(co->domain);
/* trim trailing dots */
if(dlen && (domain[dlen - 1] == '.'))
dlen--;
if(clen && (co->domain[clen - 1] == '.'))
clen--;
if((dlen < sizeof(lcase)) && (clen < sizeof(lcookie))) {
const psl_ctx_t *psl = Curl_psl_use(data);
if(psl) {
/* the PSL check requires lowercase domain name and pattern */
Curl_strntolower(lcase, domain, dlen + 1);
Curl_strntolower(lcookie, co->domain, clen + 1);
Curl_strntolower(lcase, domain, dlen);
lcase[dlen] = 0;
Curl_strntolower(lcookie, co->domain, clen);
lcookie[clen] = 0;
acceptable = psl_is_cookie_domain_acceptable(psl, lcase, lcookie);
Curl_psl_release(data);
}
@@ -819,7 +859,7 @@ static bool is_public_suffix(struct Curl_easy *data,
/* returns TRUE when replaced */
static bool replace_existing(struct Curl_easy *data,
struct Cookie *co,
struct CookieInfo *ci,
const struct CookieInfo *ci,
bool secure,
bool *replacep)
{
@@ -834,8 +874,10 @@ static bool replace_existing(struct Curl_easy *data,
bool matching_domains = FALSE;
if(clist->domain && co->domain) {
if(curl_strequal(clist->domain, co->domain))
/* The domains are identical */
if(cookie_tailmatch(clist->domain, strlen(clist->domain),
co->domain) ||
cookie_tailmatch(co->domain, strlen(co->domain), clist->domain))
/* The existing one is a tail of the new or vice versa */
matching_domains = TRUE;
}
else if(!clist->domain && !co->domain)
@@ -862,7 +904,7 @@ static bool replace_existing(struct Curl_easy *data,
else
cllen = strlen(clist->path);
if(curl_strnequal(clist->path, co->path, cllen)) {
if(!strncmp(clist->path, co->path, cllen)) {
infof(data, "cookie '%s' for domain '%s' dropped, would "
"overlay an existing cookie", co->name, co->domain);
return FALSE;
@@ -886,7 +928,7 @@ static bool replace_existing(struct Curl_easy *data,
/* the domains were identical */
if(clist->path && co->path &&
!curl_strequal(clist->path, co->path))
strcmp(clist->path, co->path))
replace_old = FALSE;
else if(!clist->path != !co->path)
replace_old = FALSE;
@@ -1152,7 +1194,7 @@ static CURLcode cookie_load(struct Curl_easy *data, const char *file,
curlx_fclose(handle);
}
data->state.cookie_engine = TRUE;
ci->running = TRUE; /* now, we are running */
ci->running = TRUE; /* now, we are running */
return result;
}
@@ -1237,9 +1279,9 @@ static int cookie_sort_ct(const void *p1, const void *p2)
return (c2->creationtime > c1->creationtime) ? 1 : -1;
}
bool Curl_secure_context(struct connectdata *conn, const char *host)
bool Curl_secure_context(struct Curl_easy *data, const char *host)
{
return conn->scheme->protocol & (CURLPROTO_HTTPS | CURLPROTO_WSS) ||
return Curl_xfer_is_secure(data) ||
curl_strequal("localhost", host) ||
!strcmp(host, "127.0.0.1") ||
!strcmp(host, "::1");
@@ -1249,15 +1291,13 @@ bool Curl_secure_context(struct connectdata *conn, const char *host)
* Curl_cookie_getlist
*
* For a given host and path, return a linked list of cookies that the client
* should send to the server if used now. The secure boolean informs the cookie
* if a secure connection is achieved or not.
* should send to the server if used now.
*
* It shall only return cookies that have not expired.
*
* 'okay' is TRUE when there is a list returned.
*/
CURLcode Curl_cookie_getlist(struct Curl_easy *data,
struct connectdata *conn,
bool *okay,
const char *host,
struct Curl_llist *list)
@@ -1266,7 +1306,7 @@ CURLcode Curl_cookie_getlist(struct Curl_easy *data,
const bool is_ip = Curl_host_is_ipnum(host);
const size_t myhash = cookiehash(host);
struct Curl_llist_node *n;
const bool secure = Curl_secure_context(conn, host);
const bool secure = Curl_secure_context(data, host);
struct CookieInfo *ci = data->cookies;
const char *path = data->state.up.path;
CURLcode result = CURLE_OK;
@@ -1561,7 +1601,7 @@ error:
return result;
}
static struct curl_slist *cookie_list(struct Curl_easy *data)
static struct curl_slist *cookie_list(const struct Curl_easy *data)
{
struct curl_slist *list = NULL;
struct curl_slist *beg;
+2 -2
View File
@@ -109,7 +109,7 @@ struct connectdata;
* are only used if the header boolean is TRUE.
*/
bool Curl_secure_context(struct connectdata *conn, const char *host);
bool Curl_secure_context(struct Curl_easy *data, const char *host);
CURLcode Curl_cookie_add(struct Curl_easy *data,
struct CookieInfo *ci,
bool httpheader,
@@ -118,7 +118,7 @@ CURLcode Curl_cookie_add(struct Curl_easy *data,
const char *domain,
const char *path,
bool secure) WARN_UNUSED_RESULT;
CURLcode Curl_cookie_getlist(struct Curl_easy *data, struct connectdata *conn,
CURLcode Curl_cookie_getlist(struct Curl_easy *data,
bool *okay, const char *host,
struct Curl_llist *list) WARN_UNUSED_RESULT;
void Curl_cookie_clearall(struct CookieInfo *ci);
+189
View File
@@ -0,0 +1,189 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "curl_setup.h"
#include <stddef.h> /* for offsetof() */
#include "creds.h"
#include "curl_trc.h"
#include "strcase.h"
#include "urldata.h"
CURLcode Curl_creds_create(const char *user,
const char *passwd,
const char *oauth_bearer,
const char *sasl_authzid,
const char *sasl_service,
uint8_t source,
struct Curl_creds **pcreds)
{
struct Curl_creds *creds = NULL;
size_t ulen = user ? strlen(user) : 0;
size_t plen = passwd ? strlen(passwd) : 0;
size_t olen = oauth_bearer ? strlen(oauth_bearer) : 0;
size_t salen = sasl_authzid ? strlen(sasl_authzid) : 0;
size_t sslen = sasl_service ? strlen(sasl_service) : 0;
char *s, *buf;
CURLcode result = CURLE_OK;
Curl_creds_unlink(pcreds);
/* Everything empty/NULL, this is the NULL credential */
if(!user && !passwd && !olen && !salen && !sslen)
goto out;
if((ulen > CURL_MAX_INPUT_LENGTH) ||
(plen > CURL_MAX_INPUT_LENGTH) ||
(olen > CURL_MAX_INPUT_LENGTH) ||
(salen > CURL_MAX_INPUT_LENGTH) ||
(sslen > CURL_MAX_INPUT_LENGTH)) {
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto out;
}
/* null-terminator for user already part of struct */
creds = curlx_calloc(1, sizeof(*creds) +
ulen + plen + 1 + olen + 1 + salen + 1 + sslen + 1);
if(!creds) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
creds->refcount = 1;
creds->source = source;
/* Some compilers try to be too smart about our dynamic struct size */
buf = ((char *)creds) + offsetof(struct Curl_creds, buf);
creds->user = s = buf;
if(ulen)
memcpy(s, user, ulen + 1);
creds->passwd = s = buf + ulen + 1;
if(plen)
memcpy(s, passwd, plen + 1);
creds->oauth_bearer = s = buf + ulen + 1 + plen + 1;
if(olen)
memcpy(s, oauth_bearer, olen + 1);
creds->sasl_authzid = s = buf + ulen + 1 + plen + 1 + olen + 1;
if(salen)
memcpy(s, sasl_authzid, salen + 1);
creds->sasl_service = s = buf + ulen + 1 + plen + 1 + olen + 1 + salen + 1;
if(sslen)
memcpy(s, sasl_service, sslen + 1);
out:
if(!result)
*pcreds = creds;
else
Curl_creds_unlink(&creds);
return result;
}
CURLcode Curl_creds_merge(const char *user,
const char *passwd,
struct Curl_creds *creds_in,
uint8_t source,
struct Curl_creds **pcreds_out)
{
struct Curl_creds *creds_out = NULL;
CURLcode result;
if(!creds_in) {
result = Curl_creds_create(user, passwd, NULL, NULL, NULL,
source, &creds_out);
}
else {
result = Curl_creds_create(user ? user : Curl_creds_user(creds_in),
passwd ? passwd : Curl_creds_passwd(creds_in),
Curl_creds_oauth_bearer(creds_in),
Curl_creds_sasl_authzid(creds_in),
Curl_creds_sasl_service(creds_in),
source, &creds_out);
}
Curl_creds_link(pcreds_out, creds_out);
Curl_creds_unlink(&creds_out);
return result;
}
void Curl_creds_link(struct Curl_creds **pdest, struct Curl_creds *src)
{
if(*pdest != src) {
Curl_creds_unlink(pdest);
*pdest = src;
if(src) {
DEBUGASSERT(src->refcount < UINT32_MAX);
src->refcount++;
}
}
}
void Curl_creds_unlink(struct Curl_creds **pcreds)
{
if(*pcreds) {
struct Curl_creds *creds = *pcreds;
DEBUGASSERT(creds->refcount);
*pcreds = NULL;
if(creds->refcount)
creds->refcount--;
if(!creds->refcount) {
curlx_free(creds);
}
}
}
bool Curl_creds_same(struct Curl_creds *c1, struct Curl_creds *c2)
{
return (c1 == c2) ||
(c1 && c2 &&
!Curl_timestrcmp(c1->user, c2->user) &&
!Curl_timestrcmp(c1->passwd, c2->passwd) &&
!Curl_timestrcmp(c1->oauth_bearer, c2->oauth_bearer) &&
!Curl_timestrcmp(c1->sasl_authzid, c2->sasl_authzid) &&
!Curl_timestrcmp(c1->sasl_service, c2->sasl_service));
}
bool Curl_creds_equal(struct Curl_creds *c1, struct Curl_creds *c2)
{
return Curl_creds_same(c1, c2) &&
((c1 == c2) || (c1 && c2 && (c1->source == c2->source)));
}
#ifdef CURLVERBOSE
void Curl_creds_trace(struct Curl_easy *data, struct Curl_creds *creds,
const char *msg)
{
if(creds) {
CURL_TRC_M(data, "%s: user=%s, passwd=%s, "
"sasl_authzid=%s, oauth_bearer=%s, source=%d",
msg,
Curl_creds_user(creds),
Curl_creds_has_passwd(creds) ? "***" : "",
Curl_creds_sasl_authzid(creds),
Curl_creds_has_oauth_bearer(creds) ? "***" : "",
creds->source);
}
else
CURL_TRC_M(data, "%s: -", msg);
}
#endif
+91
View File
@@ -0,0 +1,91 @@
#ifndef HEADER_CURL_CREDS_H
#define HEADER_CURL_CREDS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
struct Curl_easy;
#define CREDS_NONE 0 /* used for default username/passwd */
#define CREDS_URL 1 /* username/passwd from URL */
#define CREDS_OPTION 2 /* username/passwd set with a CURLOPT_ */
#define CREDS_NETRC 3 /* username/passwd found in netrc */
struct Curl_creds {
const char *user; /* non-NULL, maybe empty string */
const char *passwd; /* non-NULL, maybe empty string */
const char *oauth_bearer; /* non-NULL, maybe empty string */
const char *sasl_authzid; /* non-NULL, maybe empty string */
const char *sasl_service; /* non-NULL, maybe empty string */
uint32_t refcount;
uint8_t source; /* CREDS_* value */
char buf[1];
};
CURLcode Curl_creds_create(const char *user,
const char *passwd,
const char *oauth_bearer,
const char *sasl_authzid,
const char *sasl_service,
uint8_t source,
struct Curl_creds **pcreds);
/* Create credentials by overriding `user` and/or `passwd` in `creds_in` */
CURLcode Curl_creds_merge(const char *user,
const char *passwd,
struct Curl_creds *creds_in,
uint8_t source,
struct Curl_creds **pcreds_out);
/* Unlink any creds in `*pdest`, assign src, increase src
* refcount when not NULL. */
void Curl_creds_link(struct Curl_creds **pdest, struct Curl_creds *src);
/* Drop a reference, creds may be passed as NULL */
void Curl_creds_unlink(struct Curl_creds **pcreds);
/* TRUE if both creds are NULL or have same values, except source. */
bool Curl_creds_same(struct Curl_creds *c1, struct Curl_creds *c2);
/* TRUE if both creds are NULL or have all values equal. */
bool Curl_creds_equal(struct Curl_creds *c1, struct Curl_creds *c2);
/* Provides properties for creds or, if creds is NULL, the empty string */
#define Curl_creds_has_user(c) ((c) && (c)->user[0])
#define Curl_creds_has_passwd(c) ((c) && (c)->passwd[0])
#define Curl_creds_has_user_or_pass(c) \
((c) && ((c)->user[0] || (c)->passwd[0]))
#define Curl_creds_has_oauth_bearer(c) ((c) && (c)->oauth_bearer[0])
#define Curl_creds_has_sasl_service(c) ((c) && (c)->sasl_service[0])
#define Curl_creds_user(c) ((c) ? (c)->user : "")
#define Curl_creds_passwd(c) ((c) ? (c)->passwd : "")
#define Curl_creds_oauth_bearer(c) ((c) ? (c)->oauth_bearer : "")
#define Curl_creds_sasl_authzid(c) ((c) ? (c)->sasl_authzid : "")
#define Curl_creds_sasl_service(c) ((c) ? (c)->sasl_service : "")
#ifdef CURLVERBOSE
void Curl_creds_trace(struct Curl_easy *data, struct Curl_creds *creds,
const char *msg);
#endif
#endif /* HEADER_CURL_CREDS_H */
+4 -4
View File
@@ -150,8 +150,8 @@ void Curl_cshutdn_terminate(struct Curl_easy *data,
CURL_TRC_M(admin, "[SHUTDOWN] %sclosing connection #%" FMT_OFF_T,
conn->bits.shutdown_filters ? "" : "force ",
conn->connection_id);
Curl_conn_close(admin, SECONDARYSOCKET);
Curl_conn_close(admin, FIRSTSOCKET);
Curl_conn_cf_discard_all(admin, conn, SECONDARYSOCKET);
Curl_conn_cf_discard_all(admin, conn, FIRSTSOCKET);
Curl_detach_connection(admin);
if(data->multi)
@@ -322,14 +322,14 @@ int Curl_cshutdn_init(struct cshutdn *cshutdn,
DEBUGASSERT(multi);
cshutdn->multi = multi;
Curl_llist_init(&cshutdn->list, NULL);
cshutdn->initialised = TRUE;
cshutdn->initialized = TRUE;
return 0; /* good */
}
void Curl_cshutdn_destroy(struct cshutdn *cshutdn,
struct Curl_easy *data)
{
if(cshutdn->initialised && data) {
if(cshutdn->initialized && data) {
int timeout_ms = 0;
/* for testing, run graceful shutdown */
#ifdef DEBUGBUILD
+1 -1
View File
@@ -54,7 +54,7 @@ void Curl_cshutdn_terminate(struct Curl_easy *data,
struct cshutdn {
struct Curl_llist list; /* connections being shut down */
struct Curl_multi *multi; /* the multi owning this */
BIT(initialised);
BIT(initialized);
};
/* Init as part of the given multi handle. */
+48 -5
View File
@@ -49,6 +49,7 @@
#include "curl_addrinfo.h"
#include "fake_addrinfo.h"
#include "curlx/inet_pton.h"
#include "curlx/strparse.h"
/*
* Curl_freeaddrinfo()
@@ -59,7 +60,7 @@
* any function call which actually allocates a Curl_addrinfo struct.
*/
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
/* workaround icc 9.1 optimizer issue */
# define vqualifier volatile
@@ -113,7 +114,7 @@ int Curl_getaddrinfo_ex(const char *nodename,
/* traverse the addrinfo list */
for(ai = aihead; ai != NULL; ai = ai->ai_next) {
for(ai = aihead; ai; ai = ai->ai_next) {
size_t namelen = ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0;
/* ignore elements with unsupported address family,
settle family-specific sockaddr structure size. */
@@ -256,7 +257,7 @@ struct Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port)
/* no input == no output! */
return NULL;
DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
DEBUGASSERT(he->h_name && he->h_addr_list);
for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
size_t ss_size;
@@ -443,6 +444,48 @@ bool Curl_is_ipaddr(const char *address)
return FALSE;
}
bool Curl_looks_like_ipv6(const char *s, size_t len, bool maybe_url_encoded,
struct Curl_str *host, struct Curl_str *zone)
{
const char *zonep = NULL;
size_t i = 0, hlen = 0, zlen = 0;
if(host)
memset(host, 0, sizeof(*host));
if(zone)
memset(zone, 0, sizeof(*zone));
for(i = 0; i < len; ++i, ++hlen) {
if(!s[i] || !(ISXDIGIT(s[i]) || (s[i] == ':') || (s[i] == '.')))
break;
}
if((i < len) && (s[i] == '%')) { /* address followed by a zone? */
i += 1;
if(maybe_url_encoded && !strncmp("25", s + i, 2))
i += 2;
zonep = s + i;
for(; i < len; ++i, ++zlen) {
/* Allow unreserved characters as defined in RFC 3986 */
if(!s[i] || !(ISALPHA(s[i]) || ISXDIGIT(s[i]) || (s[i] == '-') ||
(s[i] == '.') || (s[i] == '_') || (s[i] == '~')))
break;
}
}
if(i != len)
return FALSE; /* invalid chars in zone */
if(host && hlen) {
host->str = s;
host->len = hlen;
}
if(zone && zlen) {
zone->str = zonep;
zone->len = zlen;
}
return TRUE;
}
#ifdef USE_UNIX_SOCKETS
/**
* Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo
@@ -560,7 +603,7 @@ int curl_dbg_getaddrinfo(const char *hostname,
#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
/*
* Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and macOS
* Works around the sin6_port is always zero bug on iOS 9.3.2 and macOS
* 10.11.5.
*/
void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
@@ -570,7 +613,7 @@ void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
#ifdef USE_IPV6
struct sockaddr_in6 *addr6;
#endif
for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
for(ca = addrinfo; ca; ca = ca->ai_next) {
switch(ca->ai_family) {
case AF_INET:
addr = (void *)ca->ai_addr; /* storage area for this info */
+5
View File
@@ -40,6 +40,8 @@
# include <inet.h>
#endif
struct Curl_str;
/*
* Curl_addrinfo is our internal struct definition that we use to allow
* consistent internal handling of this data. We use this even when the system
@@ -73,6 +75,9 @@ struct Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port);
bool Curl_is_ipv4addr(const char *address);
bool Curl_is_ipaddr(const char *address);
bool Curl_looks_like_ipv6(const char *s, size_t len, bool maybe_url_encoded,
struct Curl_str *host, struct Curl_str *zone);
CURLcode Curl_str2addr(const char *dotted, uint16_t port,
struct Curl_addrinfo **addrp);
+10 -1
View File
@@ -227,6 +227,12 @@
/* Define to 1 if you have the `opendir' function. */
#cmakedefine HAVE_OPENDIR 1
/* Define to 1 if you have the memset_explicit (C23) function. */
#cmakedefine HAVE_MEMSET_EXPLICIT 1
/* Define to 1 if you have the memset_s (C11) function. */
#cmakedefine HAVE_MEMSET_S 1
/* Define to 1 if you have the fcntl function. */
#cmakedefine HAVE_FCNTL 1
@@ -248,7 +254,7 @@
/* Define to 1 if you have a working getaddrinfo function. */
#cmakedefine HAVE_GETADDRINFO 1
/* Define to 1 if the getaddrinfo function is threadsafe. */
/* Define to 1 if the getaddrinfo function is thread-safe. */
#cmakedefine HAVE_GETADDRINFO_THREADSAFE 1
/* Define to 1 if you have the `geteuid' function. */
@@ -713,6 +719,9 @@ ${SIZEOF_TIME_T_CODE}
/* if libuv is in use */
#cmakedefine USE_LIBUV 1
/* if HTTP/3 proxy support is available */
#cmakedefine USE_PROXY_HTTP3 1
/* Define to 1 if you have the <uv.h> header file. */
#cmakedefine HAVE_UV_H 1
+3 -3
View File
@@ -34,7 +34,7 @@
*
* Parameters:
*
* buf [in] - A pointer to a 2 byte buffer.
* buf [in] - A pointer to a 2-byte buffer.
*
* Returns the integer.
*/
@@ -53,7 +53,7 @@ unsigned short Curl_read16_le(const unsigned char *buf)
*
* Parameters:
*
* buf [in] - A pointer to a 4 byte buffer.
* buf [in] - A pointer to a 4-byte buffer.
*
* Returns the integer.
*/
@@ -72,7 +72,7 @@ unsigned int Curl_read32_le(const unsigned char *buf)
*
* Parameters:
*
* buf [in] - A pointer to a 2 byte buffer.
* buf [in] - A pointer to a 2-byte buffer.
*
* Returns the integer.
*/
+10 -10
View File
@@ -96,25 +96,25 @@ static int parsekeyword(const unsigned char **pattern, unsigned char *charset)
#undef KEYLEN
*pattern = p; /* move caller's pattern pointer */
if(strcmp(keyword, "digit") == 0)
if(!strcmp(keyword, "digit"))
charset[CURLFNM_DIGIT] = 1;
else if(strcmp(keyword, "alnum") == 0)
else if(!strcmp(keyword, "alnum"))
charset[CURLFNM_ALNUM] = 1;
else if(strcmp(keyword, "alpha") == 0)
else if(!strcmp(keyword, "alpha"))
charset[CURLFNM_ALPHA] = 1;
else if(strcmp(keyword, "xdigit") == 0)
else if(!strcmp(keyword, "xdigit"))
charset[CURLFNM_XDIGIT] = 1;
else if(strcmp(keyword, "print") == 0)
else if(!strcmp(keyword, "print"))
charset[CURLFNM_PRINT] = 1;
else if(strcmp(keyword, "graph") == 0)
else if(!strcmp(keyword, "graph"))
charset[CURLFNM_GRAPH] = 1;
else if(strcmp(keyword, "space") == 0)
else if(!strcmp(keyword, "space"))
charset[CURLFNM_SPACE] = 1;
else if(strcmp(keyword, "blank") == 0)
else if(!strcmp(keyword, "blank"))
charset[CURLFNM_BLANK] = 1;
else if(strcmp(keyword, "upper") == 0)
else if(!strcmp(keyword, "upper"))
charset[CURLFNM_UPPER] = 1;
else if(strcmp(keyword, "lower") == 0)
else if(!strcmp(keyword, "lower"))
charset[CURLFNM_LOWER] = 1;
else
return SETCHARSET_FAIL;
+3 -3
View File
@@ -42,13 +42,13 @@
*/
#ifdef _WIN32
#define PATHSEP "\\"
#define PATHSEP "\\"
#define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
#elif defined(MSDOS) || defined(OS2)
#define PATHSEP "\\"
#define PATHSEP "\\"
#define IS_SEP(x) ((x) == '\\')
#else
#define PATHSEP "/"
#define PATHSEP "/"
#define IS_SEP(x) ((x) == '/')
#endif
+2 -3
View File
@@ -260,7 +260,7 @@ static OM_uint32 stub_gss_init_sec_context(
used = curl_msnprintf(token, length, "%s:%.*s:%d:", creds,
(int)target_desc.length,
(const char *)target_desc.value,
ctx->sent);
(int)ctx->sent);
gss_release_buffer(&minor_status, &target_desc);
}
@@ -302,8 +302,7 @@ static OM_uint32 stub_gss_delete_sec_context(
return GSS_S_FAILURE;
}
curlx_free(*context);
*context = NULL;
curlx_safefree(*context);
*min = 0;
return GSS_S_COMPLETE;
+12 -13
View File
@@ -24,26 +24,26 @@
*
***************************************************************************/
#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) || \
!defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \
#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) || \
!defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \
defined(USE_LIBSSH2) || defined(USE_SSL)
#define HMAC_MD5_LENGTH 16
typedef CURLcode (*HMAC_hinit)(void *context);
typedef void (*HMAC_hupdate)(void *context,
const unsigned char *data,
unsigned int len);
typedef void (*HMAC_hfinal)(unsigned char *result, void *context);
typedef void (*HMAC_hupdate)(void *context,
const unsigned char *data,
unsigned int len);
typedef void (*HMAC_hfinal)(unsigned char *result, void *context);
/* Per-hash function HMAC parameters. */
struct HMAC_params {
HMAC_hinit hinit; /* Initialize context procedure. */
HMAC_hupdate hupdate; /* Update context with data. */
HMAC_hfinal hfinal; /* Get final result procedure. */
unsigned int ctxtsize; /* Context structure size. */
unsigned int maxkeylen; /* Maximum key length (bytes). */
unsigned int resultlen; /* Result length (bytes). */
HMAC_hinit hinit; /* Initialize context procedure. */
HMAC_hupdate hupdate; /* Update context with data. */
HMAC_hfinal hfinal; /* Get final result procedure. */
unsigned int ctxtsize; /* Context structure size. */
unsigned int maxkeylen; /* Maximum key length (bytes). */
unsigned int resultlen; /* Result length (bytes). */
};
/* HMAC computation context. */
@@ -66,7 +66,6 @@ CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
const unsigned char *key, const size_t keylen,
const unsigned char *data, size_t datalen,
unsigned char *output);
#endif
#endif /* HEADER_CURL_HMAC_H */
+7 -7
View File
@@ -38,16 +38,16 @@ typedef void (*Curl_MD5_update_func)(void *context,
typedef void (*Curl_MD5_final_func)(unsigned char *result, void *context);
struct MD5_params {
Curl_MD5_init_func md5_init_func; /* Initialize context procedure */
Curl_MD5_update_func md5_update_func; /* Update context with data */
Curl_MD5_final_func md5_final_func; /* Get final result procedure */
unsigned int md5_ctxtsize; /* Context structure size */
unsigned int md5_resultlen; /* Result length (bytes) */
Curl_MD5_init_func md5_init_func; /* Initialize context procedure */
Curl_MD5_update_func md5_update_func; /* Update context with data */
Curl_MD5_final_func md5_final_func; /* Get final result procedure */
unsigned int md5_ctxtsize; /* Context structure size */
unsigned int md5_resultlen; /* Result length (bytes) */
};
struct MD5_context {
const struct MD5_params *md5_hash; /* Hash function definition */
void *md5_hashctx; /* Hash function context */
const struct MD5_params *md5_hash; /* Hash function definition */
void *md5_hashctx; /* Hash function context */
};
extern const struct MD5_params Curl_DIGEST_MD5;
+17 -9
View File
@@ -49,6 +49,13 @@
in NTLM type-3 messages.
*/
#ifdef USE_GNUTLS
#include <nettle/version.h>
#if NETTLE_VERSION_MAJOR < 4
#define USE_GNUTLS_DES
#endif
#endif
#if defined(USE_OPENSSL) && defined(HAVE_DES_ECB_ENCRYPT)
# include <openssl/des.h>
@@ -63,7 +70,7 @@
# include <wolfssl/wolfcrypt/des3.h>
# define USE_WOLFSSL_DES
#elif defined(USE_GNUTLS)
#elif defined(USE_GNUTLS_DES)
# include <nettle/des.h>
# define USE_CURL_DES_SET_ODD_PARITY
#elif defined(USE_MBEDTLS) && defined(HAVE_MBEDTLS_DES_CRYPT_ECB)
@@ -175,7 +182,7 @@ static void setup_des_key(const unsigned char *key_56, Des *des)
wc_Des_SetKey(des, key, NULL, 0);
}
#elif defined(USE_GNUTLS)
#elif defined(USE_GNUTLS_DES)
static void setup_des_key(const unsigned char *key_56, struct des_ctx *des)
{
char key[8];
@@ -244,6 +251,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
char key[8];
} blob;
DWORD len = 8;
BOOL res;
/* Acquire the crypto provider */
if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
@@ -273,19 +281,19 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
memcpy(out, in, 8);
/* Perform the encryption */
CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len);
res = CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len);
CryptDestroyKey(hkey);
CryptReleaseContext(hprov, 0);
return TRUE;
return res;
}
#endif /* crypto backends */
/*
* takes a 21 byte array and treats it as 3 56-bit DES keys. The
* 8 byte plaintext is encrypted with each key and the resulting 24
* takes a 21-byte array and treats it as 3 56-bit DES keys. The
* 8-byte plaintext is encrypted with each key and the resulting 24
* bytes are stored in the results array.
*/
void Curl_ntlm_core_lm_resp(const unsigned char *keys,
@@ -314,7 +322,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
wc_Des_EcbEncrypt(&des, results + 8, plaintext, DES_KEY_SIZE);
setup_des_key(keys + 14, &des);
wc_Des_EcbEncrypt(&des, results + 16, plaintext, DES_KEY_SIZE);
#elif defined(USE_GNUTLS)
#elif defined(USE_GNUTLS_DES)
struct des_ctx des;
setup_des_key(keys, &des);
des_encrypt(&des, 8, results, plaintext);
@@ -367,7 +375,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
wc_Des_EcbEncrypt(&des, lmbuffer, magic, DES_KEY_SIZE);
setup_des_key(pw + 7, &des);
wc_Des_EcbEncrypt(&des, lmbuffer + 8, magic, DES_KEY_SIZE);
#elif defined(USE_GNUTLS)
#elif defined(USE_GNUTLS_DES)
struct des_ctx des;
setup_des_key(pw, &des);
des_encrypt(&des, 8, lmbuffer, magic);
@@ -625,7 +633,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(const unsigned char *ntlmv2hash,
*
* ntlmv2hash [in] - The NTLMv2 hash (16 bytes)
* challenge_client [in] - The client nonce (8 bytes)
* challenge_client [in] - The server challenge (8 bytes)
* challenge_server [in] - The server challenge (8 bytes)
* lmresp [out] - The LMv2 response (24 bytes)
*
* Returns CURLE_OK on success.
+1 -1
View File
@@ -30,7 +30,7 @@
struct ntlmdata;
/* Helpers to generate function byte arguments in little endian order */
#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
+57 -80
View File
@@ -35,7 +35,7 @@
#include "curl_setup.h"
#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_SMTP) || \
!defined(CURL_DISABLE_POP3) || \
!defined(CURL_DISABLE_POP3) || \
(!defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP))
#include "urldata.h"
@@ -276,7 +276,7 @@ static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
{
/* Have credentials been provided? */
if(data->conn->user[0])
if(data->conn->creds)
return TRUE;
/* EXTERNAL can authenticate without a username and/or password */
@@ -299,13 +299,15 @@ struct sasl_ctx {
static bool sasl_choose_external(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if((sctx->enabledmechs & SASL_MECH_EXTERNAL) && !sctx->conn->passwd[0]) {
if((sctx->enabledmechs & SASL_MECH_EXTERNAL) &&
!Curl_creds_has_passwd(sctx->conn->creds)) {
sctx->mech = SASL_MECH_STRING_EXTERNAL;
sctx->state1 = SASL_EXTERNAL;
sctx->sasl->authused = SASL_MECH_EXTERNAL;
if(sctx->sasl->force_ir || data->set.sasl_ir)
Curl_auth_create_external_message(sctx->conn->user, &sctx->resp);
Curl_auth_create_external_message(
Curl_creds_user(sctx->conn->creds), &sctx->resp);
return TRUE;
}
return FALSE;
@@ -316,10 +318,9 @@ static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if((sctx->enabledmechs & SASL_MECH_GSSAPI) &&
Curl_auth_is_gssapi_supported() &&
Curl_auth_user_contains_domain(sctx->conn->user)) {
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sctx->sasl->params->service;
Curl_auth_user_contains_domain(sctx->conn->creds)) {
const char *service = Curl_creds_has_sasl_service(sctx->conn->creds) ?
Curl_creds_sasl_service(sctx->conn->creds) : sctx->sasl->params->service;
sctx->sasl->mutual_auth = FALSE;
sctx->mech = SASL_MECH_STRING_GSSAPI;
@@ -330,9 +331,9 @@ static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
if(sctx->sasl->force_ir || data->set.sasl_ir) {
struct kerberos5data *krb5 = Curl_auth_krb5_get(sctx->conn);
sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_gssapi_user_message(data, sctx->conn->user,
sctx->conn->passwd,
service, sctx->conn->host.name,
Curl_auth_create_gssapi_user_message(data, sctx->conn->creds,
service,
sctx->conn->origin->hostname,
(bool)sctx->sasl->mutual_auth,
NULL, krb5, &sctx->resp);
}
@@ -374,8 +375,7 @@ static bool sasl_choose_gsasl(struct Curl_easy *data, struct sasl_ctx *sctx)
Curl_bufref_init(&nullmsg);
sctx->state1 = SASL_GSASL;
sctx->state2 = SASL_GSASL;
sctx->result = Curl_auth_gsasl_start(data, sctx->conn->user,
sctx->conn->passwd, gsasl);
sctx->result = Curl_auth_gsasl_start(data, sctx->conn->creds, gsasl);
if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir))
sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp);
return TRUE;
@@ -411,9 +411,8 @@ static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
{
if((sctx->enabledmechs & SASL_MECH_NTLM) &&
Curl_auth_is_ntlm_supported()) {
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sctx->sasl->params->service;
const char *service = Curl_creds_has_sasl_service(sctx->conn->creds) ?
Curl_creds_sasl_service(sctx->conn->creds) : sctx->sasl->params->service;
const char *hostname;
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, NULL);
@@ -426,9 +425,7 @@ static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
if(sctx->sasl->force_ir || data->set.sasl_ir) {
struct ntlmdata *ntlm = Curl_auth_ntlm_get(sctx->conn, FALSE);
sctx->result = !ntlm ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_ntlm_type1_message(data,
sctx->conn->user,
sctx->conn->passwd,
Curl_auth_create_ntlm_type1_message(data, sctx->conn->creds,
service, hostname,
ntlm, &sctx->resp);
}
@@ -440,11 +437,8 @@ static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx)
static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
{
const char *oauth_bearer =
(!data->state.this_is_a_follow || data->set.allow_auth_to_other_hosts) ?
data->set.str[STRING_BEARER] : NULL;
if(oauth_bearer && (sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
if(Curl_creds_has_oauth_bearer(data->state.creds) &&
(sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) {
const char *hostname;
int port;
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
@@ -456,9 +450,8 @@ static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result =
Curl_auth_create_oauth_bearer_message(sctx->conn->user,
hostname, port,
oauth_bearer, &sctx->resp);
Curl_auth_create_oauth_bearer_message(sctx->conn->creds,
hostname, port, &sctx->resp);
return TRUE;
}
return FALSE;
@@ -466,19 +459,15 @@ static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx)
static bool sasl_choose_oauth2(struct Curl_easy *data, struct sasl_ctx *sctx)
{
const char *oauth_bearer =
(!data->state.this_is_a_follow || data->set.allow_auth_to_other_hosts) ?
data->set.str[STRING_BEARER] : NULL;
if(oauth_bearer && (sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
if(Curl_creds_has_oauth_bearer(sctx->conn->creds) &&
(sctx->enabledmechs & SASL_MECH_XOAUTH2)) {
sctx->mech = SASL_MECH_STRING_XOAUTH2;
sctx->state1 = SASL_OAUTH2;
sctx->sasl->authused = SASL_MECH_XOAUTH2;
if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result = Curl_auth_create_xoauth_bearer_message(sctx->conn->user,
oauth_bearer,
&sctx->resp);
sctx->result = Curl_auth_create_xoauth_bearer_message(
sctx->conn->creds, &sctx->resp);
return TRUE;
}
return FALSE;
@@ -493,9 +482,7 @@ static bool sasl_choose_plain(struct Curl_easy *data, struct sasl_ctx *sctx)
if(sctx->sasl->force_ir || data->set.sasl_ir)
sctx->result =
Curl_auth_create_plain_message(sctx->conn->sasl_authzid,
sctx->conn->user, sctx->conn->passwd,
&sctx->resp);
Curl_auth_create_plain_message(sctx->conn->creds, &sctx->resp);
return TRUE;
}
return FALSE;
@@ -510,7 +497,8 @@ static bool sasl_choose_login(struct Curl_easy *data, struct sasl_ctx *sctx)
sctx->sasl->authused = SASL_MECH_LOGIN;
if(sctx->sasl->force_ir || data->set.sasl_ir)
Curl_auth_create_login_message(sctx->conn->user, &sctx->resp);
Curl_auth_create_login_message(
Curl_creds_user(sctx->conn->creds), &sctx->resp);
return TRUE;
}
return FALSE;
@@ -599,13 +587,6 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
struct bufref resp;
const char *hostname;
int port;
#if defined(USE_KERBEROS5) || defined(USE_NTLM) || \
!defined(CURL_DISABLE_DIGEST_AUTH)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sasl->params->service;
#endif
const char *oauth_bearer = data->set.str[STRING_BEARER];
struct bufref serverdata;
Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port);
@@ -633,18 +614,17 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
*progress = SASL_DONE;
return result;
case SASL_PLAIN:
result = Curl_auth_create_plain_message(conn->sasl_authzid,
conn->user, conn->passwd, &resp);
result = Curl_auth_create_plain_message(conn->creds, &resp);
break;
case SASL_LOGIN:
Curl_auth_create_login_message(conn->user, &resp);
Curl_auth_create_login_message(Curl_creds_user(conn->creds), &resp);
newstate = SASL_LOGIN_PASSWD;
break;
case SASL_LOGIN_PASSWD:
Curl_auth_create_login_message(conn->passwd, &resp);
Curl_auth_create_login_message(Curl_creds_passwd(conn->creds), &resp);
break;
case SASL_EXTERNAL:
Curl_auth_create_external_message(conn->user, &resp);
Curl_auth_create_external_message(Curl_creds_user(conn->creds), &resp);
break;
#ifdef USE_GSASL
case SASL_GSASL:
@@ -662,15 +642,16 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_CRAMMD5:
result = get_server_message(sasl, data, &serverdata);
if(!result)
result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
conn->passwd, &resp);
result = Curl_auth_create_cram_md5_message(&serverdata, conn->creds,
&resp);
break;
case SASL_DIGESTMD5:
result = get_server_message(sasl, data, &serverdata);
if(!result)
result = Curl_auth_create_digest_md5_message(data, &serverdata,
conn->user, conn->passwd,
service, &resp);
conn->creds,
sasl->params->service,
&resp);
if(!result && (sasl->params->flags & SASL_FLAG_BASE64))
newstate = SASL_DIGESTMD5_RESP;
break;
@@ -684,9 +665,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
/* Create the type-1 message */
struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE);
result = !ntlm ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_ntlm_type1_message(data,
conn->user, conn->passwd,
service, hostname,
Curl_auth_create_ntlm_type1_message(data, conn->creds,
sasl->params->service, hostname,
ntlm, &resp);
newstate = SASL_NTLM_TYPE2MSG;
break;
@@ -699,9 +679,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
if(!result)
result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm);
if(!result)
result = Curl_auth_create_ntlm_type3_message(data, conn->user,
conn->passwd, ntlm,
&resp);
result = Curl_auth_create_ntlm_type3_message(data, conn->creds,
ntlm, &resp);
break;
}
#endif
@@ -710,8 +689,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_GSSAPI: {
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
result = !krb5 ? CURLE_OUT_OF_MEMORY :
Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd,
service, conn->host.name,
Curl_auth_create_gssapi_user_message(data, conn->creds,
sasl->params->service,
conn->origin->hostname,
(bool)sasl->mutual_auth, NULL,
krb5, &resp);
newstate = SASL_GSSAPI_TOKEN;
@@ -726,7 +706,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
else if(sasl->mutual_auth) {
/* Decode the user token challenge and create the optional response
message */
result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
result = Curl_auth_create_gssapi_user_message(data, NULL,
NULL, NULL,
(bool)sasl->mutual_auth,
&serverdata,
@@ -735,10 +715,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
}
else
/* Decode the security challenge and create the response message */
result = Curl_auth_create_gssapi_security_message(data,
conn->sasl_authzid,
&serverdata,
krb5, &resp);
result = Curl_auth_create_gssapi_security_message(
data, Curl_creds_sasl_authzid(conn->creds), &serverdata,
krb5, &resp);
}
break;
case SASL_GSSAPI_NO_DATA:
@@ -749,10 +728,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
if(!krb5)
result = CURLE_OUT_OF_MEMORY;
else
result = Curl_auth_create_gssapi_security_message(data,
conn->sasl_authzid,
&serverdata,
krb5, &resp);
result = Curl_auth_create_gssapi_security_message(
data, Curl_creds_sasl_authzid(conn->creds), &serverdata,
krb5, &resp);
}
break;
#endif
@@ -760,18 +738,16 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
case SASL_OAUTH2:
/* Create the authorization message */
if(sasl->authused == SASL_MECH_OAUTHBEARER) {
result = Curl_auth_create_oauth_bearer_message(conn->user,
result = Curl_auth_create_oauth_bearer_message(conn->creds,
hostname,
port,
oauth_bearer,
&resp);
/* Failures maybe sent by the server as continuations for OAUTHBEARER */
newstate = SASL_OAUTH2_RESP;
}
else
result = Curl_auth_create_xoauth_bearer_message(conn->user,
oauth_bearer,
result = Curl_auth_create_xoauth_bearer_message(conn->creds,
&resp);
break;
@@ -861,7 +837,7 @@ static void sasl_unchosen(struct Curl_easy *data, unsigned short mech,
else {
if(param_missing)
infof(data, "SASL: %s is missing %s", mname, param_missing);
if(!data->conn->user[0])
if(!Curl_creds_has_user(data->conn->creds))
infof(data, "SASL: %s is missing username", mname);
}
}
@@ -903,7 +879,8 @@ CURLcode Curl_sasl_is_blocked(struct SASL *sasl, struct Curl_easy *data)
"auth mechanisms");
else {
infof(data, "SASL: no auth mechanism offered could be selected");
if((enabledmechs & SASL_MECH_EXTERNAL) && data->conn->passwd[0])
if((enabledmechs & SASL_MECH_EXTERNAL) &&
Curl_creds_has_passwd(data->conn->creds))
infof(data, "SASL: auth EXTERNAL not chosen with password");
sasl_unchosen(data, SASL_MECH_GSSAPI, enabledmechs,
CURL_SASL_KERBEROS5, Curl_auth_is_gssapi_supported(), NULL);
@@ -918,10 +895,10 @@ CURLcode Curl_sasl_is_blocked(struct SASL *sasl, struct Curl_easy *data)
sasl_unchosen(data, SASL_MECH_NTLM, enabledmechs,
CURL_SASL_NTLM, Curl_auth_is_ntlm_supported(), NULL);
sasl_unchosen(data, SASL_MECH_OAUTHBEARER, enabledmechs, TRUE, TRUE,
data->set.str[STRING_BEARER] ?
Curl_creds_has_oauth_bearer(data->conn->creds) ?
NULL : "CURLOPT_XOAUTH2_BEARER");
sasl_unchosen(data, SASL_MECH_XOAUTH2, enabledmechs, TRUE, TRUE,
data->set.str[STRING_BEARER] ?
Curl_creds_has_oauth_bearer(data->conn->creds) ?
NULL : "CURLOPT_XOAUTH2_BEARER");
}
#endif /* CURLVERBOSE */
+68 -6
View File
@@ -223,7 +223,7 @@
/* please, do it beyond the point further indicated in this file. */
/* ================================================================ */
/* Give calloc a chance to be dragging in early, so we do not redefine */
/* Give calloc a chance to be included early, so we do not redefine */
#ifdef HAVE_THREADS_POSIX
# include <pthread.h>
#endif
@@ -465,7 +465,7 @@
# undef HAVE_FCNTL
# undef HAVE_FCNTL_O_NONBLOCK
# else
/* use libc networking and hence close() and fnctl() */
/* use libc networking and hence close() and fcntl() */
# undef HAVE_CLOSESOCKET_CAMEL
# undef HAVE_IOCTLSOCKET_CAMEL
# endif
@@ -602,7 +602,7 @@
# endif
#endif
#if (SIZEOF_CURL_OFF_T < 8)
#if SIZEOF_CURL_OFF_T < 8
#error "too small curl_off_t"
#else
/* assume SIZEOF_CURL_OFF_T == 8 */
@@ -613,7 +613,7 @@
#define FMT_OFF_T CURL_FORMAT_CURL_OFF_T
#define FMT_OFF_TU CURL_FORMAT_CURL_OFF_TU
#if (SIZEOF_TIME_T == 4)
#if SIZEOF_TIME_T == 4
# ifdef HAVE_TIME_T_UNSIGNED
# define TIME_T_MAX UINT_MAX
# define TIME_T_MIN 0
@@ -1152,6 +1152,15 @@ typedef unsigned int curl_bit;
#define SOCKEWOULDBLOCK EWOULDBLOCK
#endif
/* The socket error may be EWOULDBLOCK or on some systems EAGAIN when
it returned due to its inability to send/read data without blocking.
We treat both error codes the same here. */
#if !defined(USE_WINSOCK) && EAGAIN != SOCKEWOULDBLOCK
#define SOCK_EAGAIN(e) ((e) == SOCKEWOULDBLOCK || (e) == EAGAIN)
#else
#define SOCK_EAGAIN(e) ((e) == SOCKEWOULDBLOCK)
#endif
/*
* Macro argv_item_t hides platform details to code using it.
*/
@@ -1344,6 +1353,20 @@ extern curl_calloc_callback Curl_ccalloc;
(ptr) = NULL; \
} while(0)
/* Same as curlx_safefree() but zeroes memory before freeing */
#define curlx_safefreezero(ptr, size) \
do { \
curlx_freezero(ptr, size); \
(ptr) = NULL; \
} while(0)
/* Same as curlx_safefreezero() but determines length with strlen() */
#define curlx_safefreezeroz(ptr) \
do { \
curlx_freezeroz(ptr); \
(ptr) = NULL; \
} while(0)
#include <curl/curl.h> /* for CURL_EXTERN, curl_socket_t, mprintf.h */
#ifdef DEBUGBUILD
@@ -1557,7 +1580,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#endif
#if defined(USE_UNIX_SOCKETS) && defined(_WIN32)
/* Offered by mingw-w64 v10+. MS SDK 10.17763/~VS2017+. */
/* Offered by mingw-w64 v10+, MS SDK 10.0.16299.0/VS2017 15.4+ */
#if defined(__MINGW32__) && (__MINGW64_VERSION_MAJOR >= 10)
# include <afunix.h>
#elif !defined(UNIX_PATH_MAX) /* Replicate logic present in afunix.h */
@@ -1593,7 +1616,7 @@ typedef struct sockaddr_un {
/* The code is compiled with C++ compiler.
C++ always supports 'inline'. */
# define CURL_INLINE inline /* 'inline' keyword supported */
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 (and later) supports 'inline' keyword */
# define CURL_INLINE inline /* 'inline' keyword supported */
#elif defined(__GNUC__) && __GNUC__ >= 3
@@ -1623,4 +1646,43 @@ typedef struct sockaddr_un {
#define NOVERBOSE(x) x
#endif
/* For FreeBSD it is included from curl/curl.h */
#if defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <sys/param.h> /* for __DragonFly_version, OpenBSD,
__NetBSD_Version__ */
#endif
#ifndef _CURL_LOCAL_MEMZERO /* to be removed after a couple of releases */
#ifdef _WIN32
#if defined(_MSC_VER) && defined(NTDDI_VERSION) && \
(NTDDI_VERSION >= 0x0A000010) /* MS SDK 10.0.26100.0+ */
#pragma comment(lib, "volatileaccessu.lib")
#define curlx_memzero(buf, size) SecureZeroMemory2(buf, size)
#else
#define curlx_memzero(buf, size) SecureZeroMemory(buf, size)
#endif
#elif defined(HAVE_MEMSET_S)
#define curlx_memzero(buf, size) (void)memset_s(buf, size, 0, size)
#elif defined(HAVE_MEMSET_EXPLICIT)
#define curlx_memzero(buf, size) (void)memset_explicit(buf, 0, size)
#elif defined(__CYGWIN__) || \
(defined(__NEWLIB__) && !defined(__CLIB2__)) || \
(defined(__GLIBC__) && \
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))) || \
(defined(__DragonFly__) && __DragonFly_version >= 500600 /* v5.6+ */) || \
(defined(__FreeBSD__) && __FreeBSD_version >= 1100037 /* v11.0+ */) || \
(defined(__OpenBSD__) && OpenBSD >= 201405 /* v5.5+ */)
#define curlx_memzero(buf, size) explicit_bzero(buf, size)
#elif defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 /* v7.2+ */
#define curlx_memzero(buf, size) (void)explicit_memset(buf, 0, size)
#endif
#endif /* !_CURL_LOCAL_MEMZERO */
#ifndef curlx_memzero
#define USE_CURLX_MEMZERO
void curlx_memzero(void *buf, size_t size);
#endif
void curlx_freezero(void *buf, size_t size);
void curlx_freezeroz(void *buf);
#endif /* HEADER_CURL_SETUP_H */
+26 -26
View File
@@ -44,7 +44,7 @@
# define USE_OPENSSL_SHA512_256 1
# define HAS_SHA512_256_IMPLEMENTATION 1
# ifdef __NetBSD__
/* Some NetBSD versions has a bug in SHA-512/256.
/* Some NetBSD versions have 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
@@ -54,7 +54,6 @@
* NetBSD 10.99.11 development.
* It is safe to apply the workaround even if the bug is not present, as
* the workaround reduces performance slightly. */
# include <sys/param.h>
# if __NetBSD_Version__ < 904000000 || \
(__NetBSD_Version__ >= 999000000 && \
__NetBSD_Version__ < 1000000000) || \
@@ -75,7 +74,8 @@
#endif
#if !defined(HAS_SHA512_256_IMPLEMENTATION) && defined(USE_GNUTLS)
# include <nettle/sha.h>
# include <nettle/sha2.h>
# include <nettle/version.h>
# ifdef SHA512_256_DIGEST_SIZE
# define USE_GNUTLS_SHA512_256 1
# endif
@@ -102,7 +102,7 @@
typedef EVP_MD_CTX *Curl_sha512_256_ctx;
/**
* Initialise structure for SHA-512/256 calculation.
* Initialize structure for SHA-512/256 calculation.
*
* @param context the calculation context
* @return CURLE_OK if succeed,
@@ -145,7 +145,7 @@ static CURLcode Curl_sha512_256_update(void *context,
Curl_sha512_256_ctx * const ctx = (Curl_sha512_256_ctx *)context;
if(!EVP_DigestUpdate(*ctx, data, length))
return CURLE_SSL_CIPHER;
return CURLE_BAD_FUNCTION_ARGUMENT;
return CURLE_OK;
}
@@ -168,14 +168,14 @@ static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context)
/* 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[CURL_SHA512_256_DIGEST_SIZE * 2];
result = EVP_DigestFinal_ex(*ctx,
tmp_digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
result = EVP_DigestFinal_ex(*ctx, tmp_digest, NULL) ?
CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
if(result == CURLE_OK)
memcpy(digest, tmp_digest, CURL_SHA512_256_DIGEST_SIZE);
explicit_memset(tmp_digest, 0, sizeof(tmp_digest));
curlx_memzero(tmp_digest, sizeof(tmp_digest));
#else /* !NEED_NETBSD_SHA512_256_WORKAROUND */
result = EVP_DigestFinal_ex(*ctx, digest, NULL) ?
CURLE_OK : CURLE_SSL_CIPHER;
CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
#endif /* NEED_NETBSD_SHA512_256_WORKAROUND */
EVP_MD_CTX_destroy(*ctx);
@@ -206,7 +206,7 @@ static CURLcode Curl_sha512_256_update(void *ctx,
do {
word32 ilen = (word32)CURLMIN(length, UINT_MAX);
if(wc_Sha512_256Update(ctx, data, ilen))
return CURLE_SSL_CIPHER;
return CURLE_BAD_FUNCTION_ARGUMENT;
length -= ilen;
data += ilen;
} while(length);
@@ -216,7 +216,7 @@ static CURLcode Curl_sha512_256_update(void *ctx,
static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *ctx)
{
if(wc_Sha512_256Final(ctx, digest))
return CURLE_SSL_CIPHER;
return CURLE_BAD_FUNCTION_ARGUMENT;
return CURLE_OK;
}
@@ -231,7 +231,7 @@ static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *ctx)
typedef struct sha512_256_ctx Curl_sha512_256_ctx;
/**
* Initialise structure for SHA-512/256 calculation.
* Initialize structure for SHA-512/256 calculation.
*
* @param context the calculation context
* @return always CURLE_OK
@@ -262,7 +262,7 @@ static CURLcode Curl_sha512_256_update(void *context,
{
Curl_sha512_256_ctx * const ctx = (Curl_sha512_256_ctx *)context;
DEBUGASSERT((data != NULL) || (length == 0));
DEBUGASSERT(data || (length == 0));
sha512_256_update(ctx, length, (const uint8_t *)data);
@@ -281,8 +281,12 @@ static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context)
{
Curl_sha512_256_ctx * const ctx = (Curl_sha512_256_ctx *)context;
#if NETTLE_VERSION_MAJOR >= 4
sha512_256_digest(ctx, (uint8_t *)digest);
#else
sha512_256_digest(ctx,
(size_t)CURL_SHA512_256_DIGEST_SIZE, (uint8_t *)digest);
#endif
return CURLE_OK;
}
@@ -296,7 +300,7 @@ static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context)
#ifdef __GNUC__
# if defined(__has_attribute) && defined(__STDC_VERSION__)
# if __has_attribute(always_inline) && __STDC_VERSION__ >= 199901
# if __has_attribute(always_inline) && __STDC_VERSION__ >= 199901L
# define CURL_FORCEINLINE CURL_INLINE __attribute__((always_inline))
# endif
# endif
@@ -430,7 +434,7 @@ struct Curl_sha512_256ctx {
typedef struct Curl_sha512_256ctx Curl_sha512_256_ctx;
/**
* Initialise structure for SHA-512/256 calculation.
* Initialize structure for SHA-512/256 calculation.
*
* @param context the calculation context
* @return always CURLE_OK
@@ -456,7 +460,7 @@ static CURLcode Curl_sha512_256_init(void *context)
ctx->H[6] = UINT64_C(0x2B0199FC2C85B8AA);
ctx->H[7] = UINT64_C(0x0EB72DDC81C52CA2);
/* Initialise number of bytes and high part of number of bits. */
/* Initialize number of bytes and high part of number of bits. */
ctx->count = UINT64_C(0);
ctx->count_bits_hi = UINT64_C(0);
@@ -494,14 +498,10 @@ static void Curl_sha512_256_transform(uint64_t H[SHA512_256_HASH_SIZE_WORDS],
/* Four 'Sigma' macro functions.
See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
#define SIG0(x) \
(Curl_rotr64(x, 28) ^ Curl_rotr64(x, 34) ^ Curl_rotr64(x, 39))
#define SIG1(x) \
(Curl_rotr64(x, 14) ^ Curl_rotr64(x, 18) ^ Curl_rotr64(x, 41))
#define sig0(x) \
(Curl_rotr64(x, 1) ^ Curl_rotr64(x, 8) ^ ((x) >> 7))
#define sig1(x) \
(Curl_rotr64(x, 19) ^ Curl_rotr64(x, 61) ^ ((x) >> 6))
#define SIG0(x) (Curl_rotr64(x, 28) ^ Curl_rotr64(x, 34) ^ Curl_rotr64(x, 39))
#define SIG1(x) (Curl_rotr64(x, 14) ^ Curl_rotr64(x, 18) ^ Curl_rotr64(x, 41))
#define sig0(x) (Curl_rotr64(x, 1) ^ Curl_rotr64(x, 8) ^ ((x) >> 7))
#define sig1(x) (Curl_rotr64(x, 19) ^ Curl_rotr64(x, 61) ^ ((x) >> 6))
if(1) {
unsigned int t;
@@ -645,7 +645,7 @@ static CURLcode Curl_sha512_256_update(void *context,
/* the void pointer here is required to mute Intel compiler warning */
void * const ctx_buf = ctx->buffer;
DEBUGASSERT((data != NULL) || (length == 0));
DEBUGASSERT(data || (length == 0));
if(length == 0)
return CURLE_OK; /* Shortcut, do nothing */
@@ -711,7 +711,7 @@ static CURLcode Curl_sha512_256_update(void *context,
static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context)
{
struct Curl_sha512_256ctx * const ctx = (struct Curl_sha512_256ctx *)context;
uint64_t num_bits; /* Number of processed bits */
uint64_t num_bits; /* Number of processed bits */
unsigned int bytes_have; /* Number of bytes in the context buffer */
/* the void pointer here is required to mute Intel compiler warning */
void * const ctx_buf = ctx->buffer;
+1 -1
View File
@@ -260,7 +260,7 @@ CURLSHcode curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
case CURL_LOCK_DATA_CONNECT:
/* It is safe to set this option several times on a share. */
if(!share->cpool.initialised) {
if(!share->cpool.initialized) {
Curl_cpool_init(&share->cpool, share->admin, share, 103);
}
break;
+3 -3
View File
@@ -81,9 +81,9 @@ CURLSHcode Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
CURLSHcode Curl_share_unlock(struct Curl_easy *data, curl_lock_data type);
/* convenience macro to check if this handle is using a shared SSL spool */
#define CURL_SHARE_ssl_scache(data) ((data)->share && \
((data)->share->specifier & \
(1 << CURL_LOCK_DATA_SSL_SESSION)))
#define CURL_SHARE_ssl_scache(data) \
((data)->share && \
((data)->share->specifier & (1 << CURL_LOCK_DATA_SSL_SESSION)))
CURLcode Curl_share_easy_unlink(struct Curl_easy *data);
CURLcode Curl_share_easy_link(struct Curl_easy *data,
+5 -5
View File
@@ -52,25 +52,25 @@ extern PSecurityFunctionTable Curl_pSecFn;
#define SP_NAME_NEGOTIATE "Negotiate"
#define SP_NAME_KERBEROS "Kerberos"
/* Offered by mingw-w64 v9+. MS SDK 7.0A+. */
/* Offered by mingw-w64 v9+, MS SDK 7.0A/VS2010+ */
#ifndef ISC_REQ_USE_HTTP_STYLE
#define ISC_REQ_USE_HTTP_STYLE 0x01000000
#endif
/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */
/* Offered by mingw-w64 v8+, MS SDK 6.0A/VS2008+ */
#ifndef SEC_E_INVALID_PARAMETER
#define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL)
#endif
/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */
/* Offered by mingw-w64 v8+, MS SDK 6.0A/VS2008+ */
#ifndef SEC_E_DELEGATION_POLICY
#define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL)
#endif
/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */
/* Offered by mingw-w64 v8+, MS SDK 6.0A/VS2008+ */
#ifndef SEC_E_POLICY_NLTM_ONLY
#define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL)
#endif
/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */
/* Offered by mingw-w64 v8+, MS SDK 6.0A/VS2008+ */
#ifndef SEC_I_SIGNATURE_NEEDED
#define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL)
#endif
+8 -1
View File
@@ -29,8 +29,9 @@
#include "multiif.h"
#include "cf-dns.h"
#include "cf-recvbuf.h"
#include "cf-socket.h"
#include "connect.h"
#include "cf-setup.h"
#include "http2.h"
#include "http_proxy.h"
#include "cf-h1-proxy.h"
@@ -563,6 +564,9 @@ static struct trc_cft_def trc_cfts[] = {
{ &Curl_cft_unix, TRC_CT_NETWORK },
{ &Curl_cft_tcp_accept, TRC_CT_NETWORK },
{ &Curl_cft_ip_happy, TRC_CT_NETWORK },
#ifndef CURL_DISABLE_WEBSOCKETS
{ &Curl_cft_recvbuf, TRC_CT_PROTOCOL },
#endif
{ &Curl_cft_setup, TRC_CT_PROTOCOL },
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2)
{ &Curl_cft_nghttp2, TRC_CT_PROTOCOL },
@@ -578,6 +582,9 @@ static struct trc_cft_def trc_cfts[] = {
{ &Curl_cft_h1_proxy, TRC_CT_PROXY },
#ifdef USE_NGHTTP2
{ &Curl_cft_h2_proxy, TRC_CT_PROXY },
#endif
#if defined(USE_PROXY_HTTP3) && defined(USE_NGHTTP3)
{ &Curl_cft_h3_proxy, TRC_CT_PROXY },
#endif
{ &Curl_cft_http_proxy, TRC_CT_PROXY },
#endif /* !CURL_DISABLE_HTTP */
+2 -2
View File
@@ -80,7 +80,7 @@ static wchar_t *fn_convert_UTF8_to_wchar(const char *str_utf8)
}
#endif
/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */
/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old Windows */
#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
(_WIN32_WINNT < _WIN32_WINNT_WIN10)
WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *);
@@ -247,7 +247,7 @@ cleanup:
CURLX_FREE(ibuf);
CURLX_FREE(obuf);
#endif
return *out ? true : false;
return !!*out;
}
#ifndef CURL_WINDOWS_UWP
+2 -2
View File
@@ -30,10 +30,10 @@
*
* Provide the target buffer @dest and size of the target buffer @dsize, If
* the source string @src with its *string length* @slen fits in the target
* buffer it is copied there - including storing a null terminator.
* buffer it is copied there - including storing a null-terminator.
*
* If the target buffer is too small, the copy is not performed but if the
* target buffer has a non-zero size it gets a null terminator stored.
* target buffer has a non-zero size it gets a null-terminator stored.
*/
void curlx_strcopy(char *dest, /* destination buffer */
size_t dsize, /* size of target buffer */
+29
View File
@@ -94,3 +94,32 @@ void *curlx_memdup0(const char *src, size_t length)
buf[length] = 0;
return buf;
}
#ifdef USE_CURLX_MEMZERO
static void *(* const volatile p_curlx_memset)(void *buf, int val,
size_t size) = memset;
/* Local fallback in case there is no system function to securely zero a memory
buffer. */
void curlx_memzero(void *buf, size_t size)
{
if(buf)
p_curlx_memset(buf, 0, size);
}
#endif
/* Free 'buf' after zeroing its content. */
void curlx_freezero(void *buf, size_t size)
{
if(buf)
curlx_memzero(buf, size);
curlx_free(buf);
}
/* Free 'buf' after zeroing its content, where 'buf' is null-terminated. */
void curlx_freezeroz(void *buf)
{
if(buf)
curlx_memzero(buf, strlen(buf));
curlx_free(buf);
}
+2 -2
View File
@@ -190,7 +190,7 @@ static const char *get_winsock_error(int err, char *buf, size_t len)
p = "Winsock library is not ready";
break;
case WSANOTINITIALISED:
p = "Winsock library not initialised";
p = "Winsock library not initialized";
break;
case WSAVERNOTSUPPORTED:
p = "Winsock version not supported";
@@ -268,7 +268,7 @@ const char *curlx_strerror(int err, char *buf, size_t buflen)
!get_winsock_error(err, buf, buflen) &&
#endif
!curlx_get_winapi_error((DWORD)err, buf, buflen))
SNPRINTF(buf, buflen, "Unknown error %d (%#x)", err, err);
SNPRINTF(buf, buflen, "Unknown error %d (%#x)", err, (unsigned int)err);
#else /* !_WIN32 */
#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
+7 -3
View File
@@ -45,13 +45,17 @@ void curlx_str_trim(struct Curl_str *out, size_t len)
}
/* Get a word until the first DELIM or end of string. At least one byte long.
return non-zero on error */
return non-zero on error. If 'max' is zero, it will always return error. */
int curlx_str_until(const char **linep, struct Curl_str *out,
const size_t max, char delim)
{
const char *s = *linep;
const char *s;
size_t len = 0;
DEBUGASSERT(linep && *linep && out && max && delim);
DEBUGASSERT(linep);
DEBUGASSERT(*linep);
DEBUGASSERT(out);
DEBUGASSERT(delim);
s = *linep;
curlx_str_init(out);
while(*s && (*s != delim)) {
+1 -1
View File
@@ -195,7 +195,7 @@ static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx,
if(nwritten == CURL_WRITEFUNC_PAUSE) {
if(data->conn->scheme->flags & PROTOPT_NONETWORK) {
/* Protocols that work without network cannot be paused. This is
actually only FILE:// now, and it cannot pause since the transfer is
actually only file:// now, and it cannot pause since the transfer is
not done using the "normal" procedure. */
failf(data, "Write callback asked for PAUSE when not supported");
return CURLE_WRITE_ERROR;
+7 -5
View File
@@ -117,7 +117,8 @@ static CURLcode cw_pause_flush(struct Curl_easy *data,
result = Curl_cwriter_write(data, cw_pause->next, (*plast)->type,
(const char *)buf, wlen);
CURL_TRC_WRITE(data, "[PAUSE] flushed %zu/%zu bytes, type=%x -> %d",
wlen, ctx->buf_total, (*plast)->type, result);
wlen, ctx->buf_total, (unsigned int)(*plast)->type,
(int)result);
Curl_bufq_skip(&(*plast)->b, wlen);
DEBUGASSERT(ctx->buf_total >= wlen);
ctx->buf_total -= wlen;
@@ -128,7 +129,8 @@ static CURLcode cw_pause_flush(struct Curl_easy *data,
result = Curl_cwriter_write(data, cw_pause->next, (*plast)->type,
(const char *)buf, 0);
CURL_TRC_WRITE(data, "[PAUSE] flushed 0/%zu bytes, type=%x -> %d",
ctx->buf_total, (*plast)->type, result);
ctx->buf_total, (unsigned int)(*plast)->type,
(int)result);
}
if(Curl_bufq_is_empty(&(*plast)->b)) {
@@ -165,7 +167,7 @@ static CURLcode cw_pause_write(struct Curl_easy *data,
wtype &= ~CLIENTWRITE_EOS;
result = Curl_cwriter_write(data, writer->next, wtype, buf, wlen);
CURL_TRC_WRITE(data, "[PAUSE] writing %zu/%zu bytes of type %x -> %d",
wlen, blen, wtype, result);
wlen, blen, (unsigned int)wtype, (int)result);
if(result)
return result;
buf += wlen;
@@ -191,8 +193,8 @@ static CURLcode cw_pause_write(struct Curl_easy *data,
result = Curl_bufq_cwrite(&ctx->buf->b, buf, blen, &nwritten);
}
CURL_TRC_WRITE(data, "[PAUSE] buffer %zu more bytes of type %x, "
"total=%zu -> %d", nwritten, type, ctx->buf_total + wlen,
result);
"total=%zu -> %d", nwritten, (unsigned int)type,
ctx->buf_total + wlen, (int)result);
if(result)
return result;
buf += nwritten;
+1 -1
View File
@@ -148,7 +148,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
*done = TRUE; /* unconditionally */
/* url-decode path before further evaluation */
/* URL-decode path before further evaluation */
result = Curl_urldecode(data->state.up.path, 0, &path, NULL, REJECT_CTRL);
if(result)
return result;
+1 -1
View File
@@ -31,7 +31,7 @@
#if defined(_WIN32) && !defined(CURL_STATICLIB)
#if defined(USE_OPENSSL) && \
!defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) && \
!defined(OPENSSL_IS_AWSLC) && !defined(OPENSSL_IS_BORINGSSL) && \
!defined(LIBRESSL_VERSION_NUMBER)
#define PREVENT_OPENSSL_MEMLEAK
#endif
+3 -17
View File
@@ -351,7 +351,7 @@ UNITTEST CURLcode dns_shuffle_addr(struct Curl_easy *data,
if(num_addrs > 1) {
struct Curl_addrinfo **nodes;
CURL_TRC_DNS(data, "Shuffling %i addresses", num_addrs);
CURL_TRC_DNS(data, "Shuffling %d addresses", num_addrs);
nodes = curlx_malloc(num_addrs * sizeof(*nodes));
if(nodes) {
@@ -616,20 +616,6 @@ CURLcode Curl_dnscache_add_negative(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
struct Curl_dns_entry *Curl_dns_entry_link(struct Curl_easy *data,
struct Curl_dns_entry *dns)
{
if(!dns)
return NULL;
else {
struct Curl_dnscache *dnscache = dnscache_get(data);
dnscache_lock(data, dnscache);
dns->refcount++;
dnscache_unlock(data, dnscache);
return dns;
}
}
/*
* Curl_dns_entry_unlink() releases a reference to the given cached DNS entry.
* When the reference count reaches 0, the entry is destroyed. It is important
@@ -789,7 +775,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
result = Curl_str2addr(address, port, &ai);
if(result) {
infof(data, "Resolve address '%s' found illegal", address);
infof(data, "Resolve IP address '%s' found is illegal", address);
goto err;
}
@@ -842,7 +828,7 @@ err:
Curl_hash_delete(&dnscache->entries, entry_id, entry_len + 1);
}
/* put this new host in the cache, an overridy for ALL dns queries */
/* put this new host in the cache, an override for ALL dns queries */
dns = dnscache_add_addr(data, dnscache, CURL_DNSQ_ALL,
&head, curlx_str(&source),
curlx_strlen(&source), port, permanent);
-5
View File
@@ -80,11 +80,6 @@ void Curl_dns_entry_set_https_rr(struct Curl_dns_entry *dns,
struct Curl_https_rrinfo *hinfo);
#endif /* USE_HTTPSRR */
/* Increase the ref counter and return it for storing in another place.
* May be called with NULL, in which case it returns NULL. */
struct Curl_dns_entry *Curl_dns_entry_link(struct Curl_easy *data,
struct Curl_dns_entry *dns);
/* unlink a dns entry, frees all resources if it was the last reference.
* Always clears `*pdns`` */
void Curl_dns_entry_unlink(struct Curl_easy *data,
+18 -5
View File
@@ -259,7 +259,6 @@ static void doh_probe_done(struct Curl_easy *data,
result = curlx_dyn_addn(&dohp->probe_resp[i].body,
curlx_dyn_ptr(&doh_req->resp_body),
curlx_dyn_len(&doh_req->resp_body));
curlx_dyn_free(&doh_req->resp_body);
}
Curl_meta_remove(doh, CURL_EZM_DOH_PROBE);
@@ -319,7 +318,7 @@ static CURLcode doh_probe_run(struct Curl_easy *data,
sizeof(doh_req->req_body),
&doh_req->req_body_len);
if(d) {
failf(data, "Failed to encode DoH packet [%d]", d);
failf(data, "Failed to encode DoH packet [%d]", (int)d);
result = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -418,7 +417,8 @@ static CURLcode doh_probe_run(struct Curl_easy *data,
}
(void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS,
(long)data->set.ssl.primary.ssl_options);
((long)data->set.ssl.primary.ssl_options &
~CURLSSLOPT_AUTO_CLIENT_CERT));
doh->state.internal = TRUE;
doh->master_mid = data->mid; /* master transfer of this one */
@@ -724,7 +724,9 @@ UNITTEST void de_init(struct dohentry *de)
curlx_dyn_init(&de->cname[i], DYN_DOH_CNAME);
}
/* @unittest 1655 */
/* TTL value cap */
#define MAX_DNS_TTL 86400U /* 24 hours */
/* @unittest 1650 */
UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
size_t dohlen,
DNStype dnstype,
@@ -794,6 +796,8 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
return DOH_DNS_OUT_OF_RANGE;
ttl = doh_get32bit(doh, index);
if(ttl > MAX_DNS_TTL)
ttl = MAX_DNS_TTL;
if(ttl < d->ttl)
d->ttl = ttl;
index += 4;
@@ -1087,10 +1091,14 @@ static CURLcode doh_decode_rdata_name(const unsigned char **buf,
DEBUGASSERT(buf && remaining && dnsname);
if(!buf || !remaining || !dnsname || !*remaining)
return CURLE_OUT_OF_MEMORY;
curlx_dyn_init(&thename, CURL_MAXLEN_host_name);
curlx_dyn_init(&thename, CURL_MAXLEN_HOST_NAME);
rem = *remaining;
cp = *buf;
clen = *cp++;
/* RFC 9460 says it must be uncompressed */
if(clen > 63)
return CURLE_WEIRD_SERVER_REPLY;
if(clen == 0) {
/* special case - return "." as name */
if(curlx_dyn_addn(&thename, ".", 1))
@@ -1112,6 +1120,11 @@ static CURLcode doh_decode_rdata_name(const unsigned char **buf,
return CURLE_OUT_OF_MEMORY;
}
clen = *cp++;
if(clen > 63) {
/* invalid format */
curlx_dyn_free(&thename);
return CURLE_WEIRD_SERVER_REPLY;
}
}
*buf = cp;
*remaining = rem - 1;
-1
View File
@@ -167,7 +167,6 @@ void Curl_doh_cleanup(struct Curl_easy *data,
struct Curl_resolv_async *async);
#define Curl_doh_wanted(d) (!!(d)->set.doh)
#else /* CURL_DISABLE_DOH */
#define Curl_doh(a, b) NULL
#define Curl_doh_take_result(x, y, z) CURLE_COULDNT_RESOLVE_HOST
+8 -3
View File
@@ -78,8 +78,8 @@
#include "easy_lock.h"
/* true globals -- for curl_global_init() and curl_global_cleanup() */
static unsigned int initialized;
static long easy_init_flags;
static unsigned int initialized;
static long easy_init_flags;
#ifdef GLOBAL_INIT_IS_THREADSAFE
@@ -942,7 +942,7 @@ static void dupeasy_meta_freeentry(void *p)
/* Always FALSE. Cannot use a 0 assert here since compilers
* are not in agreement if they then want a NORETURN attribute or
* not. *sigh* */
DEBUGASSERT(p == NULL);
DEBUGASSERT(!p);
}
/*
@@ -1052,6 +1052,11 @@ CURL *curl_easy_duphandle(CURL *curl)
(void)Curl_hsts_loadfile(outcurl,
outcurl->hsts, outcurl->set.str[STRING_HSTS]);
(void)Curl_hsts_loadcb(outcurl, outcurl->hsts);
/* Copy entries learned at runtime. (E.g. Strict-Transport-Security
headers.) */
if(Curl_hsts_copy(outcurl->hsts, data->hsts))
goto fail;
}
#endif
+1 -1
View File
@@ -64,7 +64,7 @@ static struct addrinfo *mk_getaddrinfo(const struct ares_addrinfo *aihead)
const char *name = aihead->name;
/* traverse the addrinfo list */
for(ai = aihead->nodes; ai != NULL; ai = ai->ai_next) {
for(ai = aihead->nodes; ai; ai = ai->ai_next) {
size_t ss_size;
size_t namelen = name ? strlen(name) + 1 : 0;
/* ignore elements with unsupported address family,
+3 -3
View File
@@ -154,7 +154,7 @@ static void AddFormInfo(struct FormInfo *form_info, struct FormInfo *parent)
static void free_formlist(struct FormInfo *ptr)
{
for(; ptr != NULL; ptr = ptr->more) {
for(; ptr; ptr = ptr->more) {
Curl_bufref_free(&ptr->name);
Curl_bufref_free(&ptr->value);
Curl_bufref_free(&ptr->contenttype);
@@ -184,7 +184,7 @@ static void free_formlist(struct FormInfo *ptr)
*
* name/value pair where only the content pointer is remembered:
* curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",
* CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10,
* CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10L,
* CURLFORM_END);
* (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
*
@@ -223,7 +223,7 @@ static CURLFORMcode FormAddCheck(struct FormInfo *first_form,
/* go through the list, check for completeness and if everything is
* alright add the HttpPost item otherwise set retval accordingly */
for(form = first_form; form != NULL; form = form->more) {
for(form = first_form; form; form = form->more) {
const char *name = Curl_bufref_ptr(&form->name);
if(((!name || !Curl_bufref_ptr(&form->value)) && !post) ||
+2 -2
View File
@@ -113,10 +113,10 @@ struct ftp_conn {
char *account;
char *alternative_to_user;
char *entrypath; /* the PWD reply when we logged on */
const char *file; /* url-decoded filename (or path), points into rawpath */
const char *file; /* URL-decoded filename (or path), points into rawpath */
char *rawpath; /* URL decoded, allocated, version of the path */
struct pathcomp *dirs; /* allocated array for path components */
char *prevpath; /* url-decoded conn->path from the previous transfer */
char *prevpath; /* URL-decoded conn->path from the previous transfer */
char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
and others (A/I or zero) */
char *server_os; /* The target server operating system. */
+152 -153
View File
@@ -355,7 +355,6 @@ static void close_secondarysocket(struct Curl_easy *data,
{
(void)ftpc;
CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_CSTATE(ftpc));
Curl_conn_close(data, SECONDARYSOCKET);
Curl_conn_cf_discard_all(data, data->conn, SECONDARYSOCKET);
}
@@ -733,7 +732,7 @@ static CURLcode getftpresponse(struct Curl_easy *data,
pp->pending_resp = FALSE;
CURL_TRC_FTP(data, "getftpresponse -> result=%d, nread=%zu, ftpcode=%d",
result, *nreadp, *ftpcodep);
(int)result, *nreadp, *ftpcodep);
return result;
}
@@ -743,7 +742,7 @@ static CURLcode ftp_state_user(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = Curl_pp_sendf(data, &ftpc->pp, "USER %s",
conn->user ? conn->user : "");
Curl_creds_user(conn->creds));
if(!result) {
ftpc->ftp_trying_alternative = FALSE;
ftp_state(data, ftpc, FTP_USER);
@@ -1084,7 +1083,7 @@ static CURLcode ftp_port_open_socket(struct Curl_easy *data,
curl_socket_t *portsockp)
{
char buffer[STRERROR_LEN];
int error = 0;
int sockerr = 0;
const struct Curl_addrinfo *ai;
CURLcode result = CURLE_FTP_PORT_FAILED;
@@ -1096,14 +1095,14 @@ static CURLcode ftp_port_open_socket(struct Curl_easy *data,
if(result == CURLE_OUT_OF_MEMORY)
return result;
result = CURLE_FTP_PORT_FAILED;
error = SOCKERRNO;
sockerr = SOCKERRNO;
continue;
}
break;
}
if(!ai) {
failf(data, "socket failure: %s",
curlx_strerror(error, buffer, sizeof(buffer)));
curlx_strerror(sockerr, buffer, sizeof(buffer)));
return CURLE_FTP_PORT_FAILED;
}
*aip = ai;
@@ -1132,7 +1131,7 @@ static CURLcode ftp_port_bind_socket(struct Curl_easy *data,
#endif
char buffer[STRERROR_LEN];
unsigned short port;
int error;
int sockerr;
memcpy(sa, ai->ai_addr, ai->ai_addrlen);
*sslen_io = ai->ai_addrlen;
@@ -1145,13 +1144,13 @@ static CURLcode ftp_port_bind_socket(struct Curl_easy *data,
sa6->sin6_port = htons(port);
#endif
if(bind(portsock, sa, *sslen_io)) {
error = SOCKERRNO;
if(non_local && (error == SOCKEADDRNOTAVAIL)) {
sockerr = SOCKERRNO;
if(non_local && (sockerr == SOCKEADDRNOTAVAIL)) {
/* The requested bind address is not local. Use the address used for
* the control connection instead and restart the port loop.
*/
infof(data, "bind(port=%hu) on non-local address failed: %s", port,
curlx_strerror(error, buffer, sizeof(buffer)));
curlx_strerror(sockerr, buffer, sizeof(buffer)));
*sslen_io = sizeof(*ss);
if(getsockname(conn->sock[FIRSTSOCKET], sa, sslen_io)) {
@@ -1163,9 +1162,9 @@ static CURLcode ftp_port_bind_socket(struct Curl_easy *data,
non_local = FALSE; /* do not try this again */
continue;
}
if(error != SOCKEADDRINUSE && error != SOCKEACCES) {
if(sockerr != SOCKEADDRINUSE && sockerr != SOCKEACCES) {
failf(data, "bind(port=%hu) failed: %s", port,
curlx_strerror(error, buffer, sizeof(buffer)));
curlx_strerror(sockerr, buffer, sizeof(buffer)));
return CURLE_FTP_PORT_FAILED;
}
}
@@ -1188,8 +1187,7 @@ static CURLcode ftp_port_bind_socket(struct Curl_easy *data,
curlx_strerror(SOCKERRNO, buffer, sizeof(buffer)));
return CURLE_FTP_PORT_FAILED;
}
CURL_TRC_FTP(data, "ftp_port_bind_socket(), socket bound to port %d",
port);
CURL_TRC_FTP(data, "ftp_port_bind_socket(), socket bound to port %d", port);
return CURLE_OK;
}
@@ -1276,8 +1274,7 @@ static CURLcode ftp_port_send_command(struct Curl_easy *data,
* EPRT |2|1080::8:800:200C:417A|5282|
*/
result = Curl_pp_sendf(data, &ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
sa->sa_family == AF_INET ? 1 : 2,
myhost, port);
sa->sa_family == AF_INET ? 1 : 2, myhost, port);
if(result) {
failf(data, "Failure sending EPRT command: %s",
curl_easy_strerror(result));
@@ -1393,10 +1390,13 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
ftp_state(data, ftpc, FTP_STOP);
}
else {
/* successfully set up the listen socket filter. SSL needed? */
/* successfully set up the listen socket filter. SSL needed?
* Use the control connections origin for cert verification. */
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);
result = Curl_ssl_cfilter_add(
data, Curl_conn_get_origin(conn, FIRSTSOCKET),
conn, SECONDARYSOCKET);
}
conn->bits.do_more = FALSE;
Curl_pgrsTime(data, TIMER_STARTACCEPT);
@@ -1983,11 +1983,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
if(conn->bits.ipv6
#ifndef CURL_DISABLE_PROXY
&& !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
#endif
) {
if(conn->bits.ipv6 && !Curl_conn_is_tunneling(conn, FIRSTSOCKET)) {
/* We cannot disable EPSV when doing IPv6, so this is instead a fail */
failf(data, "Failed EPSV attempt, exiting");
return CURLE_WEIRD_SERVER_REPLY;
@@ -2019,8 +2015,8 @@ static CURLcode ftp_control_addr_dup(struct Curl_easy *data, char **newhostp)
the effective control connection address is the proxy address,
not the ftp host. */
#ifndef CURL_DISABLE_PROXY
if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
*newhostp = curlx_strdup(conn->host.name);
if(Curl_conn_is_tunneling(conn, FIRSTSOCKET))
*newhostp = curlx_strdup(conn->origin->hostname);
else
#endif
if(!Curl_conn_get_ip_info(data, conn, FIRSTSOCKET, &is_ipv6, &ipquad) &&
@@ -2059,8 +2055,6 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
{
struct connectdata *conn = data->conn;
CURLcode result;
struct Curl_dns_entry *dns = NULL;
unsigned short connectport; /* the local port connect() should use! */
const struct pingpong *pp = &ftpc->pp;
char *newhost = NULL;
unsigned short newport = 0;
@@ -2075,7 +2069,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
ptr++;
/* |||12345| */
sep = ptr[0];
if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) {
if(sep && (ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) {
const char *p = &ptr[3];
curl_off_t num;
if(curlx_str_number(&p, &num, 0xffff) || (*p != sep)) {
@@ -2125,7 +2119,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
/* told to ignore the remotely given IP but instead use the host we used
for the control connection */
infof(data, "Skip %u.%u.%u.%u for data connection, reuse %s instead",
ip[0], ip[1], ip[2], ip[3], conn->host.name);
ip[0], ip[1], ip[2], ip[3], conn->origin->hostname);
result = ftp_control_addr_dup(data, &newhost);
if(result)
return result;
@@ -2147,67 +2141,25 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
return CURLE_FTP_WEIRD_PASV_REPLY;
}
#ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy) {
/* This connection uses a proxy and we need to connect to the proxy again
* here. We do not want to rely on a former host lookup that might have
* expired now, instead we remake the lookup here and now! */
struct ip_quadruple ipquad;
bool is_ipv6;
const char * const host_name = conn->bits.socksproxy ?
conn->socks_proxy.host.name : conn->http_proxy.host.name;
DEBUGASSERT(newhost);
Curl_peer_unlink(&conn->origin2);
result = Curl_peer_create(data, conn->scheme, newhost, newport,
&conn->origin2);
if(result)
goto error;
result = Curl_conn_get_ip_info(data, data->conn, FIRSTSOCKET,
&is_ipv6, &ipquad);
/* If FIRSTSOCKET goes via another peer, SECONDARY needs as well,
* but with its new port. */
if(conn->via_peer) {
Curl_peer_unlink(&conn->via_peer2);
result = Curl_peer_create(data, conn->via_peer->scheme,
conn->via_peer->hostname, newport,
&conn->via_peer2);
if(result)
goto error;
(void)Curl_resolv_blocking(
data, is_ipv6 ? CURL_DNSQ_AAAA : CURL_DNSQ_A,
host_name, ipquad.remote_port, Curl_conn_get_transport(data, conn),
&dns);
/* we connect to the proxy's port */
connectport = (unsigned short)ipquad.remote_port;
if(!dns) {
failf(data, "cannot resolve proxy host %s:%hu", host_name, connectport);
result = CURLE_COULDNT_RESOLVE_PROXY;
goto error;
}
}
else
#endif
{
/* normal, direct, ftp connection */
DEBUGASSERT(newhost);
/* postponed address resolution in case of tcp fastopen */
if(conn->bits.tcp_fastopen && !conn->bits.reuse && !newhost[0]) {
curlx_free(newhost);
result = ftp_control_addr_dup(data, &newhost);
if(result)
goto error;
}
(void)Curl_resolv_blocking(
data, Curl_resolv_dns_queries(data, conn->ip_version),
newhost, newport, Curl_conn_get_transport(data, conn), &dns);
connectport = newport; /* we connect to the remote port */
if(!dns) {
failf(data, "cannot resolve new host %s:%hu", newhost, connectport);
result = CURLE_FTP_CANT_GET_HOST;
goto error;
}
}
DEBUGASSERT(newhost);
curlx_free(conn->secondaryhostname);
conn->secondary_port = newport;
conn->secondaryhostname = newhost;
newhost = NULL;
result = Curl_conn_setup(data, conn, SECONDARYSOCKET, dns,
result = Curl_conn_setup(data, conn, SECONDARYSOCKET,
conn->bits.ftp_use_data_ssl ?
CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
@@ -2227,13 +2179,10 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
#ifdef CURLVERBOSE
if(data->set.verbose) {
/* Dump information about this second connection when we have issued a PASV
* command before and thus we have connected to a possibly new IP address.
*/
char buf[256];
Curl_printable_address(dns->addr, buf, sizeof(buf));
infof(data, "Connecting to %s (%s) port %d",
conn->secondaryhostname, buf, connectport);
/* Dump information about this second connection when we have issued
* a PASV command. */
infof(data, "Connecting to %s port %d",
conn->origin2->hostname, conn->origin2->port);
}
#endif
@@ -2241,7 +2190,6 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
ftp_state(data, ftpc, FTP_STOP); /* this phase is completed */
error:
Curl_dns_entry_unlink(data, &dns);
curlx_free(newhost);
return result;
}
@@ -2267,10 +2215,10 @@ static CURLcode ftp_statemach(struct Curl_easy *data,
* This function shall be called when the second FTP (data) connection is
* connected.
*
* 'complete' can return 0 for incomplete, 1 for done and -1 for go back
* 'more' can return DOMORE_INCOMPLETE, DOMORE_DONE or DOMORE_GOBACK
* (which is for when PASV is being sent to retry a failed EPSV).
*/
static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
static CURLcode ftp_do_more(struct Curl_easy *data, domore *more)
{
struct connectdata *conn = data->conn;
struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN);
@@ -2285,7 +2233,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(!ftpc || !ftp)
return CURLE_FAILED_INIT;
*completep = 0; /* default to stay in the state */
*more = DOMORE_INCOMPLETE; /* default to stay in the state */
/* if the second connection has been set up, try to connect it fully
* to the remote host. This may not complete at this time, for several
@@ -2303,7 +2251,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(result || (!connected && !is_eptr &&
!Curl_conn_is_ip_connected(data, SECONDARYSOCKET))) {
if(result && !is_eptr && (ftpc->count1 == 0)) {
*completep = -1; /* go back to DOING please */
*more = DOMORE_GOBACK; /* go back to DOING please */
/* this is a EPSV connect failing, try PASV instead */
return ftp_epsv_disable(data, ftpc, conn);
}
@@ -2316,7 +2264,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
They are only done to kickstart the do_more state */
result = ftp_statemach(data, ftpc, &complete);
*completep = (int)complete;
if(complete)
*more = DOMORE_DONE;
/* if we got an error or if we do not wait for a data connection return
immediately */
@@ -2326,7 +2275,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
/* if we reach the end of the FTP state machine here, *complete will be
TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
data connection and therefore we are not actually complete */
*completep = 0;
*more = DOMORE_INCOMPLETE;
}
if(ftp->transfer <= PPTRANSFER_INFO) {
@@ -2348,8 +2297,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(result)
return result;
*completep = 1; /* this state is now complete when the server has
connected back to us */
*more = DOMORE_DONE; /* this state is now complete when the server has
connected back to us */
}
else {
result = ftp_check_ctrl_on_data_wait(data, ftpc);
@@ -2368,7 +2317,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
* deemed necessary and directly sent `STORE name`. If this was
* then complete, but we are still waiting on the data connection,
* the transfer has not been initiated yet. */
*completep = (int)(ftpc->wait_data_conn ? 0 : complete);
*more = (!ftpc->wait_data_conn && complete) ?
DOMORE_DONE : DOMORE_INCOMPLETE;
}
else {
/* download */
@@ -2411,7 +2361,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
}
result = ftp_statemach(data, ftpc, &complete);
*completep = (int)complete;
if(complete)
*more = DOMORE_DONE;
}
return result;
}
@@ -2421,7 +2372,7 @@ 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;
*more = DOMORE_DONE;
CURL_TRC_FTP(data, "[%s] DO-MORE phase ends with %d", FTP_CSTATE(ftpc),
(int)result);
}
@@ -2436,7 +2387,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data,
bool connected)
{
if(connected) {
int completed;
domore completed;
CURLcode result = ftp_do_more(data, &completed);
if(result) {
@@ -2950,7 +2901,7 @@ static CURLcode ftp_state_loggedin(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
if(data->conn->bits.ftp_use_control_ssl) {
if(Curl_conn_is_ssl(data->conn, FIRSTSOCKET)) {
/* PBSZ = PROTECTION BUFFER SIZE.
The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
@@ -2986,7 +2937,8 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data,
if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
/* 331 Password required for ...
(the server requires to send the user's password too) */
result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s", data->conn->passwd);
result = Curl_pp_sendf(data, &ftpc->pp, "PASS %s",
Curl_creds_passwd(data->conn->creds));
if(!result)
ftp_state(data, ftpc, FTP_PASS);
}
@@ -3161,8 +3113,8 @@ static CURLcode ftp_wait_resp(struct Curl_easy *data,
CURLcode result = CURLE_OK;
if(ftpcode == 230) {
/* 230 User logged in - already! Take as 220 if TLS required. */
if(data->set.use_ssl <= CURLUSESSL_TRY ||
conn->bits.ftp_use_control_ssl)
if(ftpc->use_ssl <= CURLUSESSL_TRY ||
Curl_conn_is_ssl(conn, FIRSTSOCKET))
return ftp_state_user_resp(data, ftpc, ftpcode);
}
else if(ftpcode != 220) {
@@ -3171,7 +3123,7 @@ static CURLcode ftp_wait_resp(struct Curl_easy *data,
return CURLE_WEIRD_SERVER_REPLY;
}
if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
if(ftpc->use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
/* We do not have an SSL/TLS control connection yet, but FTPS is
requested. Try an FTPS connection now */
@@ -3243,16 +3195,17 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
/* this was BLOCKING, keep it so for now */
bool done;
if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
result = Curl_ssl_cfilter_add(
data, Curl_conn_get_origin(conn, FIRSTSOCKET), conn, FIRSTSOCKET);
if(result) {
/* we failed and bail out */
return CURLE_USE_SSL_FAILED;
}
}
/* BLOCKING */
result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, &done);
if(!result) {
conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */
result = ftp_state_user(data, ftpc, conn);
}
}
@@ -3264,7 +3217,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
/* remain in this same state */
}
else {
if(data->set.use_ssl > CURLUSESSL_TRY)
if(ftpc->use_ssl > CURLUSESSL_TRY)
/* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
result = CURLE_USE_SSL_FAILED;
else
@@ -3285,7 +3238,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
case FTP_PBSZ:
result =
Curl_pp_sendf(data, &ftpc->pp, "PROT %c",
data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
ftpc->use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
if(!result)
ftp_state(data, ftpc, FTP_PROT);
break;
@@ -3293,10 +3246,10 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
case FTP_PROT:
if(ftpcode / 100 == 2)
/* We have enabled SSL for the data connection! */
conn->bits.ftp_use_data_ssl = (data->set.use_ssl != CURLUSESSL_CONTROL);
conn->bits.ftp_use_data_ssl = (ftpc->use_ssl != CURLUSESSL_CONTROL);
/* FTP servers typically responds with 500 if they decide to reject
our 'P' request */
else if(data->set.use_ssl > CURLUSESSL_CONTROL)
else if(ftpc->use_ssl > CURLUSESSL_CONTROL)
/* we failed and bails out */
return CURLE_USE_SSL_FAILED;
@@ -3572,7 +3525,6 @@ static CURLcode ftp_connect(struct Curl_easy *data,
result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
if(result)
return result;
conn->bits.ftp_use_control_ssl = TRUE;
}
Curl_pp_init(pp, Curl_pgrs_now(data)); /* once per transfer */
@@ -3641,30 +3593,10 @@ static CURLcode ftp_sendquote(struct Curl_easy *data,
return CURLE_OK;
}
/***********************************************************************
*
* ftp_done()
*
* The DONE function. This does what needs to be done after a single DO has
* performed.
*
* Input argument is already checked for validity.
*/
static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
bool premature)
static CURLcode ftp_done_status(struct connectdata *conn,
struct ftp_conn *ftpc, CURLcode status,
bool premature)
{
struct connectdata *conn = data->conn;
struct FTP *ftp = Curl_meta_get(data, CURL_META_FTP_EASY);
struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN);
struct pingpong *pp;
size_t nread;
int ftpcode;
CURLcode result = CURLE_OK;
if(!ftp || !ftpc)
return CURLE_OK;
pp = &ftpc->pp;
switch(status) {
case CURLE_BAD_DOWNLOAD_RESUME:
case CURLE_FTP_WEIRD_PASV_REPLY:
@@ -3693,10 +3625,13 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
current path, as this connection is going */
connclose(conn, "FTP ended with bad error code");
result = status; /* use the already set error code */
break;
return status; /* use the already set error code */
}
return CURLE_OK;
}
static void ftp_done_wildcard(struct Curl_easy *data, struct ftp_conn *ftpc)
{
if(data->state.wildcardmatch) {
if(data->set.chunk_end && ftpc->file) {
Curl_set_in_callback(data, TRUE);
@@ -3706,14 +3641,18 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
}
ftpc->known_filesize = -1;
}
}
static void ftp_done_path(struct Curl_easy *data, struct ftp_conn *ftpc,
CURLcode result)
{
struct connectdata *conn = data->conn;
if(result) {
/* We can limp along anyway (and should try to since we may already be in
* the error path) */
ftpc->ctl_valid = FALSE; /* mark control connection as bad */
connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
curlx_free(ftpc->prevpath);
ftpc->prevpath = NULL; /* no path remembering */
curlx_safefree(ftpc->prevpath); /* no path remembering */
}
else { /* remember working directory for connection reuse */
const char *rawPath = ftpc->rawpath;
@@ -3740,13 +3679,17 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
if(ftpc->prevpath)
infof(data, "Remembering we are in directory \"%s\"", ftpc->prevpath);
}
}
/* shut down the socket to inform the server we are done */
static CURLcode ftp_done_secondary_socket(struct Curl_easy *data,
struct ftp_conn *ftpc,
CURLcode result)
{
struct connectdata *conn = data->conn;
if(Curl_conn_is_setup(conn, SECONDARYSOCKET)) {
if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
/* partial download completed */
result = Curl_pp_sendf(data, pp, "%s", "ABOR");
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "ABOR");
if(result) {
failf(data, "Failure sending ABOR command: %s",
curl_easy_strerror(result));
@@ -3757,16 +3700,27 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
close_secondarysocket(data, ftpc);
}
return result;
}
static CURLcode ftp_done_control_reply(struct Curl_easy *data,
struct ftp_conn *ftpc,
struct FTP *ftp, CURLcode result,
bool premature)
{
struct connectdata *conn = data->conn;
size_t nread;
int ftpcode;
if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
pp->pending_resp && !premature) {
ftpc->pp.pending_resp && !premature) {
/*
* Let's see what the server says about the transfer we performed, but
* lower the timeout as sometimes this connection has died while the data
* has been transferred. This happens when doing through NATs etc that
* abandon old silent connections.
*/
pp->response = *Curl_pgrs_now(data); /* timeout relative now */
ftpc->pp.response = *Curl_pgrs_now(data); /* timeout relative now */
result = getftpresponse(data, &nread, &ftpcode);
if(!nread && (result == CURLE_OPERATION_TIMEDOUT)) {
@@ -3803,7 +3757,14 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
}
}
}
return result;
}
static CURLcode ftp_done_check_partial(struct Curl_easy *data,
struct ftp_conn *ftpc,
struct FTP *ftp, CURLcode result,
bool premature)
{
if(result || premature)
/* the response code from the transfer showed an error already so no
use checking further */
@@ -3837,6 +3798,35 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
result = CURLE_FTP_COULDNT_RETR_FILE;
}
}
return result;
}
/***********************************************************************
*
* ftp_done()
*
* The DONE function. This does what needs to be done after a single DO has
* performed.
*
* Input argument is already checked for validity.
*/
static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
bool premature)
{
struct FTP *ftp = Curl_meta_get(data, CURL_META_FTP_EASY);
struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN);
CURLcode result;
if(!ftp || !ftpc)
return CURLE_OK;
result = ftp_done_status(data->conn, ftpc, status, premature);
ftp_done_wildcard(data, ftpc);
ftp_done_path(data, ftpc, result);
result = ftp_done_secondary_socket(data, ftpc, result);
result = ftp_done_control_reply(data, ftpc, ftp, result, premature);
result = ftp_done_check_partial(data, ftpc, ftp, result, premature);
/* clear these for next connection */
ftp->transfer = PPTRANSFER_BODY;
@@ -3845,7 +3835,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, ftpc, data->set.postquote);
CURL_TRC_FTP(data, "[%s] done, result=%d", FTP_CSTATE(ftpc), result);
CURL_TRC_FTP(data, "[%s] done, result=%d", FTP_CSTATE(ftpc), (int)result);
return result;
}
@@ -4455,7 +4445,8 @@ 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(ftpc), result);
CURL_TRC_FTP(data, "[%s] setup connection -> %d", FTP_CSTATE(ftpc),
(int)result);
return result;
}
@@ -4463,14 +4454,22 @@ bool ftp_conns_match(struct connectdata *needle, struct connectdata *conn)
{
struct ftp_conn *nftpc = Curl_conn_meta_get(needle, CURL_META_FTP_CONN);
struct ftp_conn *cftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN);
/* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
/* Also match ACCOUNT, ALTERNATIVE-TO-USER and CCC options */
if(!nftpc || !cftpc ||
Curl_timestrcmp(nftpc->account, cftpc->account) ||
Curl_timestrcmp(nftpc->alternative_to_user,
cftpc->alternative_to_user) ||
(nftpc->use_ssl != cftpc->use_ssl) ||
(nftpc->ccc != cftpc->ccc))
return FALSE;
/* A mismatch on `use_ssl` MUST have been found in connection matching
* before we come here. This is a check on MAYBE/MUST use of STARTTLS and
* it only works on FTP. But IMAP/SMTP etc have the same `use_ssl` and
* no extra match like FTP. We lack tests in this area, so let FTP fail
* loudly here to help other cases. */
if(nftpc->use_ssl > cftpc->use_ssl) {
DEBUGASSERT(0);
return FALSE;
}
return TRUE;
}
+7 -8
View File
@@ -196,13 +196,11 @@ void Curl_wildcard_dtor(struct WildcardData **wcp)
wc->dtor = ZERO_NULL;
wc->ftpwc = NULL;
}
DEBUGASSERT(wc->ftpwc == NULL);
DEBUGASSERT(!wc->ftpwc);
Curl_llist_destroy(&wc->filelist, NULL);
curlx_free(wc->path);
wc->path = NULL;
curlx_free(wc->pattern);
wc->pattern = NULL;
curlx_safefree(wc->path);
curlx_safefree(wc->pattern);
wc->state = CURLWC_INIT;
curlx_free(wc);
*wcp = NULL;
@@ -312,8 +310,9 @@ static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
str + parser->offsets.group : NULL;
finfo->strings.perm = parser->offsets.perm ?
str + parser->offsets.perm : NULL;
finfo->strings.target = parser->offsets.symlink_target ?
str + parser->offsets.symlink_target : NULL;
finfo->strings.target = parser->offsets.symlink_target &&
(finfo->filetype == CURLFILETYPE_SYMLINK) ?
str + parser->offsets.symlink_target : NULL;
finfo->strings.time = str + parser->offsets.time;
finfo->strings.user = parser->offsets.user ?
str + parser->offsets.user : NULL;
@@ -940,7 +939,7 @@ static CURLcode parse_winnt(struct Curl_easy *data,
parser->item_length++;
if(c == ' ') {
mem[parser->item_offset + parser->item_length - 1] = 0;
if(strcmp("<DIR>", mem + parser->item_offset) == 0) {
if(!strcmp("<DIR>", mem + parser->item_offset)) {
finfo->filetype = CURLFILETYPE_DIRECTORY;
finfo->size = 0;
}
+1 -1
View File
@@ -48,7 +48,7 @@
#define SEND_TYPE_ARG3 int
#define SEND_TYPE_RETV int
#elif defined(__AMIGA__) /* Any AmigaOS flavour */
#elif defined(__AMIGA__) /* Any AmigaOS flavor */
/* long recv(long, char *, long, long); */
#define RECV_TYPE_ARG1 long
+2 -5
View File
@@ -67,11 +67,8 @@ void Curl_initinfo(struct Curl_easy *data)
info->httpauthpicked = 0;
info->numconnects = 0;
curlx_free(info->contenttype);
info->contenttype = NULL;
curlx_free(info->wouldredirect);
info->wouldredirect = NULL;
curlx_safefree(info->contenttype);
curlx_safefree(info->wouldredirect);
memset(&info->primary, 0, sizeof(info->primary));
info->retry_after = 0;
+1 -1
View File
@@ -133,7 +133,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
if(!timeout_ms)
timeout_ms = TIMEDIFF_T_MAX;
/* Do not busyloop. The entire loop thing is a work-around as it causes a
/* Do not busyloop. The entire loop thing is a workaround as it causes a
BLOCKING behavior which is a NO-NO. This function should rather be
split up in a do and a doing piece where the pieces that are not
possible to send now will be sent in the doing function repeatedly
+1 -1
View File
@@ -305,7 +305,7 @@ static CURLcode hds_cw_collect_write(struct Curl_easy *data,
CURLH_HEADER)));
CURLcode result = Curl_headers_push(data, buf, blen, htype);
CURL_TRC_WRITE(data, "header_collect pushed(type=%x, len=%zu) -> %d",
htype, blen, result);
htype, blen, (int)result);
if(result)
return result;
}
+44 -45
View File
@@ -70,10 +70,6 @@
#define USE_ALARM_TIMEOUT
#endif
#define MAX_HOSTCACHE_LEN (255 + 7) /* max FQDN + colon + port number + zero */
#define MAX_DNS_CACHE_SIZE 29999
#define RESOLV_FAIL(for_proxy) \
((for_proxy) ? CURLE_COULDNT_RESOLVE_PROXY : CURLE_COULDNT_RESOLVE_HOST)
@@ -511,7 +507,6 @@ const struct Curl_addrinfo *Curl_resolv_get_ai(struct Curl_easy *data,
return Curl_async_get_ai(data, async, ai_family, index);
}
#ifdef USE_HTTPSRR
const struct Curl_https_rrinfo *
Curl_resolv_get_https(struct Curl_easy *data, uint32_t resolv_id)
@@ -529,7 +524,6 @@ bool Curl_resolv_knows_https(struct Curl_easy *data, uint32_t resolv_id)
return TRUE;
return Curl_async_knows_https(data, async);
}
#endif /* USE_HTTPSRR */
#endif /* USE_CURL_ASYNC */
@@ -740,7 +734,7 @@ out:
failf(data, "Could not resolve: %s:%u", hostname, port);
}
else {
failf(data, "Error %d resolving %s:%u", result, hostname, port);
failf(data, "Error %d resolving %s:%u", (int)result, hostname, port);
}
}
else if(cache_dns && *pdns) {
@@ -795,9 +789,6 @@ CURL_NORETURN static void alarmfunc(int sig)
(void)sig;
siglongjmp(curl_jmpenv, 1);
}
#endif /* USE_ALARM_TIMEOUT */
#ifdef USE_ALARM_TIMEOUT
static CURLcode resolv_alarm_timeout(struct Curl_easy *data,
uint8_t dns_queries,
@@ -935,6 +926,33 @@ clean_up:
#endif /* USE_ALARM_TIMEOUT */
#ifdef USE_UNIX_SOCKETS
static CURLcode resolv_unix(struct Curl_easy *data,
const char *unix_path,
bool abstract_path,
struct Curl_dns_entry **pdns)
{
struct Curl_addrinfo *addr;
CURLcode result;
DEBUGASSERT(unix_path);
*pdns = NULL;
result = Curl_unix2addr(unix_path, abstract_path, &addr);
if(result) {
if(result == CURLE_TOO_LARGE) {
/* Long paths are not supported for now */
failf(data, "Unix socket path too long: '%s'", unix_path);
result = CURLE_COULDNT_RESOLVE_HOST;
}
return result;
}
*pdns = Curl_dnscache_mk_entry(data, 0, &addr, NULL, 0);
return *pdns ? CURLE_OK : CURLE_OUT_OF_MEMORY;
}
#endif /* USE_UNIX_SOCKETS */
/*
* Curl_resolv() is the main name resolve function within libcurl. It resolves
* a name and returns a pointer to the entry in the 'entry' argument. This
@@ -956,16 +974,14 @@ clean_up:
* any other CURLcode error, *pdns == NULL
*/
CURLcode Curl_resolv(struct Curl_easy *data,
struct Curl_peer *peer,
uint8_t dns_queries,
const char *hostname,
uint16_t port,
uint8_t transport,
bool for_proxy,
timediff_t timeout_ms,
uint32_t *presolv_id,
struct Curl_dns_entry **pdns)
{
DEBUGASSERT(hostname && *hostname);
*presolv_id = 0;
*pdns = NULL;
@@ -975,14 +991,23 @@ CURLcode Curl_resolv(struct Curl_easy *data,
else if(!timeout_ms)
timeout_ms = CURL_TIMEOUT_RESOLVE_MS;
#ifdef USE_UNIX_SOCKETS
if(peer->unix_socket)
return resolv_unix(data, peer->hostname, (bool)peer->abstract_uds, pdns);
#else
if(peer->unix_socket)
return hostip_resolv_failed(data, peer->hostname, for_proxy);
#endif
#ifdef USE_ALARM_TIMEOUT
if(timeout_ms && data->set.no_signal) {
/* Cannot use ALARM when signals are disabled */
timeout_ms = 0;
}
if(timeout_ms && !Curl_doh_wanted(data)) {
return resolv_alarm_timeout(data, dns_queries, hostname, port, transport,
for_proxy, timeout_ms, presolv_id, pdns);
return resolv_alarm_timeout(data, dns_queries, peer->hostname, peer->port,
transport, for_proxy, timeout_ms, presolv_id,
pdns);
}
#endif /* !USE_ALARM_TIMEOUT */
@@ -991,8 +1016,9 @@ CURLcode Curl_resolv(struct Curl_easy *data,
infof(data, "timeout on name lookup is not supported");
#endif
return hostip_resolv(data, dns_queries, hostname, port, transport,
for_proxy, timeout_ms, TRUE, presolv_id, pdns);
return hostip_resolv(data, dns_queries, peer->hostname, peer->port,
transport, for_proxy, timeout_ms, TRUE, presolv_id,
pdns);
}
#ifdef USE_CURL_ASYNC
@@ -1047,7 +1073,7 @@ CURLcode Curl_resolv_take_result(struct Curl_easy *data, uint32_t resolv_id,
}
else if(result) {
failf(data, "Error %d resolving %s:%u",
result, async->hostname, async->port);
(int)result, async->hostname, async->port);
}
return result;
}
@@ -1101,30 +1127,3 @@ void Curl_resolv_destroy_all(struct Curl_easy *data)
}
#endif /* USE_CURL_ASYNC */
#ifdef USE_UNIX_SOCKETS
CURLcode Curl_resolv_unix(struct Curl_easy *data,
const char *unix_path,
bool abstract_path,
struct Curl_dns_entry **pdns)
{
struct Curl_addrinfo *addr;
CURLcode result;
DEBUGASSERT(unix_path);
*pdns = NULL;
result = Curl_unix2addr(unix_path, abstract_path, &addr);
if(result) {
if(result == CURLE_TOO_LARGE) {
/* Long paths are not supported for now */
failf(data, "Unix socket path too long: '%s'", unix_path);
result = CURLE_COULDNT_RESOLVE_HOST;
}
return result;
}
*pdns = Curl_dnscache_mk_entry(data, 0, &addr, NULL, 0);
return *pdns ? CURLE_OK : CURLE_OUT_OF_MEMORY;
}
#endif /* USE_UNIX_SOCKETS */
+2 -9
View File
@@ -45,6 +45,7 @@ struct easy_pollset;
struct Curl_https_rrinfo;
struct Curl_multi;
struct Curl_dns_entry;
struct Curl_peer;
/* DNS query types */
#define CURL_DNSQ_A (1U << 0)
@@ -96,9 +97,8 @@ void Curl_printable_address(const struct Curl_addrinfo *ai,
* - other: the operation failed, `*pdns` is NULL, `*presolv_id` is 0.
*/
CURLcode Curl_resolv(struct Curl_easy *data,
struct Curl_peer *peer,
uint8_t dns_queries,
const char *hostname,
uint16_t port,
uint8_t transport,
bool for_proxy,
timediff_t timeout_ms,
@@ -184,11 +184,4 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data,
uint8_t transport);
#endif
#ifdef USE_UNIX_SOCKETS
CURLcode Curl_resolv_unix(struct Curl_easy *data,
const char *unix_path,
bool abstract_path,
struct Curl_dns_entry **pdns);
#endif
#endif /* HEADER_CURL_HOSTIP_H */
+1 -1
View File
@@ -64,7 +64,7 @@
* the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
* HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
* has the corresponding rules. This is primarily on *nix. Note that some Unix
* flavours have thread-safe versions of the plain gethostbyname() etc.
* flavors have thread-safe versions of the plain gethostbyname() etc.
*
*/
struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data,
+87 -58
View File
@@ -96,7 +96,7 @@ void Curl_hsts_cleanup(struct hsts **hp)
static void hsts_append(struct hsts *h, struct stsentry *sts)
{
if(Curl_llist_count(&h->list) == MAX_HSTS_ENTRIES) {
/* It's full. Remove the first entry in the list */
/* It is full. Remove the first entry in the list */
struct Curl_llist_node *e = Curl_llist_head(&h->list);
struct stsentry *oldsts = Curl_node_elem(e);
Curl_node_remove(e);
@@ -121,7 +121,7 @@ static CURLcode hsts_create(struct hsts *h,
struct stsentry *sts = curlx_calloc(1, sizeof(struct stsentry) + hlen);
if(!sts)
return CURLE_OUT_OF_MEMORY;
/* the null terminator is already there */
/* the null-terminator is already there */
memcpy(sts->host, hostname, hlen);
sts->expires = expires;
sts->includeSubDomains = subdomains;
@@ -130,6 +130,81 @@ static CURLcode hsts_create(struct hsts *h,
return CURLE_OK;
}
/* Copy all live entries from src into dst. Used by curl_easy_duphandle so the
* clone inherits entries learned at runtime. E.g. Strict-Transport-Security.
*/
CURLcode Curl_hsts_copy(struct hsts *dst, struct hsts *src)
{
struct Curl_llist_node *e;
time_t now = time(NULL);
for(e = Curl_llist_head(&src->list); e; e = Curl_node_next(e)) {
struct stsentry *sts = Curl_node_elem(e);
if(sts->expires > now) {
CURLcode result = hsts_create(dst, sts->host, strlen(sts->host),
sts->includeSubDomains != 0, sts->expires);
if(result)
return result;
}
}
return CURLE_OK;
}
/*
* Return the matching HSTS entry, or NULL if the given hostname is not
* currently an HSTS one.
*
* The 'subdomain' argument tells the function if subdomain matching should be
* attempted.
*
* @unittest 1660
*/
UNITTEST struct stsentry *hsts_check(struct hsts *h, const char *hostname,
size_t hlen, bool subdomain);
UNITTEST struct stsentry *hsts_check(struct hsts *h, const char *hostname,
size_t hlen, bool subdomain)
{
struct stsentry *bestsub = NULL;
if(h) {
time_t now = time(NULL);
struct Curl_llist_node *e;
struct Curl_llist_node *n;
size_t blen = 0;
if((hlen > MAX_HSTS_HOSTLEN) || !hlen)
return NULL;
if(hostname[hlen - 1] == '.')
/* remove the trailing dot */
--hlen;
for(e = Curl_llist_head(&h->list); e; e = n) {
struct stsentry *sts = Curl_node_elem(e);
size_t ntail;
n = Curl_node_next(e);
if(sts->expires <= now) {
/* remove expired entries */
Curl_node_remove(&sts->node);
hsts_free(sts);
continue;
}
ntail = strlen(sts->host);
if((subdomain && sts->includeSubDomains) && (ntail < hlen)) {
size_t offs = hlen - ntail;
if((hostname[offs - 1] == '.') &&
curl_strnequal(&hostname[offs], sts->host, ntail) &&
(ntail > blen)) {
/* save the tail match with the longest tail */
bestsub = sts;
blen = ntail;
}
}
/* avoid curl_strequal because the hostname is not null-terminated */
if((hlen == ntail) && curl_strnequal(hostname, sts->host, hlen))
return sts;
}
}
return bestsub;
}
CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
const char *header)
{
@@ -203,7 +278,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
if(!expires) {
/* remove the entry if present verbatim (without subdomain match) */
sts = Curl_hsts(h, hostname, hlen, FALSE);
sts = hsts_check(h, hostname, hlen, FALSE);
if(sts) {
Curl_node_remove(&sts->node);
hsts_free(sts);
@@ -218,7 +293,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
expires += now;
/* check if it already exists */
sts = Curl_hsts(h, hostname, hlen, FALSE);
sts = hsts_check(h, hostname, hlen, FALSE);
if(sts) {
/* update these fields */
sts->expires = expires;
@@ -230,57 +305,6 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
return CURLE_OK;
}
/*
* Return TRUE if the given hostname is currently an HSTS one.
*
* The 'subdomain' argument tells the function if subdomain matching should be
* attempted.
*/
struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
size_t hlen, bool subdomain)
{
struct stsentry *bestsub = NULL;
if(h) {
time_t now = time(NULL);
struct Curl_llist_node *e;
struct Curl_llist_node *n;
size_t blen = 0;
if((hlen > MAX_HSTS_HOSTLEN) || !hlen)
return NULL;
if(hostname[hlen - 1] == '.')
/* remove the trailing dot */
--hlen;
for(e = Curl_llist_head(&h->list); e; e = n) {
struct stsentry *sts = Curl_node_elem(e);
size_t ntail;
n = Curl_node_next(e);
if(sts->expires <= now) {
/* remove expired entries */
Curl_node_remove(&sts->node);
hsts_free(sts);
continue;
}
ntail = strlen(sts->host);
if((subdomain && sts->includeSubDomains) && (ntail < hlen)) {
size_t offs = hlen - ntail;
if((hostname[offs - 1] == '.') &&
curl_strnequal(&hostname[offs], sts->host, ntail) &&
(ntail > blen)) {
/* save the tail match with the longest tail */
bestsub = sts;
blen = ntail;
}
}
/* avoid curl_strequal because the hostname is not null-terminated */
if((hlen == ntail) && curl_strnequal(hostname, sts->host, hlen))
return sts;
}
}
return bestsub;
}
/*
* Send this HSTS entry to the write callback.
*/
@@ -437,10 +461,10 @@ static CURLcode hsts_add_host_expire(struct hsts *h,
if(hostlen) {
/* only add it if not already present */
e = Curl_hsts(h, host, hostlen, subdomain);
e = hsts_check(h, host, hostlen, subdomain);
if(!e)
result = hsts_create(h, host, hostlen, subdomain, expires);
/* 'host' is not necessarily null terminated */
/* 'host' is not necessarily null-terminated */
else if((hostlen == strlen(e->host) &&
curl_strnequal(host, e->host, hostlen))) {
/* the same hostname, use the largest expire time and keep the strictest
@@ -504,7 +528,7 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
const char *date = e.expire;
if(!e.name[0] || e.expire[MAX_HSTS_DATELEN] ||
e.name[MAX_HSTS_HOSTLEN])
/* bail out if no name was stored or if a null terminator is gone */
/* bail out if no name was stored or if a null-terminator is gone */
return CURLE_BAD_FUNCTION_ARGUMENT;
if(!date[0])
date = UNLIMITED;
@@ -610,6 +634,11 @@ CURLcode Curl_hsts_loadfiles(struct Curl_easy *data)
return result;
}
bool Curl_hsts_applies(struct hsts *h, const struct Curl_peer *dest)
{
return !!hsts_check(h, dest->hostname, strlen(dest->hostname), TRUE);
}
#if defined(DEBUGBUILD) || defined(UNITTESTS)
#undef time
#endif
+8 -2
View File
@@ -25,9 +25,13 @@
***************************************************************************/
#include "curl_setup.h"
struct hsts;
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
#include "llist.h"
struct Curl_peer;
#define MAX_HSTS_ENTRIES 10000
#if defined(DEBUGBUILD) || defined(UNITTESTS)
@@ -50,10 +54,9 @@ struct hsts {
struct hsts *Curl_hsts_init(void);
void Curl_hsts_cleanup(struct hsts **hp);
CURLcode Curl_hsts_copy(struct hsts *dst, struct hsts *src);
CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
const char *header);
struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
size_t hlen, bool subdomain);
CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
const char *file);
CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
@@ -61,6 +64,9 @@ CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
struct hsts *h);
CURLcode Curl_hsts_loadfiles(struct Curl_easy *data);
bool Curl_hsts_applies(struct hsts *h, const struct Curl_peer *dest);
#else
#define Curl_hsts_cleanup(x)
#define Curl_hsts_loadcb(x, y) CURLE_OK
+194 -202
View File
@@ -154,7 +154,7 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
{
struct curl_slist *head;
for(head = (conn->bits.proxy && data->set.sep_headers) ?
for(head = (conn->http_proxy.peer && data->set.sep_headers) ?
data->set.proxyheaders : data->set.headers;
head; head = head->next) {
if(curl_strnequal(head->data, thisheader, thislen) &&
@@ -250,34 +250,38 @@ char *Curl_copy_header_value(const char *header)
*
* Returns CURLcode.
*/
static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
static CURLcode http_output_basic(struct Curl_easy *data,
struct connectdata *conn, bool proxy)
{
size_t size = 0;
char *authorization = NULL;
char **userp;
const char *user;
const char *pwd;
char **p_hd;
CURLcode result;
struct Curl_creds *creds = NULL;
char *out;
/* credentials are unique per transfer for HTTP, do not use the ones for the
connection */
if(proxy) {
#ifndef CURL_DISABLE_PROXY
userp = &data->req.proxyuserpwd;
user = data->state.aptr.proxyuser;
pwd = data->state.aptr.proxypasswd;
p_hd = &data->req.hd_proxy_auth;
creds = conn->http_proxy.creds;
#else
(void)conn;
return CURLE_NOT_BUILT_IN;
#endif
}
else {
userp = &data->req.userpwd;
user = data->state.aptr.user;
pwd = data->state.aptr.passwd;
p_hd = &data->req.hd_auth;
creds = data->state.creds;
}
out = curl_maprintf("%s:%s", user ? user : "", pwd ? pwd : "");
if(!creds) {
DEBUGASSERT(0);
return CURLE_FAILED_INIT;
}
out = curl_maprintf("%s:%s", creds->user, creds->passwd);
if(!out)
return CURLE_OUT_OF_MEMORY;
@@ -291,12 +295,12 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
goto fail;
}
curlx_free(*userp);
*userp = curl_maprintf("%sAuthorization: Basic %s\r\n",
proxy ? "Proxy-" : "",
authorization);
curlx_free(*p_hd);
*p_hd = curl_maprintf("%sAuthorization: Basic %s\r\n",
proxy ? "Proxy-" : "",
authorization);
curlx_free(authorization);
if(!*userp) {
if(!*p_hd) {
result = CURLE_OUT_OF_MEMORY;
goto fail;
}
@@ -320,10 +324,11 @@ static CURLcode http_output_bearer(struct Curl_easy *data)
char **userp;
CURLcode result = CURLE_OK;
userp = &data->req.userpwd;
DEBUGASSERT(Curl_creds_has_oauth_bearer(data->state.creds));
userp = &data->req.hd_auth;
curlx_free(*userp);
*userp = curl_maprintf("Authorization: Bearer %s\r\n",
data->set.str[STRING_BEARER]);
Curl_creds_oauth_bearer(data->state.creds));
if(!*userp) {
result = CURLE_OUT_OF_MEMORY;
@@ -333,7 +338,6 @@ static CURLcode http_output_bearer(struct Curl_easy *data)
fail:
return result;
}
#endif
#endif
@@ -343,8 +347,10 @@ fail:
*
* return TRUE if one was picked
*/
static bool pickoneauth(struct auth *pick, unsigned long mask)
static bool pickoneauth(struct auth *pick, unsigned long mask,
struct Curl_creds *creds)
{
bool have_user_pass = Curl_creds_has_user_or_pass(creds);
bool picked;
/* only deal with authentication we want */
unsigned long avail = pick->avail & pick->want & mask;
@@ -352,20 +358,20 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
/* The order of these checks is highly relevant, as this will be the order
of preference in case of the existence of multiple accepted types. */
if(avail & CURLAUTH_NEGOTIATE)
if(avail & CURLAUTH_NEGOTIATE) /* available on empty creds */
pick->picked = CURLAUTH_NEGOTIATE;
#ifndef CURL_DISABLE_BEARER_AUTH
else if(avail & CURLAUTH_BEARER)
else if((avail & CURLAUTH_BEARER) && Curl_creds_has_oauth_bearer(creds))
pick->picked = CURLAUTH_BEARER;
#endif
#ifndef CURL_DISABLE_DIGEST_AUTH
else if(avail & CURLAUTH_DIGEST)
else if((avail & CURLAUTH_DIGEST) && have_user_pass)
pick->picked = CURLAUTH_DIGEST;
#endif
else if(avail & CURLAUTH_NTLM)
pick->picked = CURLAUTH_NTLM;
#ifndef CURL_DISABLE_BASIC_AUTH
else if(avail & CURLAUTH_BASIC)
else if((avail & CURLAUTH_BASIC) && have_user_pass)
pick->picked = CURLAUTH_BASIC;
#endif
#ifndef CURL_DISABLE_AWS
@@ -527,10 +533,10 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
* Either we are not authenticating, or we are supposed to be authenticating
* something else. This is an error.
*/
if((httpcode == 401) && !data->state.aptr.user)
if((httpcode == 401) && !data->state.creds)
return TRUE;
#ifndef CURL_DISABLE_PROXY
if((httpcode == 407) && !data->conn->bits.proxy_user_passwd)
if((httpcode == 407) && !data->conn->http_proxy.creds)
return TRUE;
#endif
@@ -551,7 +557,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
CURLcode result = CURLE_OK;
unsigned long authmask = ~0UL;
if(!data->set.str[STRING_BEARER])
if(!Curl_creds_has_oauth_bearer(data->state.creds))
authmask &= (unsigned long)~CURLAUTH_BEARER;
if(100 <= data->req.httpcode && data->req.httpcode <= 199)
@@ -561,10 +567,10 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
if(data->state.authproblem)
return data->set.http_fail_on_error ? CURLE_HTTP_RETURNED_ERROR : CURLE_OK;
if((data->state.aptr.user || data->set.str[STRING_BEARER]) &&
if(data->state.creds &&
((data->req.httpcode == 401) ||
(data->req.authneg && data->req.httpcode < 300))) {
pickhost = pickoneauth(&data->state.authhost, authmask);
pickhost = pickoneauth(&data->state.authhost, authmask, data->state.creds);
if(!pickhost)
data->state.authproblem = TRUE;
else
@@ -578,11 +584,12 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
}
}
#ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy_user_passwd &&
if(conn->http_proxy.creds &&
((data->req.httpcode == 407) ||
(data->req.authneg && data->req.httpcode < 300))) {
pickproxy = pickoneauth(&data->state.authproxy,
authmask & ~CURLAUTH_BEARER);
authmask & ~CURLAUTH_BEARER,
conn->http_proxy.creds);
if(!pickproxy)
data->state.authproblem = TRUE;
else
@@ -694,14 +701,16 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
/* Basic */
if(
#ifndef CURL_DISABLE_PROXY
(proxy && conn->bits.proxy_user_passwd &&
(proxy && conn->http_proxy.creds &&
Curl_creds_has_user_or_pass(conn->http_proxy.creds) &&
!Curl_checkProxyheaders(data, conn,
STRCONST("Proxy-authorization"))) ||
#endif
(!proxy && data->state.aptr.user &&
(!proxy && data->state.creds &&
Curl_creds_has_user_or_pass(data->state.creds) &&
!Curl_checkheaders(data, STRCONST("Authorization")))) {
auth = "Basic";
result = http_output_basic(data, proxy);
result = http_output_basic(data, conn, proxy);
if(result)
return result;
}
@@ -714,8 +723,7 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
#ifndef CURL_DISABLE_BEARER_AUTH
if(authstatus->picked == CURLAUTH_BEARER) {
/* Bearer */
if(!proxy && data->set.str[STRING_BEARER] &&
Curl_auth_allowed_to_host(data) &&
if(!proxy && Curl_creds_has_oauth_bearer(data->state.creds) &&
!Curl_checkheaders(data, STRCONST("Authorization"))) {
auth = "Bearer";
result = http_output_bearer(data);
@@ -737,15 +745,15 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
data->info.httpauthpicked = authstatus->picked;
infof(data, "%s auth using %s with user '%s'",
proxy ? "Proxy" : "Server", auth,
proxy ? (data->state.aptr.proxyuser ?
data->state.aptr.proxyuser : "") :
(data->state.aptr.user ?
data->state.aptr.user : ""));
proxy ? (conn->http_proxy.creds ?
conn->http_proxy.creds->user : "") :
(data->state.creds ?
data->state.creds->user : ""));
#else
(void)proxy;
infof(data, "Server auth using %s with user '%s'",
auth, data->state.aptr.user ?
data->state.aptr.user : "");
auth, data->state.creds ?
data->state.creds->user : "");
#endif
authstatus->multipass = !authstatus->done;
}
@@ -760,53 +768,47 @@ static CURLcode output_auth_headers(struct Curl_easy *data,
return result;
}
/**
* Curl_http_output_auth() setups the authentication headers for the
* host/proxy and the correct authentication
* method. data->state.authdone is set to TRUE when authentication is
* done.
*
* @param conn all information about the current connection
* @param request pointer to the request keyword
* @param path pointer to the requested path; should include query part
* @param proxytunnel boolean if this is the request setting up a "proxy
* tunnel"
*
* @returns CURLcode
*/
CURLcode Curl_http_output_auth(struct Curl_easy *data,
struct connectdata *conn,
const char *request,
Curl_HttpReq httpreq,
const char *path,
bool proxytunnel) /* TRUE if this is
the request setting up
the proxy tunnel */
const char *query,
bool is_connect)
{
CURLcode result = CURLE_OK;
struct auth *authhost;
struct auth *authproxy;
const char *path_and_query = path;
char *tmp_str = NULL;
DEBUGASSERT(data);
authhost = &data->state.authhost;
authproxy = &data->state.authproxy;
if(
#ifndef CURL_DISABLE_PROXY
(conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
(!conn->http_proxy.peer || !conn->http_proxy.creds) &&
#endif
data->state.aptr.user ||
#ifdef USE_SPNEGO
authhost->want & CURLAUTH_NEGOTIATE ||
authproxy->want & CURLAUTH_NEGOTIATE ||
!(authhost->want & CURLAUTH_NEGOTIATE) &&
!(authproxy->want & CURLAUTH_NEGOTIATE) &&
#endif
data->set.str[STRING_BEARER])
/* continue please */;
else {
!data->state.creds) {
/* no authentication with no user or password */
authhost->done = TRUE;
authproxy->done = TRUE;
return CURLE_OK; /* no authentication with no user or password */
result = CURLE_OK;
goto out;
}
if(query) {
tmp_str = curl_maprintf("%s?%s", path, query);
if(!tmp_str) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
path_and_query = tmp_str;
}
if(authhost->want && !authhost->picked)
@@ -823,28 +825,25 @@ CURLcode Curl_http_output_auth(struct Curl_easy *data,
#ifndef CURL_DISABLE_PROXY
/* Send proxy authentication header if needed */
if(conn->bits.httpproxy &&
(conn->bits.tunnel_proxy == (curl_bit)proxytunnel)) {
result = output_auth_headers(data, conn, authproxy, request, path, TRUE);
if(conn->bits.origin_is_proxy || is_connect) {
result = output_auth_headers(data, conn, authproxy, request,
path_and_query, TRUE);
if(result)
return result;
goto out;
}
else
#else
(void)proxytunnel;
(void)is_connect;
#endif /* CURL_DISABLE_PROXY */
/* we have no proxy so let's pretend we are done authenticating
with it */
authproxy->done = TRUE;
/* To prevent the user+password to get sent to other than the original host
due to a location-follow */
if(Curl_auth_allowed_to_host(data)
#ifndef CURL_DISABLE_NETRC
|| conn->bits.netrc
#endif
)
result = output_auth_headers(data, conn, authhost, request, path, FALSE);
/* Either we have credentials for the origin we talk to or
performing authentication is allowed here */
if(data->state.creds || Curl_auth_allowed_to_host(data))
result = output_auth_headers(data, conn, authhost, request,
path_and_query, FALSE);
else
authhost->done = TRUE;
@@ -859,27 +858,31 @@ CURLcode Curl_http_output_auth(struct Curl_easy *data,
else
data->req.authneg = FALSE;
out:
curlx_free(tmp_str);
return result;
}
#else
#else /* !CURL_DISABLE_HTTP_AUTH */
/* when disabled */
CURLcode Curl_http_output_auth(struct Curl_easy *data,
struct connectdata *conn,
const char *request,
Curl_HttpReq httpreq,
const char *path,
bool proxytunnel)
const char *query,
bool is_connect)
{
(void)data;
(void)conn;
(void)request;
(void)httpreq;
(void)path;
(void)proxytunnel;
(void)query;
(void)is_connect;
return CURLE_OK;
}
#endif
#endif /* !CURL_DISABLE_HTTP_AUTH, else */
#if defined(USE_SPNEGO) || defined(USE_NTLM) || \
!defined(CURL_DISABLE_DIGEST_AUTH) || \
@@ -1134,9 +1137,9 @@ static void http_switch_to_get(struct Curl_easy *data, int code)
Curl_creader_set_rewind(data, FALSE);
}
#define HTTPREQ_IS_POST(data) \
((data)->state.httpreq == HTTPREQ_POST || \
(data)->state.httpreq == HTTPREQ_POST_FORM || \
#define HTTPREQ_IS_POST(data) \
((data)->state.httpreq == HTTPREQ_POST || \
(data)->state.httpreq == HTTPREQ_POST_FORM || \
(data)->state.httpreq == HTTPREQ_POST_MIME)
CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
@@ -1227,8 +1230,6 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
return CURLE_OUT_OF_MEMORY;
}
else {
bool same_origin;
CURLcode result;
CURLU *u = curl_url();
if(!u)
return CURLE_OUT_OF_MEMORY;
@@ -1242,29 +1243,16 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl,
return Curl_uc_to_curlcode(uc);
}
same_origin = Curl_url_same_origin(u, data->state.uh);
curl_url_cleanup(u);
#ifndef CURL_DISABLE_DIGEST_AUTH
if(!same_origin)
Curl_auth_digest_cleanup(&data->state.digest);
{
bool same_origin = Curl_url_same_origin(u, data->state.uh);
curl_url_cleanup(u);
if(!same_origin)
Curl_auth_digest_cleanup(&data->state.digest);
}
#else
curl_url_cleanup(u);
#endif
if((!same_origin && !data->set.allow_auth_to_other_hosts) ||
!data->set.str[STRING_USERNAME]) {
result = Curl_reset_userpwd(data);
if(result) {
curlx_free(follow_url);
return result;
}
curlx_safefree(data->state.aptr.user);
curlx_safefree(data->state.aptr.passwd);
}
result = Curl_reset_proxypwd(data);
if(result) {
curlx_free(follow_url);
return result;
}
}
DEBUGASSERT(follow_url);
@@ -1753,8 +1741,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
if(is_connect)
proxy = HEADER_CONNECT;
else
proxy = data->conn->bits.httpproxy && !data->conn->bits.tunnel_proxy ?
HEADER_PROXY : HEADER_SERVER;
proxy = data->conn->bits.origin_is_proxy ? HEADER_PROXY : HEADER_SERVER;
switch(proxy) {
case HEADER_SERVER:
@@ -1773,6 +1760,12 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
else
h[0] = data->set.headers;
break;
case HEADER_CONNECT_UDP:
if(data->set.sep_headers)
h[0] = data->set.proxyheaders;
else
h[0] = data->set.headers;
break;
}
#else
(void)is_connect;
@@ -1992,10 +1985,8 @@ static CURLcode http_useragent(struct Curl_easy *data)
it might have been used in the proxy connect, but if we have got a header
with the user-agent string specified, we erase the previously made string
here. */
if(Curl_checkheaders(data, STRCONST("User-Agent"))) {
curlx_free(data->state.aptr.uagent);
data->state.aptr.uagent = NULL;
}
if(Curl_checkheaders(data, STRCONST("User-Agent")))
curlx_safefree(data->state.aptr.uagent);
return CURLE_OK;
}
@@ -2005,25 +1996,15 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data)
struct dynamically_allocated_data *aptr = &data->state.aptr;
const char *ptr;
if(!data->state.this_is_a_follow) {
/* Free to avoid leaking memory on multiple requests */
curlx_free(data->state.first_host);
data->state.first_host = curlx_strdup(conn->host.name);
if(!data->state.first_host)
return CURLE_OUT_OF_MEMORY;
data->state.first_remote_port = conn->remote_port;
data->state.first_remote_protocol = conn->scheme->protocol;
}
curlx_safefree(aptr->host);
#ifndef CURL_DISABLE_COOKIES
curlx_safefree(data->req.cookiehost);
#endif
ptr = Curl_checkheaders(data, STRCONST("Host"));
if(ptr && (!data->state.this_is_a_follow ||
curl_strequal(data->state.first_host, conn->host.name))) {
if(ptr &&
(!data->state.this_is_a_follow ||
Curl_peer_equal(data->state.initial_origin, data->state.origin))) {
#ifndef CURL_DISABLE_COOKIES
/* If we have a given custom Host: header, we extract the hostname in
order to possibly use it for cookie reasons later on. We only allow the
@@ -2067,18 +2048,19 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data)
}
else {
/* Use the hostname as present in the URL if it was IPv6. */
char *host = (data->state.up.hostname[0] == '[') ?
data->state.up.hostname : conn->host.name;
char *host = (data->state.origin->user_hostname[0] == '[') ?
data->state.origin->user_hostname : data->state.origin->hostname;
if(((conn->given->protocol & (CURLPROTO_HTTPS | CURLPROTO_WSS)) &&
(conn->remote_port == PORT_HTTPS)) ||
(data->state.origin->port == PORT_HTTPS)) ||
((conn->given->protocol & (CURLPROTO_HTTP | CURLPROTO_WS)) &&
(conn->remote_port == PORT_HTTP)))
(data->state.origin->port == PORT_HTTP)))
/* if(HTTPS on port 443) OR (HTTP on port 80) then do not include
the port number in the host string */
aptr->host = curl_maprintf("Host: %s\r\n", host);
else
aptr->host = curl_maprintf("Host: %s:%d\r\n", host, conn->remote_port);
aptr->host = curl_maprintf("Host: %s:%d\r\n",
host, data->state.origin->port);
if(!aptr->host)
/* without Host: we cannot make a nice request */
@@ -2106,7 +2088,7 @@ static CURLcode http_target(struct Curl_easy *data,
}
#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
if(conn->bits.origin_is_proxy) {
/* Using a proxy but does not tunnel through it */
/* The path sent to the proxy is in fact the entire URL, but if the remote
@@ -2120,8 +2102,8 @@ static CURLcode http_target(struct Curl_easy *data,
if(!h)
return CURLE_OUT_OF_MEMORY;
if(conn->host.dispname != conn->host.name) {
uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
if(data->state.origin->user_hostname != data->state.origin->hostname) {
uc = curl_url_set(h, CURLUPART_HOST, data->state.origin->hostname, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
@@ -2146,6 +2128,19 @@ static CURLcode http_target(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
}
else if(data->state.creds && (data->state.creds->source != CREDS_URL)) {
/* credentials not from the URL need to be set */
uc = curl_url_set(h, CURLUPART_USER,
data->state.creds->user, CURLU_URLENCODE);
if(!uc)
uc = curl_url_set(h, CURLUPART_PASSWORD,
data->state.creds->passwd, CURLU_URLENCODE);
if(uc) {
curl_url_cleanup(h);
return Curl_uc_to_curlcode(uc);
}
}
/* Extract the URL to use in the request. */
uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
if(uc) {
@@ -2541,7 +2536,8 @@ static CURLcode http_cookies(struct Curl_easy *data,
char *addcookies = NULL;
bool linecap = FALSE;
if(data->set.str[STRING_COOKIE] &&
!Curl_checkheaders(data, STRCONST("Cookie")))
!Curl_checkheaders(data, STRCONST("Cookie")) &&
Curl_auth_allowed_to_host(data))
addcookies = data->set.str[STRING_COOKIE];
if(data->cookies || addcookies) {
@@ -2551,9 +2547,9 @@ static CURLcode http_cookies(struct Curl_easy *data,
if(data->cookies && data->state.cookie_engine) {
bool okay;
const char *host = data->req.cookiehost ?
data->req.cookiehost : data->conn->host.name;
data->req.cookiehost : data->state.origin->hostname;
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
result = Curl_cookie_getlist(data, data->conn, &okay, host, &list);
result = Curl_cookie_getlist(data, &okay, host, &list);
if(!result && okay) {
struct Curl_llist_node *n;
size_t clen = 8; /* hold the size of the generated Cookie: header */
@@ -2737,13 +2733,16 @@ static CURLcode http_check_new_conn(struct Curl_easy *data)
alpn = Curl_conn_get_alpn_negotiated(data, conn);
if(alpn && !strcmp("h3", alpn)) {
DEBUGASSERT(Curl_conn_http_version(data, conn) == 30);
#ifndef CURL_DISABLE_PROXY
if(!conn->bits.origin_is_proxy)
#endif
DEBUGASSERT(Curl_conn_http_version(data, conn) == 30);
info_version = "HTTP/3";
}
else if(alpn && !strcmp("h2", alpn)) {
#ifndef CURL_DISABLE_PROXY
if((Curl_conn_http_version(data, conn) != 20) &&
conn->bits.proxy && !conn->bits.tunnel_proxy) {
conn->bits.origin_is_proxy) {
result = Curl_http2_switch(data);
if(result)
return result;
@@ -2842,7 +2841,7 @@ typedef enum {
#ifndef CURL_DISABLE_PROXY
H1_HD_PROXY_AUTH,
#endif
H1_HD_USER_AUTH,
H1_HD_AUTH,
H1_HD_RANGE,
H1_HD_USER_AGENT,
H1_HD_ACCEPT,
@@ -2897,14 +2896,14 @@ static CURLcode http_add_hd(struct Curl_easy *data,
#ifndef CURL_DISABLE_PROXY
case H1_HD_PROXY_AUTH:
if(data->req.proxyuserpwd)
result = curlx_dyn_add(req, data->req.proxyuserpwd);
if(data->req.hd_proxy_auth)
result = curlx_dyn_add(req, data->req.hd_proxy_auth);
break;
#endif
case H1_HD_USER_AUTH:
if(data->req.userpwd)
result = curlx_dyn_add(req, data->req.userpwd);
case H1_HD_AUTH:
if(data->req.hd_auth)
result = curlx_dyn_add(req, data->req.hd_auth);
break;
case H1_HD_RANGE:
@@ -2952,8 +2951,7 @@ static CURLcode http_add_hd(struct Curl_easy *data,
#ifndef CURL_DISABLE_PROXY
case H1_HD_PROXY_CONNECTION:
if(conn->bits.httpproxy &&
!conn->bits.tunnel_proxy &&
if(conn->bits.origin_is_proxy &&
!Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
!Curl_checkProxyheaders(data, data->conn, STRCONST("Proxy-Connection")))
result = curlx_dyn_add(req, "Proxy-Connection: Keep-Alive\r\n");
@@ -2966,10 +2964,10 @@ static CURLcode http_add_hd(struct Curl_easy *data,
#ifndef CURL_DISABLE_ALTSVC
case H1_HD_ALT_USED:
if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used")))
if(conn->bits.altused && conn->via_peer &&
!Curl_checkheaders(data, STRCONST("Alt-Used")))
result = curlx_dyn_addf(req, "Alt-Used: %s:%u\r\n",
conn->conn_to_host.name,
conn->conn_to_port);
conn->via_peer->hostname, conn->via_peer->port);
break;
#endif
@@ -3062,29 +3060,16 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* select host to send */
result = http_set_aptr_host(data);
if(!result) {
/* setup the authentication headers, how that method and host are known */
char *pq = NULL;
if(data->state.up.query) {
pq = curl_maprintf("%s?%s", data->state.up.path, data->state.up.query);
if(!pq) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
}
/* setup the authentication headers, how that method and host are known */
if(!result)
result = Curl_http_output_auth(data, data->conn, method, httpreq,
(pq ? pq : data->state.up.path), FALSE);
curlx_free(pq);
}
if(result)
goto out;
result = http_useragent(data);
if(result)
goto out;
data->state.up.path,
data->state.up.query, FALSE);
if(!result)
result = http_useragent(data);
/* Setup input reader, resume information and ranges */
result = set_reader(data, httpreq);
if(!result)
result = set_reader(data, httpreq);
if(!result)
result = http_resume(data, httpreq);
if(!result)
@@ -3209,7 +3194,6 @@ static CURLcode http_header_a(struct Curl_easy *data,
{
#ifndef CURL_DISABLE_ALTSVC
const char *v;
struct connectdata *conn = data->conn;
v = (data->asi &&
(Curl_xfer_is_secure(data) ||
#ifdef DEBUGBUILD
@@ -3224,8 +3208,9 @@ static CURLcode http_header_a(struct Curl_easy *data,
struct SingleRequest *k = &data->req;
enum alpnid id = (k->httpversion == 30) ? ALPN_h3 :
(k->httpversion == 20) ? ALPN_h2 : ALPN_h1;
return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
curlx_uitous((unsigned int)conn->remote_port));
return Curl_altsvc_parse(
data, data->asi, v, id, data->state.origin->hostname,
curlx_uitous((unsigned int)data->state.origin->port));
}
#else
(void)data;
@@ -3443,7 +3428,7 @@ static CURLcode http_header_p(struct Curl_easy *data,
const char *v = HD_VAL(hd, hdlen, "Proxy-Connection:");
if(v) {
struct connectdata *conn = data->conn;
if((k->httpversion == 10) && conn->bits.httpproxy &&
if((k->httpversion == 10) && conn->http_proxy.peer &&
HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
/*
* When an HTTP/1.0 reply comes when using a proxy, the
@@ -3454,7 +3439,7 @@ static CURLcode http_header_p(struct Curl_easy *data,
connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
infof(data, "HTTP/1.0 proxy connection set to keep alive");
}
else if((k->httpversion == 11) && conn->bits.httpproxy &&
else if((k->httpversion == 11) && conn->http_proxy.peer &&
HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
/*
* We get an HTTP/1.1 response from a proxy and it says it will
@@ -3537,7 +3522,6 @@ static CURLcode http_header_s(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_HSTS)
struct connectdata *conn = data->conn;
const char *v;
#else
(void)data;
@@ -3552,8 +3536,8 @@ static CURLcode http_header_s(struct Curl_easy *data,
/* If there is a custom-set Host: name, use it here, or else use
* real peer hostname. */
const char *host = data->req.cookiehost ?
data->req.cookiehost : conn->host.name;
const bool secure_context = Curl_secure_context(conn, host);
data->req.cookiehost : data->state.origin->hostname;
const bool secure_context = Curl_secure_context(data, host);
CURLcode result;
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
result = Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
@@ -3575,8 +3559,8 @@ static CURLcode http_header_s(struct Curl_easy *data,
)
) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
if(v) {
CURLcode result =
Curl_hsts_parse(data->hsts, conn->host.name, v);
CURLcode result = Curl_hsts_parse(
data->hsts, data->state.origin->hostname, v);
if(result) {
if(result == CURLE_OUT_OF_MEMORY)
return result;
@@ -3827,8 +3811,8 @@ static CURLcode http_size(struct Curl_easy *data)
return CURLE_OK;
}
static CURLcode verify_header(struct Curl_easy *data,
const char *hd, size_t hdlen)
CURLcode Curl_verify_header(struct Curl_easy *data,
const char *hd, size_t hdlen)
{
struct SingleRequest *k = &data->req;
const char *ptr = memchr(hd, 0x00, hdlen);
@@ -3837,6 +3821,14 @@ static CURLcode verify_header(struct Curl_easy *data,
failf(data, "Nul byte in header");
return CURLE_WEIRD_SERVER_REPLY;
}
if(hdlen > 2) {
ptr = memchr(hd, '\r', hdlen - 2);
if(ptr) {
/* CR may only precede the LF, nothing else */
failf(data, "Carriage return found in header");
return CURLE_WEIRD_SERVER_REPLY;
}
}
if(k->headerline < 2)
/* the first "header" is the status-line and it has no colon */
return CURLE_OK;
@@ -4191,6 +4183,17 @@ static CURLcode http_on_response(struct Curl_easy *data,
goto out;
}
/* final response without error, prepare to receive the body */
result = http_firstwrite(data);
if(result)
goto out;
/* This is the last response that we get for the current request. Check on
* the body size and determine if the response is complete. */
result = http_size(data);
if(result)
goto out;
/* If we requested a "no body", this is a good time to get
* out and return home.
*/
@@ -4204,14 +4207,6 @@ static CURLcode http_on_response(struct Curl_easy *data,
if((k->maxdownload == 0) && (k->httpversion_sent < 20))
k->download_done = TRUE;
/* final response without error, prepare to receive the body */
result = http_firstwrite(data);
if(!result)
/* This is the last response that we get for the current request. Check on
* the body size and determine if the response is complete. */
result = http_size(data);
out:
if(last_hd)
/* if not written yet, write it now */
@@ -4367,7 +4362,7 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
}
}
result = verify_header(data, hd, hdlen);
result = Curl_verify_header(data, hd, hdlen);
if(result)
return result;
@@ -4876,7 +4871,6 @@ struct name_const {
size_t namelen;
};
/* keep them sorted by length! */
static const struct name_const H2_NON_FIELD[] = {
{ STRCONST("Host") },
{ STRCONST("Upgrade") },
@@ -4890,10 +4884,8 @@ static bool h2_permissible_field(struct dynhds_entry *e)
{
size_t i;
for(i = 0; i < CURL_ARRAYSIZE(H2_NON_FIELD); ++i) {
if(e->namelen < H2_NON_FIELD[i].namelen)
return TRUE;
if(e->namelen == H2_NON_FIELD[i].namelen &&
curl_strequal(H2_NON_FIELD[i].name, e->name))
curl_strnequal(H2_NON_FIELD[i].name, e->name, e->namelen))
return FALSE;
}
return TRUE;
@@ -4950,7 +4942,7 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
infof(data, "set pseudo header %s to %s", HTTP_PSEUDO_SCHEME, scheme);
}
else {
scheme = Curl_xfer_is_secure(data) ? "https" : "http";
scheme = data->state.origin->scheme->name;
}
}
+10 -7
View File
@@ -83,8 +83,6 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
CURLcode Curl_add_timecondition(struct Curl_easy *data, struct dynbuf *req);
CURLcode Curl_add_custom_headers(struct Curl_easy *data, bool is_connect,
int httpversion, struct dynbuf *req);
CURLcode Curl_dynhds_add_custom(struct Curl_easy *data, bool is_connect,
struct dynhds *hds);
void Curl_http_to_fold(struct dynbuf *bf);
@@ -108,6 +106,11 @@ CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
const char *hd, size_t hdlen,
bool is_eos);
/* check a received header line for forbidden bytes/format, the same checks
applied to regular response headers */
CURLcode Curl_verify_header(struct Curl_easy *data,
const char *hd, size_t hdlen);
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
const char *auth);
@@ -180,8 +183,9 @@ CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
* @param request pointer to the request keyword
* @param httpreq is the request type
* @param path pointer to the requested path
* @param proxytunnel boolean if this is the request setting up a "proxy
* tunnel"
* @param query pointer to the requested query or NULL
* @param is_connect boolean if this is a CONNECT request
* (where httpreq is HTTPREQ_GET since there is no HTTPREQ_CONNECT)
*
* @returns CURLcode
*/
@@ -190,9 +194,8 @@ CURLcode Curl_http_output_auth(struct Curl_easy *data,
const char *request,
Curl_HttpReq httpreq,
const char *path,
bool proxytunnel); /* TRUE if this is
the request setting up
the proxy tunnel */
const char *query,
bool is_connect);
/* Decode HTTP status code string. */
CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len);
+65 -100
View File
@@ -47,14 +47,11 @@
#include "curlx/dynbuf.h"
#include "headers.h"
#if (NGHTTP2_VERSION_NUM < 0x010c00)
#error too old nghttp2 version, upgrade!
#if NGHTTP2_VERSION_NUM < 0x010f00
#error "nghttp2 1.15.0 or greater required"
#endif
#if (NGHTTP2_VERSION_NUM >= 0x010c00)
#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
#endif
/* buffer dimensioning:
* use 16K as chunk size, as that fits H2 DATA frames well */
@@ -189,6 +186,8 @@ static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade)
static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
{
if(ctx && ctx->initialized) {
if(ctx->h2)
nghttp2_session_del(ctx->h2);
Curl_bufq_free(&ctx->inbufq);
Curl_bufq_free(&ctx->outbufq);
Curl_bufcp_free(&ctx->stream_bufcp);
@@ -199,14 +198,6 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
curlx_free(ctx);
}
static void cf_h2_ctx_close(struct cf_h2_ctx *ctx)
{
if(ctx->h2) {
nghttp2_session_del(ctx->h2);
ctx->h2 = NULL;
}
}
static uint32_t cf_h2_initial_win_size(struct Curl_easy *data)
{
#if NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
@@ -221,8 +212,8 @@ static uint32_t cf_h2_initial_win_size(struct Curl_easy *data)
}
static size_t populate_settings(nghttp2_settings_entry *iv,
struct Curl_easy *data,
struct cf_h2_ctx *ctx)
struct Curl_easy *data,
struct cf_h2_ctx *ctx)
{
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
@@ -232,7 +223,7 @@ static size_t populate_settings(nghttp2_settings_entry *iv,
if(ctx)
ctx->initial_win_size = iv[1].value;
iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
iv[2].value = data->multi->push_cb != NULL;
iv[2].value = !!data->multi->push_cb;
return 3;
}
@@ -469,8 +460,7 @@ static int h2_client_new(struct Curl_cfilter *cf,
return rc;
/* We handle window updates ourself to enforce buffer limits */
nghttp2_option_set_no_auto_window_update(o, 1);
#if NGHTTP2_VERSION_NUM >= 0x013200
/* with 1.50.0 */
#if NGHTTP2_VERSION_NUM >= 0x013200 /* with 1.50.0 */
/* turn off RFC 9113 leading and trailing white spaces validation against
HTTP field value. */
nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1);
@@ -859,7 +849,7 @@ static int push_promise(struct Curl_cfilter *cf,
result = http2_data_setup(cf, newhandle, &newstream);
if(result) {
failf(data, "error setting up stream: %d", result);
failf(data, "error setting up stream: %d", (int)result);
discard_newhandle(cf, newhandle);
rv = CURL_PUSH_DENY;
goto fail;
@@ -908,7 +898,7 @@ static void h2_xfer_write_resp_hd(struct Curl_cfilter *cf,
stream->xfer_result = cf_h2_update_local_win(cf, data, stream);
if(stream->xfer_result)
CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of headers",
stream->id, stream->xfer_result, blen);
stream->id, (int)stream->xfer_result, blen);
}
}
@@ -925,7 +915,7 @@ static void h2_xfer_write_resp(struct Curl_cfilter *cf,
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);
stream->id, (int)stream->xfer_result, blen);
nghttp2_submit_rst_stream(ctx->h2, 0, stream->id,
(uint32_t)NGHTTP2_ERR_CALLBACK_FAILURE);
}
@@ -1389,7 +1379,7 @@ static void cf_h2_header_error(struct Curl_cfilter *cf,
{
struct cf_h2_ctx *ctx = cf->ctx;
failf(data, "Error receiving HTTP2 header: %d(%s)", result,
failf(data, "Error receiving HTTP2 header: %d(%s)", (int)result,
curl_easy_strerror(result));
if(stream) {
nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
@@ -1409,7 +1399,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
struct Curl_cfilter *cf = userp;
struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream;
struct Curl_easy *data_s;
struct Curl_easy *data;
int32_t stream_id = frame->hd.stream_id;
CURLcode result;
(void)flags;
@@ -1417,15 +1407,15 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
/* get the stream from the hash based on Stream ID */
data_s = nghttp2_session_get_stream_user_data(session, stream_id);
if(!GOOD_EASY_HANDLE(data_s))
data = nghttp2_session_get_stream_user_data(session, stream_id);
if(!GOOD_EASY_HANDLE(data))
/* Receiving a Stream ID not in the hash should not happen, this is an
internal error more than anything else! */
return NGHTTP2_ERR_CALLBACK_FAILURE;
stream = H2_STREAM_CTX(ctx, data_s);
stream = H2_STREAM_CTX(ctx, data);
if(!stream) {
failf(data_s, "Internal NULL stream");
failf(data, "Internal NULL stream");
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@@ -1438,14 +1428,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
!strncmp(HTTP_PSEUDO_AUTHORITY, (const char *)name, namelen)) {
/* pseudo headers are lower case */
int rc = 0;
char *check = curl_maprintf("%s:%d", cf->conn->host.name,
cf->conn->remote_port);
char *check = curl_maprintf("%s:%d", data->state.origin->hostname,
data->state.origin->port);
if(!check)
/* no memory */
return NGHTTP2_ERR_CALLBACK_FAILURE;
if(!curl_strequal(check, (const char *)value) &&
((cf->conn->remote_port != cf->conn->given->defport) ||
!curl_strequal(cf->conn->host.name, (const char *)value))) {
((data->state.origin->port != cf->conn->given->defport) ||
!curl_strequal(data->state.origin->hostname, (const char *)value))) {
/* This is push is not for the same authority that was asked for in
* the URL. RFC 7540 section 8.2 says: "A client MUST treat a
* PUSH_PROMISE for which the server is not authoritative as a stream
@@ -1473,7 +1463,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
char **headp;
if(stream->push_headers_alloc > 1000) {
/* this is beyond crazy many headers, bail out */
failf(data_s, "Too many PUSH_PROMISE headers");
failf(data, "Too many PUSH_PROMISE headers");
free_push_headers(stream);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@@ -1497,13 +1487,13 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(stream->bodystarted) {
/* This is a trailer */
CURL_TRC_CF(data_s, cf, "[%d] trailer: %.*s: %.*s",
CURL_TRC_CF(data, cf, "[%d] trailer: %.*s: %.*s",
stream->id, (int)namelen, name, (int)valuelen, value);
result = Curl_dynhds_add(&stream->resp_trailers,
(const char *)name, namelen,
(const char *)value, valuelen);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
cf_h2_header_error(cf, data, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@@ -1511,21 +1501,21 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
}
if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 &&
memcmp(HTTP_PSEUDO_STATUS, name, namelen) == 0) {
!memcmp(HTTP_PSEUDO_STATUS, name, namelen)) {
/* nghttp2 guarantees :status is received first and only once. */
char buffer[32];
size_t hlen;
result = Curl_http_decode_status(&stream->status_code,
(const char *)value, valuelen);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
cf_h2_header_error(cf, data, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
hlen = curl_msnprintf(buffer, sizeof(buffer), HTTP_PSEUDO_STATUS ":%d\r",
stream->status_code);
result = Curl_headers_push(data_s, buffer, hlen, CURLH_PSEUDO);
result = Curl_headers_push(data, buffer, hlen, CURLH_PSEUDO);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
cf_h2_header_error(cf, data, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
curlx_dyn_reset(&ctx->scratch);
@@ -1535,17 +1525,17 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(!result)
result = curlx_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
if(!result)
h2_xfer_write_resp_hd(cf, data_s, stream, curlx_dyn_ptr(&ctx->scratch),
h2_xfer_write_resp_hd(cf, data, stream, curlx_dyn_ptr(&ctx->scratch),
curlx_dyn_len(&ctx->scratch), FALSE);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
cf_h2_header_error(cf, data, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
/* if we receive data for another handle, wake that up */
if(CF_DATA_CURRENT(cf) != data_s)
Curl_multi_mark_dirty(data_s);
if(CF_DATA_CURRENT(cf) != data)
Curl_multi_mark_dirty(data);
CURL_TRC_CF(data_s, cf, "[%d] status: HTTP/2 %03d",
CURL_TRC_CF(data, cf, "[%d] status: HTTP/2 %03d",
stream->id, stream->status_code);
return 0;
}
@@ -1562,17 +1552,17 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(!result)
result = curlx_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
if(!result)
h2_xfer_write_resp_hd(cf, data_s, stream, curlx_dyn_ptr(&ctx->scratch),
h2_xfer_write_resp_hd(cf, data, stream, curlx_dyn_ptr(&ctx->scratch),
curlx_dyn_len(&ctx->scratch), FALSE);
if(result) {
cf_h2_header_error(cf, data_s, stream, result);
cf_h2_header_error(cf, data, stream, result);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
/* if we receive data for another handle, wake that up */
if(CF_DATA_CURRENT(cf) != data_s)
Curl_multi_mark_dirty(data_s);
if(CF_DATA_CURRENT(cf) != data)
Curl_multi_mark_dirty(data);
CURL_TRC_CF(data_s, cf, "[%d] header: %.*s: %.*s",
CURL_TRC_CF(data, cf, "[%d] header: %.*s: %.*s",
stream->id, (int)namelen, name, (int)valuelen, value);
return 0; /* 0 is successful */
@@ -1620,7 +1610,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
nread = (ssize_t)n;
CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d",
stream_id, length, stream->body_eos, nread, result);
stream_id, length, stream->body_eos, nread, (int)result);
if(stream->body_eos && Curl_bufq_is_empty(&stream->sendbuf)) {
*data_flags = NGHTTP2_DATA_FLAG_EOF;
@@ -1701,12 +1691,12 @@ static CURLcode http2_handle_stream_close(struct Curl_cfilter *cf,
return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
}
else 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;
return CURLE_OK;
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;
return CURLE_OK;
}
failf(data, "HTTP/2 stream %d reset by %s (error 0x%x %s)",
stream->id, stream->reset_by_server ? "server" : "curl",
@@ -1754,7 +1744,7 @@ static CURLcode http2_handle_stream_close(struct Curl_cfilter *cf,
result = CURLE_OK;
out:
CURL_TRC_CF(data, cf, "handle_stream_close -> %d, %zu", result, *pnlen);
CURL_TRC_CF(data, cf, "handle_stream_close -> %d, %zu", (int)result, *pnlen);
return result;
}
@@ -1778,16 +1768,12 @@ static int sweight_in_effect(const struct Curl_easy *data)
* struct.
*/
static void h2_pri_spec(struct cf_h2_ctx *ctx,
struct Curl_easy *data,
static void h2_pri_spec(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(ctx, prio->parent);
int32_t depstream_id = depstream ? depstream->id : 0;
nghttp2_priority_spec_init(pri_spec, depstream_id,
sweight_wanted(data),
data->set.priority.exclusive);
nghttp2_priority_spec_init(pri_spec, 0,
sweight_wanted(data), FALSE);
data->state.priority = *prio;
}
@@ -1805,13 +1791,11 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
int rv = 0;
if(stream && stream->id > 0 &&
((sweight_wanted(data) != sweight_in_effect(data)) ||
(data->set.priority.exclusive != data->state.priority.exclusive) ||
(data->set.priority.parent != data->state.priority.parent))) {
(sweight_wanted(data) != sweight_in_effect(data))) {
/* send new weight and/or dependency */
nghttp2_priority_spec pri_spec;
h2_pri_spec(ctx, data, &pri_spec);
h2_pri_spec(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,
@@ -1869,7 +1853,7 @@ static CURLcode stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(result && (result != CURLE_AGAIN))
CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %d, %zu",
stream->id, len, result, *pnread);
stream->id, len, (int)result, *pnread);
return result;
}
@@ -1920,7 +1904,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread);
if(result) {
if(result != CURLE_AGAIN) {
failf(data, "Failed receiving HTTP2 data: %d(%s)", result,
failf(data, "Failed receiving HTTP2 data: %d(%s)", (int)result,
curl_easy_strerror(result));
return result;
}
@@ -2015,7 +1999,7 @@ out:
}
CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu, "
"window=%d/%d, connection %d/%d",
stream->id, len, result, *pnread,
stream->id, len, (int)result, *pnread,
nghttp2_session_get_stream_effective_recv_data_length(
ctx->h2, stream->id),
nghttp2_session_get_stream_effective_local_window_size(
@@ -2123,7 +2107,7 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream,
goto out;
}
h2_pri_spec(ctx, data, &pri_spec);
h2_pri_spec(data, &pri_spec);
if(!nghttp2_session_check_request_allowed(ctx->h2))
CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)");
@@ -2200,7 +2184,7 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream,
out:
CURL_TRC_CF(data, cf, "[%d] submit -> %d, %zu",
stream ? stream->id : -1, result, *pnwritten);
stream ? stream->id : -1, (int)result, *pnwritten);
curlx_safefree(nva);
*pstream = stream;
Curl_dynhds_free(&h2_headers);
@@ -2234,7 +2218,7 @@ static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(eos);
result = cf_h2_body_send(cf, data, stream, buf, 0, eos, &n);
CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %d, %zu, eos=%d",
stream->id, result, n, eos);
stream->id, (int)result, n, eos);
if(result)
goto out;
*pnwritten = len;
@@ -2242,7 +2226,7 @@ static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
else {
result = cf_h2_body_send(cf, data, stream, buf, len, eos, pnwritten);
CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %d, %zu, eos=%d",
stream->id, len, result, *pnwritten, eos);
stream->id, len, (int)result, *pnwritten, eos);
}
/* Call the nghttp2 send loop and flush to write ALL buffered data,
@@ -2278,7 +2262,7 @@ out:
CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, "
"eos=%d, h2 windows %d-%d (stream-conn), "
"buffers %zu-%zu (stream-conn)",
stream->id, len, result, *pnwritten,
stream->id, len, (int)result, *pnwritten,
stream->body_eos,
nghttp2_session_get_stream_remote_window_size(
ctx->h2, stream->id),
@@ -2289,7 +2273,7 @@ out:
else {
CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zu, "
"connection-window=%d, nw_send_buffer(%zu)",
len, result, *pnwritten,
len, (int)result, *pnwritten,
nghttp2_session_get_remote_window_size(ctx->h2),
Curl_bufq_len(&ctx->outbufq));
}
@@ -2322,7 +2306,7 @@ out:
CURL_TRC_CF(data, cf, "[%d] flush -> %d, "
"h2 windows %d-%d (stream-conn), "
"buffers %zu-%zu (stream-conn)",
stream->id, result,
stream->id, (int)result,
nghttp2_session_get_stream_remote_window_size(
ctx->h2, stream->id),
nghttp2_session_get_remote_window_size(ctx->h2),
@@ -2332,7 +2316,7 @@ out:
else {
CURL_TRC_CF(data, cf, "flush -> %d, "
"connection-window=%d, nw_send_buffer(%zu)",
result, nghttp2_session_get_remote_window_size(ctx->h2),
(int)result, nghttp2_session_get_remote_window_size(ctx->h2),
Curl_bufq_len(&ctx->outbufq));
}
CF_DATA_RESTORE(cf, save);
@@ -2551,27 +2535,11 @@ static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
result = CURLE_OK;
out:
CURL_TRC_CF(data, cf, "cf_connect() -> %d, %d, ", result, *done);
CURL_TRC_CF(data, cf, "cf_connect() -> %d, %d, ", (int)result, *done);
CF_DATA_RESTORE(cf, save);
return result;
}
static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
if(ctx) {
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
cf_h2_ctx_close(ctx);
CF_DATA_RESTORE(cf, save);
cf->connected = FALSE;
}
if(cf->next)
cf->next->cft->do_close(cf->next, data);
}
static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
@@ -2794,7 +2762,6 @@ struct Curl_cftype Curl_cft_nghttp2 = {
CURL_LOG_LVL_NONE,
cf_h2_destroy,
cf_h2_connect,
cf_h2_close,
cf_h2_shutdown,
cf_h2_adjust_pollset,
cf_h2_data_pending,
@@ -2869,9 +2836,7 @@ bool Curl_http2_may_switch(struct Curl_easy *data)
(data->state.http_neg.wanted & CURL_HTTP_V2x) &&
data->state.http_neg.h2_prior_knowledge) {
#ifndef CURL_DISABLE_PROXY
if(data->conn->bits.httpproxy && !data->conn->bits.tunnel_proxy) {
/* We do not support HTTP/2 proxies yet. Also it is debatable
whether or not this setting should apply to HTTP/2 proxies. */
if(data->conn->bits.origin_is_proxy) {
infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
return FALSE;
}
@@ -2951,7 +2916,7 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
result = Curl_bufq_write(&ctx->inbufq,
(const unsigned char *)mem, nread, &copied);
if(result) {
failf(data, "error on copying HTTP Upgrade response: %d", result);
failf(data, "error on copying HTTP Upgrade response: %d", (int)result);
return CURLE_RECV_ERROR;
}
if(copied < nread) {
+286 -173
View File
@@ -271,13 +271,12 @@ static bool should_urlencode(struct Curl_str *service_name)
* should_urlencode == true is equivalent to should_urlencode_uri_path
* from the AWS SDK. Urls are already normalized by the curl URL parser
*/
if(curlx_str_cmp(service_name, "s3") ||
curlx_str_cmp(service_name, "s3-express") ||
curlx_str_cmp(service_name, "s3-outposts")) {
return false;
return FALSE;
}
return true;
return TRUE;
}
/* maximum length for the aws sivg4 parts */
@@ -384,7 +383,7 @@ static CURLcode make_headers(struct Curl_easy *data,
char date_full_hdr[DATE_FULL_HDR_LEN];
struct curl_slist *head = NULL;
struct curl_slist *tmp_head = NULL;
CURLcode ret = CURLE_OUT_OF_MEMORY;
CURLcode result = CURLE_OUT_OF_MEMORY;
struct curl_slist *l;
bool again = TRUE;
@@ -516,8 +515,8 @@ static CURLcode make_headers(struct Curl_easy *data,
}
} while(again);
ret = merge_duplicate_headers(head);
if(ret)
result = merge_duplicate_headers(head);
if(result)
goto fail;
for(l = head; l; l = l->next) {
@@ -540,11 +539,11 @@ static CURLcode make_headers(struct Curl_easy *data,
goto fail;
}
ret = CURLE_OK;
result = CURLE_OK;
fail:
curl_slist_free_all(head);
return ret;
return result;
}
#define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256"))
@@ -618,12 +617,12 @@ static CURLcode calc_s3_payload_hash(struct Curl_easy *data,
bool empty_payload = (empty_method || data->set.filesize == 0);
/* The POST payload is in memory */
bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields);
CURLcode ret = CURLE_OUT_OF_MEMORY;
CURLcode result = CURLE_OUT_OF_MEMORY;
if(empty_payload || post_payload) {
/* Calculate a real hash when we know the request payload */
ret = calc_payload_hash(data, sha_hash, sha_hex);
if(ret)
result = calc_payload_hash(data, sha_hash, sha_hex);
if(result)
goto fail;
}
else {
@@ -638,9 +637,9 @@ static CURLcode calc_s3_payload_hash(struct Curl_easy *data,
curl_msnprintf(header, CONTENT_SHA256_HDR_LEN,
"x-%.*s-content-sha256: %s", (int)plen, provider1, sha_hex);
ret = CURLE_OK;
result = CURLE_OK;
fail:
return ret;
return result;
}
static int compare_func(const void *a, const void *b)
@@ -818,66 +817,14 @@ fail:
return result;
}
CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
static CURLcode parse_sigv4_params(struct Curl_easy *data,
const char *hostname,
struct Curl_str *provider0,
struct Curl_str *provider1,
struct Curl_str *region,
struct Curl_str *service)
{
CURLcode result = CURLE_OUT_OF_MEMORY;
struct connectdata *conn = data->conn;
const char *line;
struct Curl_str provider0;
struct Curl_str provider1;
struct Curl_str region = { NULL, 0 };
struct Curl_str service = { NULL, 0 };
const char *hostname = conn->host.name;
time_t clock;
struct tm tm;
char timestamp[TIMESTAMP_SIZE];
char date[9];
struct dynbuf canonical_headers;
struct dynbuf signed_headers;
struct dynbuf canonical_query;
struct dynbuf canonical_path;
char *date_header = NULL;
Curl_HttpReq httpreq;
const char *method = NULL;
const char *payload_hash = NULL;
size_t payload_hash_len = 0;
unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
char sha_hex[SHA256_HEX_LENGTH];
char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
char *canonical_request = NULL;
char *request_type = NULL;
char *credential_scope = NULL;
char *str_to_sign = NULL;
const char *user = data->state.aptr.user ? data->state.aptr.user : "";
char *secret = NULL;
unsigned char sign0[CURL_SHA256_DIGEST_LENGTH] = { 0 };
unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = { 0 };
char *auth_headers = NULL;
if(data->set.path_as_is) {
failf(data, "Cannot use sigv4 authentication with path-as-is flag");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(Curl_checkheaders(data, STRCONST("Authorization"))) {
/* Authorization already present, Bailing out */
return CURLE_OK;
}
/* we init those buffers here, so goto fail will free initialized dynbuf */
curlx_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
curlx_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
curlx_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
curlx_dyn_init(&canonical_path, CURL_MAX_HTTP_HEADER);
/*
* Parameters parsing
* Google and Outscale use the same OSC or GOOG,
* but Amazon uses AWS and AMZ for header arguments.
* AWS is the default because most of non-amazon providers
* are still using aws:amz as a prefix.
*/
line = data->set.str[STRING_AWS_SIGV4];
const char *line = data->set.str[STRING_AWS_SIGV4];
if(!line || !*line)
line = "aws:amz";
@@ -885,71 +832,89 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
No string can be longer than N bytes of non-whitespace
*/
if(curlx_str_until(&line, &provider0, MAX_SIGV4_LEN, ':')) {
if(curlx_str_until(&line, provider0, MAX_SIGV4_LEN, ':')) {
failf(data, "first aws-sigv4 provider cannot be empty");
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto fail;
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(curlx_str_single(&line, ':') ||
curlx_str_until(&line, &provider1, MAX_SIGV4_LEN, ':')) {
provider1 = provider0;
curlx_str_until(&line, provider1, MAX_SIGV4_LEN, ':')) {
*provider1 = *provider0;
}
else if(curlx_str_single(&line, ':') ||
curlx_str_until(&line, &region, MAX_SIGV4_LEN, ':') ||
curlx_str_until(&line, region, MAX_SIGV4_LEN, ':') ||
curlx_str_single(&line, ':') ||
curlx_str_until(&line, &service, MAX_SIGV4_LEN, ':')) {
curlx_str_until(&line, service, MAX_SIGV4_LEN, ':')) {
/* nothing to do */
}
if(!curlx_strlen(&service)) {
if(!curlx_strlen(service)) {
const char *p = hostname;
if(curlx_str_until(&p, &service, MAX_SIGV4_LEN, '.') ||
if(curlx_str_until(&p, service, MAX_SIGV4_LEN, '.') ||
curlx_str_single(&p, '.')) {
failf(data, "aws-sigv4: service missing in parameters and hostname");
result = CURLE_URL_MALFORMAT;
goto fail;
return CURLE_URL_MALFORMAT;
}
infof(data, "aws_sigv4: picked service %.*s from host",
(int)curlx_strlen(&service), curlx_str(&service));
(int)curlx_strlen(service), curlx_str(service));
if(!curlx_strlen(&region)) {
if(curlx_str_until(&p, &region, MAX_SIGV4_LEN, '.') ||
if(!curlx_strlen(region)) {
if(curlx_str_until(&p, region, MAX_SIGV4_LEN, '.') ||
curlx_str_single(&p, '.')) {
failf(data, "aws-sigv4: region missing in parameters and hostname");
result = CURLE_URL_MALFORMAT;
goto fail;
return CURLE_URL_MALFORMAT;
}
infof(data, "aws_sigv4: picked region %.*s from host",
(int)curlx_strlen(&region), curlx_str(&region));
(int)curlx_strlen(region), curlx_str(region));
}
}
Curl_http_method(data, &method, &httpreq);
return CURLE_OK;
}
payload_hash =
parse_content_sha_hdr(data, curlx_str(&provider1),
curlx_strlen(&provider1), &payload_hash_len);
static CURLcode get_payload_hash(struct Curl_easy *data,
Curl_HttpReq httpreq,
struct Curl_str *provider0,
struct Curl_str *provider1,
struct Curl_str *service,
unsigned char *sha_hash,
char *sha_hex,
char *content_sha256_hdr,
const char **payload_hash_out,
size_t *payload_hash_len_out)
{
*payload_hash_out =
parse_content_sha_hdr(data, curlx_str(provider1),
curlx_strlen(provider1), payload_hash_len_out);
if(!payload_hash) {
if(!*payload_hash_out) {
CURLcode result;
/* AWS S3 requires a x-amz-content-sha256 header, and supports special
* values like UNSIGNED-PAYLOAD */
bool sign_as_s3 = curlx_str_casecompare(&provider0, "aws") &&
curlx_str_casecompare(&service, "s3");
bool sign_as_s3 = curlx_str_casecompare(provider0, "aws") &&
curlx_str_casecompare(service, "s3");
if(sign_as_s3)
result = calc_s3_payload_hash(data, httpreq, curlx_str(&provider1),
curlx_strlen(&provider1), sha_hash,
result = calc_s3_payload_hash(data, httpreq, curlx_str(provider1),
curlx_strlen(provider1), sha_hash,
sha_hex, content_sha256_hdr);
else
result = calc_payload_hash(data, sha_hash, sha_hex);
if(result)
goto fail;
return result;
payload_hash = sha_hex;
*payload_hash_out = sha_hex;
/* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */
payload_hash_len = strlen(sha_hex);
*payload_hash_len_out = strlen(sha_hex);
}
return CURLE_OK;
}
static CURLcode get_timestamp(char *timestamp, size_t stampsize)
{
time_t clock;
struct tm tm;
CURLcode result;
#ifdef DEBUGBUILD
{
@@ -963,43 +928,54 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
clock = time(NULL);
#endif
result = curlx_gmtime(clock, &tm);
if(result) {
goto fail;
}
if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
result = CURLE_OUT_OF_MEMORY;
goto fail;
}
if(result)
return result;
if(!strftime(timestamp, stampsize, "%Y%m%dT%H%M%SZ", &tm))
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
}
static CURLcode make_canonical_request(struct Curl_easy *data,
const char *hostname,
char *timestamp,
struct Curl_str *provider1,
struct Curl_str *service,
const char *method,
const char *payload_hash,
size_t payload_hash_len,
char **date_header_out,
char *content_sha256_hdr,
struct dynbuf *canonical_headers,
struct dynbuf *signed_headers,
char **canonical_request_out)
{
struct dynbuf canonical_query;
struct dynbuf canonical_path;
CURLcode result;
curlx_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
curlx_dyn_init(&canonical_path, CURL_MAX_HTTP_HEADER);
result = make_headers(data, hostname, timestamp,
curlx_str(&provider1), curlx_strlen(&provider1),
&date_header, content_sha256_hdr,
&canonical_headers, &signed_headers);
curlx_str(provider1), curlx_strlen(provider1),
date_header_out, content_sha256_hdr,
canonical_headers, signed_headers);
if(result)
goto fail;
if(*content_sha256_hdr) {
/* make_headers() needed this without the \r\n for canonicalization */
size_t hdrlen = strlen(content_sha256_hdr);
DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr));
memcpy(content_sha256_hdr + hdrlen, "\r\n", 3);
}
memcpy(date, timestamp, sizeof(date));
date[sizeof(date) - 1] = 0;
result = canon_query(data->state.up.query, &canonical_query);
if(result)
goto fail;
result = canon_path(data->state.up.path, strlen(data->state.up.path),
&canonical_path,
should_urlencode(&service));
should_urlencode(service));
if(result)
goto fail;
result = CURLE_OUT_OF_MEMORY;
canonical_request =
*canonical_request_out =
curl_maprintf("%s\n" /* HTTPRequestMethod */
"%s\n" /* CanonicalURI */
"%s\n" /* CanonicalQueryString */
@@ -1010,37 +986,65 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
curlx_dyn_ptr(&canonical_path),
curlx_dyn_ptr(&canonical_query) ?
curlx_dyn_ptr(&canonical_query) : "",
curlx_dyn_ptr(&canonical_headers),
curlx_dyn_ptr(&signed_headers),
curlx_dyn_ptr(canonical_headers),
curlx_dyn_ptr(signed_headers),
(int)payload_hash_len, payload_hash);
if(!canonical_request)
if(!*canonical_request_out) {
result = CURLE_OUT_OF_MEMORY;
goto fail;
}
infof(data, "aws_sigv4: Canonical request (enclosed in []) - [%s]",
canonical_request);
result = CURLE_OK;
fail:
curlx_dyn_free(&canonical_query);
curlx_dyn_free(&canonical_path);
return result;
}
static CURLcode make_string_to_sign(struct Curl_easy *data,
struct Curl_str *provider0,
struct Curl_str *region,
struct Curl_str *service,
const char *date,
const char *timestamp,
const char *canonical_request,
char **request_type_out,
char **credential_scope_out,
char **str_to_sign_out)
{
char *request_type;
char *credential_scope;
char *str_to_sign;
unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
char sha_hex[SHA256_HEX_LENGTH];
request_type = curl_maprintf("%.*s4_request",
(int)curlx_strlen(&provider0),
curlx_str(&provider0));
(int)curlx_strlen(provider0),
curlx_str(provider0));
if(!request_type)
goto fail;
return CURLE_OUT_OF_MEMORY;
/* provider0 is lowercased *after* curl_maprintf() so that the buffer
can be written to */
Curl_strntolower(request_type, request_type, curlx_strlen(&provider0));
Curl_strntolower(request_type, request_type, curlx_strlen(provider0));
credential_scope = curl_maprintf("%s/%.*s/%.*s/%s", date,
(int)curlx_strlen(&region),
curlx_str(&region),
(int)curlx_strlen(&service),
curlx_str(&service),
(int)curlx_strlen(region),
curlx_str(region),
(int)curlx_strlen(service),
curlx_str(service),
request_type);
if(!credential_scope)
goto fail;
if(!credential_scope) {
curlx_free(request_type);
return CURLE_OUT_OF_MEMORY;
}
if(Curl_sha256it(sha_hash, (unsigned char *)canonical_request,
strlen(canonical_request)))
goto fail;
if(Curl_sha256it(sha_hash, (const unsigned char *)canonical_request,
strlen(canonical_request))) {
curlx_free(request_type);
curlx_free(credential_scope);
return CURLE_OUT_OF_MEMORY;
}
sha256_to_hex(sha_hex, sha_hash);
@@ -1052,36 +1056,69 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
"%s\n" /* RequestDateTime */
"%s\n" /* CredentialScope */
"%s", /* HashedCanonicalRequest in hex */
(int)curlx_strlen(&provider0),
curlx_str(&provider0),
(int)curlx_strlen(provider0),
curlx_str(provider0),
timestamp,
credential_scope,
sha_hex);
if(!str_to_sign)
goto fail;
if(!str_to_sign) {
curlx_free(request_type);
curlx_free(credential_scope);
return CURLE_OUT_OF_MEMORY;
}
/* make provider0 part done uppercase */
Curl_strntoupper(str_to_sign, curlx_str(&provider0),
curlx_strlen(&provider0));
Curl_strntoupper(str_to_sign, curlx_str(provider0),
curlx_strlen(provider0));
infof(data, "aws_sigv4: String to sign (enclosed in []) - [%s]",
str_to_sign);
secret = curl_maprintf("%.*s4%s", (int)curlx_strlen(&provider0),
curlx_str(&provider0), data->state.aptr.passwd ?
data->state.aptr.passwd : "");
*request_type_out = request_type;
*credential_scope_out = credential_scope;
*str_to_sign_out = str_to_sign;
return CURLE_OK;
}
static CURLcode sign_and_set_auth_headers(struct Curl_easy *data,
struct Curl_str *provider0,
struct Curl_str *region,
struct Curl_str *service,
const char *request_type,
const char *credential_scope,
const char *date,
const char *str_to_sign,
const char *date_header,
const char *content_sha256_hdr,
struct dynbuf *signed_headers)
{
CURLcode result = CURLE_OUT_OF_MEMORY;
const char *passwd = Curl_creds_passwd(data->state.creds);
char *secret = NULL;
unsigned char sign0[CURL_SHA256_DIGEST_LENGTH] = { 0 };
unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = { 0 };
char sha_hex[SHA256_HEX_LENGTH];
char *auth_headers = NULL;
char *user = curl_escape(Curl_creds_user(data->state.creds), 0);
if(!user)
return CURLE_OUT_OF_MEMORY;
secret = curl_maprintf("%.*s4%s", (int)curlx_strlen(provider0),
curlx_str(provider0), passwd);
if(!secret)
goto fail;
/* make provider0 part done uppercase */
Curl_strntoupper(secret, curlx_str(&provider0), curlx_strlen(&provider0));
Curl_strntoupper(secret, curlx_str(provider0), curlx_strlen(provider0));
HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0);
HMAC_SHA256(sign0, sizeof(sign0),
curlx_str(&region), curlx_strlen(&region), sign1);
curlx_str(region), curlx_strlen(region), sign1);
HMAC_SHA256(sign1, sizeof(sign1),
curlx_str(&service), curlx_strlen(&service), sign0);
HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
curlx_str(service), curlx_strlen(service), sign0);
HMAC_SHA256(sign0, sizeof(sign0),
request_type, strlen(request_type), sign1);
HMAC_SHA256(sign1, sizeof(sign1),
str_to_sign, strlen(str_to_sign), sign0);
sha256_to_hex(sha_hex, sign0);
@@ -1091,43 +1128,119 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
"Credential=%s/%s, "
"SignedHeaders=%s, "
"Signature=%s\r\n"
"%s"
"%s%s",
(int)curlx_strlen(provider0),
curlx_str(provider0),
user,
credential_scope,
curlx_dyn_ptr(signed_headers),
sha_hex,
/*
* date_header is added here, only if it was not
* user-specified (using CURLOPT_HTTPHEADER).
* date_header includes \r\n
*/
"%s"
"%s", /* optional sha256 header includes \r\n */
(int)curlx_strlen(&provider0),
curlx_str(&provider0),
user,
credential_scope,
curlx_dyn_ptr(&signed_headers),
sha_hex,
date_header ? date_header : "",
content_sha256_hdr);
if(!auth_headers) {
content_sha256_hdr,
content_sha256_hdr[0] ? "\r\n": "");
if(!auth_headers)
goto fail;
}
/* provider 0 uppercase */
Curl_strntoupper(&auth_headers[sizeof("Authorization: ") - 1],
curlx_str(&provider0), curlx_strlen(&provider0));
curlx_str(provider0), curlx_strlen(provider0));
curlx_free(data->req.userpwd);
data->req.userpwd = auth_headers;
curlx_free(data->req.hd_auth);
data->req.hd_auth = auth_headers;
data->state.authhost.done = TRUE;
result = CURLE_OK;
fail:
curlx_dyn_free(&canonical_query);
curlx_dyn_free(&canonical_path);
curlx_free(user);
curlx_free(secret);
return result;
}
CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
{
CURLcode result = CURLE_OUT_OF_MEMORY;
struct Curl_str provider0 = { NULL, 0 };
struct Curl_str provider1 = { NULL, 0 };
struct Curl_str region = { NULL, 0 };
struct Curl_str service = { NULL, 0 };
const char *hostname = data->state.origin->hostname;
char timestamp[TIMESTAMP_SIZE];
char date[9];
struct dynbuf canonical_headers;
struct dynbuf signed_headers;
char *date_header = NULL;
Curl_HttpReq httpreq;
const char *method = NULL;
const char *payload_hash = NULL;
size_t payload_hash_len = 0;
unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
char sha_hex[SHA256_HEX_LENGTH];
char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
char *canonical_request = NULL;
char *request_type = NULL;
char *credential_scope = NULL;
char *str_to_sign = NULL;
if(data->set.path_as_is) {
failf(data, "Cannot use sigv4 authentication with path-as-is flag");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(Curl_checkheaders(data, STRCONST("Authorization")))
/* Authorization already present, Bailing out */
return CURLE_OK;
/* we init those buffers here, so goto fail will free initialized dynbuf */
curlx_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
curlx_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
result = parse_sigv4_params(data, hostname, &provider0, &provider1,
&region, &service);
if(!result) {
Curl_http_method(data, &method, &httpreq);
result = get_payload_hash(data, httpreq, &provider0, &provider1, &service,
sha_hash, sha_hex, content_sha256_hdr,
&payload_hash, &payload_hash_len);
}
if(!result)
result = get_timestamp(timestamp, sizeof(timestamp));
if(!result)
result = make_canonical_request(data, hostname, timestamp,
&provider1, &service,
method, payload_hash, payload_hash_len,
&date_header, content_sha256_hdr,
&canonical_headers, &signed_headers,
&canonical_request);
if(!result) {
/* the timestamp might have been updated in make_canonical_request */
memcpy(date, timestamp, sizeof(date) - 1);
date[sizeof(date) - 1] = 0;
result = make_string_to_sign(data, &provider0, &region, &service,
date, timestamp, canonical_request,
&request_type, &credential_scope,
&str_to_sign);
}
if(!result)
result = sign_and_set_auth_headers(data, &provider0, &region, &service,
request_type, credential_scope,
date, str_to_sign, date_header,
content_sha256_hdr, &signed_headers);
curlx_dyn_free(&canonical_headers);
curlx_dyn_free(&signed_headers);
curlx_free(canonical_request);
curlx_free(request_type);
curlx_free(credential_scope);
curlx_free(str_to_sign);
curlx_free(secret);
curlx_free(date_header);
return result;
}

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