Merge branch 'upstream-curl' into update-curl

* upstream-curl:
  curl 2020-03-04 (b8d13668)
This commit is contained in:
Brad King 2020-03-04 14:34:39 -05:00
commit d61c3bd505
226 changed files with 13126 additions and 6792 deletions

View File

@ -11,13 +11,7 @@ if(CURL_HIDDEN_SYMBOLS)
set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
elseif(CMAKE_COMPILER_IS_GNUCC)
if(NOT CMAKE_VERSION VERSION_LESS 2.8.10)
set(GCC_VERSION ${CMAKE_C_COMPILER_VERSION})
else()
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
endif()
if(NOT GCC_VERSION VERSION_LESS 3.4)
if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
# note: this is considered buggy prior to 4.0 but the autotools don't care, so let's ignore that fact
set(SUPPORTS_SYMBOL_HIDING TRUE)
set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
@ -29,7 +23,7 @@ if(CURL_HIDDEN_SYMBOLS)
set(_CFLAG_SYMBOLS_HIDE "-xldscope=hidden")
elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0)
# note: this should probably just check for version 9.1.045 but I'm not 100% sure
# so let's to it the same way autotools do.
# so let's do it the same way autotools do.
set(SUPPORTS_SYMBOL_HIDING TRUE)
set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -125,6 +125,7 @@ int main(void)
#if defined(HAVE_GETHOSTBYADDR_R_5) || \
defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT)
rc = gethostbyaddr_r(address, length, type, &h, &hdata);
(void)rc;
#elif defined(HAVE_GETHOSTBYADDR_R_7) || \
defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT)
hp = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &h_errnop);
@ -132,6 +133,7 @@ int main(void)
#elif defined(HAVE_GETHOSTBYADDR_R_8) || \
defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT)
rc = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &hp, &h_errnop);
(void)rc;
#endif
#if defined(HAVE_GETHOSTBYNAME_R_3) || \

View File

@ -0,0 +1,9 @@
find_path(BEARSSL_INCLUDE_DIRS bearssl.h)
find_library(BEARSSL_LIBRARY bearssl)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(BEARSSL DEFAULT_MSG
BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)
mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)

View File

@ -7,34 +7,16 @@
# also defined, but not for general use are
# CARES_LIBRARY, where to find the c-ares library.
find_path(CARES_INCLUDE_DIR ares.h
/usr/local/include
/usr/include
)
find_path(CARES_INCLUDE_DIR ares.h)
set(CARES_NAMES ${CARES_NAMES} cares)
find_library(CARES_LIBRARY
NAMES ${CARES_NAMES}
PATHS /usr/lib /usr/local/lib
)
if(CARES_LIBRARY AND CARES_INCLUDE_DIR)
set(CARES_LIBRARIES ${CARES_LIBRARY})
set(CARES_FOUND "YES")
else()
set(CARES_FOUND "NO")
endif()
if(CARES_FOUND)
if(NOT CARES_FIND_QUIETLY)
message(STATUS "Found c-ares: ${CARES_LIBRARIES}")
endif()
else()
if(CARES_FIND_REQUIRED)
message(FATAL_ERROR "Could not find c-ares library")
endif()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(CARES
REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR)
mark_as_advanced(
CARES_LIBRARY

View File

@ -62,6 +62,7 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi"
OUTPUT_VARIABLE _GSS_CFLAGS
RESULT_VARIABLE _GSS_CONFIGURE_FAILED
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "CFLAGS: ${_GSS_CFLAGS}")
if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
@ -84,6 +85,7 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi"
OUTPUT_VARIABLE _GSS_LIB_FLAGS
RESULT_VARIABLE _GSS_CONFIGURE_FAILED
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}")
@ -110,6 +112,7 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version"
OUTPUT_VARIABLE _GSS_VERSION
RESULT_VARIABLE _GSS_CONFIGURE_FAILED
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# older versions may not have the "--version" parameter. In this case we just don't care.
@ -121,6 +124,7 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor"
OUTPUT_VARIABLE _GSS_VENDOR
RESULT_VARIABLE _GSS_CONFIGURE_FAILED
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# older versions may not have the "--vendor" parameter. In this case we just don't care.
@ -134,7 +138,7 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
endif()
endif()
else() # either there is no config script or we are on platform that doesn't provide one (Windows?)
else() # either there is no config script or we are on a platform that doesn't provide one (Windows?)
find_path(_GSS_INCLUDE_DIR
NAMES
@ -164,7 +168,7 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
set(CMAKE_REQUIRED_DEFINITIONS "")
endif()
else()
# I'm not convienced if this is the right way but this is what autotools do at the moment
# I'm not convinced if this is the right way but this is what autotools do at the moment
find_path(_GSS_INCLUDE_DIR
NAMES
"gssapi.h"

View File

@ -5,31 +5,18 @@
# LIBSSH2_INCLUDE_DIR - the libssh2 include directory
# LIBSSH2_LIBRARY - the libssh2 library name
if(LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY)
set(LibSSH2_FIND_QUIETLY TRUE)
endif()
find_path(LIBSSH2_INCLUDE_DIR libssh2.h)
find_path(LIBSSH2_INCLUDE_DIR libssh2.h
)
find_library(LIBSSH2_LIBRARY NAMES ssh2
)
find_library(LIBSSH2_LIBRARY NAMES ssh2 libssh2)
if(LIBSSH2_INCLUDE_DIR)
file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9][0-9][0-9][0-9][0-9].*")
string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_MAJOR "${libssh2_version_str}")
string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9]([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_MINOR "${libssh2_version_str}")
string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9][0-9][0-9]([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_PATCH "${libssh2_version_str}")
string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_MAJOR "${LIBSSH2_VERSION_MAJOR}")
string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_MINOR "${LIBSSH2_VERSION_MINOR}")
string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_PATCH "${LIBSSH2_VERSION_PATCH}")
set(LIBSSH2_VERSION "${LIBSSH2_VERSION_MAJOR}.${LIBSSH2_VERSION_MINOR}.${LIBSSH2_VERSION_PATCH}")
file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION[\t ]+\"(.*)\"")
string(REGEX REPLACE "^.*\"([^\"]+)\"" "\\1" LIBSSH2_VERSION "${libssh2_version_str}")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibSSH2 DEFAULT_MSG LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY )
find_package_handle_standard_args(LibSSH2
REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR
VERSION_VAR LIBSSH2_VERSION)
mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY LIBSSH2_VERSION_MAJOR LIBSSH2_VERSION_MINOR LIBSSH2_VERSION_PATCH LIBSSH2_VERSION)
mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)

View File

@ -10,9 +10,9 @@ find_package_handle_standard_args(NGHTTP2
REQUIRED_VARS
NGHTTP2_LIBRARY
NGHTTP2_INCLUDE_DIR
FAIL_MESSAGE
"Could NOT find NGHTTP2"
)
set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR})
set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY})
mark_as_advanced(NGHTTP2_INCLUDE_DIRS NGHTTP2_LIBRARIES)

View File

@ -0,0 +1,17 @@
if(UNIX)
find_package(PkgConfig QUIET)
pkg_search_module(PC_NSS nss)
endif()
if(NOT PC_NSS_FOUND)
return()
endif()
set(NSS_LIBRARIES ${PC_NSS_LINK_LIBRARIES})
set(NSS_INCLUDE_DIRS ${PC_NSS_INCLUDE_DIRS})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(NSS
REQUIRED_VARS NSS_LIBRARIES NSS_INCLUDE_DIRS
VERSION_VAR PC_NSS_VERSION)
mark_as_advanced(NSS_INCLUDE_DIRS NSS_LIBRARIES)

View File

@ -32,7 +32,7 @@ int main(void) {
return 0;
}" curl_cv_recv)
if(curl_cv_recv)
if(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
if(NOT DEFINED curl_cv_func_recv_args OR curl_cv_func_recv_args STREQUAL "unknown")
foreach(recv_retv "int" "ssize_t" )
foreach(recv_arg1 "SOCKET" "int" )
foreach(recv_arg2 "char *" "void *" )
@ -81,7 +81,7 @@ if(curl_cv_recv)
string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" RECV_TYPE_RETV "${curl_cv_func_recv_args}")
endif()
if("${curl_cv_func_recv_args}" STREQUAL "unknown")
if(curl_cv_func_recv_args STREQUAL "unknown")
message(FATAL_ERROR "Cannot find proper types to use for recv args")
endif()
else()

View File

@ -7,7 +7,6 @@ if(NOT UNIX)
set(HAVE_LIBNSL 0)
set(HAVE_GETHOSTNAME 1)
set(HAVE_LIBZ 0)
set(HAVE_LIBCRYPTO 0)
set(HAVE_DLOPEN 0)

View File

@ -2,12 +2,11 @@
# Returns a list of arguments that evaluate to true
function(count_true output_count_var)
set(lst)
set(lst_len 0)
foreach(option_var IN LISTS ARGN)
if(${option_var})
list(APPEND lst ${option_var})
math(EXPR lst_len "${lst_len} + 1")
endif()
endforeach()
list(LENGTH lst lst_len)
set(${output_count_var} ${lst_len} PARENT_SCOPE)
endfunction()

View File

@ -91,7 +91,7 @@ endif()
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
# Copyright (C) 1998 - 2020, 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
@ -136,7 +136,7 @@ if(0) # This code not needed for building within CMake.
message(WARNING "the curl cmake build system is poorly maintained. Be aware")
endif()
file(READ ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS)
file(STRINGS ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS REGEX "#define LIBCURL_VERSION( |_NUM )")
string(REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*"
CURL_VERSION ${CURL_VERSION_H_CONTENTS})
string(REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION})
@ -168,7 +168,18 @@ option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
if(WIN32)
option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF)
option(ENABLE_INET_PTON "Set to OFF to prevent usage of inet_pton when building against modern SDKs while still requiring compatibility with older Windows versions, such as Windows XP, Windows Server 2003 etc." ON)
set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string")
if(CURL_TARGET_WINDOWS_VERSION)
add_definitions(-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION})
elseif(ENABLE_INET_PTON)
# _WIN32_WINNT_VISTA (0x0600)
add_definitions(-D_WIN32_WINNT=0x0600)
else()
# _WIN32_WINNT_WINXP (0x0501)
add_definitions(-D_WIN32_WINNT=0x0501)
endif()
endif()
option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF)
if(0) # This code not needed for building within CMake.
cmake_dependent_option(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup"
@ -184,8 +195,9 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers -Wno-pedantic-ms-format)
# surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
# test result in.
check_c_compiler_flag(${_CCOPT} OPT${_CCOPT})
if(OPT${_CCOPT})
string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname)
check_c_compiler_flag(${_CCOPT} ${_optvarname})
if(${_optvarname})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT}")
endif()
endforeach()
@ -216,7 +228,6 @@ if(ENABLE_ARES)
set(USE_ARES 1)
find_package(CARES REQUIRED)
list(APPEND CURL_LIBS ${CARES_LIBRARY})
set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY})
endif()
if(0) # This code not needed for building within CMake.
@ -267,6 +278,7 @@ if(HTTP_ONLY)
set(CURL_DISABLE_RTSP ON)
set(CURL_DISABLE_POP3 ON)
set(CURL_DISABLE_IMAP ON)
set(CURL_DISABLE_SMB ON)
set(CURL_DISABLE_SMTP ON)
set(CURL_DISABLE_GOPHER ON)
endif()
@ -332,6 +344,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES AIX)
endif()
# Include all the necessary files for macros
include(CMakePushCheckState)
include(CheckFunctionExists)
include(CheckIncludeFile)
include(CheckIncludeFiles)
@ -359,7 +372,7 @@ endif()
# Check for all needed libraries
if(0) # This code not needed for building within CMake.
check_library_exists_concat("dl" dlopen HAVE_LIBDL)
check_library_exists_concat("${CMAKE_DL_LIBS}" dlopen HAVE_LIBDL)
else()
# Use the cmake-defined dl libs as dl is should not be used
# on HPUX, but rather dld this avoids a warning
@ -390,7 +403,7 @@ if(WIN32)
endif()
# check SSL libraries
# TODO support GNUTLS, NSS, POLARSSL, CYASSL
# TODO support GnuTLS and WolfSSL
if(APPLE)
option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF)
@ -401,9 +414,11 @@ if(WIN32)
CMAKE_USE_WINSSL OFF)
endif()
option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF)
option(CMAKE_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF)
option(CMAKE_USE_NSS "Enable NSS for SSL/TLS" OFF)
set(openssl_default ON)
if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS)
if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS)
set(openssl_default OFF)
endif()
@ -412,6 +427,8 @@ count_true(enabled_ssl_options_count
CMAKE_USE_SECTRANSP
CMAKE_USE_OPENSSL
CMAKE_USE_MBEDTLS
CMAKE_USE_BEARSSL
CMAKE_USE_NSS
)
if(enabled_ssl_options_count GREATER "1")
set(CURL_WITH_MULTI_SSL ON)
@ -457,8 +474,6 @@ if(CMAKE_USE_OPENSSL)
endif()
set(SSL_ENABLED ON)
set(USE_OPENSSL ON)
set(HAVE_LIBCRYPTO ON)
set(HAVE_LIBSSL ON)
list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
include_directories(${OPENSSL_INCLUDE_DIR})
@ -492,6 +507,27 @@ if(CMAKE_USE_MBEDTLS)
include_directories(${MBEDTLS_INCLUDE_DIRS})
endif()
if(CMAKE_USE_BEARSSL)
find_package(BearSSL REQUIRED)
set(SSL_ENABLED ON)
set(USE_BEARSSL ON)
list(APPEND CURL_LIBS ${BEARSSL_LIBRARY})
include_directories(${BEARSSL_INCLUDE_DIRS})
endif()
if(CMAKE_USE_NSS)
find_package(NSS REQUIRED)
include_directories(${NSS_INCLUDE_DIRS})
list(APPEND CURL_LIBS ${NSS_LIBRARIES})
set(SSL_ENABLED ON)
set(USE_NSS ON)
cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES ${NSS_INCLUDE_DIRS})
set(CMAKE_REQUIRED_LIBRARIES ${NSS_LIBRARIES})
check_symbol_exists(PK11_CreateManagedGenericObject "pk11pub.h" HAVE_PK11_CREATEMANAGEDGENERICOBJECT)
cmake_pop_check_state()
endif()
option(USE_NGHTTP2 "Use Nghttp2 library" OFF)
if(USE_NGHTTP2)
find_package(NGHTTP2 REQUIRED)
@ -499,6 +535,10 @@ if(USE_NGHTTP2)
list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES})
endif()
if(WIN32)
set(USE_WIN32_CRYPTO ON)
endif()
if(NOT CURL_DISABLE_LDAP)
if(WIN32)
option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
@ -653,7 +693,7 @@ endif()
option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
set(HAVE_BROTLI OFF)
if(CURL_BROTLI)
find_package(BROTLI QUIET)
find_package(Brotli QUIET)
if(BROTLI_FOUND)
set(HAVE_BROTLI ON)
list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
@ -793,7 +833,9 @@ elseif("${CURL_CA_PATH}" STREQUAL "none")
unset(CURL_CA_PATH CACHE)
elseif("${CURL_CA_PATH}" STREQUAL "auto")
unset(CURL_CA_PATH CACHE)
set(CURL_CA_PATH_AUTODETECT TRUE)
if(NOT USE_NSS)
set(CURL_CA_PATH_AUTODETECT TRUE)
endif()
else()
set(CURL_CA_PATH_SET TRUE)
endif()
@ -983,6 +1025,7 @@ check_symbol_exists(strlcat "${CURL_INCLUDES}" HAVE_STRLCAT)
check_symbol_exists(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID)
check_symbol_exists(getpwuid_r "${CURL_INCLUDES}" HAVE_GETPWUID_R)
check_symbol_exists(geteuid "${CURL_INCLUDES}" HAVE_GETEUID)
check_symbol_exists(usleep "${CURL_INCLUDES}" HAVE_USLEEP)
check_symbol_exists(utime "${CURL_INCLUDES}" HAVE_UTIME)
check_symbol_exists(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R)
check_symbol_exists(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R)
@ -1010,6 +1053,7 @@ check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE)
check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME)
check_symbol_exists(getpeername "${CURL_INCLUDES}" HAVE_GETPEERNAME)
check_symbol_exists(getsockname "${CURL_INCLUDES}" HAVE_GETSOCKNAME)
check_symbol_exists(if_nametoindex "${CURL_INCLUDES}" HAVE_IF_NAMETOINDEX)
check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT)
check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE)
check_symbol_exists(setmode "${CURL_INCLUDES}" HAVE_SETMODE)
@ -1018,20 +1062,7 @@ check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL)
check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL)
check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT)
check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME)
# symbol exists in win32, but function does not.
if(WIN32)
if(ENABLE_INET_PTON)
check_function_exists(inet_pton HAVE_INET_PTON)
# _WIN32_WINNT_VISTA (0x0600)
add_definitions(-D_WIN32_WINNT=0x0600)
else()
# _WIN32_WINNT_WINXP (0x0501)
add_definitions(-D_WIN32_WINNT=0x0501)
endif()
else()
check_function_exists(inet_pton HAVE_INET_PTON)
endif()
check_symbol_exists(inet_pton "${CURL_INCLUDES}" HAVE_INET_PTON)
check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR)
if(HAVE_FSETXATTR)
@ -1255,6 +1286,23 @@ if(CURL_WERROR)
endif()
endif()
if(CURL_LTO)
if(CMAKE_VERSION VERSION_LESS 3.9)
message(FATAL_ERROR "Requested LTO but your cmake version ${CMAKE_VERSION} is to old. You need at least 3.9")
endif()
cmake_policy(SET CMP0069 NEW)
include(CheckIPOSupported)
check_ipo_supported(RESULT CURL_HAS_LTO OUTPUT CURL_LTO_ERROR LANGUAGES C)
if(CURL_HAS_LTO)
message(STATUS "LTO supported and enabled")
else()
message(FATAL_ERROR "LTO was requested - but compiler doesn't support it\n${CURL_LTO_ERROR}")
endif()
endif()
# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
function(transform_makefile_inc INPUT_FILE OUTPUT_FILE)
file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT)
@ -1309,14 +1357,22 @@ if(BUILD_TESTING)
add_subdirectory(tests)
endif()
# NTLM support requires crypto function adaptions from various SSL libs
# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_DARWINSSL OR USE_MBEDTLS OR USE_WIN32_CRYPTO))
set(use_ntlm ON)
else()
set(use_ntlm OFF)
endif()
# Helper to populate a list (_items) with a label when conditions (the remaining
# args) are satisfied
function(_add_if label)
# TODO need to disable policy CMP0054 (CMake 3.1) to allow this indirection
macro(_add_if label)
# needs to be a macro to allow this indirection
if(${ARGN})
set(_items ${_items} "${label}" PARENT_SCOPE)
set(_items ${_items} "${label}")
endif()
endfunction()
endmacro()
# Clear list and try to detect available features
set(_items)
@ -1338,15 +1394,14 @@ _add_if("Kerberos" NOT CURL_DISABLE_CRYPTO_AUTH AND
(HAVE_GSSAPI OR USE_WINDOWS_SSPI))
# NTLM support requires crypto function adaptions from various SSL libs
# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_SECTRANSP OR USE_MBEDTLS))
_add_if("NTLM" 1)
# TODO missing option (autoconf: --enable-ntlm-wb)
_add_if("NTLM_WB" NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
endif()
_add_if("NTLM" use_ntlm)
# TODO missing option (autoconf: --enable-ntlm-wb)
_add_if("NTLM_WB" use_ntlm AND NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
# TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP
_add_if("TLS-SRP" USE_TLS_SRP)
# TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header
_add_if("HTTP2" USE_NGHTTP2)
_add_if("HTTPS-proxy" SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS))
string(REPLACE ";" " " SUPPORT_FEATURES "${_items}")
message(STATUS "Enabled features: ${SUPPORT_FEATURES}")
@ -1371,6 +1426,8 @@ _add_if("POP3" NOT CURL_DISABLE_POP3)
_add_if("POP3S" NOT CURL_DISABLE_POP3 AND SSL_ENABLED)
_add_if("IMAP" NOT CURL_DISABLE_IMAP)
_add_if("IMAPS" NOT CURL_DISABLE_IMAP AND SSL_ENABLED)
_add_if("SMB" NOT CURL_DISABLE_SMB AND use_ntlm)
_add_if("SMBS" NOT CURL_DISABLE_SMB AND SSL_ENABLED AND use_ntlm)
_add_if("SMTP" NOT CURL_DISABLE_SMTP)
_add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED)
_add_if("SCP" USE_LIBSSH2)
@ -1389,6 +1446,8 @@ _add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI)
_add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL)
_add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP)
_add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS)
_add_if("BearSSL" SSL_ENABLED AND USE_BEARSSL)
_add_if("NSS" SSL_ENABLED AND USE_NSS)
if(_items)
list(SORT _items)
endif()

View File

@ -1,6 +1,6 @@
COPYRIGHT AND PERMISSION NOTICE
Copyright (c) 1996 - 2019, Daniel Stenberg, <daniel@haxx.se>, and many
Copyright (c) 1996 - 2020, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
All rights reserved.

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
#ifndef __CURL_CURLVER_H
#define __CURL_CURLVER_H
#ifndef CURLINC_CURLVER_H
#define CURLINC_CURLVER_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -26,16 +26,16 @@
a script at release-time. This was made its own header file in 7.11.2 */
/* This is the global package copyright */
#define LIBCURL_COPYRIGHT "1996 - 2019 Daniel Stenberg, <daniel@haxx.se>."
#define LIBCURL_COPYRIGHT "1996 - 2020 Daniel Stenberg, <daniel@haxx.se>."
/* This is the version number of the libcurl package from which this header
file origins: */
#define LIBCURL_VERSION "7.65.0"
#define LIBCURL_VERSION "7.69.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 7
#define LIBCURL_VERSION_MINOR 65
#define LIBCURL_VERSION_MINOR 69
#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
@ -57,7 +57,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 0x074100
#define LIBCURL_VERSION_NUM 0x074500
/*
* This is the date and time when the full source package was created. The
@ -74,4 +74,4 @@
#define CURL_AT_LEAST_VERSION(x,y,z) \
(LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
#endif /* __CURL_CURLVER_H */
#endif /* CURLINC_CURLVER_H */

View File

@ -1,5 +1,5 @@
#ifndef __CURL_EASY_H
#define __CURL_EASY_H
#ifndef CURLINC_EASY_H
#define CURLINC_EASY_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -1,5 +1,5 @@
#ifndef __CURL_MPRINTF_H
#define __CURL_MPRINTF_H
#ifndef CURLINC_MPRINTF_H
#define CURLINC_MPRINTF_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -47,4 +47,4 @@ CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
}
#endif
#endif /* __CURL_MPRINTF_H */
#endif /* CURLINC_MPRINTF_H */

View File

@ -1,5 +1,5 @@
#ifndef __CURL_MULTI_H
#define __CURL_MULTI_H
#ifndef CURLINC_MULTI_H
#define CURLINC_MULTI_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -72,6 +72,8 @@ typedef enum {
attempted to get added - again */
CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
callback */
CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */
CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */
CURLM_LAST
} CURLMcode;
@ -173,6 +175,29 @@ CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
int timeout_ms,
int *ret);
/*
* Name: curl_multi_poll()
*
* Desc: Poll on all fds within a CURLM set as well as any
* additional fds passed to the function.
*
* Returns: CURLMcode type, general multi error code.
*/
CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle,
struct curl_waitfd extra_fds[],
unsigned int extra_nfds,
int timeout_ms,
int *ret);
/*
* Name: curl_multi_wakeup()
*
* Desc: wakes up a sleeping curl_multi_poll call.
*
* Returns: CURLMcode type, general multi error code.
*/
CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);
/*
* Name: curl_multi_perform()
*
@ -319,68 +344,58 @@ CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
long *milliseconds);
#undef CINIT /* re-using the same name as in curl.h */
#ifdef CURL_ISOCPP
#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num
#else
/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
#define LONG CURLOPTTYPE_LONG
#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
#define OFF_T CURLOPTTYPE_OFF_T
#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
#endif
typedef enum {
/* This is the socket callback function pointer */
CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1),
/* This is the argument passed to the socket callback */
CINIT(SOCKETDATA, OBJECTPOINT, 2),
CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2),
/* set to 1 to enable pipelining for this multi handle */
CINIT(PIPELINING, LONG, 3),
CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3),
/* This is the timer callback function pointer */
CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4),
/* This is the argument passed to the timer callback */
CINIT(TIMERDATA, OBJECTPOINT, 5),
CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5),
/* maximum number of entries in the connection cache */
CINIT(MAXCONNECTS, LONG, 6),
CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6),
/* maximum number of (pipelining) connections to one host */
CINIT(MAX_HOST_CONNECTIONS, LONG, 7),
CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7),
/* maximum number of requests in a pipeline */
CINIT(MAX_PIPELINE_LENGTH, LONG, 8),
CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8),
/* a connection with a content-length longer than this
will not be considered for pipelining */
CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9),
CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9),
/* a connection with a chunk length longer than this
will not be considered for pipelining */
CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10),
CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10),
/* a list of site names(+port) that are blacklisted from
pipelining */
CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11),
CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11),
/* a list of server types that are blacklisted from
pipelining */
CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12),
CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12),
/* maximum number of open connections in total */
CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13),
CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13),
/* This is the server push callback function pointer */
CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14),
CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14),
/* This is the argument passed to the server push callback */
CINIT(PUSHDATA, OBJECTPOINT, 15),
CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15),
/* maximum number of concurrent streams to support on a connection */
CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16),
CURLMOPT_LASTENTRY /* the last unused */
} CURLMoption;

View File

@ -1,5 +1,5 @@
#ifndef __STDC_HEADERS_H
#define __STDC_HEADERS_H
#ifndef CURLINC_STDCHEADERS_H
#define CURLINC_STDCHEADERS_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -30,4 +30,4 @@ size_t fwrite(const void *, size_t, size_t, FILE *);
int strcasecmp(const char *, const char *);
int strncasecmp(const char *, const char *, size_t);
#endif /* __STDC_HEADERS_H */
#endif /* CURLINC_STDCHEADERS_H */

View File

@ -1,5 +1,5 @@
#ifndef __CURL_SYSTEM_H
#define __CURL_SYSTEM_H
#ifndef CURLINC_SYSTEM_H
#define CURLINC_SYSTEM_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -137,15 +137,26 @@
# define CURL_TYPEOF_CURL_SOCKLEN_T int
#elif defined(__LCC__)
# define CURL_TYPEOF_CURL_OFF_T long
# define CURL_FORMAT_CURL_OFF_T "ld"
# define CURL_FORMAT_CURL_OFF_TU "lu"
# define CURL_SUFFIX_CURL_OFF_T L
# define CURL_SUFFIX_CURL_OFF_TU UL
# define CURL_TYPEOF_CURL_SOCKLEN_T int
# if defined(__e2k__) /* MCST eLbrus C Compiler */
# define CURL_TYPEOF_CURL_OFF_T long
# define CURL_FORMAT_CURL_OFF_T "ld"
# define CURL_FORMAT_CURL_OFF_TU "lu"
# define CURL_SUFFIX_CURL_OFF_T L
# define CURL_SUFFIX_CURL_OFF_TU UL
# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
# define CURL_PULL_SYS_TYPES_H 1
# define CURL_PULL_SYS_SOCKET_H 1
# else /* Local (or Little) C Compiler */
# define CURL_TYPEOF_CURL_OFF_T long
# define CURL_FORMAT_CURL_OFF_T "ld"
# define CURL_FORMAT_CURL_OFF_TU "lu"
# define CURL_SUFFIX_CURL_OFF_T L
# define CURL_SUFFIX_CURL_OFF_TU UL
# define CURL_TYPEOF_CURL_SOCKLEN_T int
# endif
#elif defined(__SYMBIAN32__)
# if defined(__EABI__) /* Treat all ARM compilers equally */
# if defined(__EABI__) /* Treat all ARM compilers equally */
# define CURL_TYPEOF_CURL_OFF_T long long
# define CURL_FORMAT_CURL_OFF_T "lld"
# define CURL_FORMAT_CURL_OFF_TU "llu"
@ -288,7 +299,6 @@
# define CURL_TYPEOF_CURL_SOCKLEN_T int
#elif defined(__TINYC__) /* also known as tcc */
# define CURL_TYPEOF_CURL_OFF_T long long
# define CURL_FORMAT_CURL_OFF_T "lld"
# define CURL_FORMAT_CURL_OFF_TU "llu"
@ -377,6 +387,7 @@
# define CURL_SUFFIX_CURL_OFF_TU ULL
# elif defined(__LP64__) || \
defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \
defined(__e2k__) || \
(defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \
(defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L)
# define CURL_TYPEOF_CURL_OFF_T long
@ -473,21 +484,21 @@
*/
#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
# define __CURL_OFF_T_C_HLPR2(x) x
# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x)
# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
__CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
__CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
# define CURLINC_OFF_T_C_HLPR2(x) x
# define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x)
# define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \
CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
# define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \
CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
#else
# ifdef CURL_ISOCPP
# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
# define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
# else
# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
# define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
# endif
# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix)
# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
# define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix)
# define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
# define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
#endif
#endif /* __CURL_SYSTEM_H */
#endif /* CURLINC_SYSTEM_H */

View File

@ -1,5 +1,5 @@
#ifndef __CURL_TYPECHECK_GCC_H
#define __CURL_TYPECHECK_GCC_H
#ifndef CURLINC_TYPECHECK_GCC_H
#define CURLINC_TYPECHECK_GCC_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -25,10 +25,10 @@
/* wraps curl_easy_setopt() with typechecking */
/* To add a new kind of warning, add an
* if(_curl_is_sometype_option(_curl_opt))
* if(!_curl_is_sometype(value))
* if(curlcheck_sometype_option(_curl_opt))
* if(!curlcheck_sometype(value))
* _curl_easy_setopt_err_sometype();
* block and define _curl_is_sometype_option, _curl_is_sometype and
* block and define curlcheck_sometype_option, curlcheck_sometype and
* _curl_easy_setopt_err_sometype below
*
* NOTE: We use two nested 'if' statements here instead of the && operator, in
@ -38,112 +38,112 @@
* To add an option that uses the same type as an existing option, you'll just
* need to extend the appropriate _curl_*_option macro
*/
#define curl_easy_setopt(handle, option, value) \
__extension__ ({ \
__typeof__(option) _curl_opt = option; \
if(__builtin_constant_p(_curl_opt)) { \
if(_curl_is_long_option(_curl_opt)) \
if(!_curl_is_long(value)) \
_curl_easy_setopt_err_long(); \
if(_curl_is_off_t_option(_curl_opt)) \
if(!_curl_is_off_t(value)) \
_curl_easy_setopt_err_curl_off_t(); \
if(_curl_is_string_option(_curl_opt)) \
if(!_curl_is_string(value)) \
_curl_easy_setopt_err_string(); \
if(_curl_is_write_cb_option(_curl_opt)) \
if(!_curl_is_write_cb(value)) \
_curl_easy_setopt_err_write_callback(); \
if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \
if(!_curl_is_resolver_start_callback(value)) \
_curl_easy_setopt_err_resolver_start_callback(); \
if((_curl_opt) == CURLOPT_READFUNCTION) \
if(!_curl_is_read_cb(value)) \
_curl_easy_setopt_err_read_cb(); \
if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \
if(!_curl_is_ioctl_cb(value)) \
_curl_easy_setopt_err_ioctl_cb(); \
if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \
if(!_curl_is_sockopt_cb(value)) \
_curl_easy_setopt_err_sockopt_cb(); \
if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \
if(!_curl_is_opensocket_cb(value)) \
_curl_easy_setopt_err_opensocket_cb(); \
if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \
if(!_curl_is_progress_cb(value)) \
_curl_easy_setopt_err_progress_cb(); \
if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \
if(!_curl_is_debug_cb(value)) \
_curl_easy_setopt_err_debug_cb(); \
if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \
if(!_curl_is_ssl_ctx_cb(value)) \
_curl_easy_setopt_err_ssl_ctx_cb(); \
if(_curl_is_conv_cb_option(_curl_opt)) \
if(!_curl_is_conv_cb(value)) \
_curl_easy_setopt_err_conv_cb(); \
if((_curl_opt) == CURLOPT_SEEKFUNCTION) \
if(!_curl_is_seek_cb(value)) \
_curl_easy_setopt_err_seek_cb(); \
if(_curl_is_cb_data_option(_curl_opt)) \
if(!_curl_is_cb_data(value)) \
_curl_easy_setopt_err_cb_data(); \
if((_curl_opt) == CURLOPT_ERRORBUFFER) \
if(!_curl_is_error_buffer(value)) \
_curl_easy_setopt_err_error_buffer(); \
if((_curl_opt) == CURLOPT_STDERR) \
if(!_curl_is_FILE(value)) \
_curl_easy_setopt_err_FILE(); \
if(_curl_is_postfields_option(_curl_opt)) \
if(!_curl_is_postfields(value)) \
_curl_easy_setopt_err_postfields(); \
if((_curl_opt) == CURLOPT_HTTPPOST) \
if(!_curl_is_arr((value), struct curl_httppost)) \
_curl_easy_setopt_err_curl_httpost(); \
if((_curl_opt) == CURLOPT_MIMEPOST) \
if(!_curl_is_ptr((value), curl_mime)) \
_curl_easy_setopt_err_curl_mimepost(); \
if(_curl_is_slist_option(_curl_opt)) \
if(!_curl_is_arr((value), struct curl_slist)) \
_curl_easy_setopt_err_curl_slist(); \
if((_curl_opt) == CURLOPT_SHARE) \
if(!_curl_is_ptr((value), CURLSH)) \
_curl_easy_setopt_err_CURLSH(); \
} \
curl_easy_setopt(handle, _curl_opt, value); \
})
#define curl_easy_setopt(handle, option, value) \
__extension__({ \
__typeof__(option) _curl_opt = option; \
if(__builtin_constant_p(_curl_opt)) { \
if(curlcheck_long_option(_curl_opt)) \
if(!curlcheck_long(value)) \
_curl_easy_setopt_err_long(); \
if(curlcheck_off_t_option(_curl_opt)) \
if(!curlcheck_off_t(value)) \
_curl_easy_setopt_err_curl_off_t(); \
if(curlcheck_string_option(_curl_opt)) \
if(!curlcheck_string(value)) \
_curl_easy_setopt_err_string(); \
if(curlcheck_write_cb_option(_curl_opt)) \
if(!curlcheck_write_cb(value)) \
_curl_easy_setopt_err_write_callback(); \
if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \
if(!curlcheck_resolver_start_callback(value)) \
_curl_easy_setopt_err_resolver_start_callback(); \
if((_curl_opt) == CURLOPT_READFUNCTION) \
if(!curlcheck_read_cb(value)) \
_curl_easy_setopt_err_read_cb(); \
if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \
if(!curlcheck_ioctl_cb(value)) \
_curl_easy_setopt_err_ioctl_cb(); \
if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \
if(!curlcheck_sockopt_cb(value)) \
_curl_easy_setopt_err_sockopt_cb(); \
if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \
if(!curlcheck_opensocket_cb(value)) \
_curl_easy_setopt_err_opensocket_cb(); \
if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \
if(!curlcheck_progress_cb(value)) \
_curl_easy_setopt_err_progress_cb(); \
if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \
if(!curlcheck_debug_cb(value)) \
_curl_easy_setopt_err_debug_cb(); \
if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \
if(!curlcheck_ssl_ctx_cb(value)) \
_curl_easy_setopt_err_ssl_ctx_cb(); \
if(curlcheck_conv_cb_option(_curl_opt)) \
if(!curlcheck_conv_cb(value)) \
_curl_easy_setopt_err_conv_cb(); \
if((_curl_opt) == CURLOPT_SEEKFUNCTION) \
if(!curlcheck_seek_cb(value)) \
_curl_easy_setopt_err_seek_cb(); \
if(curlcheck_cb_data_option(_curl_opt)) \
if(!curlcheck_cb_data(value)) \
_curl_easy_setopt_err_cb_data(); \
if((_curl_opt) == CURLOPT_ERRORBUFFER) \
if(!curlcheck_error_buffer(value)) \
_curl_easy_setopt_err_error_buffer(); \
if((_curl_opt) == CURLOPT_STDERR) \
if(!curlcheck_FILE(value)) \
_curl_easy_setopt_err_FILE(); \
if(curlcheck_postfields_option(_curl_opt)) \
if(!curlcheck_postfields(value)) \
_curl_easy_setopt_err_postfields(); \
if((_curl_opt) == CURLOPT_HTTPPOST) \
if(!curlcheck_arr((value), struct curl_httppost)) \
_curl_easy_setopt_err_curl_httpost(); \
if((_curl_opt) == CURLOPT_MIMEPOST) \
if(!curlcheck_ptr((value), curl_mime)) \
_curl_easy_setopt_err_curl_mimepost(); \
if(curlcheck_slist_option(_curl_opt)) \
if(!curlcheck_arr((value), struct curl_slist)) \
_curl_easy_setopt_err_curl_slist(); \
if((_curl_opt) == CURLOPT_SHARE) \
if(!curlcheck_ptr((value), CURLSH)) \
_curl_easy_setopt_err_CURLSH(); \
} \
curl_easy_setopt(handle, _curl_opt, value); \
})
/* wraps curl_easy_getinfo() with typechecking */
#define curl_easy_getinfo(handle, info, arg) \
__extension__ ({ \
__typeof__(info) _curl_info = info; \
if(__builtin_constant_p(_curl_info)) { \
if(_curl_is_string_info(_curl_info)) \
if(!_curl_is_arr((arg), char *)) \
_curl_easy_getinfo_err_string(); \
if(_curl_is_long_info(_curl_info)) \
if(!_curl_is_arr((arg), long)) \
_curl_easy_getinfo_err_long(); \
if(_curl_is_double_info(_curl_info)) \
if(!_curl_is_arr((arg), double)) \
_curl_easy_getinfo_err_double(); \
if(_curl_is_slist_info(_curl_info)) \
if(!_curl_is_arr((arg), struct curl_slist *)) \
_curl_easy_getinfo_err_curl_slist(); \
if(_curl_is_tlssessioninfo_info(_curl_info)) \
if(!_curl_is_arr((arg), struct curl_tlssessioninfo *)) \
_curl_easy_getinfo_err_curl_tlssesssioninfo(); \
if(_curl_is_certinfo_info(_curl_info)) \
if(!_curl_is_arr((arg), struct curl_certinfo *)) \
_curl_easy_getinfo_err_curl_certinfo(); \
if(_curl_is_socket_info(_curl_info)) \
if(!_curl_is_arr((arg), curl_socket_t)) \
_curl_easy_getinfo_err_curl_socket(); \
if(_curl_is_off_t_info(_curl_info)) \
if(!_curl_is_arr((arg), curl_off_t)) \
_curl_easy_getinfo_err_curl_off_t(); \
} \
curl_easy_getinfo(handle, _curl_info, arg); \
})
#define curl_easy_getinfo(handle, info, arg) \
__extension__({ \
__typeof__(info) _curl_info = info; \
if(__builtin_constant_p(_curl_info)) { \
if(curlcheck_string_info(_curl_info)) \
if(!curlcheck_arr((arg), char *)) \
_curl_easy_getinfo_err_string(); \
if(curlcheck_long_info(_curl_info)) \
if(!curlcheck_arr((arg), long)) \
_curl_easy_getinfo_err_long(); \
if(curlcheck_double_info(_curl_info)) \
if(!curlcheck_arr((arg), double)) \
_curl_easy_getinfo_err_double(); \
if(curlcheck_slist_info(_curl_info)) \
if(!curlcheck_arr((arg), struct curl_slist *)) \
_curl_easy_getinfo_err_curl_slist(); \
if(curlcheck_tlssessioninfo_info(_curl_info)) \
if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \
_curl_easy_getinfo_err_curl_tlssesssioninfo(); \
if(curlcheck_certinfo_info(_curl_info)) \
if(!curlcheck_arr((arg), struct curl_certinfo *)) \
_curl_easy_getinfo_err_curl_certinfo(); \
if(curlcheck_socket_info(_curl_info)) \
if(!curlcheck_arr((arg), curl_socket_t)) \
_curl_easy_getinfo_err_curl_socket(); \
if(curlcheck_off_t_info(_curl_info)) \
if(!curlcheck_arr((arg), curl_off_t)) \
_curl_easy_getinfo_err_curl_off_t(); \
} \
curl_easy_getinfo(handle, _curl_info, arg); \
})
/*
* For now, just make sure that the functions are called with three arguments
@ -156,83 +156,83 @@ __extension__ ({ \
* functions */
/* To define a new warning, use _CURL_WARNING(identifier, "message") */
#define _CURL_WARNING(id, message) \
static void __attribute__((__warning__(message))) \
__attribute__((__unused__)) __attribute__((__noinline__)) \
#define CURLWARNING(id, message) \
static void __attribute__((__warning__(message))) \
__attribute__((__unused__)) __attribute__((__noinline__)) \
id(void) { __asm__(""); }
_CURL_WARNING(_curl_easy_setopt_err_long,
CURLWARNING(_curl_easy_setopt_err_long,
"curl_easy_setopt expects a long argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_curl_off_t,
CURLWARNING(_curl_easy_setopt_err_curl_off_t,
"curl_easy_setopt expects a curl_off_t argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_string,
CURLWARNING(_curl_easy_setopt_err_string,
"curl_easy_setopt expects a "
"string ('char *' or char[]) argument for this option"
)
_CURL_WARNING(_curl_easy_setopt_err_write_callback,
CURLWARNING(_curl_easy_setopt_err_write_callback,
"curl_easy_setopt expects a curl_write_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_resolver_start_callback,
CURLWARNING(_curl_easy_setopt_err_resolver_start_callback,
"curl_easy_setopt expects a "
"curl_resolver_start_callback argument for this option"
)
_CURL_WARNING(_curl_easy_setopt_err_read_cb,
CURLWARNING(_curl_easy_setopt_err_read_cb,
"curl_easy_setopt expects a curl_read_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb,
CURLWARNING(_curl_easy_setopt_err_ioctl_cb,
"curl_easy_setopt expects a curl_ioctl_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb,
CURLWARNING(_curl_easy_setopt_err_sockopt_cb,
"curl_easy_setopt expects a curl_sockopt_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb,
CURLWARNING(_curl_easy_setopt_err_opensocket_cb,
"curl_easy_setopt expects a "
"curl_opensocket_callback argument for this option"
)
_CURL_WARNING(_curl_easy_setopt_err_progress_cb,
CURLWARNING(_curl_easy_setopt_err_progress_cb,
"curl_easy_setopt expects a curl_progress_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_debug_cb,
CURLWARNING(_curl_easy_setopt_err_debug_cb,
"curl_easy_setopt expects a curl_debug_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb,
CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb,
"curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_conv_cb,
CURLWARNING(_curl_easy_setopt_err_conv_cb,
"curl_easy_setopt expects a curl_conv_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_seek_cb,
CURLWARNING(_curl_easy_setopt_err_seek_cb,
"curl_easy_setopt expects a curl_seek_callback argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_cb_data,
CURLWARNING(_curl_easy_setopt_err_cb_data,
"curl_easy_setopt expects a "
"private data pointer as argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_error_buffer,
CURLWARNING(_curl_easy_setopt_err_error_buffer,
"curl_easy_setopt expects a "
"char buffer of CURL_ERROR_SIZE as argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_FILE,
CURLWARNING(_curl_easy_setopt_err_FILE,
"curl_easy_setopt expects a 'FILE *' argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_postfields,
CURLWARNING(_curl_easy_setopt_err_postfields,
"curl_easy_setopt expects a 'void *' or 'char *' argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
CURLWARNING(_curl_easy_setopt_err_curl_httpost,
"curl_easy_setopt expects a 'struct curl_httppost *' "
"argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost,
CURLWARNING(_curl_easy_setopt_err_curl_mimepost,
"curl_easy_setopt expects a 'curl_mime *' "
"argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_curl_slist,
CURLWARNING(_curl_easy_setopt_err_curl_slist,
"curl_easy_setopt expects a 'struct curl_slist *' argument for this option")
_CURL_WARNING(_curl_easy_setopt_err_CURLSH,
CURLWARNING(_curl_easy_setopt_err_CURLSH,
"curl_easy_setopt expects a CURLSH* argument for this option")
_CURL_WARNING(_curl_easy_getinfo_err_string,
CURLWARNING(_curl_easy_getinfo_err_string,
"curl_easy_getinfo expects a pointer to 'char *' for this info")
_CURL_WARNING(_curl_easy_getinfo_err_long,
CURLWARNING(_curl_easy_getinfo_err_long,
"curl_easy_getinfo expects a pointer to long for this info")
_CURL_WARNING(_curl_easy_getinfo_err_double,
CURLWARNING(_curl_easy_getinfo_err_double,
"curl_easy_getinfo expects a pointer to double for this info")
_CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
CURLWARNING(_curl_easy_getinfo_err_curl_slist,
"curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info")
_CURL_WARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo,
CURLWARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo,
"curl_easy_getinfo expects a pointer to "
"'struct curl_tlssessioninfo *' for this info")
_CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo,
CURLWARNING(_curl_easy_getinfo_err_curl_certinfo,
"curl_easy_getinfo expects a pointer to "
"'struct curl_certinfo *' for this info")
_CURL_WARNING(_curl_easy_getinfo_err_curl_socket,
CURLWARNING(_curl_easy_getinfo_err_curl_socket,
"curl_easy_getinfo expects a pointer to curl_socket_t for this info")
_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
"curl_easy_getinfo expects a pointer to curl_off_t for this info")
/* groups of curl_easy_setops options that take the same type of argument */
@ -244,14 +244,14 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
*/
/* evaluates to true if option takes a long argument */
#define _curl_is_long_option(option) \
#define curlcheck_long_option(option) \
(0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)
#define _curl_is_off_t_option(option) \
#define curlcheck_off_t_option(option) \
((option) > CURLOPTTYPE_OFF_T)
/* evaluates to true if option takes a char* argument */
#define _curl_is_string_option(option) \
#define curlcheck_string_option(option) \
((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \
(option) == CURLOPT_ACCEPT_ENCODING || \
(option) == CURLOPT_ALTSVC || \
@ -300,15 +300,18 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_PROXY_SSLKEY || \
(option) == CURLOPT_PROXY_SSLKEYTYPE || \
(option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \
(option) == CURLOPT_PROXY_TLS13_CIPHERS || \
(option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \
(option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \
(option) == CURLOPT_PROXY_TLSAUTH_TYPE || \
(option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \
(option) == CURLOPT_RANDOM_FILE || \
(option) == CURLOPT_RANGE || \
(option) == CURLOPT_REFERER || \
(option) == CURLOPT_REQUEST_TARGET || \
(option) == CURLOPT_RTSP_SESSION_ID || \
(option) == CURLOPT_RTSP_STREAM_URI || \
(option) == CURLOPT_RTSP_TRANSPORT || \
(option) == CURLOPT_SASL_AUTHZID || \
(option) == CURLOPT_SERVICE_NAME || \
(option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
(option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
@ -321,6 +324,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_SSLKEY || \
(option) == CURLOPT_SSLKEYTYPE || \
(option) == CURLOPT_SSL_CIPHER_LIST || \
(option) == CURLOPT_TLS13_CIPHERS || \
(option) == CURLOPT_TLSAUTH_PASSWORD || \
(option) == CURLOPT_TLSAUTH_TYPE || \
(option) == CURLOPT_TLSAUTH_USERNAME || \
@ -333,18 +337,18 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
0)
/* evaluates to true if option takes a curl_write_callback argument */
#define _curl_is_write_cb_option(option) \
((option) == CURLOPT_HEADERFUNCTION || \
#define curlcheck_write_cb_option(option) \
((option) == CURLOPT_HEADERFUNCTION || \
(option) == CURLOPT_WRITEFUNCTION)
/* evaluates to true if option takes a curl_conv_callback argument */
#define _curl_is_conv_cb_option(option) \
((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \
(option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \
#define curlcheck_conv_cb_option(option) \
((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \
(option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \
(option) == CURLOPT_CONV_FROM_UTF8_FUNCTION)
/* evaluates to true if option takes a data argument to pass to a callback */
#define _curl_is_cb_data_option(option) \
#define curlcheck_cb_data_option(option) \
((option) == CURLOPT_CHUNK_DATA || \
(option) == CURLOPT_CLOSESOCKETDATA || \
(option) == CURLOPT_DEBUGDATA || \
@ -362,17 +366,17 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_SSL_CTX_DATA || \
(option) == CURLOPT_WRITEDATA || \
(option) == CURLOPT_RESOLVER_START_DATA || \
(option) == CURLOPT_CURLU || \
(option) == CURLOPT_TRAILERDATA || \
0)
/* evaluates to true if option takes a POST data argument (void* or char*) */
#define _curl_is_postfields_option(option) \
#define curlcheck_postfields_option(option) \
((option) == CURLOPT_POSTFIELDS || \
(option) == CURLOPT_COPYPOSTFIELDS || \
0)
/* evaluates to true if option takes a struct curl_slist * argument */
#define _curl_is_slist_option(option) \
#define curlcheck_slist_option(option) \
((option) == CURLOPT_HTTP200ALIASES || \
(option) == CURLOPT_HTTPHEADER || \
(option) == CURLOPT_MAIL_RCPT || \
@ -382,45 +386,46 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_QUOTE || \
(option) == CURLOPT_RESOLVE || \
(option) == CURLOPT_TELNETOPTIONS || \
(option) == CURLOPT_CONNECT_TO || \
0)
/* groups of curl_easy_getinfo infos that take the same type of argument */
/* evaluates to true if info expects a pointer to char * argument */
#define _curl_is_string_info(info) \
#define curlcheck_string_info(info) \
(CURLINFO_STRING < (info) && (info) < CURLINFO_LONG)
/* evaluates to true if info expects a pointer to long argument */
#define _curl_is_long_info(info) \
#define curlcheck_long_info(info) \
(CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE)
/* evaluates to true if info expects a pointer to double argument */
#define _curl_is_double_info(info) \
#define curlcheck_double_info(info) \
(CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST)
/* true if info expects a pointer to struct curl_slist * argument */
#define _curl_is_slist_info(info) \
#define curlcheck_slist_info(info) \
(((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST))
/* true if info expects a pointer to struct curl_tlssessioninfo * argument */
#define _curl_is_tlssessioninfo_info(info) \
#define curlcheck_tlssessioninfo_info(info) \
(((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION))
/* true if info expects a pointer to struct curl_certinfo * argument */
#define _curl_is_certinfo_info(info) ((info) == CURLINFO_CERTINFO)
#define curlcheck_certinfo_info(info) ((info) == CURLINFO_CERTINFO)
/* true if info expects a pointer to struct curl_socket_t argument */
#define _curl_is_socket_info(info) \
#define curlcheck_socket_info(info) \
(CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T)
/* true if info expects a pointer to curl_off_t argument */
#define _curl_is_off_t_info(info) \
#define curlcheck_off_t_info(info) \
(CURLINFO_OFF_T < (info))
/* typecheck helpers -- check whether given expression has requested type*/
/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros,
/* For pointers, you can use the curlcheck_ptr/curlcheck_arr macros,
* otherwise define a new macro. Search for __builtin_types_compatible_p
* in the GCC manual.
* NOTE: these macros MUST NOT EVALUATE their arguments! The argument is
@ -430,35 +435,35 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
*/
/* XXX: should evaluate to true if expr is a pointer */
#define _curl_is_any_ptr(expr) \
#define curlcheck_any_ptr(expr) \
(sizeof(expr) == sizeof(void *))
/* evaluates to true if expr is NULL */
/* XXX: must not evaluate expr, so this check is not accurate */
#define _curl_is_NULL(expr) \
#define curlcheck_NULL(expr) \
(__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL)))
/* evaluates to true if expr is type*, const type* or NULL */
#define _curl_is_ptr(expr, type) \
(_curl_is_NULL(expr) || \
__builtin_types_compatible_p(__typeof__(expr), type *) || \
#define curlcheck_ptr(expr, type) \
(curlcheck_NULL(expr) || \
__builtin_types_compatible_p(__typeof__(expr), type *) || \
__builtin_types_compatible_p(__typeof__(expr), const type *))
/* evaluates to true if expr is one of type[], type*, NULL or const type* */
#define _curl_is_arr(expr, type) \
(_curl_is_ptr((expr), type) || \
#define curlcheck_arr(expr, type) \
(curlcheck_ptr((expr), type) || \
__builtin_types_compatible_p(__typeof__(expr), type []))
/* evaluates to true if expr is a string */
#define _curl_is_string(expr) \
(_curl_is_arr((expr), char) || \
_curl_is_arr((expr), signed char) || \
_curl_is_arr((expr), unsigned char))
#define curlcheck_string(expr) \
(curlcheck_arr((expr), char) || \
curlcheck_arr((expr), signed char) || \
curlcheck_arr((expr), unsigned char))
/* evaluates to true if expr is a long (no matter the signedness)
* XXX: for now, int is also accepted (and therefore short and char, which
* are promoted to int when passed to a variadic function) */
#define _curl_is_long(expr) \
#define curlcheck_long(expr) \
(__builtin_types_compatible_p(__typeof__(expr), long) || \
__builtin_types_compatible_p(__typeof__(expr), signed long) || \
__builtin_types_compatible_p(__typeof__(expr), unsigned long) || \
@ -473,59 +478,59 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
__builtin_types_compatible_p(__typeof__(expr), unsigned char))
/* evaluates to true if expr is of type curl_off_t */
#define _curl_is_off_t(expr) \
#define curlcheck_off_t(expr) \
(__builtin_types_compatible_p(__typeof__(expr), curl_off_t))
/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */
/* XXX: also check size of an char[] array? */
#define _curl_is_error_buffer(expr) \
(_curl_is_NULL(expr) || \
__builtin_types_compatible_p(__typeof__(expr), char *) || \
#define curlcheck_error_buffer(expr) \
(curlcheck_NULL(expr) || \
__builtin_types_compatible_p(__typeof__(expr), char *) || \
__builtin_types_compatible_p(__typeof__(expr), char[]))
/* evaluates to true if expr is of type (const) void* or (const) FILE* */
#if 0
#define _curl_is_cb_data(expr) \
(_curl_is_ptr((expr), void) || \
_curl_is_ptr((expr), FILE))
#define curlcheck_cb_data(expr) \
(curlcheck_ptr((expr), void) || \
curlcheck_ptr((expr), FILE))
#else /* be less strict */
#define _curl_is_cb_data(expr) \
_curl_is_any_ptr(expr)
#define curlcheck_cb_data(expr) \
curlcheck_any_ptr(expr)
#endif
/* evaluates to true if expr is of type FILE* */
#define _curl_is_FILE(expr) \
(_curl_is_NULL(expr) || \
#define curlcheck_FILE(expr) \
(curlcheck_NULL(expr) || \
(__builtin_types_compatible_p(__typeof__(expr), FILE *)))
/* evaluates to true if expr can be passed as POST data (void* or char*) */
#define _curl_is_postfields(expr) \
(_curl_is_ptr((expr), void) || \
_curl_is_arr((expr), char) || \
_curl_is_arr((expr), unsigned char))
#define curlcheck_postfields(expr) \
(curlcheck_ptr((expr), void) || \
curlcheck_arr((expr), char) || \
curlcheck_arr((expr), unsigned char))
/* helper: __builtin_types_compatible_p distinguishes between functions and
* function pointers, hide it */
#define _curl_callback_compatible(func, type) \
(__builtin_types_compatible_p(__typeof__(func), type) || \
#define curlcheck_cb_compatible(func, type) \
(__builtin_types_compatible_p(__typeof__(func), type) || \
__builtin_types_compatible_p(__typeof__(func) *, type))
/* evaluates to true if expr is of type curl_resolver_start_callback */
#define _curl_is_resolver_start_callback(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_resolver_start_callback))
#define curlcheck_resolver_start_callback(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_resolver_start_callback))
/* evaluates to true if expr is of type curl_read_callback or "similar" */
#define _curl_is_read_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), __typeof__(fread) *) || \
_curl_callback_compatible((expr), curl_read_callback) || \
_curl_callback_compatible((expr), _curl_read_callback1) || \
_curl_callback_compatible((expr), _curl_read_callback2) || \
_curl_callback_compatible((expr), _curl_read_callback3) || \
_curl_callback_compatible((expr), _curl_read_callback4) || \
_curl_callback_compatible((expr), _curl_read_callback5) || \
_curl_callback_compatible((expr), _curl_read_callback6))
#define curlcheck_read_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), __typeof__(fread) *) || \
curlcheck_cb_compatible((expr), curl_read_callback) || \
curlcheck_cb_compatible((expr), _curl_read_callback1) || \
curlcheck_cb_compatible((expr), _curl_read_callback2) || \
curlcheck_cb_compatible((expr), _curl_read_callback3) || \
curlcheck_cb_compatible((expr), _curl_read_callback4) || \
curlcheck_cb_compatible((expr), _curl_read_callback5) || \
curlcheck_cb_compatible((expr), _curl_read_callback6))
typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *);
typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *);
typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *);
@ -534,16 +539,16 @@ typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *);
typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *);
/* evaluates to true if expr is of type curl_write_callback or "similar" */
#define _curl_is_write_cb(expr) \
(_curl_is_read_cb(expr) || \
_curl_callback_compatible((expr), __typeof__(fwrite) *) || \
_curl_callback_compatible((expr), curl_write_callback) || \
_curl_callback_compatible((expr), _curl_write_callback1) || \
_curl_callback_compatible((expr), _curl_write_callback2) || \
_curl_callback_compatible((expr), _curl_write_callback3) || \
_curl_callback_compatible((expr), _curl_write_callback4) || \
_curl_callback_compatible((expr), _curl_write_callback5) || \
_curl_callback_compatible((expr), _curl_write_callback6))
#define curlcheck_write_cb(expr) \
(curlcheck_read_cb(expr) || \
curlcheck_cb_compatible((expr), __typeof__(fwrite) *) || \
curlcheck_cb_compatible((expr), curl_write_callback) || \
curlcheck_cb_compatible((expr), _curl_write_callback1) || \
curlcheck_cb_compatible((expr), _curl_write_callback2) || \
curlcheck_cb_compatible((expr), _curl_write_callback3) || \
curlcheck_cb_compatible((expr), _curl_write_callback4) || \
curlcheck_cb_compatible((expr), _curl_write_callback5) || \
curlcheck_cb_compatible((expr), _curl_write_callback6))
typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *);
typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t,
const void *);
@ -554,37 +559,37 @@ typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t,
typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *);
/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */
#define _curl_is_ioctl_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_ioctl_callback) || \
_curl_callback_compatible((expr), _curl_ioctl_callback1) || \
_curl_callback_compatible((expr), _curl_ioctl_callback2) || \
_curl_callback_compatible((expr), _curl_ioctl_callback3) || \
_curl_callback_compatible((expr), _curl_ioctl_callback4))
#define curlcheck_ioctl_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_ioctl_callback) || \
curlcheck_cb_compatible((expr), _curl_ioctl_callback1) || \
curlcheck_cb_compatible((expr), _curl_ioctl_callback2) || \
curlcheck_cb_compatible((expr), _curl_ioctl_callback3) || \
curlcheck_cb_compatible((expr), _curl_ioctl_callback4))
typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *);
typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *);
typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *);
typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *);
/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */
#define _curl_is_sockopt_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_sockopt_callback) || \
_curl_callback_compatible((expr), _curl_sockopt_callback1) || \
_curl_callback_compatible((expr), _curl_sockopt_callback2))
#define curlcheck_sockopt_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_sockopt_callback) || \
curlcheck_cb_compatible((expr), _curl_sockopt_callback1) || \
curlcheck_cb_compatible((expr), _curl_sockopt_callback2))
typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype);
typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t,
curlsocktype);
/* evaluates to true if expr is of type curl_opensocket_callback or
"similar" */
#define _curl_is_opensocket_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_opensocket_callback) || \
_curl_callback_compatible((expr), _curl_opensocket_callback1) || \
_curl_callback_compatible((expr), _curl_opensocket_callback2) || \
_curl_callback_compatible((expr), _curl_opensocket_callback3) || \
_curl_callback_compatible((expr), _curl_opensocket_callback4))
#define curlcheck_opensocket_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_opensocket_callback) || \
curlcheck_cb_compatible((expr), _curl_opensocket_callback1) || \
curlcheck_cb_compatible((expr), _curl_opensocket_callback2) || \
curlcheck_cb_compatible((expr), _curl_opensocket_callback3) || \
curlcheck_cb_compatible((expr), _curl_opensocket_callback4))
typedef curl_socket_t (*_curl_opensocket_callback1)
(void *, curlsocktype, struct curl_sockaddr *);
typedef curl_socket_t (*_curl_opensocket_callback2)
@ -595,28 +600,28 @@ typedef curl_socket_t (*_curl_opensocket_callback4)
(const void *, curlsocktype, const struct curl_sockaddr *);
/* evaluates to true if expr is of type curl_progress_callback or "similar" */
#define _curl_is_progress_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_progress_callback) || \
_curl_callback_compatible((expr), _curl_progress_callback1) || \
_curl_callback_compatible((expr), _curl_progress_callback2))
#define curlcheck_progress_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_progress_callback) || \
curlcheck_cb_compatible((expr), _curl_progress_callback1) || \
curlcheck_cb_compatible((expr), _curl_progress_callback2))
typedef int (*_curl_progress_callback1)(void *,
double, double, double, double);
typedef int (*_curl_progress_callback2)(const void *,
double, double, double, double);
/* evaluates to true if expr is of type curl_debug_callback or "similar" */
#define _curl_is_debug_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_debug_callback) || \
_curl_callback_compatible((expr), _curl_debug_callback1) || \
_curl_callback_compatible((expr), _curl_debug_callback2) || \
_curl_callback_compatible((expr), _curl_debug_callback3) || \
_curl_callback_compatible((expr), _curl_debug_callback4) || \
_curl_callback_compatible((expr), _curl_debug_callback5) || \
_curl_callback_compatible((expr), _curl_debug_callback6) || \
_curl_callback_compatible((expr), _curl_debug_callback7) || \
_curl_callback_compatible((expr), _curl_debug_callback8))
#define curlcheck_debug_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_debug_callback) || \
curlcheck_cb_compatible((expr), _curl_debug_callback1) || \
curlcheck_cb_compatible((expr), _curl_debug_callback2) || \
curlcheck_cb_compatible((expr), _curl_debug_callback3) || \
curlcheck_cb_compatible((expr), _curl_debug_callback4) || \
curlcheck_cb_compatible((expr), _curl_debug_callback5) || \
curlcheck_cb_compatible((expr), _curl_debug_callback6) || \
curlcheck_cb_compatible((expr), _curl_debug_callback7) || \
curlcheck_cb_compatible((expr), _curl_debug_callback8))
typedef int (*_curl_debug_callback1) (CURL *,
curl_infotype, char *, size_t, void *);
typedef int (*_curl_debug_callback2) (CURL *,
@ -636,17 +641,17 @@ typedef int (*_curl_debug_callback8) (CURL *,
/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */
/* this is getting even messier... */
#define _curl_is_ssl_ctx_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_ssl_ctx_callback) || \
_curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \
_curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \
_curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \
_curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \
_curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \
_curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \
_curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \
_curl_callback_compatible((expr), _curl_ssl_ctx_callback8))
#define curlcheck_ssl_ctx_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_ssl_ctx_callback) || \
curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback1) || \
curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback2) || \
curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback3) || \
curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback4) || \
curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback5) || \
curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback6) || \
curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback7) || \
curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback8))
typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
@ -669,26 +674,26 @@ typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8;
#endif
/* evaluates to true if expr is of type curl_conv_callback or "similar" */
#define _curl_is_conv_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_conv_callback) || \
_curl_callback_compatible((expr), _curl_conv_callback1) || \
_curl_callback_compatible((expr), _curl_conv_callback2) || \
_curl_callback_compatible((expr), _curl_conv_callback3) || \
_curl_callback_compatible((expr), _curl_conv_callback4))
#define curlcheck_conv_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_conv_callback) || \
curlcheck_cb_compatible((expr), _curl_conv_callback1) || \
curlcheck_cb_compatible((expr), _curl_conv_callback2) || \
curlcheck_cb_compatible((expr), _curl_conv_callback3) || \
curlcheck_cb_compatible((expr), _curl_conv_callback4))
typedef CURLcode (*_curl_conv_callback1)(char *, size_t length);
typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length);
typedef CURLcode (*_curl_conv_callback3)(void *, size_t length);
typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length);
/* evaluates to true if expr is of type curl_seek_callback or "similar" */
#define _curl_is_seek_cb(expr) \
(_curl_is_NULL(expr) || \
_curl_callback_compatible((expr), curl_seek_callback) || \
_curl_callback_compatible((expr), _curl_seek_callback1) || \
_curl_callback_compatible((expr), _curl_seek_callback2))
#define curlcheck_seek_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_seek_callback) || \
curlcheck_cb_compatible((expr), _curl_seek_callback1) || \
curlcheck_cb_compatible((expr), _curl_seek_callback2))
typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int);
typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int);
#endif /* __CURL_TYPECHECK_GCC_H */
#endif /* CURLINC_TYPECHECK_GCC_H */

View File

@ -1,5 +1,5 @@
#ifndef __CURL_URLAPI_H
#define __CURL_URLAPI_H
#ifndef CURLINC_URLAPI_H
#define CURLINC_URLAPI_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@ -77,6 +77,8 @@ typedef enum {
#define CURLU_URLENCODE (1<<7) /* URL encode on set */
#define CURLU_APPENDQUERY (1<<8) /* append a form style part */
#define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */
#define CURLU_NO_AUTHORITY (1<<10) /* Allow empty authority when the
scheme is unknown. */
typedef struct Curl_URL CURLU;
@ -120,4 +122,4 @@ CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
} /* end of extern "C" */
#endif
#endif
#endif /* CURLINC_URLAPI_H */

View File

@ -20,7 +20,6 @@ list(APPEND HHEADERS
if(MSVC AND NOT CURL_STATICLIB)
list(APPEND CSOURCES libcurl.rc)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4127")
endif()
# SET(CSOURCES
@ -121,6 +120,12 @@ endif()
set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "")
if(CURL_HAS_LTO)
set_target_properties(${LIB_NAME} PROPERTIES
INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
endif()
if(WIN32)
if(BUILD_SHARED_LIBS)
# Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib"

View File

@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
# Copyright (C) 1998 - 2020, 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
@ -28,14 +28,22 @@ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \
LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h
LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \
vtls/polarssl.c vtls/polarssl_threadlock.c \
vtls/cyassl.c vtls/schannel.c vtls/schannel_verify.c \
vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c
vtls/mbedtls_threadlock.c vtls/wolfssl.c vtls/schannel.c \
vtls/schannel_verify.c vtls/sectransp.c vtls/gskit.c vtls/mbedtls.c \
vtls/mesalink.c vtls/bearssl.c
LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \
vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h \
vtls/cyassl.h vtls/schannel.h vtls/sectransp.h vtls/gskit.h \
vtls/mbedtls.h vtls/mesalink.h
LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h vtls/nssg.h \
vtls/mbedtls_threadlock.h vtls/wolfssl.h vtls/schannel.h \
vtls/sectransp.h vtls/gskit.h vtls/mbedtls.h vtls/mesalink.h \
vtls/bearssl.h
LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c
LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h
LIB_VSSH_CFILES = vssh/libssh2.c vssh/libssh.c vssh/wolfssh.c
LIB_VSSH_HFILES = vssh/ssh.h
LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \
@ -46,7 +54,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \
strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \
inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \
ssh.c ssh-libssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \
curl_addrinfo.c socks_gssapi.c socks_sspi.c \
curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \
pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \
openldap.c curl_gethostname.c gopher.c idn_win32.c \
@ -55,7 +63,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
curl_multibyte.c hostcheck.c conncache.c dotdot.c \
x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \
mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \
doh.c urlapi.c curl_get_line.c altsvc.c
doh.c urlapi.c curl_get_line.c altsvc.c socketpair.c rename.c
LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \
@ -66,7 +74,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \
inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \
easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \
socks.h ssh.h curl_base64.h curl_addrinfo.h curl_sspi.h \
socks.h curl_base64.h curl_addrinfo.h curl_sspi.h \
slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \
rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \
curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \
@ -76,9 +84,11 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \
curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h \
curl_get_line.h altsvc.h
curl_get_line.h altsvc.h quic.h socketpair.h rename.h
LIB_RCFILES = libcurl.rc
CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES)
HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES)
CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) \
$(LIB_VQUIC_CFILES) $(LIB_VSSH_CFILES)
HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) \
$(LIB_VQUIC_HFILES) $(LIB_VSSH_HFILES)

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2019 - 2020, 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
@ -34,6 +34,8 @@
#include "parsedate.h"
#include "sendf.h"
#include "warnless.h"
#include "rand.h"
#include "rename.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -48,15 +50,19 @@
#define MAX_ALTSVC_ALPNLENSTR "10"
#define MAX_ALTSVC_ALPNLEN 10
#if (defined(USE_QUICHE) || defined(USE_NGTCP2)) && !defined(UNITTESTS)
#define H3VERSION "h3-27"
#else
#define H3VERSION "h3"
#endif
static enum alpnid alpn2alpnid(char *name)
{
if(strcasecompare(name, "h1"))
return ALPN_h1;
if(strcasecompare(name, "h2"))
return ALPN_h2;
if(strcasecompare(name, "h2c"))
return ALPN_h2c;
if(strcasecompare(name, "h3"))
if(strcasecompare(name, H3VERSION))
return ALPN_h3;
return ALPN_none; /* unknown, probably rubbish input */
}
@ -69,10 +75,8 @@ const char *Curl_alpnid2str(enum alpnid id)
return "h1";
case ALPN_h2:
return "h2";
case ALPN_h2c:
return "h2c";
case ALPN_h3:
return "h3";
return H3VERSION;
default:
return ""; /* bad */
}
@ -81,8 +85,8 @@ const char *Curl_alpnid2str(enum alpnid id)
static void altsvc_free(struct altsvc *as)
{
free(as->srchost);
free(as->dsthost);
free(as->src.host);
free(as->dst.host);
free(as);
}
@ -97,17 +101,17 @@ static struct altsvc *altsvc_createid(const char *srchost,
if(!as)
return NULL;
as->srchost = strdup(srchost);
if(!as->srchost)
as->src.host = strdup(srchost);
if(!as->src.host)
goto error;
as->dsthost = strdup(dsthost);
if(!as->dsthost)
as->dst.host = strdup(dsthost);
if(!as->dst.host)
goto error;
as->srcalpnid = srcalpnid;
as->dstalpnid = dstalpnid;
as->srcport = curlx_ultous(srcport);
as->dstport = curlx_ultous(dstport);
as->src.alpnid = srcalpnid;
as->dst.alpnid = dstalpnid;
as->src.port = curlx_ultous(srcport);
as->dst.port = curlx_ultous(dstport);
return as;
error:
@ -156,7 +160,7 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
date, &persist, &prio);
if(9 == rc) {
struct altsvc *as;
time_t expires = curl_getdate(date, NULL);
time_t expires = Curl_getdate_capped(date);
as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport);
if(as) {
as->expires = expires;
@ -183,7 +187,16 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
{
CURLcode result = CURLE_OK;
char *line = NULL;
FILE *fp = fopen(file, FOPEN_READTEXT);
FILE *fp;
/* we need a private copy of the file name so that the altsvc cache file
name survives an easy handle reset */
free(asi->filename);
asi->filename = strdup(file);
if(!asi->filename)
return CURLE_OUT_OF_MEMORY;
fp = fopen(file, FOPEN_READTEXT);
if(fp) {
line = malloc(MAX_ALTSVC_LINE);
if(!line)
@ -204,6 +217,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
return result;
fail:
Curl_safefree(asi->filename);
free(line);
fclose(fp);
return CURLE_OUT_OF_MEMORY;
@ -226,8 +240,8 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
"\"%d%02d%02d "
"%02d:%02d:%02d\" "
"%u %d\n",
Curl_alpnid2str(as->srcalpnid), as->srchost, as->srcport,
Curl_alpnid2str(as->dstalpnid), as->dsthost, as->dstport,
Curl_alpnid2str(as->src.alpnid), as->src.host, as->src.port,
Curl_alpnid2str(as->dst.alpnid), as->dst.host, as->dst.port,
stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
stamp.tm_hour, stamp.tm_min, stamp.tm_sec,
as->persist, as->prio);
@ -252,7 +266,7 @@ struct altsvcinfo *Curl_altsvc_init(void)
#ifdef USE_NGHTTP2
| CURLALTSVC_H2
#endif
#ifdef USE_HTTP3
#ifdef ENABLE_QUIC
| CURLALTSVC_H3
#endif
;
@ -297,6 +311,7 @@ void Curl_altsvc_cleanup(struct altsvcinfo *altsvc)
n = e->next;
altsvc_free(as);
}
free(altsvc->filename);
free(altsvc);
}
}
@ -304,34 +319,57 @@ void Curl_altsvc_cleanup(struct altsvcinfo *altsvc)
/*
* Curl_altsvc_save() writes the altsvc cache to a file.
*/
CURLcode Curl_altsvc_save(struct altsvcinfo *altsvc, const char *file)
CURLcode Curl_altsvc_save(struct Curl_easy *data,
struct altsvcinfo *altsvc, const char *file)
{
struct curl_llist_element *e;
struct curl_llist_element *n;
CURLcode result = CURLE_OK;
FILE *out;
char *tempstore;
unsigned char randsuffix[9];
if(!altsvc)
/* no cache activated */
return CURLE_OK;
if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file[0])
/* marked as read-only or zero length file name */
/* if not new name is given, use the one we stored from the load */
if(!file && altsvc->filename)
file = altsvc->filename;
if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
/* marked as read-only, no file or zero length file name */
return CURLE_OK;
out = fopen(file, FOPEN_WRITETEXT);
if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix)))
return CURLE_FAILED_INIT;
tempstore = aprintf("%s.%s.tmp", file, randsuffix);
if(!tempstore)
return CURLE_OUT_OF_MEMORY;
out = fopen(tempstore, FOPEN_WRITETEXT);
if(!out)
return CURLE_WRITE_ERROR;
fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n"
"# This file was generated by libcurl! Edit at your own risk.\n",
out);
for(e = altsvc->list.head; e; e = n) {
struct altsvc *as = e->ptr;
n = e->next;
result = altsvc_out(as, out);
result = CURLE_WRITE_ERROR;
else {
fputs("# Your alt-svc cache. https://curl.haxx.se/docs/alt-svc.html\n"
"# This file was generated by libcurl! Edit at your own risk.\n",
out);
for(e = altsvc->list.head; e; e = n) {
struct altsvc *as = e->ptr;
n = e->next;
result = altsvc_out(as, out);
if(result)
break;
}
fclose(out);
if(!result && Curl_rename(tempstore, file))
result = CURLE_WRITE_ERROR;
if(result)
break;
unlink(tempstore);
}
fclose(out);
free(tempstore);
return result;
}
@ -343,15 +381,15 @@ static CURLcode getalnum(const char **ptr, char *alpnbuf, size_t buflen)
while(*p && ISBLANK(*p))
p++;
protop = p;
while(*p && ISALNUM(*p))
while(*p && !ISBLANK(*p) && (*p != ';') && (*p != '='))
p++;
len = p - protop;
*ptr = p;
if(!len || (len >= buflen))
return CURLE_BAD_FUNCTION_ARGUMENT;
memcpy(alpnbuf, protop, len);
alpnbuf[len] = 0;
*ptr = p;
return CURLE_OK;
}
@ -365,9 +403,9 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
for(e = asi->list.head; e; e = n) {
struct altsvc *as = e->ptr;
n = e->next;
if((srcalpnid == as->srcalpnid) &&
(srcport == as->srcport) &&
strcasecompare(srchost, as->srchost)) {
if((srcalpnid == as->src.alpnid) &&
(srcport == as->src.port) &&
strcasecompare(srchost, as->src.host)) {
Curl_llist_remove(&asi->list, e, NULL);
altsvc_free(as);
asi->num--;
@ -397,6 +435,10 @@ static time_t debugtime(void *unused)
*
* 'value' points to the header *value*. That's contents to the right of the
* header name.
*
* Currently this function rejects invalid data without returning an error.
* Invalid host name, port number will result in the specific alternative
* being rejected. Unknown protocols are skipped.
*/
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
struct altsvcinfo *asi, const char *value,
@ -410,12 +452,11 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
char alpnbuf[MAX_ALTSVC_ALPNLEN] = "";
struct altsvc *as;
unsigned short dstport = srcport; /* the same by default */
const char *semip;
time_t maxage = 24 * 3600; /* default is 24 hours */
bool persist = FALSE;
CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
if(result)
return result;
if(result) {
infof(data, "Excessive alt-svc header, ignoring...\n");
return CURLE_OK;
}
DEBUGASSERT(asi);
@ -427,47 +468,20 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
return CURLE_OK;
}
/* The 'ma' and 'persist' flags are annoyingly meant for all alternatives
but are set after the list on the line. Scan for the semicolons and get
those fields first! */
semip = p;
do {
semip = strchr(semip, ';');
if(semip) {
char option[32];
unsigned long num;
char *end_ptr;
semip++; /* pass the semicolon */
result = getalnum(&semip, option, sizeof(option));
if(result)
break;
while(*semip && ISBLANK(*semip))
semip++;
if(*semip != '=')
continue;
semip++;
num = strtoul(semip, &end_ptr, 10);
if(num < ULONG_MAX) {
if(strcasecompare("ma", option))
maxage = num;
else if(strcasecompare("persist", option) && (num == 1))
persist = TRUE;
}
semip = end_ptr;
}
} while(semip);
do {
if(*p == '=') {
/* [protocol]="[host][:port]" */
dstalpnid = alpn2alpnid(alpnbuf);
if(!dstalpnid) {
infof(data, "Unknown alt-svc protocol \"%s\", ignoring...\n", alpnbuf);
return CURLE_OK;
}
p++;
if(*p == '\"') {
const char *dsthost;
const char *value_ptr;
char option[32];
unsigned long num;
char *end_ptr;
bool quoted = FALSE;
time_t maxage = 24 * 3600; /* default is 24 hours */
bool persist = FALSE;
p++;
if(*p != ':') {
/* host name starts here */
@ -475,11 +489,15 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
p++;
len = p - hostp;
if(!len || (len >= MAX_ALTSVC_HOSTLEN))
return CURLE_BAD_FUNCTION_ARGUMENT;
memcpy(namebuf, hostp, len);
namebuf[len] = 0;
dsthost = namebuf;
if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
infof(data, "Excessive alt-svc host name, ignoring...\n");
dstalpnid = ALPN_none;
}
else {
memcpy(namebuf, hostp, len);
namebuf[len] = 0;
dsthost = namebuf;
}
}
else {
/* no destination name, use source host */
@ -487,31 +505,86 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
}
if(*p == ':') {
/* a port number */
char *end_ptr;
unsigned long port = strtoul(++p, &end_ptr, 10);
if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
infof(data, "Unknown alt-svc port number, ignoring...\n");
return CURLE_OK;
dstalpnid = ALPN_none;
}
p = end_ptr;
dstport = curlx_ultous(port);
}
if(*p++ != '\"')
return CURLE_BAD_FUNCTION_ARGUMENT;
as = altsvc_createid(srchost, dsthost,
srcalpnid, dstalpnid,
srcport, dstport);
if(as) {
/* The expires time also needs to take the Age: value (if any) into
account. [See RFC 7838 section 3.1] */
as->expires = maxage + time(NULL);
as->persist = persist;
Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
asi->num++; /* one more entry */
infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
Curl_alpnid2str(dstalpnid));
break;
/* Handle the optional 'ma' and 'persist' flags. Unknown flags
are skipped. */
for(;;) {
while(*p && ISBLANK(*p) && *p != ';' && *p != ',')
p++;
if(!*p || *p == ',')
break;
p++; /* pass the semicolon */
if(!*p)
break;
result = getalnum(&p, option, sizeof(option));
if(result) {
/* skip option if name is too long */
option[0] = '\0';
}
while(*p && ISBLANK(*p))
p++;
if(*p != '=')
return CURLE_OK;
p++;
while(*p && ISBLANK(*p))
p++;
if(!*p)
return CURLE_OK;
if(*p == '\"') {
/* quoted value */
p++;
quoted = TRUE;
}
value_ptr = p;
if(quoted) {
while(*p && *p != '\"')
p++;
if(!*p++)
return CURLE_OK;
}
else {
while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
p++;
}
num = strtoul(value_ptr, &end_ptr, 10);
if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
if(strcasecompare("ma", option))
maxage = num;
else if(strcasecompare("persist", option) && (num == 1))
persist = TRUE;
}
}
if(dstalpnid) {
as = altsvc_createid(srchost, dsthost,
srcalpnid, dstalpnid,
srcport, dstport);
if(as) {
/* The expires time also needs to take the Age: value (if any) into
account. [See RFC 7838 section 3.1] */
as->expires = maxage + time(NULL);
as->persist = persist;
Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
asi->num++; /* one more entry */
infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
Curl_alpnid2str(dstalpnid));
}
}
else {
infof(data, "Unknown alt-svc protocol \"%s\", skipping...\n",
alpnbuf);
}
}
else
break;
/* after the double quote there can be a comma if there's another
string or a semicolon if no more */
if(*p == ',') {
@ -519,11 +592,11 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
p++;
result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
if(result)
/* failed to parse, but since we already did at least one host we
return OK */
return CURLE_OK;
break;
}
}
else
break;
} while(*p && (*p != ';') && (*p != '\n') && (*p != '\r'));
return CURLE_OK;
@ -535,31 +608,31 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
bool Curl_altsvc_lookup(struct altsvcinfo *asi,
enum alpnid srcalpnid, const char *srchost,
int srcport,
enum alpnid *dstalpnid, const char **dsthost,
int *dstport)
struct altsvc **dstentry,
const int versions) /* one or more bits */
{
struct curl_llist_element *e;
struct curl_llist_element *n;
time_t now = time(NULL);
DEBUGASSERT(asi);
DEBUGASSERT(srchost);
DEBUGASSERT(dsthost);
DEBUGASSERT(dstentry);
for(e = asi->list.head; e; e = n) {
struct altsvc *as = e->ptr;
n = e->next;
if(as->expires < now) {
/* an expired entry, remove */
Curl_llist_remove(&asi->list, e, NULL);
altsvc_free(as);
continue;
}
if((as->srcalpnid == srcalpnid) &&
strcasecompare(as->srchost, srchost) &&
as->srcport == srcport) {
if((as->src.alpnid == srcalpnid) &&
strcasecompare(as->src.host, srchost) &&
(as->src.port == srcport) &&
(versions & as->dst.alpnid)) {
/* match */
*dstalpnid = as->dstalpnid;
*dsthost = as->dsthost;
*dstport = as->dstport;
*dstentry = as;
return TRUE;
}
}

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2019 - 2020, 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
@ -28,20 +28,21 @@
#include "llist.h"
enum alpnid {
ALPN_none,
ALPN_h1,
ALPN_h2,
ALPN_h2c,
ALPN_h3
ALPN_none = 0,
ALPN_h1 = CURLALTSVC_H1,
ALPN_h2 = CURLALTSVC_H2,
ALPN_h3 = CURLALTSVC_H3
};
struct althost {
char *host;
unsigned short port;
enum alpnid alpnid;
};
struct altsvc {
char *srchost;
char *dsthost;
unsigned short srcport;
unsigned short dstport;
enum alpnid srcalpnid;
enum alpnid dstalpnid;
struct althost src;
struct althost dst;
time_t expires;
bool persist;
int prio;
@ -58,7 +59,8 @@ struct altsvcinfo {
const char *Curl_alpnid2str(enum alpnid id);
struct altsvcinfo *Curl_altsvc_init(void);
CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file);
CURLcode Curl_altsvc_save(struct altsvcinfo *asi, const char *file);
CURLcode Curl_altsvc_save(struct Curl_easy *data,
struct altsvcinfo *asi, const char *file);
CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl);
void Curl_altsvc_cleanup(struct altsvcinfo *altsvc);
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
@ -68,10 +70,10 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
bool Curl_altsvc_lookup(struct altsvcinfo *asi,
enum alpnid srcalpnid, const char *srchost,
int srcport,
enum alpnid *dstalpnid, const char **dsthost,
int *dstport);
struct altsvc **dstentry,
const int versions); /* CURLALTSVC_H* bits */
#else
/* disabled */
#define Curl_altsvc_save(a,b)
#define Curl_altsvc_save(a,b,c)
#endif /* CURL_DISABLE_HTTP || USE_ALTSVC */
#endif /* HEADER_CURL_ALTSVC_H */

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -253,16 +253,14 @@ static void destroy_async_data(struct Curl_async *async)
*/
int Curl_resolver_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
curl_socket_t *socks)
{
struct timeval maxtime;
struct timeval timebuf;
struct timeval *timeout;
long milli;
int max = ares_getsock((ares_channel)conn->data->state.resolver,
(ares_socket_t *)socks, numsocks);
(ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
maxtime.tv_usec = 0;
@ -628,26 +626,11 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
{
char *bufp;
struct Curl_easy *data = conn->data;
struct in_addr in;
int family = PF_INET;
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
struct in6_addr in6;
#endif /* CURLRES_IPV6 */
*waitp = 0; /* default to synchronous response */
/* First check if this is an IPv4 address string */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
/* This is a dotted IP address 123.123.123.123-style */
return Curl_ip2addr(AF_INET, &in, hostname, port);
}
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
/* Otherwise, check if this is an IPv6 address string */
if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
/* This must be an IPv6 address literal. */
return Curl_ip2addr(AF_INET6, &in6, hostname, port);
switch(conn->ip_version) {
default:
#if ARES_VERSION >= 0x010601
@ -686,7 +669,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
res->last_status = ARES_ENOTFOUND;
#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
if(family == PF_UNSPEC) {
if(Curl_ipv6works()) {
if(Curl_ipv6works(conn)) {
res->num_pending = 2;
/* areschannel is already setup in the Curl_open() function */
@ -734,7 +717,11 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
return CURLE_OK;
#if (ARES_VERSION >= 0x010704)
#if (ARES_VERSION >= 0x010b00)
ares_result = ares_set_servers_ports_csv(data->state.resolver, servers);
#else
ares_result = ares_set_servers_csv(data->state.resolver, servers);
#endif
switch(ares_result) {
case ARES_SUCCESS:
result = CURLE_OK;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -21,6 +21,7 @@
***************************************************************************/
#include "curl_setup.h"
#include "socketpair.h"
/***********************************************************************
* Only for threaded name resolves builds
@ -70,10 +71,10 @@
#include "strerror.h"
#include "url.h"
#include "multiif.h"
#include "inet_pton.h"
#include "inet_ntop.h"
#include "curl_threads.h"
#include "connect.h"
#include "socketpair.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@ -163,6 +164,10 @@ struct thread_sync_data {
char *hostname; /* hostname to resolve, Curl_async.hostname
duplicate */
int port;
#ifdef USE_SOCKETPAIR
struct connectdata *conn;
curl_socket_t sock_pair[2]; /* socket pair */
#endif
int sock_error;
Curl_addrinfo *res;
#ifdef HAVE_GETADDRINFO
@ -197,6 +202,15 @@ void destroy_thread_sync_data(struct thread_sync_data * tsd)
if(tsd->res)
Curl_freeaddrinfo(tsd->res);
#ifdef USE_SOCKETPAIR
/*
* close one end of the socket pair (may be done in resolver thread);
* the other end (for reading) is always closed in the parent thread.
*/
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
sclose(tsd->sock_pair[1]);
}
#endif
memset(tsd, 0, sizeof(*tsd));
}
@ -230,6 +244,14 @@ int init_thread_sync_data(struct thread_data * td,
Curl_mutex_init(tsd->mtx);
#ifdef USE_SOCKETPAIR
/* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */
if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) {
tsd->sock_pair[0] = CURL_SOCKET_BAD;
tsd->sock_pair[1] = CURL_SOCKET_BAD;
goto err_exit;
}
#endif
tsd->sock_error = CURL_ASYNC_SUCCESS;
/* Copying hostname string because original can be destroyed by parent
@ -276,6 +298,9 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
struct thread_data *td = tsd->td;
char service[12];
int rc;
#ifdef USE_SOCKETPAIR
char buf[1];
#endif
msnprintf(service, sizeof(service), "%d", tsd->port);
@ -298,6 +323,16 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
free(td);
}
else {
#ifdef USE_SOCKETPAIR
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
/* DNS has been resolved, signal client task */
buf[0] = 1;
if(swrite(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
/* update sock_erro to errno */
tsd->sock_error = SOCKERRNO;
}
}
#endif
tsd->done = 1;
Curl_mutex_release(tsd->mtx);
}
@ -348,6 +383,10 @@ static void destroy_async_data(struct Curl_async *async)
if(async->os_specific) {
struct thread_data *td = (struct thread_data*) async->os_specific;
int done;
#ifdef USE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0];
struct connectdata *conn = td->tsd.conn;
#endif
/*
* if the thread is still blocking in the resolve syscall, detach it and
@ -369,6 +408,15 @@ static void destroy_async_data(struct Curl_async *async)
free(async->os_specific);
}
#ifdef USE_SOCKETPAIR
/*
* ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
* before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
*/
if(conn)
Curl_multi_closed(conn->data, sock_rd);
sclose(sock_rd);
#endif
}
async->os_specific = NULL;
@ -569,8 +617,9 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
}
else {
/* poll for name lookup done with exponential backoff up to 250ms */
timediff_t elapsed = Curl_timediff(Curl_now(),
data->progress.t_startsingle);
/* should be fine even if this converts to 32 bit */
time_t elapsed = (time_t)Curl_timediff(Curl_now(),
data->progress.t_startsingle);
if(elapsed < 0)
elapsed = 0;
@ -592,26 +641,45 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
}
int Curl_resolver_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
curl_socket_t *socks)
{
int ret_val = 0;
time_t milli;
timediff_t ms;
struct Curl_easy *data = conn->data;
struct resdata *reslv = (struct resdata *)data->state.resolver;
#ifdef USE_SOCKETPAIR
struct thread_data *td = (struct thread_data*)conn->async.os_specific;
#else
(void)socks;
(void)numsocks;
ms = Curl_timediff(Curl_now(), reslv->start);
if(ms < 3)
milli = 0;
else if(ms <= 50)
milli = ms/3;
else if(ms <= 250)
milli = 50;
else
milli = 200;
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
return 0;
#endif
#ifdef USE_SOCKETPAIR
if(td) {
/* return read fd to client for polling the DNS resolution status */
socks[0] = td->tsd.sock_pair[0];
DEBUGASSERT(td->tsd.conn == conn || !td->tsd.conn);
td->tsd.conn = conn;
ret_val = GETSOCK_READSOCK(0);
}
else {
#endif
ms = Curl_timediff(Curl_now(), reslv->start);
if(ms < 3)
milli = 0;
else if(ms <= 50)
milli = (time_t)ms/3;
else if(ms <= 250)
milli = 50;
else
milli = 200;
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
#ifdef USE_SOCKETPAIR
}
#endif
return ret_val;
}
#ifndef HAVE_GETADDRINFO
@ -623,16 +691,11 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
int port,
int *waitp)
{
struct in_addr in;
struct Curl_easy *data = conn->data;
struct resdata *reslv = (struct resdata *)data->state.resolver;
*waitp = 0; /* default to synchronous response */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
return Curl_ip2addr(AF_INET, &in, hostname, port);
reslv->start = Curl_now();
/* fire up a new resolver thread! */
@ -657,32 +720,12 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
int *waitp)
{
struct addrinfo hints;
char sbuf[12];
int pf = PF_INET;
struct Curl_easy *data = conn->data;
struct resdata *reslv = (struct resdata *)data->state.resolver;
*waitp = 0; /* default to synchronous response */
#ifndef USE_RESOLVE_ON_IPS
{
struct in_addr in;
/* First check if this is an IPv4 address string */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
return Curl_ip2addr(AF_INET, &in, hostname, port);
}
#ifdef CURLRES_IPV6
{
struct in6_addr in6;
/* check if this is an IPv6 address string */
if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
/* This is an IPv6 address literal */
return Curl_ip2addr(AF_INET6, &in6, hostname, port);
}
#endif /* CURLRES_IPV6 */
#endif /* !USE_RESOLVE_ON_IPS */
#ifdef CURLRES_IPV6
/*
* Check if a limited name resolve has been requested.
@ -699,16 +742,15 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
break;
}
if((pf != PF_INET) && !Curl_ipv6works())
if((pf != PF_INET) && !Curl_ipv6works(conn))
/* The stack seems to be a non-IPv6 one */
pf = PF_INET;
#endif /* CURLRES_IPV6 */
memset(&hints, 0, sizeof(hints));
hints.ai_family = pf;
hints.ai_socktype = conn->socktype;
msnprintf(sbuf, sizeof(sbuf), "%d", port);
hints.ai_socktype = (conn->transport == TRNSPRT_TCP)?
SOCK_STREAM : SOCK_DGRAM;
reslv->start = Curl_now();
/* fire up a new resolver thread! */

View File

@ -114,8 +114,7 @@ void Curl_resolver_kill(struct connectdata *conn);
* return bitmask indicating what file descriptors (referring to array indexes
* in the 'sock' array) to wait for, read/write.
*/
int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock,
int numsocks);
int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock);
/*
* Curl_resolver_is_resolved()

View File

@ -24,8 +24,8 @@
#include "curl_setup.h"
#if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_LIBSSH2) || \
defined(USE_LIBSSH) || !defined(CURL_DISABLE_LDAP) || \
#if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \
!defined(CURL_DISABLE_LDAP) || \
!defined(CURL_DISABLE_DOH) || defined(USE_SSL)
#include "urldata.h" /* for the Curl_easy definition */

View File

@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus@haxx.se>
* Copyright (C) 2012 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2012 - 2020, 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
@ -40,26 +40,7 @@
#include "curl_memory.h"
#include "memdebug.h"
#ifdef CURLDEBUG
/* the debug versions of these macros make extra certain that the lock is
never doubly locked or unlocked */
#define CONN_LOCK(x) if((x)->share) { \
Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \
DEBUGASSERT(!(x)->state.conncache_lock); \
(x)->state.conncache_lock = TRUE; \
}
#define CONN_UNLOCK(x) if((x)->share) { \
DEBUGASSERT((x)->state.conncache_lock); \
(x)->state.conncache_lock = FALSE; \
Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \
}
#else
#define CONN_LOCK(x) if((x)->share) \
Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
#define CONN_UNLOCK(x) if((x)->share) \
Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
#endif
#define HASHKEY_SIZE 128
static void conn_llist_dtor(void *user, void *element)
{
@ -120,6 +101,7 @@ static int bundle_remove_conn(struct connectbundle *cb_ptr,
}
curr = curr->next;
}
DEBUGASSERT(0);
return 0;
}
@ -141,10 +123,8 @@ int Curl_conncache_init(struct conncache *connc, int size)
rc = Curl_hash_init(&connc->hash, size, Curl_hash_str,
Curl_str_key_compare, free_bundle_hash_entry);
if(rc) {
Curl_close(connc->closure_handle);
connc->closure_handle = NULL;
}
if(rc)
Curl_close(&connc->closure_handle);
else
connc->closure_handle->state.conn_cache = connc;
@ -159,23 +139,27 @@ void Curl_conncache_destroy(struct conncache *connc)
/* creates a key to find a bundle for this connection */
static void hashkey(struct connectdata *conn, char *buf,
size_t len) /* something like 128 is fine */
size_t len, /* something like 128 is fine */
const char **hostp)
{
const char *hostname;
long port = conn->remote_port;
if(conn->bits.socksproxy)
hostname = conn->socks_proxy.host.name;
else if(conn->bits.httpproxy)
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
hostname = conn->http_proxy.host.name;
port = conn->port;
}
else if(conn->bits.conn_to_host)
hostname = conn->conn_to_host.name;
else
hostname = conn->host.name;
DEBUGASSERT(len > 32);
if(hostp)
/* report back which name we used */
*hostp = hostname;
/* put the number first so that the hostname gets cut off if too long */
msnprintf(buf, len, "%ld%s", conn->port, hostname);
msnprintf(buf, len, "%ld%s", port, hostname);
}
void Curl_conncache_unlock(struct Curl_easy *data)
@ -195,30 +179,19 @@ size_t Curl_conncache_size(struct Curl_easy *data)
return num;
}
/* Returns number of connections currently held in the connections's bundle
Locks/unlocks the cache itself!
*/
size_t Curl_conncache_bundle_size(struct connectdata *conn)
{
size_t num;
CONN_LOCK(conn->data);
num = conn->bundle->num_connections;
CONN_UNLOCK(conn->data);
return num;
}
/* Look up the bundle with all the connections to the same host this
connectdata struct is setup to use.
**NOTE**: When it returns, it holds the connection cache lock! */
struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
struct conncache *connc)
struct conncache *connc,
const char **hostp)
{
struct connectbundle *bundle = NULL;
CONN_LOCK(conn->data);
if(connc) {
char key[128];
hashkey(conn, key, sizeof(key));
char key[HASHKEY_SIZE];
hashkey(conn, key, sizeof(key), hostp);
bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
}
@ -267,17 +240,17 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
struct Curl_easy *data = conn->data;
/* *find_bundle() locks the connection cache */
bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache);
bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache, NULL);
if(!bundle) {
int rc;
char key[128];
char key[HASHKEY_SIZE];
result = bundle_create(data, &new_bundle);
if(result) {
goto unlock;
}
hashkey(conn, key, sizeof(key));
hashkey(conn, key, sizeof(key), NULL);
rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
if(!rc) {
@ -423,17 +396,15 @@ conncache_find_first_connection(struct conncache *connc)
*
* Return TRUE if stored, FALSE if closed.
*/
bool Curl_conncache_return_conn(struct connectdata *conn)
bool Curl_conncache_return_conn(struct Curl_easy *data,
struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
/* data->multi->maxconnects can be negative, deal with it. */
size_t maxconnects =
(data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
data->multi->maxconnects;
struct connectdata *conn_candidate = NULL;
conn->data = NULL; /* no owner anymore */
conn->lastused = Curl_now(); /* it was used up until now */
if(maxconnects > 0 &&
Curl_conncache_size(data) > maxconnects) {
@ -536,7 +507,8 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
while(curr) {
conn = curr->ptr;
if(!CONN_INUSE(conn) && !conn->data) {
if(!CONN_INUSE(conn) && !conn->data && !conn->bits.close &&
!conn->bits.connect_only) {
/* Set higher score for the age passed since the connection was used */
score = Curl_timediff(now, conn->lastused);
@ -588,7 +560,7 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
Curl_hostcache_clean(connc->closure_handle,
connc->closure_handle->dns.hostcache);
Curl_close(connc->closure_handle);
Curl_close(&connc->closure_handle);
sigpipe_restore(&pipe_st);
}
}

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2015 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2015 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <linus@haxx.se>
*
* This software is licensed as described in the file COPYING, which
@ -42,6 +42,27 @@ struct conncache {
#define BUNDLE_UNKNOWN 0 /* initial value */
#define BUNDLE_MULTIPLEX 2
#ifdef CURLDEBUG
/* the debug versions of these macros make extra certain that the lock is
never doubly locked or unlocked */
#define CONN_LOCK(x) if((x)->share) { \
Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \
DEBUGASSERT(!(x)->state.conncache_lock); \
(x)->state.conncache_lock = TRUE; \
}
#define CONN_UNLOCK(x) if((x)->share) { \
DEBUGASSERT((x)->state.conncache_lock); \
(x)->state.conncache_lock = FALSE; \
Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \
}
#else
#define CONN_LOCK(x) if((x)->share) \
Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
#define CONN_UNLOCK(x) if((x)->share) \
Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
#endif
struct connectbundle {
int multiuse; /* supports multi-use */
size_t num_connections; /* Number of connections in the bundle */
@ -54,13 +75,14 @@ void Curl_conncache_destroy(struct conncache *connc);
/* return the correct bundle, to a host or a proxy */
struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
struct conncache *connc);
struct conncache *connc,
const char **hostp);
void Curl_conncache_unlock(struct Curl_easy *data);
/* returns number of connections currently held in the connection cache */
size_t Curl_conncache_size(struct Curl_easy *data);
size_t Curl_conncache_bundle_size(struct connectdata *conn);
bool Curl_conncache_return_conn(struct connectdata *conn);
bool Curl_conncache_return_conn(struct Curl_easy *data,
struct connectdata *conn);
CURLcode Curl_conncache_add_conn(struct conncache *connc,
struct connectdata *conn) WARN_UNUSED_RESULT;
void Curl_conncache_remove_conn(struct Curl_easy *data,

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -75,6 +75,8 @@
#include "conncache.h"
#include "multihandle.h"
#include "system_win32.h"
#include "quic.h"
#include "socks.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -165,7 +167,7 @@ tcpkeepalive(struct Curl_easy *data,
static CURLcode
singleipconnect(struct connectdata *conn,
const Curl_addrinfo *ai, /* start connecting to this */
curl_socket_t *sock);
int sockindex); /* 0 or 1 among the temp ones */
/*
* Curl_timeleft() returns the amount of milliseconds left allowed for the
@ -368,6 +370,11 @@ static CURLcode bindlocal(struct connectdata *conn,
infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
dev, af, myhost, h->addr->ai_family);
Curl_resolv_unlock(data, h);
if(af != h->addr->ai_family) {
/* bad IP version combo, signal the caller to try another address
family if available */
return CURLE_UNSUPPORTED_PROTOCOL;
}
done = 1;
}
else {
@ -590,7 +597,7 @@ static CURLcode trynextip(struct connectdata *conn,
}
if(ai) {
result = singleipconnect(conn, ai, &conn->tempsock[tempindex]);
result = singleipconnect(conn, ai, tempindex);
if(result == CURLE_COULDNT_CONNECT) {
ai = ai->ai_next;
continue;
@ -620,13 +627,10 @@ void Curl_persistconninfo(struct connectdata *conn)
conn->data->info.conn_local_port = conn->local_port;
}
UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
long *port);
/* retrieves ip address and port from a sockaddr structure.
note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
long *port)
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, long *port)
{
struct sockaddr_in *si = NULL;
#ifdef ENABLE_IPV6
@ -634,6 +638,8 @@ UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
#endif
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
struct sockaddr_un *su = NULL;
#else
(void)salen;
#endif
switch(sa->sa_family) {
@ -659,8 +665,12 @@ UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
#endif
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
case AF_UNIX:
su = (struct sockaddr_un*)sa;
msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
if(salen > (curl_socklen_t)sizeof(sa_family_t)) {
su = (struct sockaddr_un*)sa;
msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
}
else
addr[0] = 0; /* socket with no name */
*port = 0;
return TRUE;
#endif
@ -678,8 +688,8 @@ UNITTEST bool getaddressinfo(struct sockaddr *sa, char *addr,
connection */
void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
{
if(conn->socktype == SOCK_DGRAM)
/* there's no connection! */
if(conn->transport != TRNSPRT_TCP)
/* there's no TCP connection! */
return;
#if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME)
@ -688,10 +698,11 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
char buffer[STRERROR_LEN];
struct Curl_sockaddr_storage ssrem;
struct Curl_sockaddr_storage ssloc;
curl_socklen_t len;
curl_socklen_t plen;
curl_socklen_t slen;
#ifdef HAVE_GETPEERNAME
len = sizeof(struct Curl_sockaddr_storage);
if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
plen = sizeof(struct Curl_sockaddr_storage);
if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
int error = SOCKERRNO;
failf(data, "getpeername() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
@ -699,9 +710,9 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
}
#endif
#ifdef HAVE_GETSOCKNAME
len = sizeof(struct Curl_sockaddr_storage);
slen = sizeof(struct Curl_sockaddr_storage);
memset(&ssloc, 0, sizeof(ssloc));
if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
int error = SOCKERRNO;
failf(data, "getsockname() failed with errno %d: %s",
error, Curl_strerror(error, buffer, sizeof(buffer)));
@ -709,8 +720,8 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
}
#endif
#ifdef HAVE_GETPEERNAME
if(!getaddressinfo((struct sockaddr*)&ssrem,
conn->primary_ip, &conn->primary_port)) {
if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
conn->primary_ip, &conn->primary_port)) {
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
@ -718,8 +729,8 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
#endif
#ifdef HAVE_GETSOCKNAME
if(!getaddressinfo((struct sockaddr*)&ssloc,
conn->local_ip, &conn->local_port)) {
if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
conn->local_ip, &conn->local_port)) {
failf(data, "ssloc inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
@ -734,6 +745,79 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
Curl_persistconninfo(conn);
}
/* After a TCP connection to the proxy has been verified, this function does
the next magic steps. If 'done' isn't set TRUE, it is not done yet and
must be called again.
Note: this function's sub-functions call failf()
*/
static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
bool *done)
{
CURLcode result = CURLE_OK;
if(conn->bits.socksproxy) {
#ifndef CURL_DISABLE_PROXY
/* for the secondary socket (FTP), use the "connect to host"
* but ignore the "connect to port" (use the secondary port)
*/
const char * const host =
conn->bits.httpproxy ?
conn->http_proxy.host.name :
conn->bits.conn_to_host ?
conn->conn_to_host.name :
sockindex == SECONDARYSOCKET ?
conn->secondaryhostname : conn->host.name;
const int port =
conn->bits.httpproxy ? (int)conn->http_proxy.port :
sockindex == SECONDARYSOCKET ? conn->secondary_port :
conn->bits.conn_to_port ? conn->conn_to_port :
conn->remote_port;
switch(conn->socks_proxy.proxytype) {
case CURLPROXY_SOCKS5:
case CURLPROXY_SOCKS5_HOSTNAME:
result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
host, port, sockindex, conn, done);
break;
case CURLPROXY_SOCKS4:
case CURLPROXY_SOCKS4A:
result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
conn, done);
break;
default:
failf(conn->data, "unknown proxytype option given");
result = CURLE_COULDNT_CONNECT;
} /* switch proxytype */
#else
(void)sockindex;
#endif /* CURL_DISABLE_PROXY */
}
else
*done = TRUE; /* no SOCKS proxy, so consider us connected */
return result;
}
/*
* post_SOCKS() is called after a successful connect to the peer, which
* *could* be a SOCKS proxy
*/
static void post_SOCKS(struct connectdata *conn,
int sockindex,
bool *connected)
{
conn->bits.tcpconnect[sockindex] = TRUE;
*connected = TRUE;
if(sockindex == FIRSTSOCKET)
Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */
Curl_updateconninfo(conn, conn->sock[sockindex]);
Curl_verboseconnect(conn);
}
/*
* Curl_is_connected() checks if the socket has connected.
*/
@ -771,11 +855,37 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return CURLE_OPERATION_TIMEDOUT;
}
if(SOCKS_STATE(conn->cnnct.state)) {
/* still doing SOCKS */
result = connect_SOCKS(conn, sockindex, connected);
if(!result && *connected)
post_SOCKS(conn, sockindex, connected);
return result;
}
for(i = 0; i<2; i++) {
const int other = i ^ 1;
if(conn->tempsock[i] == CURL_SOCKET_BAD)
continue;
#ifdef ENABLE_QUIC
if(conn->transport == TRNSPRT_QUIC) {
result = Curl_quic_is_connected(conn, i, connected);
if(result) {
error = SOCKERRNO;
goto error;
}
if(*connected) {
/* use this socket from now on */
conn->sock[sockindex] = conn->tempsock[i];
conn->ip_addr = conn->tempaddr[i];
conn->tempsock[i] = CURL_SOCKET_BAD;
connkeep(conn, "HTTP/3 default");
}
return result;
}
#endif
#ifdef mpeix
/* Call this function once now, and ignore the results. We do this to
"clear" the error state on the socket so that we can later read it
@ -789,8 +899,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
if(rc == 0) { /* no connection yet */
error = 0;
if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
infof(data, "After %ldms connect time, move on!\n",
conn->timeoutms_per_addr);
infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
"ms connect time, move on!\n", conn->timeoutms_per_addr);
error = ETIMEDOUT;
}
@ -819,18 +929,13 @@ CURLcode Curl_is_connected(struct connectdata *conn,
conn->tempsock[other] = CURL_SOCKET_BAD;
}
/* see if we need to do any proxy magic first once we connected */
result = Curl_connected_proxy(conn, sockindex);
if(result)
/* see if we need to kick off any SOCKS proxy magic once we
connected */
result = connect_SOCKS(conn, sockindex, connected);
if(result || !*connected)
return result;
conn->bits.tcpconnect[sockindex] = TRUE;
*connected = TRUE;
if(sockindex == FIRSTSOCKET)
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
Curl_updateconninfo(conn, conn->sock[sockindex]);
Curl_verboseconnect(conn);
post_SOCKS(conn, sockindex, connected);
return CURLE_OK;
}
@ -839,6 +944,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
else if(rc & CURL_CSELECT_ERR)
(void)verifyconnect(conn->tempsock[i], &error);
#ifdef ENABLE_QUIC
error:
#endif
/*
* The connection failed here, we should attempt to connect to the "next
* address" for the given host. But first remember the latest error.
@ -848,19 +956,21 @@ CURLcode Curl_is_connected(struct connectdata *conn,
SET_SOCKERRNO(error);
if(conn->tempaddr[i]) {
CURLcode status;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
char ipaddress[MAX_IPADR_LEN];
char buffer[STRERROR_LEN];
Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
#endif
infof(data, "connect to %s port %ld failed: %s\n",
ipaddress, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
allow : allow / 2;
allow : allow / 2;
status = trynextip(conn, sockindex, i);
if(status != CURLE_COULDNT_CONNECT
|| conn->tempsock[other] == CURL_SOCKET_BAD)
if((status != CURLE_COULDNT_CONNECT) ||
conn->tempsock[other] == CURL_SOCKET_BAD)
/* the last attempt failed and no other sockets remain open */
result = status;
}
@ -892,6 +1002,14 @@ CURLcode Curl_is_connected(struct connectdata *conn,
failf(data, "Failed to connect to %s port %ld: %s",
hostname, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
#ifdef WSAETIMEDOUT
if(WSAETIMEDOUT == data->state.os_errno)
result = CURLE_OPERATION_TIMEDOUT;
#elif defined(ETIMEDOUT)
if(ETIMEDOUT == data->state.os_errno)
result = CURLE_OPERATION_TIMEDOUT;
#endif
}
return result;
@ -900,14 +1018,12 @@ CURLcode Curl_is_connected(struct connectdata *conn,
static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
{
#if defined(TCP_NODELAY)
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
struct Curl_easy *data = conn->data;
#endif
curl_socklen_t onoff = (curl_socklen_t) 1;
int level = IPPROTO_TCP;
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
struct Curl_easy *data = conn->data;
char buffer[STRERROR_LEN];
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
#else
(void) conn;
#endif
@ -915,8 +1031,6 @@ static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
sizeof(onoff)) < 0)
infof(data, "Could not set TCP_NODELAY: %s\n",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
else
infof(data, "TCP_NODELAY set\n");
#else
(void)conn;
(void)sockfd;
@ -999,7 +1113,7 @@ void Curl_sndbufset(curl_socket_t sockfd)
*/
static CURLcode singleipconnect(struct connectdata *conn,
const Curl_addrinfo *ai,
curl_socket_t *sockp)
int sockindex)
{
struct Curl_sockaddr_ex addr;
int rc = -1;
@ -1015,7 +1129,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
int optval = 1;
#endif
char buffer[STRERROR_LEN];
curl_socket_t *sockp = &conn->tempsock[sockindex];
*sockp = CURL_SOCKET_BAD;
result = Curl_socket(conn, ai, &addr, &sockfd);
@ -1026,8 +1140,8 @@ static CURLcode singleipconnect(struct connectdata *conn,
return CURLE_OK;
/* store remote address and port used in this connection attempt */
if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
ipaddress, &port)) {
if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen,
ipaddress, &port)) {
/* malformed address or bug in inet_ntop, try next address */
failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
@ -1094,8 +1208,8 @@ static CURLcode singleipconnect(struct connectdata *conn,
if(conn->num_addr > 1)
Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
/* Connect TCP sockets, bind UDP */
if(!isconnected && (conn->socktype == SOCK_STREAM)) {
/* Connect TCP and QUIC sockets */
if(!isconnected && (conn->transport != TRNSPRT_UDP)) {
if(conn->bits.tcp_fastopen) {
#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
# if defined(HAVE_BUILTIN_AVAILABLE)
@ -1124,8 +1238,6 @@ static CURLcode singleipconnect(struct connectdata *conn,
if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
(void *)&optval, sizeof(optval)) < 0)
infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd);
else
infof(data, "TCP_FASTOPEN_CONNECT set\n");
rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
#elif defined(MSG_FASTOPEN) /* old Linux */
@ -1141,6 +1253,16 @@ static CURLcode singleipconnect(struct connectdata *conn,
if(-1 == rc)
error = SOCKERRNO;
#ifdef ENABLE_QUIC
else if(conn->transport == TRNSPRT_QUIC) {
/* pass in 'sockfd' separately since it hasn't been put into the
tempsock array at this point */
result = Curl_quic_connect(conn, sockfd, sockindex,
&addr.sa_addr, addr.addrlen);
if(result)
error = SOCKERRNO;
}
#endif
}
else {
*sockp = sockfd;
@ -1214,7 +1336,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* start connecting to first IP */
while(conn->tempaddr[0]) {
result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0]));
result = singleipconnect(conn, conn->tempaddr[0], 0);
if(!result)
break;
conn->tempaddr[0] = conn->tempaddr[0]->ai_next;
@ -1326,12 +1448,11 @@ int Curl_closesocket(struct connectdata *conn,
curl_socket_t sock)
{
if(conn && conn->fclosesocket) {
if((sock == conn->sock[SECONDARYSOCKET]) &&
conn->sock_accepted[SECONDARYSOCKET])
if((sock == conn->sock[SECONDARYSOCKET]) && conn->sock_accepted)
/* if this socket matches the second socket, and that was created with
accept, then we MUST NOT call the callback but clear the accepted
status */
conn->sock_accepted[SECONDARYSOCKET] = FALSE;
conn->sock_accepted = FALSE;
else {
int rc;
Curl_multi_closed(conn->data, sock);
@ -1381,8 +1502,9 @@ CURLcode Curl_socket(struct connectdata *conn,
*/
addr->family = ai->ai_family;
addr->socktype = conn->socktype;
addr->protocol = conn->socktype == SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
addr->socktype = (conn->transport == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM;
addr->protocol = conn->transport != TRNSPRT_TCP ? IPPROTO_UDP :
ai->ai_protocol;
addr->addrlen = ai->ai_addrlen;
if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
@ -1413,6 +1535,11 @@ CURLcode Curl_socket(struct connectdata *conn,
/* no socket, no connection */
return CURLE_COULDNT_CONNECT;
if(conn->transport == TRNSPRT_QUIC) {
/* QUIC sockets need to be nonblocking */
(void)curlx_nonblock(*sockfd, TRUE);
}
#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
if(conn->scope_id && (addr->family == AF_INET6)) {
struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;

View File

@ -51,6 +51,9 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
struct connectdata **connp);
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, long *port);
/*
* Check if a connection seems to be alive.
*/

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -96,6 +96,9 @@ Example set of cookies:
#include "curl_get_line.h"
#include "curl_memrchr.h"
#include "inet_pton.h"
#include "parsedate.h"
#include "rand.h"
#include "rename.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -536,9 +539,9 @@ Curl_cookie_add(struct Curl_easy *data,
* only test for names where that can possibly be true.
*/
if(nlen > 3 && name[0] == '_' && name[1] == '_') {
if(strncasecompare("__Secure-", name, 9))
if(!strncmp("__Secure-", name, 9))
co->prefix |= COOKIE_PREFIX__SECURE;
else if(strncasecompare("__Host-", name, 7))
else if(!strncmp("__Host-", name, 7))
co->prefix |= COOKIE_PREFIX__HOST;
}
@ -715,7 +718,7 @@ Curl_cookie_add(struct Curl_easy *data,
else if(co->expirestr) {
/* Note that if the date couldn't get parsed for whatever reason,
the cookie will be treated as a session cookie */
co->expires = curl_getdate(co->expirestr, NULL);
co->expires = Curl_getdate_capped(co->expirestr);
/* Session cookies have expires set to 0 so if we get that back
from the date parser let's add a second to make it a
@ -819,22 +822,14 @@ Curl_cookie_add(struct Curl_easy *data,
badcookie = TRUE;
break;
case 1:
/* This field got its explanation on the 23rd of May 2001 by
Andrés García:
flag: A TRUE/FALSE value indicating if all machines within a given
domain can access the variable. This value is set automatically by
the browser, depending on the value you set for the domain.
As far as I can see, it is set to true when the cookie says
/* flag: A TRUE/FALSE value indicating if all machines within a given
domain can access the variable. Set TRUE when the cookie says
.domain.com and to false when the domain is complete www.domain.com
*/
co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
break;
case 2:
/* It turns out, that sometimes the file format allows the path
field to remain not filled in, we try to detect this and work
around it! Andrés García made us aware of this... */
/* The file format allows the path field to remain not filled in */
if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
/* only if the path doesn't look like a boolean option! */
co->path = strdup(ptr);
@ -1053,7 +1048,7 @@ Curl_cookie_add(struct Curl_easy *data,
*clist = *co; /* then store all the new data */
free(co); /* free the newly alloced memory */
free(co); /* free the newly allocated memory */
co = clist; /* point to the previous struct instead */
/* We have replaced a cookie, now skip the rest of the list but
@ -1098,6 +1093,8 @@ Curl_cookie_add(struct Curl_easy *data,
*
* If 'newsession' is TRUE, discard all "session cookies" on read from file.
*
* Note that 'data' might be called as NULL pointer.
*
* Returns NULL on out of memory. Invalid cookies are ignored.
****************************************************************************/
struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
@ -1168,6 +1165,8 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
}
c->running = TRUE; /* now, we're running */
if(data)
data->state.cookie_engine = TRUE;
return c;
@ -1504,11 +1503,14 @@ static char *get_netscape_format(const struct Cookie *co)
*
* The function returns non-zero on write failure.
*/
static int cookie_output(struct CookieInfo *c, const char *dumphere)
static int cookie_output(struct Curl_easy *data,
struct CookieInfo *c, const char *filename)
{
struct Cookie *co;
FILE *out;
FILE *out = NULL;
bool use_stdout = FALSE;
char *tempstore = NULL;
bool error = false;
if(!c)
/* no cookie engine alive */
@ -1517,16 +1519,24 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
/* at first, remove expired cookies */
remove_expired(c);
if(!strcmp("-", dumphere)) {
if(!strcmp("-", filename)) {
/* use stdout */
out = stdout;
use_stdout = TRUE;
}
else {
out = fopen(dumphere, FOPEN_WRITETEXT);
if(!out) {
return 1; /* failure */
}
unsigned char randsuffix[9];
if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix)))
return 2;
tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
if(!tempstore)
return 1;
out = fopen(tempstore, FOPEN_WRITETEXT);
if(!out)
goto error;
}
fputs("# Netscape HTTP Cookie File\n"
@ -1536,35 +1546,31 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
if(c->numcookies) {
unsigned int i;
unsigned int j;
size_t nvalid = 0;
struct Cookie **array;
array = malloc(sizeof(struct Cookie *) * c->numcookies);
array = calloc(1, sizeof(struct Cookie *) * c->numcookies);
if(!array) {
if(!use_stdout)
fclose(out);
return 1;
goto error;
}
j = 0;
/* only sort the cookies with a domain property */
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
for(co = c->cookies[i]; co; co = co->next) {
if(!co->domain)
continue;
array[j++] = co;
array[nvalid++] = co;
}
}
qsort(array, c->numcookies, sizeof(struct Cookie *), cookie_sort_ct);
qsort(array, nvalid, sizeof(struct Cookie *), cookie_sort_ct);
for(i = 0; i < j; i++) {
for(i = 0; i < nvalid; i++) {
char *format_ptr = get_netscape_format(array[i]);
if(format_ptr == NULL) {
fprintf(out, "#\n# Fatal libcurl error\n");
free(array);
if(!use_stdout)
fclose(out);
return 1;
goto error;
}
fprintf(out, "%s\n", format_ptr);
free(format_ptr);
@ -1572,10 +1578,24 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
free(array);
}
if(!use_stdout)
fclose(out);
return 0;
if(!use_stdout) {
fclose(out);
out = NULL;
if(Curl_rename(tempstore, filename)) {
unlink(tempstore);
goto error;
}
}
goto cleanup;
error:
error = true;
cleanup:
if(out && !use_stdout)
fclose(out);
free(tempstore);
return error ? 1 : 0;
}
static struct curl_slist *cookie_list(struct Curl_easy *data)
@ -1621,7 +1641,7 @@ struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
return list;
}
void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
{
if(data->set.str[STRING_COOKIEJAR]) {
if(data->change.cookielist) {
@ -1634,7 +1654,7 @@ void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
/* if we have a destination file for all the cookies to get dumped to */
if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
if(cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]))
infof(data, "WARNING: failed to save cookies in %s\n",
data->set.str[STRING_COOKIEJAR]);
}
@ -1650,6 +1670,7 @@ void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
Curl_cookie_cleanup(data->cookies);
data->cookies = NULL;
}
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}

View File

@ -109,7 +109,7 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies);
#define Curl_cookie_cleanup(x) Curl_nop_stmt
#define Curl_flush_cookies(x,y) Curl_nop_stmt
#else
void Curl_flush_cookies(struct Curl_easy *data, int cleanup);
void Curl_flush_cookies(struct Curl_easy *data, bool cleanup);
void Curl_cookie_cleanup(struct CookieInfo *);
struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
const char *, struct CookieInfo *, bool);

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -64,6 +64,9 @@
#define CURL_EXTERN_SYMBOL
#endif
/* Allow SMB to work on Windows */
#cmakedefine USE_WIN32_CRYPTO
/* Use Windows LDAP implementation */
#cmakedefine USE_WIN32_LDAP 1
@ -139,9 +142,6 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H 1
/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
#cmakedefine HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
/* Define to 1 if you have the <errno.h> header file. */
#cmakedefine HAVE_ERRNO_H 1
@ -232,6 +232,9 @@
/* Define to 1 if you have the `getsockname' function. */
#cmakedefine HAVE_GETSOCKNAME 1
/* Define to 1 if you have the `if_nametoindex' function. */
#cmakedefine HAVE_IF_NAMETOINDEX 1
/* Define to 1 if you have the `getpwuid' function. */
#cmakedefine HAVE_GETPWUID 1
@ -395,9 +398,6 @@
/* Define to 1 if you have the <libssh2.h> header file. */
#cmakedefine HAVE_LIBSSH2_H 1
/* Define to 1 if you have the `ssl' library (-lssl). */
#cmakedefine HAVE_LIBSSL 1
/* if zlib is available */
#cmakedefine HAVE_LIBZ 1
@ -446,9 +446,6 @@
/* Define to 1 if you have the <openssl/crypto.h> header file. */
#cmakedefine HAVE_OPENSSL_CRYPTO_H 1
/* Define to 1 if you have the <openssl/engine.h> header file. */
#cmakedefine HAVE_OPENSSL_ENGINE_H 1
/* Define to 1 if you have the <openssl/err.h> header file. */
#cmakedefine HAVE_OPENSSL_ERR_H 1
@ -575,9 +572,6 @@
/* Define to 1 if you have the `socket' function. */
#cmakedefine HAVE_SOCKET 1
/* Define to 1 if you have the `SSL_get_shutdown' function. */
#cmakedefine HAVE_SSL_GET_SHUTDOWN 1
/* Define to 1 if you have the <ssl.h> header file. */
#cmakedefine HAVE_SSL_H 1
@ -879,35 +873,44 @@
/* Define to the function return type for send. */
#cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV}
/*
Note: SIZEOF_* variables are fetched with CMake through check_type_size().
As per CMake documentation on CheckTypeSize, C preprocessor code is
generated by CMake into SIZEOF_*_CODE. This is what we use in the
following statements.
Reference: https://cmake.org/cmake/help/latest/module/CheckTypeSize.html
*/
/* The size of `int', as computed by sizeof. */
@SIZEOF_INT_CODE@
${SIZEOF_INT_CODE}
/* The size of `short', as computed by sizeof. */
@SIZEOF_SHORT_CODE@
${SIZEOF_SHORT_CODE}
/* The size of `long', as computed by sizeof. */
@SIZEOF_LONG_CODE@
${SIZEOF_LONG_CODE}
/* The size of `long long', as computed by sizeof. */
@SIZEOF_LONG_LONG_CODE@
${SIZEOF_LONG_LONG_CODE}
/* The size of `__int64', as computed by sizeof. */
@SIZEOF___INT64_CODE@
${SIZEOF___INT64_CODE}
/* The size of `off_t', as computed by sizeof. */
@SIZEOF_OFF_T_CODE@
${SIZEOF_OFF_T_CODE}
/* The size of `curl_off_t', as computed by sizeof. */
@SIZEOF_CURL_OFF_T_CODE@
${SIZEOF_CURL_OFF_T_CODE}
/* The size of `size_t', as computed by sizeof. */
@SIZEOF_SIZE_T_CODE@
${SIZEOF_SIZE_T_CODE}
/* The size of `ssize_t', as computed by sizeof. */
@SIZEOF_SSIZE_T_CODE@
${SIZEOF_SSIZE_T_CODE}
/* The size of `time_t', as computed by sizeof. */
@SIZEOF_TIME_T_CODE@
${SIZEOF_TIME_T_CODE}
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1
@ -933,15 +936,15 @@
/* if GnuTLS is enabled */
#cmakedefine USE_GNUTLS 1
/* if PolarSSL is enabled */
#cmakedefine USE_POLARSSL 1
/* if Secure Transport is enabled */
#cmakedefine USE_SECTRANSP 1
/* if mbedTLS is enabled */
#cmakedefine USE_MBEDTLS 1
/* if BearSSL is enabled */
#cmakedefine USE_BEARSSL 1
/* if libSSH2 is in use */
#cmakedefine USE_LIBSSH2 1
@ -951,6 +954,9 @@
/* if NSS is enabled */
#cmakedefine USE_NSS 1
/* if you have the PK11_CreateManagedGenericObject function */
#cmakedefine HAVE_PK11_CREATEMANAGEDGENERICOBJECT 1
/* if you want to use OpenLDAP code instead of legacy ldap implementation */
#cmakedefine USE_OPENLDAP 1

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2015, Steve Holme, <steve_holme@hotmail.com>.
* Copyright (C) 2015 - 2019, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2015, Steve Holme, <steve_holme@hotmail.com>.
* Copyright (C) 2015 - 2019, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms

View File

@ -81,6 +81,7 @@ unsigned short Curl_read16_be(const unsigned char *buf)
((unsigned short)buf[1]));
}
#if (CURL_SIZEOF_CURL_OFF_T > 4)
/*
* write32_le()
*
@ -100,7 +101,6 @@ static void write32_le(const int value, unsigned char *buffer)
buffer[3] = (char)((value & 0xFF000000) >> 24);
}
#if (CURL_SIZEOF_CURL_OFF_T > 4)
/*
* Curl_write64_le()
*

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -31,9 +31,6 @@ unsigned int Curl_read32_le(const unsigned char *buf);
/* Converts a 16-bit integer from big endian */
unsigned short Curl_read16_be(const unsigned char *buf);
/* Converts a 32-bit integer to little endian */
void Curl_write32_le(const int value, unsigned char *buffer);
#if (CURL_SIZEOF_CURL_OFF_T > 4)
/* Converts a 64-bit integer to little endian */
#if defined(HAVE_LONGLONG)

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -24,6 +24,8 @@
#ifndef CURL_DISABLE_CRYPTO_AUTH
#define HMAC_MD5_LENGTH 16
typedef void (* HMAC_hinit_func)(void *context);
typedef void (* HMAC_hupdate_func)(void *context,
const unsigned char *data,
@ -62,6 +64,11 @@ int Curl_HMAC_update(HMAC_context *context,
unsigned int len);
int Curl_HMAC_final(HMAC_context *context, unsigned char *result);
CURLcode Curl_hmacit(const HMAC_params *hashparams,
const unsigned char *key, const size_t keylen,
const unsigned char *data, const size_t datalen,
unsigned char *output);
#endif
#endif /* HEADER_CURL_HMAC_H */

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -24,14 +24,13 @@
#include "curl_setup.h"
#if defined(USE_NSS) || defined(USE_OS400CRYPTO) || \
(defined(USE_OPENSSL) && defined(OPENSSL_NO_MD4)) || \
(defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C))
#if !defined(CURL_DISABLE_CRYPTO_AUTH)
void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len);
#define MD4_DIGEST_LENGTH 16
#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) ||
(defined(USE_OPENSSL) && defined(OPENSSL_NO_MD4)) ||
(defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) */
void Curl_md4it(unsigned char *output, const unsigned char *input,
const size_t len);
#endif /* !defined(CURL_DISABLE_CRYPTO_AUTH) */
#endif /* HEADER_CURL_MD4_H */

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -49,8 +49,8 @@ typedef struct {
extern const MD5_params Curl_DIGEST_MD5[1];
extern const HMAC_params Curl_HMAC_MD5[1];
void Curl_md5it(unsigned char *output,
const unsigned char *input);
void Curl_md5it(unsigned char *output, const unsigned char *input,
const size_t len);
MD5_context * Curl_MD5_init(const MD5_params *md5params);
CURLcode Curl_MD5_update(MD5_context *context,

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -61,8 +61,13 @@ char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w);
#define Curl_convert_UTF8_to_tchar(ptr) Curl_convert_UTF8_to_wchar((ptr))
#define Curl_convert_tchar_to_UTF8(ptr) Curl_convert_wchar_to_UTF8((ptr))
#define Curl_unicodefree(ptr) \
do {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE
#define Curl_unicodefree(ptr) \
do { \
if(ptr) { \
free(ptr); \
(ptr) = NULL; \
} \
} while(0)
typedef union {
unsigned short *tchar_ptr;
@ -76,7 +81,7 @@ typedef union {
#define Curl_convert_UTF8_to_tchar(ptr) (ptr)
#define Curl_convert_tchar_to_UTF8(ptr) (ptr)
#define Curl_unicodefree(ptr) \
do {(ptr) = NULL;} WHILE_FALSE
do {(ptr) = NULL;} while(0)
typedef union {
char *tchar_ptr;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -55,11 +55,6 @@
#ifdef USE_OPENSSL
# include <openssl/des.h>
# ifndef OPENSSL_NO_MD4
# include <openssl/md4.h>
# else
# include "curl_md4.h"
# endif
# include <openssl/md5.h>
# include <openssl/ssl.h>
# include <openssl/rand.h>
@ -79,29 +74,23 @@
#elif defined(USE_GNUTLS_NETTLE)
# include <nettle/des.h>
# include <nettle/md4.h>
#elif defined(USE_GNUTLS)
# include <gcrypt.h>
# define MD5_DIGEST_LENGTH 16
# define MD4_DIGEST_LENGTH 16
#elif defined(USE_NSS)
# include <nss.h>
# include <pk11pub.h>
# include <hasht.h>
# include "curl_md4.h"
# define MD5_DIGEST_LENGTH MD5_LENGTH
#elif defined(USE_MBEDTLS)
# include <mbedtls/des.h>
# include <mbedtls/md4.h>
# if !defined(MBEDTLS_MD4_C)
# include "curl_md4.h"
# endif
# include "curl_md4.h"
#elif defined(USE_SECTRANSP)
@ -110,7 +99,6 @@
#elif defined(USE_OS400CRYPTO)
# include "cipher.mih" /* mih/cipher */
# include "curl_md4.h"
#elif defined(USE_WIN32_CRYPTO)
# include <wincrypt.h>
#else
@ -126,12 +114,12 @@
#include "warnless.h"
#include "curl_endian.h"
#include "curl_des.h"
#include "curl_md4.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
#define NTLM_HMAC_MD5_LEN (16)
#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00"
#define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4)
@ -218,7 +206,6 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
const unsigned char *key_56)
{
const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */
PK11SlotInfo *slot = NULL;
char key[8]; /* expanded 64 bit key */
SECItem key_item;
PK11SymKey *symkey = NULL;
@ -228,7 +215,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
bool rv = FALSE;
/* use internal slot for DES encryption (requires NSS to be initialized) */
slot = PK11_GetInternalKeySlot();
PK11SlotInfo *slot = PK11_GetInternalKeySlot();
if(!slot)
return FALSE;
@ -553,7 +540,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
CURLcode result;
if(len > SIZE_T_MAX/2) /* avoid integer overflow */
return CURLE_OUT_OF_MEMORY;
pw = len ? malloc(len * 2) : strdup("");
pw = len ? malloc(len * 2) : (unsigned char *)strdup("");
if(!pw)
return CURLE_OUT_OF_MEMORY;
@ -567,57 +554,10 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
if(result)
return result;
{
/* Create NT hashed password. */
#ifdef USE_OPENSSL
#if !defined(OPENSSL_NO_MD4)
MD4_CTX MD4pw;
MD4_Init(&MD4pw);
MD4_Update(&MD4pw, pw, 2 * len);
MD4_Final(ntbuffer, &MD4pw);
#else
Curl_md4it(ntbuffer, pw, 2 * len);
#endif
#elif defined(USE_GNUTLS_NETTLE)
struct md4_ctx MD4pw;
md4_init(&MD4pw);
md4_update(&MD4pw, (unsigned int)(2 * len), pw);
md4_digest(&MD4pw, MD4_DIGEST_SIZE, ntbuffer);
#elif defined(USE_GNUTLS)
gcry_md_hd_t MD4pw;
gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
gcry_md_write(MD4pw, pw, 2 * len);
memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH);
gcry_md_close(MD4pw);
#elif defined(USE_NSS)
Curl_md4it(ntbuffer, pw, 2 * len);
#elif defined(USE_MBEDTLS)
#if defined(MBEDTLS_MD4_C)
mbedtls_md4(pw, 2 * len, ntbuffer);
#else
Curl_md4it(ntbuffer, pw, 2 * len);
#endif
#elif defined(USE_SECTRANSP)
(void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer);
#elif defined(USE_OS400CRYPTO)
Curl_md4it(ntbuffer, pw, 2 * len);
#elif defined(USE_WIN32_CRYPTO)
HCRYPTPROV hprov;
if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
HCRYPTHASH hhash;
if(CryptCreateHash(hprov, CALG_MD4, 0, 0, &hhash)) {
DWORD length = 16;
CryptHashData(hhash, pw, (unsigned int)len * 2, 0);
CryptGetHashParam(hhash, HP_HASHVAL, ntbuffer, &length, 0);
CryptDestroyHash(hhash);
}
CryptReleaseContext(hprov, 0);
}
#endif
/* Create NT hashed password. */
Curl_md4it(ntbuffer, pw, 2 * len);
memset(ntbuffer + 16, 0, 21 - 16);
}
memset(ntbuffer + 16, 0, 21 - 16);
free(pw);
@ -626,25 +566,6 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
/* This returns the HMAC MD5 digest */
static CURLcode hmac_md5(const unsigned char *key, unsigned int keylen,
const unsigned char *data, unsigned int datalen,
unsigned char *output)
{
HMAC_context *ctxt = Curl_HMAC_init(Curl_HMAC_MD5, key, keylen);
if(!ctxt)
return CURLE_OUT_OF_MEMORY;
/* Update the digest with the given challenge */
Curl_HMAC_update(ctxt, data, datalen);
/* Finalise the digest */
Curl_HMAC_final(ctxt, output);
return CURLE_OK;
}
/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
* (uppercase UserName + Domain) as the data
*/
@ -674,8 +595,8 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
ascii_uppercase_to_unicode_le(identity, user, userlen);
ascii_to_unicode_le(identity + (userlen << 1), domain, domlen);
result = hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len),
ntlmv2hash);
result = Curl_hmacit(Curl_HMAC_MD5, ntlmhash, 16, identity, identity_len,
ntlmv2hash);
free(identity);
return result;
@ -721,7 +642,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
unsigned int len = 0;
unsigned char *ptr = NULL;
unsigned char hmac_output[NTLM_HMAC_MD5_LEN];
unsigned char hmac_output[HMAC_MD5_LENGTH];
curl_off_t tw;
CURLcode result = CURLE_OK;
@ -740,7 +661,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000;
/* Calculate the response len */
len = NTLM_HMAC_MD5_LEN + NTLMv2_BLOB_LEN;
len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN;
/* Allocate the response */
ptr = calloc(1, len);
@ -748,7 +669,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
return CURLE_OUT_OF_MEMORY;
/* Create the BLOB structure */
msnprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN,
msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN,
"%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */
"%c%c%c%c", /* Reserved = 0 */
NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
@ -761,7 +682,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
/* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */
memcpy(ptr + 8, &ntlm->nonce[0], 8);
result = hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8,
result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, HMAC_MD5_LENGTH, ptr + 8,
NTLMv2_BLOB_LEN + 8, hmac_output);
if(result) {
free(ptr);
@ -769,7 +690,7 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
}
/* Concatenate the HMAC MD5 output with the BLOB */
memcpy(ptr, hmac_output, NTLM_HMAC_MD5_LEN);
memcpy(ptr, hmac_output, HMAC_MD5_LENGTH);
/* Return the response */
*ntresp = ptr;
@ -804,7 +725,8 @@ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
memcpy(&data[0], challenge_server, 8);
memcpy(&data[8], challenge_client, 8);
result = hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output);
result = Curl_hmacit(Curl_HMAC_MD5, ntlmv2hash, 16, &data[0], 16,
hmac_output);
if(result)
return result;

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -46,9 +46,9 @@
#define USE_NTRESPONSES
/* Define USE_NTLM2SESSION in order to make the type-3 message include the
NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and a
Crypto engine that we have curl_ssl_md5sum() for. */
#if defined(USE_NTRESPONSES) && !defined(USE_WIN32_CRYPTO)
NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and
MD5 support */
#if defined(USE_NTRESPONSES) && !defined(CURL_DISABLE_CRYPTO_AUTH)
#define USE_NTLM2SESSION
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -76,22 +76,22 @@
# define sclose_nolog(x) close((x))
#endif
void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn)
static void ntlm_wb_cleanup(struct ntlmdata *ntlm)
{
if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
sclose(conn->ntlm_auth_hlpr_socket);
conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
sclose(ntlm->ntlm_auth_hlpr_socket);
ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
}
if(conn->ntlm_auth_hlpr_pid) {
if(ntlm->ntlm_auth_hlpr_pid) {
int i;
for(i = 0; i < 4; i++) {
pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG);
if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD)
pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG);
if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD)
break;
switch(i) {
case 0:
kill(conn->ntlm_auth_hlpr_pid, SIGTERM);
kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM);
break;
case 1:
/* Give the process another moment to shut down cleanly before
@ -99,22 +99,21 @@ void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn)
Curl_wait_ms(1);
break;
case 2:
kill(conn->ntlm_auth_hlpr_pid, SIGKILL);
kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL);
break;
case 3:
break;
}
}
conn->ntlm_auth_hlpr_pid = 0;
ntlm->ntlm_auth_hlpr_pid = 0;
}
free(conn->challenge_header);
conn->challenge_header = NULL;
free(conn->response_header);
conn->response_header = NULL;
Curl_safefree(ntlm->challenge);
Curl_safefree(ntlm->response);
}
static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm,
const char *userp)
{
curl_socket_t sockfds[2];
pid_t child_pid;
@ -128,9 +127,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
#endif
char buffer[STRERROR_LEN];
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) data;
#endif
/* Return if communication with ntlm_auth already set up */
if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
conn->ntlm_auth_hlpr_pid)
if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
ntlm->ntlm_auth_hlpr_pid)
return CURLE_OK;
username = userp;
@ -181,13 +184,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
ntlm_auth = NTLM_WB_FILE;
if(access(ntlm_auth, X_OK) != 0) {
failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s",
failf(data, "Could not access ntlm_auth: %s errno %d: %s",
ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
failf(conn->data, "Could not open socket pair. errno %d: %s",
if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
failf(data, "Could not open socket pair. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
@ -196,7 +199,7 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
if(child_pid == -1) {
sclose(sockfds[0]);
sclose(sockfds[1]);
failf(conn->data, "Could not fork. errno %d: %s",
failf(data, "Could not fork. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
goto done;
}
@ -208,13 +211,13 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
/* Don't use sclose in the child since it fools the socket leak detector */
sclose_nolog(sockfds[0]);
if(dup2(sockfds[1], STDIN_FILENO) == -1) {
failf(conn->data, "Could not redirect child stdin. errno %d: %s",
failf(data, "Could not redirect child stdin. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
failf(conn->data, "Could not redirect child stdout. errno %d: %s",
failf(data, "Could not redirect child stdout. errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
@ -234,14 +237,14 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
NULL);
sclose_nolog(sockfds[1]);
failf(conn->data, "Could not execl(). errno %d: %s",
failf(data, "Could not execl(). errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
exit(1);
}
sclose(sockfds[1]);
conn->ntlm_auth_hlpr_socket = sockfds[0];
conn->ntlm_auth_hlpr_pid = child_pid;
ntlm->ntlm_auth_hlpr_socket = sockfds[0];
ntlm->ntlm_auth_hlpr_pid = child_pid;
free(domain);
free(ntlm_auth_alloc);
return CURLE_OK;
@ -255,17 +258,21 @@ done:
/* if larger than this, something is seriously wrong */
#define MAX_NTLM_WB_RESPONSE 100000
static CURLcode ntlm_wb_response(struct connectdata *conn,
static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
const char *input, curlntlm state)
{
char *buf = malloc(NTLM_BUFSIZE);
size_t len_in = strlen(input), len_out = 0;
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) data;
#endif
if(!buf)
return CURLE_OUT_OF_MEMORY;
while(len_in > 0) {
ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in);
ssize_t written = swrite(ntlm->ntlm_auth_hlpr_socket, input, len_in);
if(written == -1) {
/* Interrupted by a signal, retry it */
if(errno == EINTR)
@ -281,7 +288,7 @@ static CURLcode ntlm_wb_response(struct connectdata *conn,
ssize_t size;
char *newbuf;
size = sread(conn->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE);
size = sread(ntlm->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE);
if(size == -1) {
if(errno == EINTR)
continue;
@ -297,7 +304,7 @@ static CURLcode ntlm_wb_response(struct connectdata *conn,
}
if(len_out > MAX_NTLM_WB_RESPONSE) {
failf(conn->data, "too large ntlm_wb response!");
failf(data, "too large ntlm_wb response!");
free(buf);
return CURLE_OUT_OF_MEMORY;
}
@ -325,9 +332,9 @@ static CURLcode ntlm_wb_response(struct connectdata *conn,
(buf[0]!='A' || buf[1]!='F' || buf[2]!=' '))
goto done;
conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3);
ntlm->response = aprintf("%.*s", len_out - 4, buf + 3);
free(buf);
if(!conn->response_header)
if(!ntlm->response)
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
done:
@ -339,6 +346,7 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
bool proxy,
const char *header)
{
struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
if(!checkprefix("NTLM", header))
@ -349,8 +357,8 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
header++;
if(*header) {
conn->challenge_header = strdup(header);
if(!conn->challenge_header)
ntlm->challenge = strdup(header);
if(!ntlm->challenge)
return CURLE_OUT_OF_MEMORY;
*state = NTLMSTATE_TYPE2; /* We got a type-2 message */
@ -389,11 +397,11 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
char **allocuserpwd;
/* point to the name and password for this */
const char *userp;
struct ntlmdata *ntlm;
curlntlm *state;
struct auth *authp;
CURLcode res = CURLE_OK;
char *input;
DEBUGASSERT(conn);
DEBUGASSERT(conn->data);
@ -401,12 +409,14 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
if(proxy) {
allocuserpwd = &conn->allocptr.proxyuserpwd;
userp = conn->http_proxy.user;
ntlm = &conn->proxyntlm;
state = &conn->proxy_ntlm_state;
authp = &conn->data->state.authproxy;
}
else {
allocuserpwd = &conn->allocptr.userpwd;
userp = conn->user;
ntlm = &conn->ntlm;
state = &conn->http_ntlm_state;
authp = &conn->data->state.authhost;
}
@ -432,38 +442,36 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
* request handling process.
*/
/* Create communication with ntlm_auth */
res = ntlm_wb_init(conn, userp);
res = ntlm_wb_init(conn->data, ntlm, userp);
if(res)
return res;
res = ntlm_wb_response(conn, "YR\n", *state);
res = ntlm_wb_response(conn->data, ntlm, "YR\n", *state);
if(res)
return res;
free(*allocuserpwd);
*allocuserpwd = aprintf("%sAuthorization: %s\r\n",
*allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
proxy ? "Proxy-" : "",
conn->response_header);
ntlm->response);
DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
free(conn->response_header);
Curl_safefree(ntlm->response);
if(!*allocuserpwd)
return CURLE_OUT_OF_MEMORY;
conn->response_header = NULL;
break;
case NTLMSTATE_TYPE2:
input = aprintf("TT %s\n", conn->challenge_header);
case NTLMSTATE_TYPE2: {
char *input = aprintf("TT %s\n", ntlm->challenge);
if(!input)
return CURLE_OUT_OF_MEMORY;
res = ntlm_wb_response(conn, input, *state);
res = ntlm_wb_response(conn->data, ntlm, input, *state);
free(input);
input = NULL;
if(res)
return res;
free(*allocuserpwd);
*allocuserpwd = aprintf("%sAuthorization: %s\r\n",
*allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
proxy ? "Proxy-" : "",
conn->response_header);
ntlm->response);
DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
*state = NTLMSTATE_TYPE3; /* we sent a type-3 */
authp->done = TRUE;
@ -471,7 +479,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
if(!*allocuserpwd)
return CURLE_OUT_OF_MEMORY;
break;
}
case NTLMSTATE_TYPE3:
/* connection is already authenticated,
* don't send a header in future requests */
@ -486,4 +494,10 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
return CURLE_OK;
}
void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn)
{
ntlm_wb_cleanup(&conn->ntlm);
ntlm_wb_cleanup(&conn->proxyntlm);
}
#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */

View File

@ -55,7 +55,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
}
if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
/* It is referenced to the home directory, so strip the leading '/~/' */
memcpy(real_path, working_path + 3, 4 + working_path_len-3);
memcpy(real_path, working_path + 3, working_path_len - 2);
else
memcpy(real_path, working_path, 1 + working_path_len);
}

View File

@ -199,13 +199,13 @@ static CURLcode rtmp_setup_connection(struct connectdata *conn)
RTMP_Free(r);
return CURLE_URL_MALFORMAT;
}
conn->proto.generic = r;
conn->proto.rtmp = r;
return CURLE_OK;
}
static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
{
RTMP *r = conn->proto.generic;
RTMP *r = conn->proto.rtmp;
SET_RCVTIMEO(tv, 10);
r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
@ -240,7 +240,7 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
static CURLcode rtmp_do(struct connectdata *conn, bool *done)
{
struct Curl_easy *data = conn->data;
RTMP *r = conn->proto.generic;
RTMP *r = conn->proto.rtmp;
if(!RTMP_ConnectStream(r, 0))
return CURLE_FAILED_INIT;
@ -268,10 +268,10 @@ static CURLcode rtmp_done(struct connectdata *conn, CURLcode status,
static CURLcode rtmp_disconnect(struct connectdata *conn,
bool dead_connection)
{
RTMP *r = conn->proto.generic;
RTMP *r = conn->proto.rtmp;
(void)dead_connection;
if(r) {
conn->proto.generic = NULL;
conn->proto.rtmp = NULL;
RTMP_Close(r);
RTMP_Free(r);
}
@ -281,7 +281,7 @@ static CURLcode rtmp_disconnect(struct connectdata *conn,
static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
size_t len, CURLcode *err)
{
RTMP *r = conn->proto.generic;
RTMP *r = conn->proto.rtmp;
ssize_t nread;
(void)sockindex; /* unused */
@ -302,7 +302,7 @@ static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
static ssize_t rtmp_send(struct connectdata *conn, int sockindex,
const void *buf, size_t len, CURLcode *err)
{
RTMP *r = conn->proto.generic;
RTMP *r = conn->proto.rtmp;
ssize_t num;
(void)sockindex; /* unused */

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com>
* Copyright (C) 2010 - 2019, Howard Chu, <hyc@highlandsun.com>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2012 - 2020, 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
@ -272,6 +272,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
data->set.str[STRING_SERVICE_NAME] :
sasl->params->service;
#endif
const char *oauth_bearer = data->set.str[STRING_BEARER];
sasl->force_ir = force_ir; /* Latch for future use */
sasl->authused = 0; /* No mechanism used yet */
@ -341,7 +342,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
}
else
#endif
if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) {
if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) {
mech = SASL_MECH_STRING_OAUTHBEARER;
state1 = SASL_OAUTH2;
state2 = SASL_OAUTH2_RESP;
@ -351,17 +352,17 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
result = Curl_auth_create_oauth_bearer_message(data, conn->user,
hostname,
port,
conn->oauth_bearer,
oauth_bearer,
&resp, &len);
}
else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) {
else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
mech = SASL_MECH_STRING_XOAUTH2;
state1 = SASL_OAUTH2;
sasl->authused = SASL_MECH_XOAUTH2;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
conn->oauth_bearer,
oauth_bearer,
&resp, &len);
}
else if(enabledmechs & SASL_MECH_PLAIN) {
@ -370,8 +371,9 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
sasl->authused = SASL_MECH_PLAIN;
if(force_ir || data->set.sasl_ir)
result = Curl_auth_create_plain_message(data, NULL, conn->user,
conn->passwd, &resp, &len);
result = Curl_auth_create_plain_message(data, conn->sasl_authzid,
conn->user, conn->passwd,
&resp, &len);
}
else if(enabledmechs & SASL_MECH_LOGIN) {
mech = SASL_MECH_STRING_LOGIN;
@ -430,6 +432,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
char *serverdata;
#endif
size_t len = 0;
const char *oauth_bearer = data->set.str[STRING_BEARER];
*progress = SASL_INPROGRESS;
@ -453,8 +456,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
*progress = SASL_DONE;
return result;
case SASL_PLAIN:
result = Curl_auth_create_plain_message(data, NULL, conn->user,
conn->passwd, &resp, &len);
result = Curl_auth_create_plain_message(data, conn->sasl_authzid,
conn->user, conn->passwd,
&resp, &len);
break;
case SASL_LOGIN:
result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
@ -556,7 +560,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
result = Curl_auth_create_oauth_bearer_message(data, conn->user,
hostname,
port,
conn->oauth_bearer,
oauth_bearer,
&resp, &len);
/* Failures maybe sent by the server as continuations for OAUTHBEARER */
@ -564,7 +568,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
}
else
result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
conn->oauth_bearer,
oauth_bearer,
&resp, &len);
break;

View File

@ -26,6 +26,14 @@
#define CURL_NO_OLDIES
#endif
/*
* Disable Visual Studio warnings:
* 4127 "conditional expression is constant"
*/
#ifdef _MSC_VER
#pragma warning(disable:4127)
#endif
/*
* Define WIN32 when build target is Win32 API
*/
@ -96,6 +104,10 @@
# include "config-vxworks.h"
#endif
#ifdef __PLAN9__
# include "config-plan9.h"
#endif
#endif /* HAVE_CONFIG_H */
#if defined(_MSC_VER)
@ -497,7 +509,6 @@
#ifdef WIN32
# define DIR_CHAR "\\"
# define DOT_CHAR "_"
#else /* WIN32 */
@ -523,14 +534,6 @@
# endif
# define DIR_CHAR "/"
# ifndef DOT_CHAR
# define DOT_CHAR "."
# endif
# ifdef MSDOS
# undef DOT_CHAR
# define DOT_CHAR "_"
# endif
# ifndef fileno /* sunos 4 have this as a macro! */
int fileno(FILE *stream);
@ -583,6 +586,12 @@
* Mutually exclusive CURLRES_* definitions.
*/
#if defined(ENABLE_IPV6) && defined(HAVE_GETADDRINFO)
# define CURLRES_IPV6
#else
# define CURLRES_IPV4
#endif
#ifdef USE_ARES
# define CURLRES_ASYNCH
# define CURLRES_ARES
@ -597,12 +606,6 @@
# define CURLRES_SYNCH
#endif
#ifdef ENABLE_IPV6
# define CURLRES_IPV6
#else
# define CURLRES_IPV4
#endif
/* ---------------------------------------------------------------- */
/*
@ -662,9 +665,10 @@ int netware_init(void);
#define LIBIDN_REQUIRED_VERSION "0.4.1"
#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
defined(USE_POLARSSL) || defined(USE_MBEDTLS) || \
defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK)
defined(USE_MBEDTLS) || \
defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) || \
defined(USE_BEARSSL)
#define USE_SSL /* SSL support has been enabled */
#endif
@ -733,7 +737,7 @@ int netware_init(void);
*/
#ifndef Curl_nop_stmt
# define Curl_nop_stmt do { } WHILE_FALSE
# define Curl_nop_stmt do { } while(0)
#endif
/*
@ -842,4 +846,8 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#define UNITTEST static
#endif
#if defined(USE_NGTCP2) || defined(USE_QUICHE)
#define ENABLE_QUIC
#endif
#endif /* HEADER_CURL_SETUP_H */

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -329,27 +329,6 @@ struct timeval {
#include "curl_ctype.h"
/*
* Macro WHILE_FALSE may be used to build single-iteration do-while loops,
* avoiding compiler warnings. Mostly intended for other macro definitions.
*/
#define WHILE_FALSE while(0)
#if defined(_MSC_VER) && !defined(__POCC__)
# undef WHILE_FALSE
# if (_MSC_VER < 1500)
# define WHILE_FALSE while(1, 0)
# else
# define WHILE_FALSE \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
while(0) \
__pragma(warning(pop))
# endif
#endif
/*
* Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type.
*/
@ -387,7 +366,7 @@ typedef int sig_atomic_t;
#ifdef DEBUGBUILD
#define DEBUGF(x) x
#else
#define DEBUGF(x) do { } WHILE_FALSE
#define DEBUGF(x) do { } while(0)
#endif
@ -395,10 +374,11 @@ typedef int sig_atomic_t;
* Macro used to include assertion code only in debug builds.
*/
#undef DEBUGASSERT
#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H)
#define DEBUGASSERT(x) assert(x)
#else
#define DEBUGASSERT(x) do { } WHILE_FALSE
#define DEBUGASSERT(x) do { } while(0)
#endif

View File

@ -7,7 +7,8 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2010, Florin Petriuc, <petriuc.florin@gmail.com>
* Copyright (C) 2017, Florin Petriuc, <petriuc.florin@gmail.com>
* Copyright (C) 2018 - 2020, 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
@ -24,8 +25,10 @@
#ifndef CURL_DISABLE_CRYPTO_AUTH
void Curl_sha256it(unsigned char *outbuffer,
const unsigned char *input);
#define SHA256_DIGEST_LENGTH 32
void Curl_sha256it(unsigned char *outbuffer, const unsigned char *input,
const size_t len);
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2018 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2018 - 2020, 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
@ -74,17 +74,50 @@ static const char *doh_strerror(DOHcode code)
#define UNITTEST static
#endif
/* @unittest 1655
*/
UNITTEST DOHcode doh_encode(const char *host,
DNStype dnstype,
unsigned char *dnsp, /* buffer */
size_t len, /* buffer size */
size_t *olen) /* output length */
{
size_t hostlen = strlen(host);
const size_t hostlen = strlen(host);
unsigned char *orig = dnsp;
const char *hostp = host;
if(len < (12 + hostlen + 4))
/* The expected output length is 16 bytes more than the length of
* the QNAME-encoding of the host name.
*
* A valid DNS name may not contain a zero-length label, except at
* the end. For this reason, a name beginning with a dot, or
* containing a sequence of two or more consecutive dots, is invalid
* and cannot be encoded as a QNAME.
*
* If the host name ends with a trailing dot, the corresponding
* QNAME-encoding is one byte longer than the host name. If (as is
* also valid) the hostname is shortened by the omission of the
* trailing dot, then its QNAME-encoding will be two bytes longer
* than the host name.
*
* Each [ label, dot ] pair is encoded as [ length, label ],
* preserving overall length. A final [ label ] without a dot is
* also encoded as [ length, label ], increasing overall length
* by one. The encoding is completed by appending a zero byte,
* representing the zero-length root label, again increasing
* the overall length by one.
*/
size_t expected_len;
DEBUGASSERT(hostlen);
expected_len = 12 + 1 + hostlen + 4;
if(host[hostlen-1]!='.')
expected_len++;
if(expected_len > (256 + 16)) /* RFCs 1034, 1035 */
return DOH_DNS_NAME_TOO_LONG;
if(len < expected_len)
return DOH_TOO_SMALL_BUFFER;
*dnsp++ = 0; /* 16 bit id */
@ -100,38 +133,43 @@ UNITTEST DOHcode doh_encode(const char *host,
*dnsp++ = '\0';
*dnsp++ = '\0'; /* ARCOUNT */
/* store a QNAME */
do {
char *dot = strchr(hostp, '.');
/* encode each label and store it in the QNAME */
while(*hostp) {
size_t labellen;
bool found = false;
if(dot) {
found = true;
char *dot = strchr(hostp, '.');
if(dot)
labellen = dot - hostp;
}
else
labellen = strlen(hostp);
if(labellen > 63) {
/* too long label, error out */
if((labellen > 63) || (!labellen)) {
/* label is too long or too short, error out */
*olen = 0;
return DOH_DNS_BAD_LABEL;
}
/* label is non-empty, process it */
*dnsp++ = (unsigned char)labellen;
memcpy(dnsp, hostp, labellen);
dnsp += labellen;
hostp += labellen + 1;
if(!found) {
*dnsp++ = 0; /* terminating zero */
break;
}
} while(1);
hostp += labellen;
/* advance past dot, but only if there is one */
if(dot)
hostp++;
} /* next label */
*dnsp++ = 0; /* append zero-length label for root */
/* There are assigned TYPE codes beyond 255: use range [1..65535] */
*dnsp++ = (unsigned char)(255 & (dnstype>>8)); /* upper 8 bit TYPE */
*dnsp++ = (unsigned char)(255 & dnstype); /* lower 8 bit TYPE */
*dnsp++ = '\0'; /* upper 8 bit TYPE */
*dnsp++ = (unsigned char)dnstype;
*dnsp++ = '\0'; /* upper 8 bit CLASS */
*dnsp++ = DNS_CLASS_IN; /* IN - "the Internet" */
*olen = dnsp - orig;
/* verify that our estimation of length is valid, since
* this has led to buffer overflows in this function */
DEBUGASSERT(*olen == expected_len);
return DOH_OK;
}
@ -180,7 +218,7 @@ do { \
result = curl_easy_setopt(doh, x, y); \
if(result) \
goto error; \
} WHILE_FALSE
} while(0)
static CURLcode dohprobe(struct Curl_easy *data,
struct dnsprobe *p, DNStype dnstype,
@ -225,7 +263,10 @@ static CURLcode dohprobe(struct Curl_easy *data,
}
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms <= 0) {
result = CURLE_OPERATION_TIMEDOUT;
goto error;
}
/* Curl_open() is the internal version of curl_easy_init() */
result = Curl_open(&doh);
if(!result) {
@ -246,6 +287,9 @@ static CURLcode dohprobe(struct Curl_easy *data,
#ifndef CURLDEBUG
/* enforce HTTPS if not debug */
ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
#else
/* in debug mode, also allow http */
ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
#endif
ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
if(data->set.verbose)
@ -259,38 +303,42 @@ static CURLcode dohprobe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
if(data->set.ssl.primary.verifyhost)
ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST, 2L);
#ifndef CURL_DISABLE_PROXY
if(data->set.proxy_ssl.primary.verifyhost)
ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYHOST, 2L);
if(data->set.ssl.primary.verifypeer)
ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER, 1L);
if(data->set.proxy_ssl.primary.verifypeer)
ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
if(data->set.str[STRING_SSL_CAFILE_PROXY]) {
ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAINFO,
data->set.str[STRING_SSL_CAFILE_PROXY]);
}
if(data->set.str[STRING_SSL_CRLFILE_PROXY]) {
ERROR_CHECK_SETOPT(CURLOPT_PROXY_CRLFILE,
data->set.str[STRING_SSL_CRLFILE_PROXY]);
}
if(data->set.proxy_ssl.no_revoke)
ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
if(data->set.str[STRING_SSL_CAPATH_PROXY]) {
ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAPATH,
data->set.str[STRING_SSL_CAPATH_PROXY]);
}
#endif
if(data->set.ssl.primary.verifypeer)
ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER, 1L);
if(data->set.ssl.primary.verifystatus)
ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS, 1L);
if(data->set.str[STRING_SSL_CAFILE_ORIG]) {
ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
data->set.str[STRING_SSL_CAFILE_ORIG]);
}
if(data->set.str[STRING_SSL_CAFILE_PROXY]) {
ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAINFO,
data->set.str[STRING_SSL_CAFILE_PROXY]);
}
if(data->set.str[STRING_SSL_CAPATH_ORIG]) {
ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
data->set.str[STRING_SSL_CAPATH_ORIG]);
}
if(data->set.str[STRING_SSL_CAPATH_PROXY]) {
ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAPATH,
data->set.str[STRING_SSL_CAPATH_PROXY]);
}
if(data->set.str[STRING_SSL_CRLFILE_ORIG]) {
ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
data->set.str[STRING_SSL_CRLFILE_ORIG]);
}
if(data->set.str[STRING_SSL_CRLFILE_PROXY]) {
ERROR_CHECK_SETOPT(CURLOPT_PROXY_CRLFILE,
data->set.str[STRING_SSL_CRLFILE_PROXY]);
}
if(data->set.ssl.certinfo)
ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
if(data->set.str[STRING_SSL_RANDOM_FILE]) {
@ -303,8 +351,6 @@ static CURLcode dohprobe(struct Curl_easy *data,
}
if(data->set.ssl.no_revoke)
ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
if(data->set.proxy_ssl.no_revoke)
ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
if(data->set.ssl.fsslctx)
ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
if(data->set.ssl.fsslctxp)
@ -325,7 +371,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
error:
free(nurl);
Curl_close(doh);
Curl_close(&doh);
return result;
}
@ -341,6 +387,7 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn,
{
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
int slot;
*waitp = TRUE; /* this never returns synchronously */
(void)conn;
(void)hostname;
@ -359,8 +406,8 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn,
if(conn->ip_version != CURL_IPRESOLVE_V6) {
/* create IPv4 DOH request */
result = dohprobe(data, &data->req.doh.probe[0], DNS_TYPE_A,
hostname, data->set.str[STRING_DOH],
result = dohprobe(data, &data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V4],
DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
data->multi, data->req.doh.headers);
if(result)
goto error;
@ -369,8 +416,8 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn,
if(conn->ip_version != CURL_IPRESOLVE_V4) {
/* create IPv6 DOH request */
result = dohprobe(data, &data->req.doh.probe[1], DNS_TYPE_AAAA,
hostname, data->set.str[STRING_DOH],
result = dohprobe(data, &data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V6],
DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
data->multi, data->req.doh.headers);
if(result)
goto error;
@ -381,10 +428,9 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn,
error:
curl_slist_free_all(data->req.doh.headers);
data->req.doh.headers = NULL;
curl_easy_cleanup(data->req.doh.probe[0].easy);
data->req.doh.probe[0].easy = NULL;
curl_easy_cleanup(data->req.doh.probe[1].easy);
data->req.doh.probe[1].easy = NULL;
for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
Curl_close(&data->req.doh.probe[slot].easy);
}
return NULL;
}
@ -419,8 +465,14 @@ static unsigned short get16bit(unsigned char *doh, int index)
static unsigned int get32bit(unsigned char *doh, int index)
{
return (doh[index] << 24) | (doh[index + 1] << 16) |
(doh[index + 2] << 8) | doh[index + 3];
/* make clang and gcc optimize this to bswap by incrementing
the pointer first. */
doh += index;
/* avoid undefined behaviour by casting to unsigned before shifting
24 bits, possibly into the sign bit. codegen is same, but
ub sanitizer won't be upset */
return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3];
}
static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d)
@ -496,7 +548,7 @@ static DOHcode store_cname(unsigned char *doh,
if((index + 1) >= dohlen)
return DOH_DNS_OUT_OF_RANGE;
/* move to the the new index */
/* move to the new index */
newpos = (length & 0x3f) << 8 | doh[index + 1];
index = newpos;
continue;
@ -561,6 +613,9 @@ static DOHcode rdata(unsigned char *doh,
if(rc)
return rc;
break;
case DNS_TYPE_DNAME:
/* explicit for clarity; just skip; rely on synthesized CNAME */
break;
default:
/* unsupported type, just skip it */
break;
@ -622,8 +677,10 @@ UNITTEST DOHcode doh_decode(unsigned char *doh,
return DOH_DNS_OUT_OF_RANGE;
type = get16bit(doh, index);
if((type != DNS_TYPE_CNAME) && (type != dnstype))
/* Not the same type as was asked for nor CNAME */
if((type != DNS_TYPE_CNAME) /* may be synthesized from DNAME */
&& (type != DNS_TYPE_DNAME) /* if present, accept and ignore */
&& (type != dnstype))
/* Not the same type as was asked for nor CNAME nor DNAME */
return DOH_DNS_UNEXPECTED_TYPE;
index += 2;
@ -884,47 +941,43 @@ UNITTEST void de_cleanup(struct dohentry *d)
CURLcode Curl_doh_is_resolved(struct connectdata *conn,
struct Curl_dns_entry **dnsp)
{
CURLcode result;
struct Curl_easy *data = conn->data;
*dnsp = NULL; /* defaults to no response */
if(!data->req.doh.probe[0].easy && !data->req.doh.probe[1].easy) {
if(!data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
!data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
failf(data, "Could not DOH-resolve: %s", conn->async.hostname);
return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
else if(!data->req.doh.pending) {
DOHcode rc;
DOHcode rc2;
DOHcode rc[DOH_PROBE_SLOTS];
struct dohentry de;
int slot;
/* remove DOH handles from multi handle and close them */
curl_multi_remove_handle(data->multi, data->req.doh.probe[0].easy);
Curl_close(data->req.doh.probe[0].easy);
curl_multi_remove_handle(data->multi, data->req.doh.probe[1].easy);
Curl_close(data->req.doh.probe[1].easy);
for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
curl_multi_remove_handle(data->multi, data->req.doh.probe[slot].easy);
Curl_close(&data->req.doh.probe[slot].easy);
}
/* parse the responses, create the struct and return it! */
init_dohentry(&de);
rc = doh_decode(data->req.doh.probe[0].serverdoh.memory,
data->req.doh.probe[0].serverdoh.size,
data->req.doh.probe[0].dnstype,
&de);
free(data->req.doh.probe[0].serverdoh.memory);
if(rc) {
infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc),
type2name(data->req.doh.probe[0].dnstype),
data->req.doh.host);
}
rc2 = doh_decode(data->req.doh.probe[1].serverdoh.memory,
data->req.doh.probe[1].serverdoh.size,
data->req.doh.probe[1].dnstype,
&de);
free(data->req.doh.probe[1].serverdoh.memory);
if(rc2) {
infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc2),
type2name(data->req.doh.probe[1].dnstype),
data->req.doh.host);
}
if(!rc || !rc2) {
for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
rc[slot] = doh_decode(data->req.doh.probe[slot].serverdoh.memory,
data->req.doh.probe[slot].serverdoh.size,
data->req.doh.probe[slot].dnstype,
&de);
Curl_safefree(data->req.doh.probe[slot].serverdoh.memory);
if(rc[slot]) {
infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]),
type2name(data->req.doh.probe[slot].dnstype),
data->req.doh.host);
}
} /* next slot */
result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */
if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) {
/* we have an address, of one kind or other */
struct Curl_dns_entry *dns;
struct Curl_addrinfo *ai;
@ -946,21 +999,26 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
de_cleanup(&de);
if(!dns)
if(!dns) {
/* returned failure, bail out nicely */
Curl_freeaddrinfo(ai);
}
else {
conn->async.dns = dns;
*dnsp = dns;
return CURLE_OK;
result = CURLE_OK; /* address resolution OK */
}
}
} /* address processing done */
/* Now process any build-specific attributes retrieved from DNS */
/* All done */
de_cleanup(&de);
return result;
return CURLE_COULDNT_RESOLVE_HOST;
}
} /* !data->req.doh.pending */
/* else wait for pending DOH transactions to complete */
return CURLE_OK;
}

View File

@ -40,8 +40,7 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn,
CURLcode Curl_doh_is_resolved(struct connectdata *conn,
struct Curl_dns_entry **dns);
int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks,
int numsocks);
int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks);
typedef enum {
DOH_OK,
@ -56,14 +55,16 @@ typedef enum {
DOH_DNS_UNEXPECTED_TYPE, /* 9 */
DOH_DNS_UNEXPECTED_CLASS, /* 10 */
DOH_NO_CONTENT, /* 11 */
DOH_DNS_BAD_ID /* 12 */
DOH_DNS_BAD_ID, /* 12 */
DOH_DNS_NAME_TOO_LONG /* 13 */
} DOHcode;
typedef enum {
DNS_TYPE_A = 1,
DNS_TYPE_NS = 2,
DNS_TYPE_CNAME = 5,
DNS_TYPE_AAAA = 28
DNS_TYPE_AAAA = 28,
DNS_TYPE_DNAME = 39 /* RFC6672 */
} DNStype;
#define DOH_MAX_ADDR 24

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -72,10 +72,11 @@
#include "warnless.h"
#include "multiif.h"
#include "sigpipe.h"
#include "ssh.h"
#include "vssh/ssh.h"
#include "setopt.h"
#include "http_digest.h"
#include "system_win32.h"
#include "http2.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -157,20 +158,20 @@ static CURLcode global_init(long flags, bool memoryfuncs)
if(!Curl_ssl_init()) {
DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
return CURLE_FAILED_INIT;
goto fail;
}
#ifdef WIN32
if(Curl_win32_init(flags)) {
DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
return CURLE_FAILED_INIT;
goto fail;
}
#endif
#ifdef __AMIGA__
if(!Curl_amiga_init()) {
DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
return CURLE_FAILED_INIT;
goto fail;
}
#endif
@ -182,33 +183,31 @@ static CURLcode global_init(long flags, bool memoryfuncs)
if(Curl_resolver_global_init()) {
DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
return CURLE_FAILED_INIT;
goto fail;
}
(void)Curl_ipv6works();
#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT)
if(libssh2_init(0)) {
DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
return CURLE_FAILED_INIT;
#if defined(USE_SSH)
if(Curl_ssh_init()) {
goto fail;
}
#endif
#if defined(USE_LIBSSH)
if(ssh_init()) {
DEBUGF(fprintf(stderr, "Error: libssh_init failed\n"));
#ifdef USE_WOLFSSH
if(WS_SUCCESS != wolfSSH_Init()) {
DEBUGF(fprintf(stderr, "Error: wolfSSH_Init failed\n"));
return CURLE_FAILED_INIT;
}
#endif
if(flags & CURL_GLOBAL_ACK_EINTR)
Curl_ack_eintr = 1;
init_flags = flags;
Curl_version_init();
return CURLE_OK;
fail:
initialized--; /* undo the increase */
return CURLE_FAILED_INIT;
}
@ -274,12 +273,10 @@ void curl_global_cleanup(void)
Curl_amiga_cleanup();
#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT)
(void)libssh2_exit();
#endif
Curl_ssh_cleanup();
#if defined(USE_LIBSSH)
(void)ssh_finalize();
#ifdef USE_WOLFSSH
(void)wolfSSH_Cleanup();
#endif
init_flags = 0;
@ -602,27 +599,11 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
while(!done && !mcode) {
int still_running = 0;
bool gotsocket = FALSE;
mcode = Curl_multi_wait(multi, NULL, 0, 1000, NULL, &gotsocket);
if(!mcode) {
if(!gotsocket) {
long sleep_ms;
/* If it returns without any filedescriptor instantly, we need to
avoid busy-looping during periods where it has nothing particular
to wait for */
curl_multi_timeout(multi, &sleep_ms);
if(sleep_ms) {
if(sleep_ms > 1000)
sleep_ms = 1000;
Curl_wait_ms((int)sleep_ms);
}
}
mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
if(!mcode)
mcode = curl_multi_perform(multi, &still_running);
}
/* only read 'still_running' if curl_multi_perform() return OK */
if(!mcode && !still_running) {
@ -710,10 +691,6 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
sigpipe_ignore(data, &pipe_st);
/* assign this after curl_multi_add_handle() since that function checks for
it and rejects this handle otherwise */
data->multi = multi;
/* run the transfer */
result = events ? easy_events(multi) : easy_transfer(multi);
@ -761,7 +738,7 @@ void curl_easy_cleanup(struct Curl_easy *data)
return;
sigpipe_ignore(data, &pipe_st);
Curl_close(data);
Curl_close(&data);
sigpipe_restore(&pipe_st);
}
@ -942,6 +919,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
*/
void curl_easy_reset(struct Curl_easy *data)
{
long old_buffer_size = data->set.buffer_size;
Curl_free_request_state(data);
/* zero out UserDefined data: */
@ -965,6 +944,18 @@ void curl_easy_reset(struct Curl_easy *data)
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
Curl_http_auth_cleanup_digest(data);
#endif
/* resize receive buffer */
if(old_buffer_size != data->set.buffer_size) {
char *newbuff = realloc(data->state.buffer, data->set.buffer_size + 1);
if(!newbuff) {
DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
/* nothing we can do here except use the old size */
data->set.buffer_size = old_buffer_size;
}
else
data->state.buffer = newbuff;
}
}
/*
@ -995,55 +986,63 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
/* put it back in the keepon */
k->keepon = newstate;
if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempcount) {
/* there are buffers for sending that can be delivered as the receive
pausing is lifted! */
unsigned int i;
unsigned int count = data->state.tempcount;
struct tempbuf writebuf[3]; /* there can only be three */
struct connectdata *conn = data->conn;
struct Curl_easy *saved_data = NULL;
if(!(newstate & KEEP_RECV_PAUSE)) {
Curl_http2_stream_pause(data, FALSE);
/* copy the structs to allow for immediate re-pausing */
for(i = 0; i < data->state.tempcount; i++) {
writebuf[i] = data->state.tempwrite[i];
data->state.tempwrite[i].buf = NULL;
if(data->state.tempcount) {
/* there are buffers for sending that can be delivered as the receive
pausing is lifted! */
unsigned int i;
unsigned int count = data->state.tempcount;
struct tempbuf writebuf[3]; /* there can only be three */
struct connectdata *conn = data->conn;
struct Curl_easy *saved_data = NULL;
/* copy the structs to allow for immediate re-pausing */
for(i = 0; i < data->state.tempcount; i++) {
writebuf[i] = data->state.tempwrite[i];
data->state.tempwrite[i].buf = NULL;
}
data->state.tempcount = 0;
/* set the connection's current owner */
if(conn->data != data) {
saved_data = conn->data;
conn->data = data;
}
for(i = 0; i < count; i++) {
/* even if one function returns error, this loops through and frees
all buffers */
if(!result)
result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf,
writebuf[i].len);
free(writebuf[i].buf);
}
/* recover previous owner of the connection */
if(saved_data)
conn->data = saved_data;
if(result)
return result;
}
data->state.tempcount = 0;
/* set the connection's current owner */
if(conn->data != data) {
saved_data = conn->data;
conn->data = data;
}
for(i = 0; i < count; i++) {
/* even if one function returns error, this loops through and frees all
buffers */
if(!result)
result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf,
writebuf[i].len);
free(writebuf[i].buf);
}
/* recover previous owner of the connection */
if(saved_data)
conn->data = saved_data;
if(result)
return result;
}
/* if there's no error and we're not pausing both directions, we want
to have this handle checked soon */
if(!result &&
((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) )
if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
data->state.drain++;
Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
if(data->multi)
Curl_update_timer(data->multi);
}
/* This transfer may have been moved in or out of the bundle, update
the corresponding socket callback, if used */
Curl_updatesocket(data);
if(!data->state.done)
/* This transfer may have been moved in or out of the bundle, update the
corresponding socket callback, if used */
Curl_updatesocket(data);
return result;
}
@ -1137,6 +1136,35 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
return result;
}
/*
* Wrapper to call functions in Curl_conncache_foreach()
*
* Returns always 0.
*/
static int conn_upkeep(struct connectdata *conn,
void *param)
{
/* Param is unused. */
(void)param;
if(conn->handler->connection_check) {
/* Do a protocol-specific keepalive check on the connection. */
conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE);
}
return 0; /* continue iteration */
}
static CURLcode upkeep(struct conncache *conn_cache, void *data)
{
/* Loop over every connection and make connection alive. */
Curl_conncache_foreach(data,
conn_cache,
data,
conn_upkeep);
return CURLE_OK;
}
/*
* Performs connection upkeep for the given session handle.
*/
@ -1148,7 +1176,7 @@ CURLcode curl_easy_upkeep(struct Curl_easy *data)
if(data->multi_easy) {
/* Use the common function to keep connections alive. */
return Curl_upkeep(&data->multi_easy->conn_cache, data);
return upkeep(&data->multi_easy->conn_cache, data);
}
else {
/* No connections, so just return success */

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -136,7 +136,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
struct Curl_easy *data = conn->data;
char *real_path;
struct FILEPROTO *file = data->req.protop;
int fd;
int fd = -1;
#ifdef DOS_FILESYSTEM
size_t i;
char *actual_path;
@ -181,7 +181,9 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
return CURLE_URL_MALFORMAT;
}
fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
if(strncmp("\\\\", actual_path, 2))
/* refuse to open path that starts with two backslashes */
fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
file->path = actual_path;
#else
if(memchr(real_path, 0, real_path_len)) {

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -55,7 +55,6 @@
#include "transfer.h"
#include "escape.h"
#include "http.h" /* for HTTP proxy tunnel stuff */
#include "socks.h"
#include "ftp.h"
#include "fileinfo.h"
#include "ftplistparser.h"
@ -78,6 +77,7 @@
#include "warnless.h"
#include "http_proxy.h"
#include "non-ascii.h"
#include "socks.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@ -132,10 +132,8 @@ static CURLcode ftp_connect(struct connectdata *conn, bool *done);
static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
int numsocks);
static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
int numsocks);
static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks);
static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks);
static CURLcode ftp_doing(struct connectdata *conn,
bool *dophase_done);
static CURLcode ftp_setup_connection(struct connectdata * conn);
@ -255,18 +253,6 @@ static void freedirs(struct ftp_conn *ftpc)
Curl_safefree(ftpc->newhost);
}
/* Returns non-zero if the given string contains CR (\r) or LF (\n),
which are not allowed within RFC 959 <string>.
Note: The input string is in the client's encoding which might
not be ASCII, so escape sequences \r & \n must be used instead
of hex values 0x0d & 0x0a.
*/
static bool isBadFtpString(const char *string)
{
return ((NULL != strchr(string, '\r')) ||
(NULL != strchr(string, '\n'))) ? TRUE : FALSE;
}
/***********************************************************************
*
* AcceptServerConnect()
@ -305,7 +291,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
conn->sock[SECONDARYSOCKET] = s;
(void)curlx_nonblock(s, TRUE); /* enable non-blocking */
conn->sock_accepted[SECONDARYSOCKET] = TRUE;
conn->sock_accepted = TRUE;
if(data->set.fsockopt) {
int error = 0;
@ -382,7 +368,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
int result;
time_t timeout_ms;
timediff_t timeout_ms;
ssize_t nread;
int ftpcode;
@ -493,7 +479,7 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
{
struct Curl_easy *data = conn->data;
time_t timeout_ms;
timediff_t timeout_ms;
CURLcode result = CURLE_OK;
*connected = FALSE;
@ -525,7 +511,7 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
}
else {
/* Add timeout to multi handle and break out of the loop */
if(!result && *connected == FALSE) {
if(*connected == FALSE) {
Curl_expire(data, data->set.accepttimeout > 0 ?
data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0);
}
@ -565,10 +551,8 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
#ifdef HAVE_GSSAPI
char * const buf = data->state.buffer;
#endif
CURLcode result = CURLE_OK;
int code;
result = Curl_pp_readresp(sockfd, pp, &code, size);
CURLcode result = Curl_pp_readresp(sockfd, pp, &code, size);
#if defined(HAVE_GSSAPI)
/* handle the security-oriented responses 6xx ***/
@ -789,9 +773,8 @@ static void _state(struct connectdata *conn,
static CURLcode ftp_state_user(struct connectdata *conn)
{
CURLcode result;
struct FTP *ftp = conn->data->req.protop;
/* send USER */
PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
PPSENDF(&conn->proto.ftpc.pp, "USER %s", conn->user?conn->user:"");
state(conn, FTP_USER);
conn->data->state.ftp_trying_alternative = FALSE;
@ -812,26 +795,24 @@ static CURLcode ftp_state_pwd(struct connectdata *conn)
/* For the FTP "protocol connect" and "doing" phases only */
static int ftp_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
curl_socket_t *socks)
{
return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
return Curl_pp_getsock(&conn->proto.ftpc.pp, socks);
}
/* For the FTP "DO_MORE" phase only */
static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
int numsocks)
static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks)
{
struct ftp_conn *ftpc = &conn->proto.ftpc;
if(!numsocks)
return GETSOCK_BLANK;
/* When in DO_MORE state, we could be either waiting for us to connect to a
* remote site, or we could wait for that site to connect to us. Or just
* handle ordinary commands.
*/
if(SOCKS_STATE(conn->cnnct.state))
return Curl_SOCKS_getsock(conn, socks, SECONDARYSOCKET);
if(FTP_STOP == ftpc->state) {
int bits = GETSOCK_READSOCK(0);
@ -858,7 +839,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
return bits;
}
return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
return Curl_pp_getsock(&conn->proto.ftpc.pp, socks);
}
/* This is called after the FTP_QUOTE state is passed.
@ -876,6 +857,10 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
/* already done and fine */
result = ftp_state_mdtm(conn);
else {
/* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */
DEBUGASSERT((conn->data->set.ftp_filemethod != FTPFILE_NOCWD) ||
!(ftpc->dirdepth && ftpc->dirs[0][0] == '/'));
ftpc->count2 = 0; /* count2 counts failed CWDs */
/* count3 is set to allow a MKD to fail once. In the case when first CWD
@ -883,10 +868,9 @@ static CURLcode ftp_state_cwd(struct connectdata *conn)
dir) this then allows for a second try to CWD to it */
ftpc->count3 = (conn->data->set.ftp_create_missing_dirs == 2)?1:0;
if((conn->data->set.ftp_filemethod == FTPFILE_NOCWD) && !ftpc->cwdcount)
/* No CWD necessary */
result = ftp_state_mdtm(conn);
else if(conn->bits.reuse && ftpc->entrypath) {
if(conn->bits.reuse && ftpc->entrypath &&
/* no need to go to entrypath when we have an absolute path */
!(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
/* This is a re-used connection. Since we change directory to where the
transfer is taking place, we must first get back to the original dir
where we ended up after login: */
@ -926,7 +910,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct Curl_easy *data = conn->data;
curl_socket_t portsock = CURL_SOCKET_BAD;
char myhost[256] = "";
char myhost[MAX_IPADR_LEN + 1] = "";
struct Curl_sockaddr_storage ss;
Curl_addrinfo *res, *ai;
@ -937,9 +921,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
#ifdef ENABLE_IPV6
struct sockaddr_in6 * const sa6 = (void *)sa;
#endif
char tmp[1024];
static const char mode[][5] = { "EPRT", "PORT" };
int rc;
enum resolve_t rc;
int error;
char *host = NULL;
char *string_ftpport = data->set.str[STRING_FTPPORT];
@ -1252,8 +1235,10 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
break;
}
if(PORT == fcmd) {
/* large enough for [IP address],[num],[num] */
char target[sizeof(myhost) + 20];
char *source = myhost;
char *dest = tmp;
char *dest = target;
/* translate x.x.x.x to x,x,x,x */
while(source && *source) {
@ -1267,7 +1252,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
*dest = 0;
msnprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], target);
if(result) {
failf(data, "Failure sending PORT command: %s",
curl_easy_strerror(result));
@ -1445,31 +1430,37 @@ static CURLcode ftp_state_list(struct connectdata *conn)
servers either... */
/*
if FTPFILE_NOCWD was specified, we are currently in
the user's home directory, so we should add the path
if FTPFILE_NOCWD was specified, we should add the path
as argument for the LIST / NLST / or custom command.
Whether the server will support this, is uncertain.
The other ftp_filemethods will CWD into dir/dir/ first and
then just do LIST (in that case: nothing to do here)
*/
char *cmd, *lstArg, *slashPos;
const char *inpath = ftp->path;
char *lstArg = NULL;
char *cmd;
lstArg = NULL;
if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
inpath && inpath[0] && strchr(inpath, '/')) {
size_t n = strlen(inpath);
/* Check if path does not end with /, as then we cut off the file part */
if(inpath[n - 1] != '/') {
/* chop off the file part if format is dir/dir/file */
slashPos = strrchr(inpath, '/');
n = slashPos - inpath;
}
result = Curl_urldecode(data, inpath, n, &lstArg, NULL, TRUE);
if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) {
/* url-decode before evaluation: e.g. paths starting/ending with %2f */
const char *slashPos = NULL;
char *rawPath = NULL;
result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, TRUE);
if(result)
return result;
slashPos = strrchr(rawPath, '/');
if(slashPos) {
/* chop off the file part if format is dir/file otherwise remove
the trailing slash for dir/dir/ except for absolute path / */
size_t n = slashPos - rawPath;
if(n == 0)
++n;
lstArg = rawPath;
lstArg[n] = '\0';
}
else
free(rawPath);
}
cmd = aprintf("%s%s%s",
@ -1478,15 +1469,12 @@ static CURLcode ftp_state_list(struct connectdata *conn)
(data->set.ftp_list_only?"NLST":"LIST"),
lstArg? " ": "",
lstArg? lstArg: "");
free(lstArg);
if(!cmd) {
free(lstArg);
if(!cmd)
return CURLE_OUT_OF_MEMORY;
}
result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
free(lstArg);
free(cmd);
if(result)
@ -1499,24 +1487,14 @@ static CURLcode ftp_state_list(struct connectdata *conn)
static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
/* We've sent the TYPE, now we must send the list of prequote strings */
result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
return result;
return ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
}
static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
/* We've sent the TYPE, now we must send the list of prequote strings */
result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
return result;
return ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
}
static CURLcode ftp_state_type(struct connectdata *conn)
@ -1819,7 +1797,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
CURLcode result;
struct Curl_easy *data = conn->data;
struct Curl_dns_entry *addr = NULL;
int rc;
enum resolve_t rc;
unsigned short connectport; /* the local port connect() should use! */
char *str = &data->state.buffer[4]; /* start on the first letter */
@ -2052,13 +2030,11 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
&year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
char timebuf[24];
time_t secs = time(NULL);
msnprintf(timebuf, sizeof(timebuf),
"%04d%02d%02d %02d:%02d:%02d GMT",
year, month, day, hour, minute, second);
/* now, convert this into a time() value: */
data->info.filetime = curl_getdate(timebuf, &secs);
data->info.filetime = Curl_getdate_capped(timebuf);
}
#ifdef CURL_FTP_HTTPSTYLE_HEAD
@ -2261,9 +2237,25 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
char *buf = data->state.buffer;
/* get the size from the ascii string: */
if(ftpcode == 213)
if(ftpcode == 213) {
/* To allow servers to prepend "rubbish" in the response string, we scan
for all the digits at the end of the response and parse only those as a
number. */
char *start = &buf[4];
char *fdigit = strchr(start, '\r');
if(fdigit) {
do
fdigit--;
while(ISDIGIT(*fdigit) && (fdigit > start));
if(!ISDIGIT(*fdigit))
fdigit++;
}
else
fdigit = start;
/* ignores parsing errors, which will make the size remain unknown */
(void)curlx_strtoofft(buf + 4, NULL, 0, &filesize);
(void)curlx_strtoofft(fdigit, NULL, 0, &filesize);
}
if(instate == FTP_SIZE) {
#ifdef CURL_FTP_HTTPSTYLE_HEAD
@ -2527,7 +2519,6 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn,
{
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
struct FTP *ftp = data->req.protop;
struct ftp_conn *ftpc = &conn->proto.ftpc;
(void)instate; /* no use for this yet */
@ -2535,7 +2526,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn,
if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
/* 331 Password required for ...
(the server requires to send the user's password too) */
PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
PPSENDF(&ftpc->pp, "PASS %s", conn->passwd?conn->passwd:"");
state(conn, FTP_PASS);
}
else if(ftpcode/100 == 2) {
@ -3134,7 +3125,8 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
ssize_t nread;
int ftpcode;
CURLcode result = CURLE_OK;
char *path = NULL;
char *rawPath = NULL;
size_t pathLen = 0;
if(!ftp)
return CURLE_OK;
@ -3172,9 +3164,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
break;
}
/* now store a copy of the directory we are in */
free(ftpc->prevpath);
if(data->state.wildcardmatch) {
if(data->set.chunk_end && ftpc->file) {
Curl_set_in_callback(data, true);
@ -3185,41 +3174,41 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
}
if(!result)
/* get the "raw" path */
result = Curl_urldecode(data, ftp->path, 0, &path, NULL, TRUE);
/* get the url-decoded "raw" path */
result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, TRUE);
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 */
free(ftpc->prevpath);
ftpc->prevpath = NULL; /* no path remembering */
}
else {
size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
size_t dlen = strlen(path)-flen;
if(!ftpc->cwdfail) {
ftpc->prevmethod = data->set.ftp_filemethod;
if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
ftpc->prevpath = path;
if(flen)
/* if 'path' is not the whole string */
ftpc->prevpath[dlen] = 0; /* terminate */
else { /* remember working directory for connection reuse */
if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */
else {
free(ftpc->prevpath);
if(!ftpc->cwdfail) {
if(data->set.ftp_filemethod == FTPFILE_NOCWD)
pathLen = 0; /* relative path => working directory is FTP home */
else
pathLen -= ftpc->file?strlen(ftpc->file):0; /* file is url-decoded */
rawPath[pathLen] = '\0';
ftpc->prevpath = rawPath;
}
else {
free(path);
/* we never changed dir */
ftpc->prevpath = strdup("");
if(!ftpc->prevpath)
return CURLE_OUT_OF_MEMORY;
free(rawPath);
ftpc->prevpath = NULL; /* no path */
}
if(ftpc->prevpath)
infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
}
else {
ftpc->prevpath = NULL; /* no path */
free(path);
}
if(ftpc->prevpath)
infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
}
/* free the dir tree and file parts */
freedirs(ftpc);
@ -3532,14 +3521,13 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
/* if we got an error or if we don't wait for a data connection return
immediately */
if(result || (ftpc->wait_data_conn != TRUE))
if(result || !ftpc->wait_data_conn)
return result;
if(ftpc->wait_data_conn)
/* if we reach the end of the FTP state machine here, *complete will be
TRUE but so is ftpc->wait_data_conn, which says we need to wait for
the data connection and therefore we're not actually complete */
*completep = 0;
/* if we reach the end of the FTP state machine here, *complete will be
TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
data connection and therefore we're not actually complete */
*completep = 0;
}
if(ftp->transfer <= FTPTRANSFER_INFO) {
@ -3573,13 +3561,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
return result;
result = ftp_multi_statemach(conn, &complete);
if(ftpc->wait_data_conn)
/* if we reach the end of the FTP state machine here, *complete will be
TRUE but so is ftpc->wait_data_conn, which says we need to wait for
the data connection and therefore we're not actually complete */
*completep = 0;
else
*completep = (int)complete;
/* ftpc->wait_data_conn is always false here */
*completep = (int)complete;
}
else {
/* download */
@ -3619,10 +3602,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
return result;
}
if(!result && (ftp->transfer != FTPTRANSFER_BODY))
/* no data to transfer. FIX: it feels like a kludge to have this here
too! */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
if(!ftpc->wait_data_conn) {
/* no waiting for the data connection so this is now complete */
@ -4100,186 +4081,142 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
/* the ftp struct is already inited in ftp_connect() */
struct FTP *ftp = data->req.protop;
struct ftp_conn *ftpc = &conn->proto.ftpc;
const char *slash_pos; /* position of the first '/' char in curpos */
const char *path_to_use = ftp->path;
const char *cur_pos;
const char *filename = NULL;
cur_pos = path_to_use; /* current position in path. point at the begin of
next path component */
const char *slashPos = NULL;
const char *fileName = NULL;
CURLcode result = CURLE_OK;
char *rawPath = NULL; /* url-decoded "raw" path */
size_t pathLen = 0;
ftpc->ctl_valid = FALSE;
ftpc->cwdfail = FALSE;
/* url-decode ftp path before further evaluation */
result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, TRUE);
if(result)
return result;
switch(data->set.ftp_filemethod) {
case FTPFILE_NOCWD:
/* fastest, but less standard-compliant */
case FTPFILE_NOCWD: /* fastest, but less standard-compliant */
/*
The best time to check whether the path is a file or directory is right
here. so:
the first condition in the if() right here, is there just in case
someone decides to set path to NULL one day
*/
if(path_to_use[0] &&
(path_to_use[strlen(path_to_use) - 1] != '/') )
filename = path_to_use; /* this is a full file path */
/*
else {
ftpc->file is not used anywhere other than for operations on a file.
In other words, never for directory operations.
So we can safely leave filename as NULL here and use it as a
argument in dir/file decisions.
}
*/
break;
case FTPFILE_SINGLECWD:
/* get the last slash */
if(!path_to_use[0]) {
/* no dir, no file */
ftpc->dirdepth = 0;
if((pathLen > 0) && (rawPath[pathLen - 1] != '/'))
fileName = rawPath; /* this is a full file path */
/*
else: ftpc->file is not used anywhere other than for operations on
a file. In other words, never for directory operations.
So we can safely leave filename as NULL here and use it as a
argument in dir/file decisions.
*/
break;
}
slash_pos = strrchr(cur_pos, '/');
if(slash_pos || !*cur_pos) {
size_t dirlen = slash_pos-cur_pos;
CURLcode result;
ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
if(!ftpc->dirs)
return CURLE_OUT_OF_MEMORY;
case FTPFILE_SINGLECWD:
slashPos = strrchr(rawPath, '/');
if(slashPos) {
/* get path before last slash, except for / */
size_t dirlen = slashPos - rawPath;
if(dirlen == 0)
dirlen++;
if(!dirlen)
dirlen++;
ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
if(!ftpc->dirs) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
slash_pos ? dirlen : 1,
&ftpc->dirs[0], NULL,
TRUE);
if(result) {
freedirs(ftpc);
return result;
ftpc->dirs[0] = calloc(1, dirlen + 1);
if(!ftpc->dirs[0]) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
strncpy(ftpc->dirs[0], rawPath, dirlen);
ftpc->dirdepth = 1; /* we consider it to be a single dir */
fileName = slashPos + 1; /* rest is file name */
}
ftpc->dirdepth = 1; /* we consider it to be a single dir */
filename = slash_pos ? slash_pos + 1 : cur_pos; /* rest is file name */
}
else
filename = cur_pos; /* this is a file name only */
break;
else
fileName = rawPath; /* file name only (or empty) */
break;
default: /* allow pretty much anything */
case FTPFILE_MULTICWD:
ftpc->dirdepth = 0;
ftpc->diralloc = 5; /* default dir depth to allocate */
ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
if(!ftpc->dirs)
return CURLE_OUT_OF_MEMORY;
default: /* allow pretty much anything */
case FTPFILE_MULTICWD: {
/* current position: begin of next path component */
const char *curPos = rawPath;
/* we have a special case for listing the root dir only */
if(!strcmp(path_to_use, "/")) {
cur_pos++; /* make it point to the zero byte */
ftpc->dirs[0] = strdup("/");
ftpc->dirdepth++;
}
else {
/* parse the URL path into separate path components */
while((slash_pos = strchr(cur_pos, '/')) != NULL) {
/* 1 or 0 pointer offset to indicate absolute directory */
ssize_t absolute_dir = ((cur_pos - ftp->path > 0) &&
(ftpc->dirdepth == 0))?1:0;
int dirAlloc = 0; /* number of entries allocated for the 'dirs' array */
const char *str = rawPath;
for(; *str != 0; ++str)
if (*str == '/')
++dirAlloc;
if(dirAlloc > 0) {
ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0]));
if(!ftpc->dirs) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
/* parse the URL path into separate path components */
while((slashPos = strchr(curPos, '/')) != NULL) {
size_t compLen = slashPos - curPos;
/* path starts with a slash: add that as a directory */
if((compLen == 0) && (ftpc->dirdepth == 0))
++compLen;
/* seek out the next path component */
if(slash_pos-cur_pos) {
/* we skip empty path components, like "x//y" since the FTP command
CWD requires a parameter and a non-existent parameter a) doesn't
work on many servers and b) has no effect on the others. */
size_t len = slash_pos - cur_pos + absolute_dir;
CURLcode result =
Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
&ftpc->dirs[ftpc->dirdepth], NULL,
TRUE);
if(result) {
freedirs(ftpc);
return result;
}
}
else {
cur_pos = slash_pos + 1; /* jump to the rest of the string */
if(!ftpc->dirdepth) {
/* path starts with a slash, add that as a directory */
ftpc->dirs[ftpc->dirdepth] = strdup("/");
if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
failf(data, "no memory");
freedirs(ftpc);
if(compLen > 0) {
char *comp = calloc(1, compLen + 1);
if(!comp) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
strncpy(comp, curPos, compLen);
ftpc->dirs[ftpc->dirdepth++] = comp;
}
continue;
}
cur_pos = slash_pos + 1; /* jump to the rest of the string */
if(++ftpc->dirdepth >= ftpc->diralloc) {
/* enlarge array */
char **bigger;
ftpc->diralloc *= 2; /* double the size each time */
bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
if(!bigger) {
freedirs(ftpc);
return CURLE_OUT_OF_MEMORY;
}
ftpc->dirs = bigger;
curPos = slashPos + 1;
}
}
DEBUGASSERT(ftpc->dirdepth <= dirAlloc);
fileName = curPos; /* the rest is the file name (or empty) */
}
filename = cur_pos; /* the rest is the file name */
break;
} /* switch */
if(filename && *filename) {
CURLcode result =
Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE);
if(result) {
freedirs(ftpc);
return result;
}
}
if(fileName && *fileName)
ftpc->file = strdup(fileName);
else
ftpc->file = NULL; /* instead of point to a zero byte, we make it a NULL
pointer */
ftpc->file = NULL; /* instead of point to a zero byte,
we make it a NULL pointer */
if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
/* We need a file name when uploading. Return error! */
failf(data, "Uploading to a URL without a file name!");
free(rawPath);
return CURLE_URL_MALFORMAT;
}
ftpc->cwddone = FALSE; /* default to not done */
if(ftpc->prevpath) {
/* prevpath is "raw" so we convert the input path before we compare the
strings */
size_t dlen;
char *path;
CURLcode result =
Curl_urldecode(conn->data, ftp->path, 0, &path, &dlen, TRUE);
if(result) {
freedirs(ftpc);
return result;
}
if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/'))
ftpc->cwddone = TRUE; /* skip CWD for absolute paths */
else { /* newly created FTP connections are already in entry path */
const char *oldPath = conn->bits.reuse ? ftpc->prevpath : "";
if(oldPath) {
size_t n = pathLen;
if(data->set.ftp_filemethod == FTPFILE_NOCWD)
n = 0; /* CWD to entry for relative paths */
else
n -= ftpc->file?strlen(ftpc->file):0;
dlen -= ftpc->file?strlen(ftpc->file):0;
if((dlen == strlen(ftpc->prevpath)) &&
!strncmp(path, ftpc->prevpath, dlen) &&
(ftpc->prevmethod == data->set.ftp_filemethod)) {
infof(data, "Request has same path as previous transfer\n");
ftpc->cwddone = TRUE;
if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
infof(data, "Request has same path as previous transfer\n");
ftpc->cwddone = TRUE;
}
}
free(path);
}
free(rawPath);
return CURLE_OK;
}
@ -4423,18 +4360,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
/* get some initial data into the ftp struct */
ftp->transfer = FTPTRANSFER_BODY;
ftp->downloadsize = 0;
/* No need to duplicate user+password, the connectdata struct won't change
during a session, but we re-init them here since on subsequent inits
since the conn struct may have changed or been replaced.
*/
ftp->user = conn->user;
ftp->passwd = conn->passwd;
if(isBadFtpString(ftp->user))
return CURLE_URL_MALFORMAT;
if(isBadFtpString(ftp->passwd))
return CURLE_URL_MALFORMAT;
conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
return CURLE_OK;

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -102,8 +102,6 @@ typedef enum {
perhaps the Curl_easy is changed between the times the connection is
used. */
struct FTP {
char *user; /* user name string */
char *passwd; /* password string */
char *path; /* points to the urlpieces struct field */
char *pathalloc; /* if non-NULL a pointer to an allocated path */
@ -121,8 +119,7 @@ struct ftp_conn {
char *entrypath; /* the PWD reply when we logged on */
char **dirs; /* realloc()ed array for path components */
int dirdepth; /* number of entries used in the 'dirs' array */
int diralloc; /* number of entries allocated for the 'dirs' array */
char *file; /* decoded file */
char *file; /* url-decoded file name (or path) */
bool dont_check; /* Set to TRUE to prevent the final (post-transfer)
file size and 226/250 status check. It should still
read the line, just ignore the result. */
@ -135,8 +132,7 @@ struct ftp_conn {
bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent
caching the current directory */
bool wait_data_conn; /* this is set TRUE if data connection is waited */
char *prevpath; /* conn->path from the previous transfer */
curl_ftpfile prevmethod; /* ftp method in 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) */
int count1; /* general purpose counter for the state machine */

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -27,25 +27,48 @@
#include "memdebug.h"
static
char *GetEnv(const char *variable)
static char *GetEnv(const char *variable)
{
#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
(void)variable;
return NULL;
#else
#ifdef WIN32
char env[MAX_PATH]; /* MAX_PATH is from windef.h */
char *temp = getenv(variable);
env[0] = '\0';
if(temp != NULL)
ExpandEnvironmentStringsA(temp, env, sizeof(env));
return (env[0] != '\0')?strdup(env):NULL;
#elif defined(WIN32)
/* This uses Windows API instead of C runtime getenv() to get the environment
variable since some changes aren't always visible to the latter. #4774 */
char *buf = NULL;
char *tmp;
DWORD bufsize;
DWORD rc = 1;
const DWORD max = 32768; /* max env var size from MSCRT source */
for(;;) {
tmp = realloc(buf, rc);
if(!tmp) {
free(buf);
return NULL;
}
buf = tmp;
bufsize = rc;
/* It's possible for rc to be 0 if the variable was found but empty.
Since getenv doesn't make that distinction we ignore it as well. */
rc = GetEnvironmentVariableA(variable, buf, bufsize);
if(!rc || rc == bufsize || rc > max) {
free(buf);
return NULL;
}
/* if rc < bufsize then rc is bytes written not including null */
if(rc < bufsize)
return buf;
/* else rc is bytes needed, try again */
}
#else
char *env = getenv(variable);
return (env && env[0])?strdup(env):NULL;
#endif
#endif
}
char *curl_getenv(const char *v)

View File

@ -235,6 +235,9 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
case 20:
*param_longp = CURL_HTTP_VERSION_2_0;
break;
case 30:
*param_longp = CURL_HTTP_VERSION_3;
break;
default:
*param_longp = CURL_HTTP_VERSION_NONE;
break;
@ -243,7 +246,6 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
case CURLINFO_PROTOCOL:
*param_longp = data->info.conn_protocol;
break;
default:
return CURLE_UNKNOWN_OPTION;
}
@ -301,7 +303,9 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
case CURLINFO_REDIRECT_TIME_T:
*param_offt = data->progress.t_redirect;
break;
case CURLINFO_RETRY_AFTER:
*param_offt = data->info.retry_after;
break;
default:
return CURLE_UNKNOWN_OPTION;
}

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -80,7 +80,7 @@ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len);
void *Curl_hash_pick(struct curl_hash *, void *key, size_t key_len);
void Curl_hash_apply(struct curl_hash *h, void *user,
void (*cb)(void *user, void *ptr));
int Curl_hash_count(struct curl_hash *h);
#define Curl_hash_count(h) ((h)->size)
void Curl_hash_destroy(struct curl_hash *h);
void Curl_hash_clean(struct curl_hash *h);
void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -30,6 +30,7 @@
#include "curl_hmac.h"
#include "curl_memory.h"
#include "warnless.h"
/* The last #include file should be: */
#include "memdebug.h"
@ -129,4 +130,40 @@ int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result)
return 0;
}
/*
* Curl_hmacit()
*
* This is used to generate a HMAC hash, for the specified input data, given
* the specified hash function and key.
*
* Parameters:
*
* hashparams [in] - The hash function (Curl_HMAC_MD5).
* key [in] - The key to use.
* keylen [in] - The length of the key.
* data [in] - The data to encrypt.
* datalen [in] - The length of the data.
* output [in/out] - The output buffer.
*
* Returns CURLE_OK on success.
*/
CURLcode Curl_hmacit(const HMAC_params *hashparams,
const unsigned char *key, const size_t keylen,
const unsigned char *data, const size_t datalen,
unsigned char *output)
{
HMAC_context *ctxt = Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen));
if(!ctxt)
return CURLE_OUT_OF_MEMORY;
/* Update the digest with the given challenge */
Curl_HMAC_update(ctxt, data, curlx_uztoui(datalen));
/* Finalise the digest */
Curl_HMAC_final(ctxt, output);
return CURLE_OK;
}
#endif /* CURL_DISABLE_CRYPTO_AUTH */

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -59,6 +59,7 @@
#include "strerror.h"
#include "url.h"
#include "inet_ntop.h"
#include "inet_pton.h"
#include "multiif.h"
#include "doh.h"
#include "warnless.h"
@ -482,16 +483,16 @@ Curl_cache_addr(struct Curl_easy *data,
* CURLRESOLV_PENDING (1) = waiting for response, no pointer
*/
int Curl_resolv(struct connectdata *conn,
const char *hostname,
int port,
bool allowDOH,
struct Curl_dns_entry **entry)
enum resolve_t Curl_resolv(struct connectdata *conn,
const char *hostname,
int port,
bool allowDOH,
struct Curl_dns_entry **entry)
{
struct Curl_dns_entry *dns = NULL;
struct Curl_easy *data = conn->data;
CURLcode result;
int rc = CURLRESOLV_ERROR; /* default to failure */
enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
*entry = NULL;
@ -512,13 +513,11 @@ int Curl_resolv(struct connectdata *conn,
if(!dns) {
/* The entry was not in the cache. Resolve it to IP address */
Curl_addrinfo *addr;
Curl_addrinfo *addr = NULL;
int respwait = 0;
/* Check what IP specifics the app has requested and if we can provide it.
* If not, bail out. */
if(!Curl_ipvalid(conn))
return CURLRESOLV_ERROR;
#ifndef USE_RESOLVE_ON_IPS
struct in_addr in;
#endif
/* notify the resolver start callback */
if(data->set.resolver_start) {
@ -531,20 +530,43 @@ int Curl_resolv(struct connectdata *conn,
return CURLRESOLV_ERROR;
}
if(allowDOH && data->set.doh) {
addr = Curl_doh(conn, hostname, port, &respwait);
#ifndef USE_RESOLVE_ON_IPS
/* First check if this is an IPv4 address string */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
addr = Curl_ip2addr(AF_INET, &in, hostname, port);
#ifdef ENABLE_IPV6
if(!addr) {
struct in6_addr in6;
/* check if this is an IPv6 address string */
if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
/* This is an IPv6 address literal */
addr = Curl_ip2addr(AF_INET6, &in6, hostname, port);
}
else {
/* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
non-zero value indicating that we need to wait for the response to the
resolve call */
addr = Curl_getaddrinfo(conn,
#endif /* ENABLE_IPV6 */
#endif /* !USE_RESOLVE_ON_IPS */
if(!addr) {
/* Check what IP specifics the app has requested and if we can provide
* it. If not, bail out. */
if(!Curl_ipvalid(conn))
return CURLRESOLV_ERROR;
if(allowDOH && data->set.doh) {
addr = Curl_doh(conn, hostname, port, &respwait);
}
else {
/* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
non-zero value indicating that we need to wait for the response to
the resolve call */
addr = Curl_getaddrinfo(conn,
#ifdef DEBUGBUILD
(data->set.str[STRING_DEVICE]
&& !strcmp(data->set.str[STRING_DEVICE],
"LocalHost"))?"localhost":
(data->set.str[STRING_DEVICE]
&& !strcmp(data->set.str[STRING_DEVICE],
"LocalHost"))?"localhost":
#endif
hostname, port, &respwait);
hostname, port, &respwait);
}
}
if(!addr) {
if(respwait) {
@ -620,11 +642,11 @@ RETSIGTYPE alarmfunc(int sig)
* CURLRESOLV_PENDING (1) = waiting for response, no pointer
*/
int Curl_resolv_timeout(struct connectdata *conn,
const char *hostname,
int port,
struct Curl_dns_entry **entry,
time_t timeoutms)
enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
const char *hostname,
int port,
struct Curl_dns_entry **entry,
timediff_t timeoutms)
{
#ifdef USE_ALARM_TIMEOUT
#ifdef HAVE_SIGACTION
@ -640,7 +662,7 @@ int Curl_resolv_timeout(struct connectdata *conn,
volatile unsigned int prev_alarm = 0;
struct Curl_easy *data = conn->data;
#endif /* USE_ALARM_TIMEOUT */
int rc;
enum resolve_t rc;
*entry = NULL;
@ -749,7 +771,7 @@ clean_up:
conn->created) / 1000;
/* the alarm period is counted in even number of seconds */
unsigned long alarm_set = prev_alarm - elapsed_secs;
unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs);
if(!alarm_set ||
((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
@ -1021,25 +1043,27 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
CURLcode Curl_resolv_check(struct connectdata *conn,
struct Curl_dns_entry **dns)
{
#if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
(void)dns;
#endif
if(conn->data->set.doh)
return Curl_doh_is_resolved(conn, dns);
return Curl_resolver_is_resolved(conn, dns);
}
int Curl_resolv_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
curl_socket_t *socks)
{
#ifdef CURLRES_ASYNCH
if(conn->data->set.doh)
/* nothing to wait for during DOH resolve, those handles have their own
sockets */
return GETSOCK_BLANK;
return Curl_resolver_getsock(conn, socks, numsocks);
return Curl_resolver_getsock(conn, socks);
#else
(void)conn;
(void)socks;
(void)numsocks;
return GETSOCK_BLANK;
#endif
}

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -25,6 +25,7 @@
#include "curl_setup.h"
#include "hash.h"
#include "curl_addrinfo.h"
#include "timeval.h" /* for timediff_t */
#include "asyn.h"
#ifdef HAVE_SETJMP_H
@ -61,7 +62,6 @@ struct connectdata;
* Returns a struct curl_hash pointer on success, NULL on failure.
*/
struct curl_hash *Curl_global_host_cache_init(void);
void Curl_global_host_cache_dtor(void);
struct Curl_dns_entry {
Curl_addrinfo *addr;
@ -79,26 +79,29 @@ struct Curl_dns_entry {
* use, or we'll leak memory!
*/
/* return codes */
#define CURLRESOLV_TIMEDOUT -2
#define CURLRESOLV_ERROR -1
#define CURLRESOLV_RESOLVED 0
#define CURLRESOLV_PENDING 1
int Curl_resolv(struct connectdata *conn,
const char *hostname,
int port,
bool allowDOH,
struct Curl_dns_entry **dnsentry);
int Curl_resolv_timeout(struct connectdata *conn, const char *hostname,
int port, struct Curl_dns_entry **dnsentry,
time_t timeoutms);
enum resolve_t {
CURLRESOLV_TIMEDOUT = -2,
CURLRESOLV_ERROR = -1,
CURLRESOLV_RESOLVED = 0,
CURLRESOLV_PENDING = 1
};
enum resolve_t Curl_resolv(struct connectdata *conn,
const char *hostname,
int port,
bool allowDOH,
struct Curl_dns_entry **dnsentry);
enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
const char *hostname, int port,
struct Curl_dns_entry **dnsentry,
timediff_t timeoutms);
#ifdef CURLRES_IPV6
/*
* Curl_ipv6works() returns TRUE if IPv6 seems to work.
*/
bool Curl_ipv6works(void);
bool Curl_ipv6works(struct connectdata *conn);
#else
#define Curl_ipv6works() FALSE
#define Curl_ipv6works(x) FALSE
#endif
/*
@ -124,9 +127,6 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
void Curl_resolv_unlock(struct Curl_easy *data,
struct Curl_dns_entry *dns);
/* for debugging purposes only: */
void Curl_scan_cache_used(void *user, void *ptr);
/* init a new dns cache and return success */
int Curl_mk_dnscache(struct curl_hash *hash);
@ -236,11 +236,6 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
*/
void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash);
/*
* Destroy the hostcache of this handle.
*/
void Curl_hostcache_destroy(struct Curl_easy *data);
/*
* Populate the cache with specified entries from CURLOPT_RESOLVE.
*/
@ -249,7 +244,6 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data);
CURLcode Curl_resolv_check(struct connectdata *conn,
struct Curl_dns_entry **dns);
int Curl_resolv_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks);
curl_socket_t *socks);
#endif /* HEADER_CURL_HOSTIP_H */

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -52,7 +52,6 @@
#include "share.h"
#include "strerror.h"
#include "url.h"
#include "inet_pton.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@ -128,28 +127,22 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
#endif
Curl_addrinfo *ai = NULL;
struct hostent *h = NULL;
struct in_addr in;
struct hostent *buf = NULL;
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
return Curl_ip2addr(AF_INET, &in, hostname, port);
#if defined(HAVE_GETADDRINFO_THREADSAFE)
else {
struct addrinfo hints;
char sbuf[12];
char *sbufptr = NULL;
struct addrinfo hints;
char sbuf[12];
char *sbufptr = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
if(port) {
msnprintf(sbuf, sizeof(sbuf), "%d", port);
sbufptr = sbuf;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
if(port) {
msnprintf(sbuf, sizeof(sbuf), "%d", port);
sbufptr = sbuf;
}
(void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
(void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
#elif defined(HAVE_GETHOSTBYNAME_R)
/*
@ -157,144 +150,141 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
* Since there are three different versions of it, the following code is
* somewhat #ifdef-ridden.
*/
else {
int h_errnop;
int h_errnop;
buf = calloc(1, CURL_HOSTENT_SIZE);
if(!buf)
return NULL; /* major failure */
/*
* The clearing of the buffer is a workaround for a gethostbyname_r bug in
* qnx nto and it is also _required_ for some of these functions on some
* platforms.
*/
buf = calloc(1, CURL_HOSTENT_SIZE);
if(!buf)
return NULL; /* major failure */
/*
* The clearing of the buffer is a workaround for a gethostbyname_r bug in
* qnx nto and it is also _required_ for some of these functions on some
* platforms.
*/
#if defined(HAVE_GETHOSTBYNAME_R_5)
/* Solaris, IRIX and more */
h = gethostbyname_r(hostname,
(struct hostent *)buf,
(char *)buf + sizeof(struct hostent),
CURL_HOSTENT_SIZE - sizeof(struct hostent),
&h_errnop);
/* Solaris, IRIX and more */
h = gethostbyname_r(hostname,
(struct hostent *)buf,
(char *)buf + sizeof(struct hostent),
CURL_HOSTENT_SIZE - sizeof(struct hostent),
&h_errnop);
/* If the buffer is too small, it returns NULL and sets errno to
* ERANGE. The errno is thread safe if this is compiled with
* -D_REENTRANT as then the 'errno' variable is a macro defined to get
* used properly for threads.
*/
/* If the buffer is too small, it returns NULL and sets errno to
* ERANGE. The errno is thread safe if this is compiled with
* -D_REENTRANT as then the 'errno' variable is a macro defined to get
* used properly for threads.
*/
if(h) {
;
}
else
#elif defined(HAVE_GETHOSTBYNAME_R_6)
/* Linux */
(void)gethostbyname_r(hostname,
(struct hostent *)buf,
(char *)buf + sizeof(struct hostent),
CURL_HOSTENT_SIZE - sizeof(struct hostent),
&h, /* DIFFERENCE */
&h_errnop);
/* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
* sudden this function returns EAGAIN if the given buffer size is too
* small. Previous versions are known to return ERANGE for the same
* problem.
*
* This wouldn't be such a big problem if older versions wouldn't
* sometimes return EAGAIN on a common failure case. Alas, we can't
* assume that EAGAIN *or* ERANGE means ERANGE for any given version of
* glibc.
*
* For now, we do that and thus we may call the function repeatedly and
* fail for older glibc versions that return EAGAIN, until we run out of
* buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
*
* If anyone has a better fix, please tell us!
*
* -------------------------------------------------------------------
*
* On October 23rd 2003, Dan C dug up more details on the mysteries of
* gethostbyname_r() in glibc:
*
* In glibc 2.2.5 the interface is different (this has also been
* discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
* explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
* (shipped/upgraded by Redhat 7.2) don't show this behavior!
*
* In this "buggy" version, the return code is -1 on error and 'errno'
* is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
* thread-safe variable.
*/
if(!h) /* failure */
#elif defined(HAVE_GETHOSTBYNAME_R_3)
/* AIX, Digital Unix/Tru64, HPUX 10, more? */
/* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
* the plain fact that it does not return unique full buffers on each
* call, but instead several of the pointers in the hostent structs will
* point to the same actual data! This have the unfortunate down-side that
* our caching system breaks down horribly. Luckily for us though, AIX 4.3
* and more recent versions have a "completely thread-safe"[*] libc where
* all the data is stored in thread-specific memory areas making calls to
* the plain old gethostbyname() work fine even for multi-threaded
* programs.
*
* This AIX 4.3 or later detection is all made in the configure script.
*
* Troels Walsted Hansen helped us work this out on March 3rd, 2003.
*
* [*] = much later we've found out that it isn't at all "completely
* thread-safe", but at least the gethostbyname() function is.
*/
if(CURL_HOSTENT_SIZE >=
(sizeof(struct hostent) + sizeof(struct hostent_data))) {
/* August 22nd, 2000: Albert Chin-A-Young brought an updated version
* that should work! September 20: Richard Prescott worked on the buffer
* size dilemma.
*/
res = gethostbyname_r(hostname,
(struct hostent *)buf,
(struct hostent_data *)((char *)buf +
sizeof(struct hostent)));
h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
}
else
res = -1; /* failure, too smallish buffer size */
if(!res) { /* success */
h = buf; /* result expected in h */
/* This is the worst kind of the different gethostbyname_r() interfaces.
* Since we don't know how big buffer this particular lookup required,
* we can't realloc down the huge alloc without doing closer analysis of
* the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
* name lookup. Fixing this would require an extra malloc() and then
* calling Curl_addrinfo_copy() that subsequent realloc()s down the new
* memory area to the actually used amount.
*/
}
else
#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
{
h = NULL; /* set return code to NULL */
free(buf);
}
#else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
/*
* Here is code for platforms that don't have a thread safe
* getaddrinfo() nor gethostbyname_r() function or for which
* gethostbyname() is the preferred one.
*/
else {
h = gethostbyname((void *)hostname);
#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
if(h) {
;
}
else
#elif defined(HAVE_GETHOSTBYNAME_R_6)
/* Linux */
(void)gethostbyname_r(hostname,
(struct hostent *)buf,
(char *)buf + sizeof(struct hostent),
CURL_HOSTENT_SIZE - sizeof(struct hostent),
&h, /* DIFFERENCE */
&h_errnop);
/* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
* sudden this function returns EAGAIN if the given buffer size is too
* small. Previous versions are known to return ERANGE for the same
* problem.
*
* This wouldn't be such a big problem if older versions wouldn't
* sometimes return EAGAIN on a common failure case. Alas, we can't
* assume that EAGAIN *or* ERANGE means ERANGE for any given version of
* glibc.
*
* For now, we do that and thus we may call the function repeatedly and
* fail for older glibc versions that return EAGAIN, until we run out of
* buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
*
* If anyone has a better fix, please tell us!
*
* -------------------------------------------------------------------
*
* On October 23rd 2003, Dan C dug up more details on the mysteries of
* gethostbyname_r() in glibc:
*
* In glibc 2.2.5 the interface is different (this has also been
* discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
* explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
* (shipped/upgraded by Redhat 7.2) don't show this behavior!
*
* In this "buggy" version, the return code is -1 on error and 'errno'
* is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
* thread-safe variable.
*/
if(!h) /* failure */
#elif defined(HAVE_GETHOSTBYNAME_R_3)
/* AIX, Digital Unix/Tru64, HPUX 10, more? */
/* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
* the plain fact that it does not return unique full buffers on each
* call, but instead several of the pointers in the hostent structs will
* point to the same actual data! This have the unfortunate down-side that
* our caching system breaks down horribly. Luckily for us though, AIX 4.3
* and more recent versions have a "completely thread-safe"[*] libc where
* all the data is stored in thread-specific memory areas making calls to
* the plain old gethostbyname() work fine even for multi-threaded
* programs.
*
* This AIX 4.3 or later detection is all made in the configure script.
*
* Troels Walsted Hansen helped us work this out on March 3rd, 2003.
*
* [*] = much later we've found out that it isn't at all "completely
* thread-safe", but at least the gethostbyname() function is.
*/
if(CURL_HOSTENT_SIZE >=
(sizeof(struct hostent) + sizeof(struct hostent_data))) {
/* August 22nd, 2000: Albert Chin-A-Young brought an updated version
* that should work! September 20: Richard Prescott worked on the buffer
* size dilemma.
*/
res = gethostbyname_r(hostname,
(struct hostent *)buf,
(struct hostent_data *)((char *)buf +
sizeof(struct hostent)));
h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
}
else
res = -1; /* failure, too smallish buffer size */
if(!res) { /* success */
h = buf; /* result expected in h */
/* This is the worst kind of the different gethostbyname_r() interfaces.
* Since we don't know how big buffer this particular lookup required,
* we can't realloc down the huge alloc without doing closer analysis of
* the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
* name lookup. Fixing this would require an extra malloc() and then
* calling Curl_addrinfo_copy() that subsequent realloc()s down the new
* memory area to the actually used amount.
*/
}
else
#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
{
h = NULL; /* set return code to NULL */
free(buf);
}
#else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
/*
* Here is code for platforms that don't have a thread safe
* getaddrinfo() nor gethostbyname_r() function or for which
* gethostbyname() is the preferred one.
*/
h = gethostbyname((void *)hostname);
#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
if(h) {
ai = Curl_he2ai(h, port);

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -62,13 +62,19 @@
/*
* Curl_ipv6works() returns TRUE if IPv6 seems to work.
*/
bool Curl_ipv6works(void)
bool Curl_ipv6works(struct connectdata *conn)
{
/* the nature of most system is that IPv6 status doesn't come and go
during a program's lifetime so we only probe the first time and then we
have the info kept for fast re-use */
static int ipv6_works = -1;
if(-1 == ipv6_works) {
if(conn) {
/* the nature of most system is that IPv6 status doesn't come and go
during a program's lifetime so we only probe the first time and then we
have the info kept for fast re-use */
DEBUGASSERT(conn);
DEBUGASSERT(conn->data);
DEBUGASSERT(conn->data->multi);
return conn->data->multi->ipv6_works;
}
else {
int ipv6_works = -1;
/* probe to see if we have a working IPv6 stack */
curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
if(s == CURL_SOCKET_BAD)
@ -78,8 +84,8 @@ bool Curl_ipv6works(void)
ipv6_works = 1;
Curl_closesocket(NULL, s);
}
return (ipv6_works>0)?TRUE:FALSE;
}
return (ipv6_works>0)?TRUE:FALSE;
}
/*
@ -89,7 +95,7 @@ bool Curl_ipv6works(void)
bool Curl_ipvalid(struct connectdata *conn)
{
if(conn->ip_version == CURL_IPRESOLVE_V6)
return Curl_ipv6works();
return Curl_ipv6works(conn);
return TRUE;
}
@ -159,13 +165,14 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
break;
}
if((pf != PF_INET) && !Curl_ipv6works())
if((pf != PF_INET) && !Curl_ipv6works(conn))
/* The stack seems to be a non-IPv6 one */
pf = PF_INET;
memset(&hints, 0, sizeof(hints));
hints.ai_family = pf;
hints.ai_socktype = conn->socktype;
hints.ai_socktype = (conn->transport == TRNSPRT_TCP) ?
SOCK_STREAM : SOCK_DGRAM;
#ifndef USE_RESOLVE_ON_IPS
/*

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -88,8 +88,7 @@
*/
static int http_getsock_do(struct connectdata *conn,
curl_socket_t *socks,
int numsocks);
curl_socket_t *socks);
static int http_should_fail(struct connectdata *conn);
#ifndef CURL_DISABLE_PROXY
@ -99,8 +98,7 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn);
#ifdef USE_SSL
static CURLcode https_connecting(struct connectdata *conn, bool *done);
static int https_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks);
curl_socket_t *socks);
#else
#define https_connecting(x,y) CURLE_COULDNT_CONNECT
#endif
@ -171,10 +169,22 @@ static CURLcode http_setup_conn(struct connectdata *conn)
Curl_mime_initpart(&http->form, conn->data);
data->req.protop = http;
if(!CONN_INUSE(conn))
/* if not already multi-using, setup connection details */
Curl_http2_setup_conn(conn);
Curl_http2_setup_req(data);
if(data->set.httpversion == CURL_HTTP_VERSION_3) {
if(conn->handler->flags & PROTOPT_SSL)
/* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does
the QUIC dance. */
conn->transport = TRNSPRT_QUIC;
else {
failf(data, "HTTP/3 requested for non-HTTPS URL");
return CURLE_URL_MALFORMAT;
}
}
else {
if(!CONN_INUSE(conn))
/* if not already multi-using, setup connection details */
Curl_http2_setup_conn(conn);
Curl_http2_setup_req(data);
}
return CURLE_OK;
}
@ -334,7 +344,7 @@ static CURLcode http_output_bearer(struct connectdata *conn)
userp = &conn->allocptr.userpwd;
free(*userp);
*userp = aprintf("Authorization: Bearer %s\r\n",
conn->oauth_bearer);
conn->data->set.str[STRING_BEARER]);
if(!*userp) {
result = CURLE_OUT_OF_MEMORY;
@ -383,7 +393,7 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
}
/*
* Curl_http_perhapsrewind()
* http_perhapsrewind()
*
* If we are doing POST or PUT {
* If we have more data to send {
@ -440,9 +450,6 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
/* figure out how much data we are expected to send */
switch(data->set.httpreq) {
case HTTPREQ_POST:
if(data->state.infilesize != -1)
expectsend = data->state.infilesize;
break;
case HTTPREQ_PUT:
if(data->state.infilesize != -1)
expectsend = data->state.infilesize;
@ -548,7 +555,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
CURLcode result = CURLE_OK;
unsigned long authmask = ~0ul;
if(!conn->oauth_bearer)
if(!data->set.str[STRING_BEARER])
authmask &= (unsigned long)~CURLAUTH_BEARER;
if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
@ -558,7 +565,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
if(data->state.authproblem)
return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
if((conn->bits.user_passwd || conn->oauth_bearer) &&
if((conn->bits.user_passwd || data->set.str[STRING_BEARER]) &&
((data->req.httpcode == 401) ||
(conn->bits.authneg && data->req.httpcode < 300))) {
pickhost = pickoneauth(&data->state.authhost, authmask);
@ -634,9 +641,7 @@ output_auth_headers(struct connectdata *conn,
{
const char *auth = NULL;
CURLcode result = CURLE_OK;
#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO)
struct Curl_easy *data = conn->data;
#endif
#ifdef CURL_DISABLE_CRYPTO_AUTH
(void)request;
@ -644,7 +649,7 @@ output_auth_headers(struct connectdata *conn,
#endif
#ifdef USE_SPNEGO
if((authstatus->picked == CURLAUTH_NEGOTIATE)) {
if(authstatus->picked == CURLAUTH_NEGOTIATE) {
auth = "Negotiate";
result = Curl_output_negotiate(conn, proxy);
if(result)
@ -700,7 +705,7 @@ output_auth_headers(struct connectdata *conn,
}
if(authstatus->picked == CURLAUTH_BEARER) {
/* Bearer */
if((!proxy && conn->oauth_bearer &&
if((!proxy && data->set.str[STRING_BEARER] &&
!Curl_checkheaders(conn, "Authorization:"))) {
auth = "Bearer";
result = http_output_bearer(conn);
@ -758,7 +763,7 @@ Curl_http_output_auth(struct connectdata *conn,
authproxy = &data->state.authproxy;
if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
conn->bits.user_passwd || conn->oauth_bearer)
conn->bits.user_passwd || data->set.str[STRING_BEARER])
/* continue please */;
else {
authhost->done = TRUE;
@ -1136,10 +1141,14 @@ Curl_send_buffer *Curl_add_buffer_init(void)
*/
void Curl_add_buffer_free(Curl_send_buffer **inp)
{
Curl_send_buffer *in = *inp;
if(in) /* deal with NULL input */
Curl_send_buffer *in;
if(!inp)
return;
in = *inp;
if(in) { /* deal with NULL input */
free(in->buffer);
free(in);
free(in);
}
*inp = NULL;
}
@ -1497,11 +1506,9 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
interface and then we're always _sending_ a request and thus we wait for
the single socket to become writable only */
static int http_getsock_do(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
curl_socket_t *socks)
{
/* write mode */
(void)numsocks; /* unused, we trust it to be at least 1 */
socks[0] = conn->sock[FIRSTSOCKET];
return GETSOCK_WRITESOCK(0);
}
@ -1555,6 +1562,13 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
CURLcode result;
DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL));
#ifdef ENABLE_QUIC
if(conn->transport == TRNSPRT_QUIC) {
*done = TRUE;
return CURLE_OK;
}
#endif
/* perform SSL initialization for this socket */
result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
if(result)
@ -1564,11 +1578,10 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
}
static int https_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
curl_socket_t *socks)
{
if(conn->handler->flags & PROTOPT_SSL)
return Curl_ssl_getsock(conn, socks, numsocks);
return Curl_ssl_getsock(conn, socks);
return GETSOCK_BLANK;
}
#endif /* USE_SSL */
@ -1602,7 +1615,8 @@ CURLcode Curl_http_done(struct connectdata *conn,
Curl_add_buffer_free(&http->send_buffer);
}
Curl_http2_done(conn, premature);
Curl_http2_done(data, premature);
Curl_quic_done(data, premature);
Curl_mime_cleanpart(&http->form);
@ -1650,6 +1664,12 @@ static bool use_http_1_1plus(const struct Curl_easy *data,
static const char *get_http_string(const struct Curl_easy *data,
const struct connectdata *conn)
{
#ifdef ENABLE_QUIC
if((data->set.httpversion == CURL_HTTP_VERSION_3) ||
(conn->httpversion == 30))
return "3";
#endif
#ifdef USE_NGHTTP2
if(conn->proto.httpc.h2)
return "2";
@ -1669,8 +1689,8 @@ static CURLcode expect100(struct Curl_easy *data,
CURLcode result = CURLE_OK;
data->state.expect100header = FALSE; /* default to false unless it is set
to TRUE below */
if(use_http_1_1plus(data, conn) &&
(conn->httpversion != 20)) {
if(!data->state.disableexpect && use_http_1_1plus(data, conn) &&
(conn->httpversion < 20)) {
/* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
Expect: 100-continue to the headers which actually speeds up post
operations (as there is one packet coming back from the web server) */
@ -1700,7 +1720,7 @@ enum proxy_use {
will return an error code if one of the headers is
not formatted correctly */
CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
Curl_send_buffer *buffer,
Curl_send_buffer **buffer,
struct Curl_easy *handle)
{
char *ptr = NULL;
@ -1726,7 +1746,7 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
/* only add correctly formatted trailers */
ptr = strchr(trailers->data, ':');
if(ptr && *(ptr + 1) == ' ') {
result = Curl_add_bufferf(&buffer, "%s%s", trailers->data,
result = Curl_add_bufferf(buffer, "%s%s", trailers->data,
endofline_native);
if(result)
return result;
@ -1735,7 +1755,7 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
infof(handle, "Malformatted trailing header ! Skipping trailer.");
trailers = trailers->next;
}
result = Curl_add_buffer(&buffer, endofline_network,
result = Curl_add_buffer(buffer, endofline_network,
strlen(endofline_network));
return result;
}
@ -1851,7 +1871,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
Connection: */
checkprefix("Connection:", compare))
;
else if((conn->httpversion == 20) &&
else if((conn->httpversion >= 20) &&
checkprefix("Transfer-Encoding:", compare))
/* HTTP/2 doesn't support chunked requests */
;
@ -1881,9 +1901,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
}
#ifndef CURL_DISABLE_PARSEDATE
CURLcode Curl_add_timecondition(struct Curl_easy *data,
CURLcode Curl_add_timecondition(const struct connectdata *conn,
Curl_send_buffer *req_buffer)
{
struct Curl_easy *data = conn->data;
const struct tm *tm;
struct tm keeptime;
CURLcode result;
@ -1916,6 +1937,11 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
break;
}
if(Curl_checkheaders(conn, condp)) {
/* A custom header was specified; it will be sent instead. */
return CURLE_OK;
}
/* The If-Modified-Since header family should have their times set in
* GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
* represented in Greenwich Mean Time (GMT), without exception. For the
@ -1941,10 +1967,10 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
}
#else
/* disabled */
CURLcode Curl_add_timecondition(struct Curl_easy *data,
CURLcode Curl_add_timecondition(const struct connectdata *conn,
Curl_send_buffer *req_buffer)
{
(void)data;
(void)conn;
(void)req_buffer;
return CURLE_OK;
}
@ -1976,55 +2002,57 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
const char *httpstring;
Curl_send_buffer *req_buffer;
curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
char *altused = NULL;
/* Always consider the DO phase done after this function call, even if there
may be parts of the request that is not yet sent, since we can deal with
the rest of the request in the PERFORM phase. */
*done = TRUE;
if(conn->httpversion < 20) { /* unless the connection is re-used and already
http2 */
switch(conn->negnpn) {
case CURL_HTTP_VERSION_2:
conn->httpversion = 20; /* we know we're on HTTP/2 now */
result = Curl_http2_switched(conn, NULL, 0);
if(result)
return result;
break;
case CURL_HTTP_VERSION_1_1:
/* continue with HTTP/1.1 when explicitly requested */
break;
default:
/* Check if user wants to use HTTP/2 with clear TCP*/
#ifdef USE_NGHTTP2
if(conn->data->set.httpversion ==
CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
/* We don't support HTTP/2 proxies yet. Also it's debatable whether
or not this setting should apply to HTTP/2 proxies. */
infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n");
break;
}
DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
conn->httpversion = 20;
if(conn->transport != TRNSPRT_QUIC) {
if(conn->httpversion < 20) { /* unless the connection is re-used and
already http2 */
switch(conn->negnpn) {
case CURL_HTTP_VERSION_2:
conn->httpversion = 20; /* we know we're on HTTP/2 now */
result = Curl_http2_switched(conn, NULL, 0);
if(result)
return result;
}
break;
case CURL_HTTP_VERSION_1_1:
/* continue with HTTP/1.1 when explicitly requested */
break;
default:
/* Check if user wants to use HTTP/2 with clear TCP*/
#ifdef USE_NGHTTP2
if(conn->data->set.httpversion ==
CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
/* We don't support HTTP/2 proxies yet. Also it's debatable
whether or not this setting should apply to HTTP/2 proxies. */
infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n");
break;
}
DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
conn->httpversion = 20;
result = Curl_http2_switched(conn, NULL, 0);
if(result)
return result;
}
#endif
break;
break;
}
}
else {
/* prepare for a http2 request */
result = Curl_http2_setup(conn);
if(result)
return result;
}
}
else {
/* prepare for a http2 request */
result = Curl_http2_setup(conn);
if(result)
return result;
}
http = data->req.protop;
DEBUGASSERT(http);
@ -2220,14 +2248,16 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
else {
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
(((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) &&
http->postsize < 0) ||
(data->set.upload && data->state.infilesize == -1))) {
http->postsize < 0) ||
((data->set.upload || httpreq == HTTPREQ_POST) &&
data->state.infilesize == -1))) {
if(conn->bits.authneg)
/* don't enable chunked during auth neg */
;
else if(use_http_1_1plus(data, conn)) {
/* HTTP, upload, unknown file size and not HTTP 1.0 */
data->req.upload_chunky = TRUE;
if(conn->httpversion < 20)
/* HTTP, upload, unknown file size and not HTTP 1.0 */
data->req.upload_chunky = TRUE;
}
else {
failf(data, "Chunky upload is not supported by HTTP 1.0");
@ -2328,7 +2358,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* and no fragment part */
CURLUcode uc;
char *url;
CURLU *h = curl_url_dup(data->state.uh);
if(!h)
return CURLE_OUT_OF_MEMORY;
@ -2359,19 +2388,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return CURLE_OUT_OF_MEMORY;
}
}
/* now extract the new version of the URL */
uc = curl_url_get(h, CURLUPART_URL, &url, 0);
/* Extract the URL to use in the request. Store in STRING_TEMP_URL for
clean-up reasons if the function returns before the free() further
down. */
uc = curl_url_get(h, CURLUPART_URL, &data->set.str[STRING_TEMP_URL], 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
if(data->change.url_alloc)
free(data->change.url);
data->change.url = url;
data->change.url_alloc = TRUE;
curl_url_cleanup(h);
if(strcasecompare("ftp", data->state.up.scheme)) {
@ -2550,12 +2575,16 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
query = NULL;
}
#ifndef CURL_DISABLE_PROXY
/* url */
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
char *url = data->change.url;
char *url = data->set.str[STRING_TEMP_URL];
result = Curl_add_buffer(&req_buffer, url, strlen(url));
Curl_safefree(data->set.str[STRING_TEMP_URL]);
}
else if(paste_ftp_userpwd)
else
#endif
if(paste_ftp_userpwd)
result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s",
conn->user, conn->passwd,
path + sizeof("ftp://") - 1);
@ -2569,6 +2598,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(result)
return result;
#ifdef USE_ALTSVC
if(conn->bits.altused && !Curl_checkheaders(conn, "Alt-Used")) {
altused = aprintf("Alt-Used: %s:%d\r\n",
conn->conn_to_host.name, conn->conn_to_port);
if(!altused)
return CURLE_OUT_OF_MEMORY;
}
#endif
result =
Curl_add_bufferf(&req_buffer,
"%s" /* ftp typecode (;type=x) */
@ -2583,7 +2620,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
"%s" /* accept-encoding */
"%s" /* referer */
"%s" /* Proxy-Connection */
"%s",/* transfer-encoding */
"%s" /* transfer-encoding */
"%s",/* Alt-Used */
ftp_typecode,
httpstring,
@ -2609,13 +2647,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
!conn->bits.tunnel_proxy &&
!Curl_checkProxyheaders(conn, "Proxy-Connection"))?
"Proxy-Connection: Keep-Alive\r\n":"",
te
te,
altused ? altused : ""
);
/* clear userpwd and proxyuserpwd to avoid re-using old credentials
* from re-used connections */
Curl_safefree(conn->allocptr.userpwd);
Curl_safefree(conn->allocptr.proxyuserpwd);
free(altused);
if(result)
return result;
@ -2635,7 +2675,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
struct Cookie *co = NULL; /* no cookies from start */
int count = 0;
if(data->cookies) {
if(data->cookies && data->state.cookie_engine) {
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
co = Curl_cookie_getlist(data->cookies,
conn->allocptr.cookiehost?
@ -2683,7 +2723,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
#endif
result = Curl_add_timecondition(data, req_buffer);
result = Curl_add_timecondition(conn, req_buffer);
if(result)
return result;
@ -3000,11 +3040,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
failf(data, "Failed sending HTTP request");
else
/* HTTP GET/HEAD download: */
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
http->postdata?FIRSTSOCKET:-1);
Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
}
if(result)
return result;
if(!postsize)
data->req.upload_done = TRUE;
if(data->req.writebytecount) {
/* if a request-body has been sent off, we make sure this progress is noted
@ -3147,6 +3188,9 @@ static CURLcode header_append(struct Curl_easy *data,
struct SingleRequest *k,
size_t length)
{
/* length is at most the size of a full read buffer, for which the upper
bound is CURL_MAX_READ_SIZE. There is thus no chance of overflow in this
calculation. */
size_t newsize = k->hbuflen + length;
if(newsize > CURL_MAX_HTTP_HEADER) {
/* The reason to have a max limit for this is to avoid the risk of a bad
@ -3501,7 +3545,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
*/
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
if(!k->upload_done) {
if(data->set.http_keep_sending_on_error) {
if((k->httpcode == 417) && data->state.expect100header) {
/* 417 Expectation Failed - try again without the Expect
header */
infof(data, "Got 417 while waiting for a 100\n");
data->state.disableexpect = TRUE;
DEBUGASSERT(!data->req.newurl);
data->req.newurl = strdup(conn->data->change.url);
Curl_done_sending(conn, k);
}
else if(data->set.http_keep_sending_on_error) {
infof(data, "HTTP error before end of send, keep sending\n");
if(k->exp100 > EXP100_SEND_DATA) {
k->exp100 = EXP100_SEND_DATA;
@ -3511,8 +3564,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
else {
infof(data, "HTTP error before end of send, stop sending\n");
streamclose(conn, "Stop sending data before everything sent");
result = Curl_done_sending(conn, k);
if(result)
return result;
k->upload_done = TRUE;
k->keepon &= ~KEEP_SEND; /* don't send */
if(data->state.expect100header)
k->exp100 = EXP100_FAILED;
}
@ -3649,6 +3704,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* guarantees on future behaviors since it isn't within the protocol.
*/
char separator;
char twoorthree[2];
nc = sscanf(HEADER1,
" HTTP/%1d.%1d%c%3d",
&httpversion_major,
@ -3656,8 +3712,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
&separator,
&k->httpcode);
if(nc == 1 && httpversion_major == 2 &&
1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) {
if(nc == 1 && httpversion_major >= 2 &&
2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) {
conn->httpversion = 0;
nc = 4;
separator = ' ';
@ -3695,7 +3751,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
else {
failf(data, "Unsupported HTTP version in response\n");
failf(data, "Unsupported HTTP version in response");
return CURLE_UNSUPPORTED_PROTOCOL;
}
}
@ -3769,6 +3825,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
"HTTP 1.1 or later with persistent connection\n"));
}
k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
switch(k->httpcode) {
case 304:
/* (quote from RFC2616, section 10.3.5): The 304 response
@ -3786,10 +3843,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* empty line after the header fields. */
k->size = 0;
k->maxdownload = 0;
k->ignorecl = TRUE; /* ignore Content-Length headers */
k->http_bodyless = TRUE;
break;
default:
/* nothing */
break;
}
}
@ -3805,8 +3861,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
return result;
/* Check for Content-Length: header lines to get size */
if(!k->ignorecl && !data->set.ignorecl &&
checkprefix("Content-Length:", k->p)) {
if(!k->http_bodyless &&
!data->set.ignorecl && checkprefix("Content-Length:", k->p)) {
curl_off_t contentlength;
CURLofft offt = curlx_strtoofft(k->p + 15, NULL, 10, &contentlength);
@ -3895,7 +3951,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
*/
streamclose(conn, "Connection: close used");
}
else if(checkprefix("Transfer-Encoding:", k->p)) {
else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", k->p)) {
/* One or more encodings. We check for chunked and/or a compression
algorithm. */
/*
@ -3911,7 +3967,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(result)
return result;
}
else if(checkprefix("Content-Encoding:", k->p) &&
else if(!k->http_bodyless && checkprefix("Content-Encoding:", k->p) &&
data->set.str[STRING_ENCODING]) {
/*
* Process Content-Encoding. Look for the values: identity,
@ -3924,7 +3980,20 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(result)
return result;
}
else if(checkprefix("Content-Range:", k->p)) {
else if(checkprefix("Retry-After:", k->p)) {
/* Retry-After = HTTP-date / delay-seconds */
curl_off_t retry_after = 0; /* zero for unknown or "now" */
time_t date = Curl_getdate_capped(&k->p[12]);
if(-1 == date) {
/* not a date, try it as a decimal number */
(void)curlx_strtoofft(&k->p[12], NULL, 10, &retry_after);
}
else
/* convert date to number of seconds into the future */
retry_after = date - time(NULL);
data->info.retry_after = retry_after; /* store it */
}
else if(!k->http_bodyless && checkprefix("Content-Range:", k->p)) {
/* Content-Range: bytes [num]-
Content-Range: bytes: [num]-
Content-Range: [num]-
@ -3954,7 +4023,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
data->state.resume_from = 0; /* get everything */
}
#if !defined(CURL_DISABLE_COOKIES)
else if(data->cookies &&
else if(data->cookies && data->state.cookie_engine &&
checkprefix("Set-Cookie:", k->p)) {
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
CURL_LOCK_ACCESS_SINGLE);
@ -3970,11 +4039,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
#endif
else if(checkprefix("Last-Modified:", k->p) &&
else if(!k->http_bodyless && checkprefix("Last-Modified:", k->p) &&
(data->set.timecondition || data->set.get_filetime) ) {
time_t secs = time(NULL);
k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"),
&secs);
k->timeofdoc = Curl_getdate_capped(k->p + strlen("Last-Modified:"));
if(data->set.get_filetime)
data->info.filetime = k->timeofdoc;
}
@ -3995,7 +4062,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(result)
return result;
}
#ifdef USE_SPNEGO
#ifdef USE_SPNEGO
else if(checkprefix("Persistent-Auth", k->p)) {
struct negotiatedata *negdata = &conn->negotiate;
struct auth *authp = &data->state.authhost;
@ -4003,14 +4070,15 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
char *persistentauth = Curl_copy_header_value(k->p);
if(!persistentauth)
return CURLE_OUT_OF_MEMORY;
negdata->noauthpersist = checkprefix("false", persistentauth);
negdata->noauthpersist = checkprefix("false", persistentauth)?
TRUE:FALSE;
negdata->havenoauthpersist = TRUE;
infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
negdata->noauthpersist, persistentauth);
free(persistentauth);
}
}
#endif
#endif
else if((k->httpcode >= 300 && k->httpcode < 400) &&
checkprefix("Location:", k->p) &&
!data->req.location) {

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -69,32 +69,24 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
size_t included_body_bytes,
int socketindex);
CURLcode Curl_add_timecondition(struct Curl_easy *data,
CURLcode Curl_add_timecondition(const struct connectdata *conn,
Curl_send_buffer *buf);
CURLcode Curl_add_custom_headers(struct connectdata *conn,
bool is_connect,
Curl_send_buffer *req_buffer);
CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
Curl_send_buffer *buffer,
Curl_send_buffer **buffer,
struct Curl_easy *handle);
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http(struct connectdata *conn, bool *done);
CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature);
CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
CURLcode Curl_http_setup_conn(struct connectdata *conn);
/* The following functions are defined in http_chunks.c */
void Curl_httpchunk_init(struct connectdata *conn);
CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
ssize_t length, ssize_t *wrote);
/* These functions are in http.c */
void Curl_http_auth_stage(struct Curl_easy *data, int stage);
CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
const char *auth);
CURLcode Curl_http_auth_act(struct connectdata *conn);
CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
/* If only the PICKNONE bit is set, there has been a round-trip and we
selected to use no auth at all. Ie, we actively select no auth, as opposed
@ -124,11 +116,15 @@ CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
*
*/
#ifndef EXPECT_100_THRESHOLD
#define EXPECT_100_THRESHOLD 1024
#define EXPECT_100_THRESHOLD (1024*1024)
#endif
#endif /* CURL_DISABLE_HTTP */
#ifdef USE_NGHTTP3
struct h3out; /* see ngtcp2 */
#endif
/****************************************************************************
* HTTP unique setup
***************************************************************************/
@ -175,20 +171,40 @@ struct HTTP {
int status_code; /* HTTP status code */
const uint8_t *pausedata; /* pointer to data received in on_data_chunk */
size_t pauselen; /* the number of bytes left in data */
bool closed; /* TRUE on HTTP2 stream close */
bool close_handled; /* TRUE if stream closure is handled by libcurl */
char *mem; /* points to a buffer in memory to store received data */
size_t len; /* size of the buffer 'mem' points to */
size_t memlen; /* size of data copied to mem */
const uint8_t *upload_mem; /* points to a buffer to read from */
size_t upload_len; /* size of the buffer 'upload_mem' points to */
curl_off_t upload_left; /* number of bytes left to upload */
char **push_headers; /* allocated array */
size_t push_headers_used; /* number of entries filled in */
size_t push_headers_alloc; /* number of entries allocated */
#endif
#if defined(USE_NGHTTP2) || defined(USE_NGHTTP3)
bool closed; /* TRUE on HTTP2 stream close */
char *mem; /* points to a buffer in memory to store received data */
size_t len; /* size of the buffer 'mem' points to */
size_t memlen; /* size of data copied to mem */
#endif
#if defined(USE_NGHTTP2) || defined(ENABLE_QUIC)
/* fields used by both HTTP/2 and HTTP/3 */
const uint8_t *upload_mem; /* points to a buffer to read from */
size_t upload_len; /* size of the buffer 'upload_mem' points to */
curl_off_t upload_left; /* number of bytes left to upload */
#endif
#ifdef ENABLE_QUIC
/*********** for HTTP/3 we store stream-local data here *************/
int64_t stream3_id; /* stream we are interested in */
bool firstheader; /* FALSE until headers arrive */
bool firstbody; /* FALSE until body arrives */
bool h3req; /* FALSE until request is issued */
bool upload_done;
#endif
#ifdef USE_NGHTTP3
size_t unacked_window;
struct h3out *h3out; /* per-stream buffers for upload */
char *overflow_buf; /* excess data received during a single Curl_read */
size_t overflow_buflen; /* amount of data currently in overflow_buf */
size_t overflow_bufsize; /* size of the overflow_buf allocation */
#endif
};
#ifdef USE_NGHTTP2

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -43,19 +43,11 @@
#define H2_BUFSIZE 32768
#if (NGHTTP2_VERSION_NUM < 0x010000)
#if (NGHTTP2_VERSION_NUM < 0x010c00)
#error too old nghttp2 version, upgrade!
#endif
#if (NGHTTP2_VERSION_NUM > 0x010800)
#define NGHTTP2_HAS_HTTP2_STRERROR 1
#endif
#if (NGHTTP2_VERSION_NUM >= 0x010900)
/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or
later */
#define NGHTTP2_HAS_ERROR_CALLBACK 1
#else
#ifdef CURL_DISABLE_VERBOSE_STRINGS
#define nghttp2_session_callbacks_set_error_callback(x,y)
#endif
@ -63,12 +55,12 @@
#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
#endif
#define HTTP2_HUGE_WINDOW_SIZE (1 << 30)
#define HTTP2_HUGE_WINDOW_SIZE (32 * 1024 * 1024) /* 32 MB */
#ifdef DEBUG_HTTP2
#define H2BUGF(x) x
#else
#define H2BUGF(x) do { } WHILE_FALSE
#define H2BUGF(x) do { } while(0)
#endif
@ -100,16 +92,11 @@ void Curl_http2_init_userset(struct UserDefined *set)
}
static int http2_perform_getsock(const struct connectdata *conn,
curl_socket_t *sock, /* points to
numsocks
number of
sockets */
int numsocks)
curl_socket_t *sock)
{
const struct http_conn *c = &conn->proto.httpc;
struct SingleRequest *k = &conn->data->req;
int bitmap = GETSOCK_BLANK;
(void)numsocks;
sock[0] = conn->sock[FIRSTSOCKET];
@ -126,11 +113,9 @@ static int http2_perform_getsock(const struct connectdata *conn,
}
static int http2_getsock(struct connectdata *conn,
curl_socket_t *sock, /* points to numsocks
number of sockets */
int numsocks)
curl_socket_t *socks)
{
return http2_perform_getsock(conn, sock, numsocks);
return http2_perform_getsock(conn, socks);
}
/*
@ -240,7 +225,7 @@ static unsigned int http2_conncheck(struct connectdata *check,
if(checks_to_perform & CONNCHECK_KEEPALIVE) {
struct curltime now = Curl_now();
time_t elapsed = Curl_timediff(now, check->keepalive);
timediff_t elapsed = Curl_timediff(now, check->keepalive);
if(elapsed > check->upkeep_interval_ms) {
/* Perform an HTTP/2 PING */
@ -269,7 +254,7 @@ static unsigned int http2_conncheck(struct connectdata *check,
return ret_val;
}
/* called from Curl_http_setup_conn */
/* called from http_setup_conn */
void Curl_http2_setup_req(struct Curl_easy *data)
{
struct HTTP *http = data->req.protop;
@ -286,7 +271,7 @@ void Curl_http2_setup_req(struct Curl_easy *data)
http->memlen = 0;
}
/* called from Curl_http_setup_conn */
/* called from http_setup_conn */
void Curl_http2_setup_conn(struct connectdata *conn)
{
conn->proto.httpc.settings.max_concurrent_streams =
@ -351,35 +336,6 @@ int Curl_http2_ver(char *p, size_t len)
return msnprintf(p, len, " nghttp2/%s", h2->version_str);
}
/* HTTP/2 error code to name based on the Error Code Registry.
https://tools.ietf.org/html/rfc7540#page-77
nghttp2_error_code enums are identical.
*/
static const char *http2_strerror(uint32_t err)
{
#ifndef NGHTTP2_HAS_HTTP2_STRERROR
const char *str[] = {
"NO_ERROR", /* 0x0 */
"PROTOCOL_ERROR", /* 0x1 */
"INTERNAL_ERROR", /* 0x2 */
"FLOW_CONTROL_ERROR", /* 0x3 */
"SETTINGS_TIMEOUT", /* 0x4 */
"STREAM_CLOSED", /* 0x5 */
"FRAME_SIZE_ERROR", /* 0x6 */
"REFUSED_STREAM", /* 0x7 */
"CANCEL", /* 0x8 */
"COMPRESSION_ERROR", /* 0x9 */
"CONNECT_ERROR", /* 0xA */
"ENHANCE_YOUR_CALM", /* 0xB */
"INADEQUATE_SECURITY", /* 0xC */
"HTTP_1_1_REQUIRED" /* 0xD */
};
return (err < sizeof(str) / sizeof(str[0])) ? str[err] : "unknown";
#else
return nghttp2_http2_strerror(err);
#endif
}
/*
* The implementation of nghttp2_send_callback type. Here we write |data| with
* size |length| to the network and return the number of bytes actually
@ -503,16 +459,14 @@ static struct Curl_easy *duphandle(struct Curl_easy *data)
/* setup the request struct */
struct HTTP *http = calloc(1, sizeof(struct HTTP));
if(!http) {
(void)Curl_close(second);
second = NULL;
(void)Curl_close(&second);
}
else {
second->req.protop = http;
http->header_recvbuf = Curl_add_buffer_init();
if(!http->header_recvbuf) {
free(http);
(void)Curl_close(second);
second = NULL;
(void)Curl_close(&second);
}
else {
Curl_http2_setup_req(second);
@ -554,7 +508,7 @@ static int push_promise(struct Curl_easy *data,
stream = data->req.protop;
if(!stream) {
failf(data, "Internal NULL stream!\n");
(void)Curl_close(newhandle);
(void)Curl_close(&newhandle);
rv = 1;
goto fail;
}
@ -576,7 +530,7 @@ static int push_promise(struct Curl_easy *data,
/* denied, kill off the new handle again */
http2_stream_free(newhandle->req.protop);
newhandle->req.protop = NULL;
(void)Curl_close(newhandle);
(void)Curl_close(&newhandle);
goto fail;
}
@ -592,7 +546,7 @@ static int push_promise(struct Curl_easy *data,
infof(data, "failed to add handle to multi\n");
http2_stream_free(newhandle->req.protop);
newhandle->req.protop = NULL;
Curl_close(newhandle);
Curl_close(&newhandle);
rv = 1;
goto fail;
}
@ -847,7 +801,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
return 0;
}
H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
http2_strerror(error_code), error_code, stream_id));
nghttp2_strerror(error_code), error_code, stream_id));
stream = data_s->req.protop;
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
@ -855,6 +809,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
stream->closed = TRUE;
httpc = &conn->proto.httpc;
drain_this(data_s, httpc);
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
httpc->error_code = error_code;
/* remove the entry from the hash as the stream is now gone */
@ -974,7 +929,9 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(!check)
/* no memory */
return NGHTTP2_ERR_CALLBACK_FAILURE;
if(!Curl_strcasecompare(check, (const char *)value)) {
if(!Curl_strcasecompare(check, (const char *)value) &&
((conn->remote_port != conn->given->defport) ||
!Curl_strcasecompare(conn->host.name, (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
@ -1144,8 +1101,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
return nread;
}
#if defined(NGHTTP2_HAS_ERROR_CALLBACK) && \
!defined(CURL_DISABLE_VERBOSE_STRINGS)
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
static int error_callback(nghttp2_session *session,
const char *msg,
size_t len,
@ -1162,9 +1118,10 @@ static void populate_settings(struct connectdata *conn,
struct http_conn *httpc)
{
nghttp2_settings_entry *iv = httpc->local_settings;
DEBUGASSERT(conn->data);
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[0].value = 100;
iv[0].value = Curl_multi_max_concurrent_streams(conn->data->multi);
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
iv[1].value = HTTP2_HUGE_WINDOW_SIZE;
@ -1175,11 +1132,10 @@ static void populate_settings(struct connectdata *conn,
httpc->local_settings_num = 3;
}
void Curl_http2_done(struct connectdata *conn, bool premature)
void Curl_http2_done(struct Curl_easy *data, bool premature)
{
struct Curl_easy *data = conn->data;
struct HTTP *http = data->req.protop;
struct http_conn *httpc = &conn->proto.httpc;
struct http_conn *httpc = &data->conn->proto.httpc;
/* there might be allocated resources done before this got the 'h2' pointer
setup */
@ -1199,9 +1155,6 @@ void Curl_http2_done(struct connectdata *conn, bool premature)
if(!httpc->h2) /* not HTTP/2 ? */
return;
if(data->state.drain)
drained_transfer(data, httpc);
if(premature) {
/* RST_STREAM */
if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
@ -1213,6 +1166,10 @@ void Curl_http2_done(struct connectdata *conn, bool premature)
httpc->pause_stream_id = 0;
}
}
if(data->state.drain)
drained_transfer(data, httpc);
/* -1 means unassigned and 0 means cleared */
if(http->stream_id > 0) {
int rv = nghttp2_session_set_stream_user_data(httpc->h2,
@ -1263,9 +1220,7 @@ static CURLcode http2_init(struct connectdata *conn)
/* nghttp2_on_header_callback */
nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
#endif
/* The nghttp2 session is not yet setup, do it */
rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
@ -1463,7 +1418,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
}
else if(httpc->error_code != NGHTTP2_NO_ERROR) {
failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)",
stream->stream_id, http2_strerror(httpc->error_code),
stream->stream_id, nghttp2_strerror(httpc->error_code),
httpc->error_code);
*err = CURLE_HTTP2_STREAM;
return -1;
@ -1541,6 +1496,7 @@ static int h2_session_send(struct Curl_easy *data,
H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
stream->stream_id, data));
DEBUGASSERT(stream->stream_id != -1);
rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
&pri_spec);
if(rv)
@ -1565,6 +1521,11 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
if(should_close_session(httpc)) {
H2BUGF(infof(data,
"http2_recv: nothing to do in this session\n"));
if(conn->bits.close) {
/* already marked for closure, return OK and we're done */
*err = CURLE_OK;
return 0;
}
*err = CURLE_HTTP2;
return -1;
}
@ -1594,8 +1555,12 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
return ncopy;
}
H2BUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
data, stream->stream_id));
H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u\n",
data, stream->stream_id,
nghttp2_session_get_local_window_size(httpc->h2),
nghttp2_session_get_stream_local_window_size(httpc->h2,
stream->stream_id)
));
if((data->state.drain) && stream->memlen) {
H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
@ -1626,7 +1591,6 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
stream->pausedata += nread;
stream->pauselen -= nread;
infof(data, "%zd data bytes written\n", nread);
if(stream->pauselen == 0) {
H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
@ -1660,6 +1624,9 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
socket is not read. But it seems that usually streams are
notified with its drain property, and socket is read again
quickly. */
if(stream->closed)
/* closed overrides paused */
return 0;
H2BUGF(infof(data, "stream %x is paused, pause id: %x\n",
stream->stream_id, httpc->pause_stream_id));
*err = CURLE_AGAIN;
@ -1754,14 +1721,16 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
else if(!stream->closed) {
drained_transfer(data, httpc);
}
else
/* this stream is closed, trigger a another read ASAP to detect that */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
return retlen;
}
/* If stream is closed, return 0 to signal the http routine to close
/* If this stream is closed, return 0 to signal the http routine to close
the connection */
if(stream->closed) {
return http2_handle_stream_close(conn, data, stream, err);
}
if(stream->closed)
return 0;
*err = CURLE_AGAIN;
H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
stream->stream_id));
@ -1772,8 +1741,9 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
field list. */
#define AUTHORITY_DST_IDX 3
/* USHRT_MAX is 65535 == 0xffff */
#define HEADER_OVERFLOW(x) \
(x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen)
(x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen)
/*
* Check header memory for the token "trailers".
@ -1880,7 +1850,11 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
are going to send or sending request body in DATA frame */
stream->upload_mem = mem;
stream->upload_len = len;
nghttp2_session_resume_data(h2, stream->stream_id);
rv = nghttp2_session_resume_data(h2, stream->stream_id);
if(nghttp2_is_fatal(rv)) {
*err = CURLE_SEND_ERROR;
return -1;
}
rv = h2_session_send(conn->data, h2);
if(nghttp2_is_fatal(rv)) {
*err = CURLE_SEND_ERROR;
@ -2019,8 +1993,10 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
nva[i].namelen = strlen((char *)nva[i].name);
}
else {
nva[i].name = (unsigned char *)hdbuf;
nva[i].namelen = (size_t)(end - hdbuf);
/* Lower case the header name for HTTP/2 */
Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
nva[i].name = (unsigned char *)hdbuf;
}
hdbuf = end + 1;
while(*hdbuf == ' ' || *hdbuf == '\t')
@ -2130,17 +2106,14 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
return -1;
}
if(stream->stream_id != -1) {
/* If whole HEADERS frame was sent off to the underlying socket,
the nghttp2 library calls data_source_read_callback. But only
it found that no data available, so it deferred the DATA
transmission. Which means that nghttp2_session_want_write()
returns 0 on http2_perform_getsock(), which results that no
writable socket check is performed. To workaround this, we
issue nghttp2_session_resume_data() here to bring back DATA
transmission from deferred state. */
nghttp2_session_resume_data(h2, stream->stream_id);
}
/* If whole HEADERS frame was sent off to the underlying socket, the nghttp2
library calls data_source_read_callback. But only it found that no data
available, so it deferred the DATA transmission. Which means that
nghttp2_session_want_write() returns 0 on http2_perform_getsock(), which
results that no writable socket check is performed. To workaround this,
we issue nghttp2_session_resume_data() here to bring back DATA
transmission from deferred state. */
nghttp2_session_resume_data(h2, stream->stream_id);
return len;
@ -2255,7 +2228,6 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
}
}
#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
HTTP2_HUGE_WINDOW_SIZE);
if(rv != 0) {
@ -2263,7 +2235,6 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
nghttp2_strerror(rv), rv);
return CURLE_HTTP2;
}
#endif
/* we are going to copy mem to httpc->inbuf. This is required since
mem is part of buffer pointed by stream->mem, and callbacks
@ -2321,6 +2292,51 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
return CURLE_OK;
}
CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
{
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
/* if it isn't HTTP/2, we're done */
if(!data->conn->proto.httpc.h2)
return CURLE_OK;
#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
else {
struct HTTP *stream = data->req.protop;
struct http_conn *httpc = &data->conn->proto.httpc;
uint32_t window = !pause * HTTP2_HUGE_WINDOW_SIZE;
int rv = nghttp2_session_set_local_window_size(httpc->h2,
NGHTTP2_FLAG_NONE,
stream->stream_id,
window);
if(rv) {
failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
nghttp2_strerror(rv), rv);
return CURLE_HTTP2;
}
/* make sure the window update gets sent */
rv = h2_session_send(data, httpc->h2);
if(rv)
return CURLE_SEND_ERROR;
DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u\n",
window, stream->stream_id));
#ifdef DEBUGBUILD
{
/* read out the stream local window again */
uint32_t window2 =
nghttp2_session_get_stream_local_window_size(httpc->h2,
stream->stream_id);
DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u\n",
window2, stream->stream_id));
}
#endif
}
#endif
return CURLE_OK;
}
CURLcode Curl_http2_add_child(struct Curl_easy *parent,
struct Curl_easy *child,
bool exclusive)
@ -2414,8 +2430,6 @@ bool Curl_h2_http_1_1_error(struct connectdata *conn)
#else /* !USE_NGHTTP2 */
/* Satisfy external references even if http2 is not compiled in. */
#define CURL_DISABLE_TYPECHECK
#include <curl/curl.h>
char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2020, 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
@ -42,16 +42,15 @@ const char *Curl_http2_strerror(uint32_t err);
CURLcode Curl_http2_init(struct connectdata *conn);
void Curl_http2_init_state(struct UrlState *state);
void Curl_http2_init_userset(struct UserDefined *set);
CURLcode Curl_http2_send_request(struct connectdata *conn);
CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
struct connectdata *conn);
CURLcode Curl_http2_setup(struct connectdata *conn);
CURLcode Curl_http2_switched(struct connectdata *conn,
const char *data, size_t nread);
/* called from Curl_http_setup_conn */
/* called from http_setup_conn */
void Curl_http2_setup_conn(struct connectdata *conn);
void Curl_http2_setup_req(struct Curl_easy *data);
void Curl_http2_done(struct connectdata *conn, bool premature);
void Curl_http2_done(struct Curl_easy *data, bool premature);
CURLcode Curl_http2_done_sending(struct connectdata *conn);
CURLcode Curl_http2_add_child(struct Curl_easy *parent,
struct Curl_easy *child,
@ -59,11 +58,11 @@ CURLcode Curl_http2_add_child(struct Curl_easy *parent,
void Curl_http2_remove_child(struct Curl_easy *parent,
struct Curl_easy *child);
void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause);
/* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */
bool Curl_h2_http_1_1_error(struct connectdata *conn);
#else /* USE_NGHTTP2 */
#define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL
@ -76,6 +75,7 @@ bool Curl_h2_http_1_1_error(struct connectdata *conn);
#define Curl_http2_add_child(x, y, z)
#define Curl_http2_remove_child(x, y)
#define Curl_http2_cleanup_dependencies(x)
#define Curl_http2_stream_pause(x, y)
#define Curl_h2_http_1_1_error(x) 0
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -109,7 +109,8 @@ void Curl_httpchunk_init(struct connectdata *conn)
CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
char *datap,
ssize_t datalen,
ssize_t *wrotep)
ssize_t *wrotep,
CURLcode *extrap)
{
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
@ -125,8 +126,10 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
chunk read process, to properly calculate the content length*/
if(data->set.http_te_skip && !k->ignorebody) {
result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, datalen);
if(result)
return CHUNKE_WRITE_ERROR;
if(result) {
*extrap = result;
return CHUNKE_PASSTHRU_ERROR;
}
}
while(length) {
@ -197,8 +200,10 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
else
result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece);
if(result)
return CHUNKE_WRITE_ERROR;
if(result) {
*extrap = result;
return CHUNKE_PASSTHRU_ERROR;
}
}
*wrote += piece;
@ -244,8 +249,10 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
if(!data->set.http_te_skip) {
result = Curl_client_write(conn, CLIENTWRITE_HEADER,
conn->trailer, conn->trlPos);
if(result)
return CHUNKE_WRITE_ERROR;
if(result) {
*extrap = result;
return CHUNKE_PASSTHRU_ERROR;
}
}
conn->trlPos = 0;
ch->state = CHUNK_TRAILER_CR;
@ -339,8 +346,9 @@ const char *Curl_chunked_strerror(CHUNKcode code)
return "Illegal or missing hexadecimal sequence";
case CHUNKE_BAD_CHUNK:
return "Malformed encoding found";
case CHUNKE_WRITE_ERROR:
return "Write error";
case CHUNKE_PASSTHRU_ERROR:
DEBUGASSERT(0); /* never used */
return "";
case CHUNKE_BAD_ENCODING:
return "Bad content-encoding found";
case CHUNKE_OUT_OF_MEMORY:

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2019, 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
@ -21,6 +21,9 @@
* KIND, either express or implied.
*
***************************************************************************/
struct connectdata;
/*
* The longest possible hexadecimal number we support in a chunked transfer.
* Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
@ -71,9 +74,9 @@ typedef enum {
CHUNKE_TOO_LONG_HEX = 1,
CHUNKE_ILLEGAL_HEX,
CHUNKE_BAD_CHUNK,
CHUNKE_WRITE_ERROR,
CHUNKE_BAD_ENCODING,
CHUNKE_OUT_OF_MEMORY,
CHUNKE_PASSTHRU_ERROR, /* Curl_httpchunk_read() returns a CURLcode to use */
CHUNKE_LAST
} CHUNKcode;
@ -87,4 +90,10 @@ struct Curl_chunker {
size_t dataleft; /* untouched data amount at the end of the last buffer */
};
/* The following functions are defined in http_chunks.c */
void Curl_httpchunk_init(struct connectdata *conn);
CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
ssize_t length, ssize_t *wrote,
CURLcode *passthru);
#endif /* HEADER_CURL_HTTP_CHUNKS_H */

View File

@ -148,10 +148,10 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
}
if(!neg_ctx->context) {
result = Curl_input_negotiate(conn, proxy, "Negotiate");
if(result == CURLE_LOGIN_DENIED) {
if(result == CURLE_AUTH_ERROR) {
/* negotiate auth failed, let's continue unauthenticated to stay
* compatible with the behavior before curl-7_64_0-158-g6c6035532 */
conn->data->state.authproblem = TRUE;
authp->done = TRUE;
return CURLE_OK;
}
else if(result)

View File

@ -44,9 +44,7 @@
/* SSL backend-specific #if branches in this file must be kept in the order
documented in curl_ntlm_core. */
#if defined(NTLM_NEEDS_NSS_INIT)
#include "vtls/nssg.h"
#elif defined(USE_WINDOWS_SSPI)
#if defined(USE_WINDOWS_SSPI)
#include "curl_sspi.h"
#endif
@ -137,11 +135,6 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
DEBUGASSERT(conn);
DEBUGASSERT(conn->data);
#if defined(NTLM_NEEDS_NSS_INIT)
if(CURLE_OK != Curl_nss_force_init(conn->data))
return CURLE_OUT_OF_MEMORY;
#endif
if(proxy) {
allocuserpwd = &conn->allocptr.proxyuserpwd;
userp = conn->http_proxy.user;

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