From 93cc249f3dd7ecd621cd063e4c08bbdb54d971e8 Mon Sep 17 00:00:00 2001 From: Curl Upstream Date: Wed, 2 Nov 2016 07:34:06 +0100 Subject: curl 2016-11-02 (3c561c65) Code extracted from: https://github.com/curl/curl.git at commit 3c561c657c2f0e553b19115a506592a8bbd744bc (curl-7_51_0). --- CMake/CurlSymbolHiding.cmake | 61 +++++++++ CMake/FindNGHTTP2.cmake | 18 +++ CMakeLists.txt | 98 +++++++------- include/curl/curl.h | 11 +- include/curl/curlver.h | 8 +- lib/CMakeLists.txt | 5 + lib/Makefile.inc | 8 +- lib/amigaos.c | 2 +- lib/base64.c | 5 + lib/conncache.c | 1 - lib/connect.c | 33 ++--- lib/connect.h | 40 ++++-- lib/cookie.c | 128 +++++++++++++------ lib/cookie.h | 4 +- lib/curl_config.h.cmake | 11 +- lib/curl_ntlm_core.c | 37 +++++- lib/curl_sasl.c | 12 +- lib/curl_setup.h | 24 +++- lib/curl_sspi.c | 20 ++- lib/curlx.h | 13 +- lib/dict.c | 25 ++-- lib/easy.c | 40 ++---- lib/escape.c | 34 +++-- lib/file.c | 11 +- lib/formdata.c | 62 +++++---- lib/formdata.h | 1 + lib/ftp.c | 107 ++++++++-------- lib/ftp.h | 4 +- lib/ftplistparser.c | 3 +- lib/getenv.c | 3 +- lib/getinfo.c | 19 ++- lib/gopher.c | 37 +++--- lib/hostcheck.c | 14 +- lib/hostip.c | 7 +- lib/http.c | 282 ++++++++++++++++++++++------------------- lib/http.h | 1 + lib/http2.c | 172 +++++++++++++++++-------- lib/http2.h | 6 +- lib/http_digest.c | 2 +- lib/http_negotiate.c | 1 - lib/http_ntlm.c | 2 +- lib/http_proxy.c | 18 ++- lib/if2ip.c | 8 +- lib/imap.c | 25 ++-- lib/krb5.c | 12 +- lib/ldap.c | 59 +++++---- lib/libcurl.rc | 6 +- lib/md5.c | 2 +- lib/mprintf.c | 26 ++-- lib/multi.c | 281 ++++++++++++++++++++++------------------ lib/multiif.h | 1 + lib/netrc.c | 18 ++- lib/parsedate.c | 20 +-- lib/pingpong.c | 3 +- lib/pipeline.c | 12 +- lib/pop3.c | 10 +- lib/progress.c | 75 +++++++++++ lib/progress.h | 6 +- lib/rawstr.c | 148 --------------------- lib/rawstr.h | 47 ------- lib/rtsp.c | 22 ++-- lib/security.c | 13 +- lib/select.c | 35 ++--- lib/select.h | 9 +- lib/smb.c | 10 +- lib/smtp.c | 8 +- lib/socks.c | 132 ++++++++++--------- lib/ssh.c | 55 ++++---- lib/strcase.c | 166 ++++++++++++++++++++++++ lib/strcase.h | 50 ++++++++ lib/strdup.c | 4 +- lib/strdup.h | 4 +- lib/strequal.c | 79 ------------ lib/strequal.h | 31 ----- lib/strerror.c | 87 +------------ lib/strerror.h | 4 +- lib/system_win32.c | 39 +++++- lib/telnet.c | 13 +- lib/tftp.c | 31 +++-- lib/transfer.c | 103 +++++---------- lib/transfer.h | 8 +- lib/url.c | 243 +++++++++++++++-------------------- lib/urldata.h | 15 ++- lib/vauth/cleartext.c | 2 - lib/vauth/digest.c | 48 ++++--- lib/vauth/digest_sspi.c | 25 +++- lib/vauth/krb5_gssapi.c | 14 ++ lib/vauth/krb5_sspi.c | 22 ++++ lib/vauth/ntlm.c | 14 ++ lib/vauth/ntlm_sspi.c | 21 +++ lib/vauth/spnego_gssapi.c | 14 ++ lib/vauth/spnego_sspi.c | 26 +++- lib/vauth/vauth.c | 41 ++++++ lib/vauth/vauth.h | 15 +++ lib/version.c | 14 +- lib/vtls/axtls.c | 3 +- lib/vtls/cyassl.c | 9 +- lib/vtls/darwinssl.c | 24 +++- lib/vtls/gskit.c | 10 +- lib/vtls/gtls.c | 12 +- lib/vtls/mbedtls.c | 14 +- lib/vtls/nss.c | 76 ++++++++--- lib/vtls/openssl.c | 108 +++++++++------- lib/vtls/polarssl.c | 80 +++++------- lib/vtls/polarssl_threadlock.c | 4 +- lib/vtls/schannel.c | 40 ++++-- lib/vtls/vtls.c | 18 +-- lib/x509asn1.c | 12 +- 108 files changed, 2276 insertions(+), 1700 deletions(-) create mode 100644 CMake/CurlSymbolHiding.cmake create mode 100644 CMake/FindNGHTTP2.cmake delete mode 100644 lib/rawstr.c delete mode 100644 lib/rawstr.h create mode 100644 lib/strcase.c create mode 100644 lib/strcase.h delete mode 100644 lib/strequal.c delete mode 100644 lib/strequal.h diff --git a/CMake/CurlSymbolHiding.cmake b/CMake/CurlSymbolHiding.cmake new file mode 100644 index 0000000..9f7d296 --- /dev/null +++ b/CMake/CurlSymbolHiding.cmake @@ -0,0 +1,61 @@ +include(CheckCSourceCompiles) + +option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) +mark_as_advanced(CURL_HIDDEN_SYMBOLS) + +if(CURL_HIDDEN_SYMBOLS) + set(SUPPORTS_SYMBOL_HIDING FALSE) + + if(CMAKE_C_COMPILER_ID MATCHES "Clang") + set(SUPPORTS_SYMBOL_HIDING TRUE) + 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) + # 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\")))") + set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") + endif() + elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0) + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__global") + 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. + set(SUPPORTS_SYMBOL_HIDING TRUE) + set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))") + set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden") + check_c_source_compiles("#include + int main (void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug) + if(NOT _no_bug) + set(SUPPORTS_SYMBOL_HIDING FALSE) + set(_SYMBOL_EXTERN "") + set(_CFLAG_SYMBOLS_HIDE "") + endif() + elseif(MSVC) + set(SUPPORTS_SYMBOL_HIDING TRUE) + endif() + + set(HIDES_CURL_PRIVATE_SYMBOLS ${SUPPORTS_SYMBOL_HIDING}) +elseif(MSVC) + if(NOT CMAKE_VERSION VERSION_LESS 3.7) + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) #present since 3.4.3 but broken + set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) + else() + message(WARNING "Hiding private symbols regardless CURL_HIDDEN_SYMBOLS being disabled.") + set(HIDES_CURL_PRIVATE_SYMBOLS TRUE) + endif() +elseif() + set(HIDES_CURL_PRIVATE_SYMBOLS FALSE) +endif() + +set(CURL_CFLAG_SYMBOLS_HIDE ${_CFLAG_SYMBOLS_HIDE}) +set(CURL_EXTERN_SYMBOL ${_SYMBOL_EXTERN}) diff --git a/CMake/FindNGHTTP2.cmake b/CMake/FindNGHTTP2.cmake new file mode 100644 index 0000000..4e566cf --- /dev/null +++ b/CMake/FindNGHTTP2.cmake @@ -0,0 +1,18 @@ +include(FindPackageHandleStandardArgs) + +find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h") + +find_library(NGHTTP2_LIBRARY NAMES nghttp2) + +find_package_handle_standard_args(NGHTTP2 + FOUND_VAR + NGHTTP2_FOUND + 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}) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f7c4d6..ed3f38a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -19,7 +19,7 @@ # KIND, either express or implied. # ########################################################################### -# cURL/libcurl CMake script +# curl/libcurl CMake script # by Tetetest and Sukender (Benoit Neil) # TODO: @@ -42,6 +42,7 @@ cmake_minimum_required(VERSION 2.8 FATAL_ERROR) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}") include(Utilities) include(Macros) +include(CMakeDependentOption) project( CURL C ) @@ -71,11 +72,17 @@ set(OS "\"${CMAKE_SYSTEM_NAME}\"") include_directories(${PROJECT_BINARY_DIR}/include/curl) include_directories( ${CURL_SOURCE_DIR}/include ) -option(BUILD_CURL_EXE "Set to ON to build cURL executable." ON) +option(BUILD_CURL_EXE "Set to ON to build curl executable." ON) option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF) option(ENABLE_ARES "Set to ON to enable c-ares support" OFF) -option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF) - +if(WIN32) + CMAKE_DEPENDENT_OPTION(ENABLE_THREADED_RESOLVER + "Set to ON to enable threaded DNS lookup" + ON "NOT ENABLE_ARES" + OFF) +else() + option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF) +endif() option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF) option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF) @@ -112,8 +119,7 @@ if(MSVC) mark_as_advanced(BUILD_RELEASE_DEBUG_DIRS) endif() -option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON) -mark_as_advanced(CURL_HIDDEN_SYMBOLS) +include(CurlSymbolHiding) option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF) mark_as_advanced(HTTP_ONLY) @@ -250,13 +256,17 @@ if(WIN32) endif(WIN32) if(ENABLE_THREADED_RESOLVER) - check_include_file_concat("pthread.h" HAVE_PTHREAD_H) - if(HAVE_PTHREAD_H) - set(CMAKE_THREAD_PREFER_PTHREAD 1) - find_package(Threads) - if(CMAKE_USE_PTHREADS_INIT) - set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) - set(USE_THREADS_POSIX 1) + if(WIN32) + set(USE_THREADS_WIN32 ON) + else() + check_include_file_concat("pthread.h" HAVE_PTHREAD_H) + if(HAVE_PTHREAD_H) + set(CMAKE_THREAD_PREFER_PTHREAD 1) + find_package(Threads) + if(CMAKE_USE_PTHREADS_INIT) + set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + set(USE_THREADS_POSIX 1) + endif() endif() endif() endif() @@ -322,6 +332,13 @@ if(CMAKE_USE_OPENSSL) endif() endif() +option(USE_NGHTTP2 "Use Nghttp2 library" OFF) +if(USE_NGHTTP2) + find_package(NGHTTP2 REQUIRED) + include_directories(${NGHTTP2_INCLUDE_DIRS}) + list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES}) +endif() + if(NOT CURL_DISABLE_LDAP) if(WIN32) option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON) @@ -432,12 +449,12 @@ if(NOT CURL_DISABLE_LDAPS) endif() # Check for idn -check_library_exists_concat("idn" idna_to_ascii_lz HAVE_LIBIDN) +check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2) # Check for symbol dlopen (same as HAVE_LIBDL) check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN) -option(CURL_ZLIB "Set to ON to enable building cURL with zlib support." ON) +option(CURL_ZLIB "Set to ON to enable building curl with zlib support." ON) set(HAVE_LIBZ OFF) set(HAVE_ZLIB_H OFF) set(HAVE_ZLIB OFF) @@ -601,7 +618,7 @@ check_include_file_concat("des.h" HAVE_DES_H) check_include_file_concat("err.h" HAVE_ERR_H) check_include_file_concat("errno.h" HAVE_ERRNO_H) check_include_file_concat("fcntl.h" HAVE_FCNTL_H) -check_include_file_concat("idn-free.h" HAVE_IDN_FREE_H) +check_include_file_concat("idn2.h" HAVE_IDN2_H) check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) check_include_file_concat("io.h" HAVE_IO_H) check_include_file_concat("krb.h" HAVE_KRB_H) @@ -631,7 +648,6 @@ check_include_file_concat("stropts.h" HAVE_STROPTS_H) check_include_file_concat("termio.h" HAVE_TERMIO_H) check_include_file_concat("termios.h" HAVE_TERMIOS_H) check_include_file_concat("time.h" HAVE_TIME_H) -check_include_file_concat("tld.h" HAVE_TLD_H) check_include_file_concat("unistd.h" HAVE_UNISTD_H) check_include_file_concat("utime.h" HAVE_UTIME_H) check_include_file_concat("x509.h" HAVE_X509_H) @@ -645,9 +661,6 @@ check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H) check_include_file_concat("stdint.h" HAVE_STDINT_H) check_include_file_concat("sockio.h" HAVE_SOCKIO_H) check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H) -check_include_file_concat("idna.h" HAVE_IDNA_H) - - check_type_size(size_t SIZEOF_SIZE_T) check_type_size(ssize_t SIZEOF_SSIZE_T) @@ -666,6 +679,7 @@ if(NOT HAVE_SIZEOF_SSIZE_T) set(ssize_t __int64) endif(NOT ssize_t AND SIZEOF___INT64 EQUAL SIZEOF_SIZE_T) endif(NOT HAVE_SIZEOF_SSIZE_T) +# off_t is sized later, after the HAVE_FILE_OFFSET_BITS test # Different sizeofs, etc. @@ -764,8 +778,6 @@ if(CMAKE_USE_OPENSSL) check_symbol_exists(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS) check_symbol_exists(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN) check_symbol_exists(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD) - check_symbol_exists(CRYPTO_cleanup_all_ex_data "${CURL_INCLUDES}" - HAVE_CRYPTO_CLEANUP_ALL_EX_DATA) if(HAVE_LIBCRYPTO AND HAVE_LIBSSL) set(USE_OPENSSL 1) endif(HAVE_LIBCRYPTO AND HAVE_LIBSSL) @@ -795,9 +807,6 @@ check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE) check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME) check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) -check_symbol_exists(idn_free "${CURL_INCLUDES}" HAVE_IDN_FREE) -check_symbol_exists(idna_strerror "${CURL_INCLUDES}" HAVE_IDNA_STRERROR) -check_symbol_exists(tld_strerror "${CURL_INCLUDES}" HAVE_TLD_STRERROR) check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) @@ -864,9 +873,14 @@ foreach(CURL_TEST ) curl_internal_test(${CURL_TEST}) endforeach(CURL_TEST) + if(HAVE_FILE_OFFSET_BITS) set(_FILE_OFFSET_BITS 64) + set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") endif(HAVE_FILE_OFFSET_BITS) +check_type_size("off_t" SIZEOF_OFF_T) +set(CMAKE_REQUIRED_FLAGS) + foreach(CURL_TEST HAVE_GLIBC_STRERROR_R HAVE_POSIX_STRERROR_R @@ -928,16 +942,6 @@ if(NOT CURL_SPECIAL_LIBZ) endif(NOT HAVE_ZLIB_H) endif(NOT CURL_SPECIAL_LIBZ) -if(_FILE_OFFSET_BITS) - set(_FILE_OFFSET_BITS 64) -endif(_FILE_OFFSET_BITS) -set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64") -set(CMAKE_EXTRA_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/curl/curl.h") -check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) -set(CMAKE_EXTRA_INCLUDE_FILES) -set(CMAKE_REQUIRED_FLAGS) - - # Check for nonblocking set(HAVE_DISABLED_NONBLOCKING 1) if(HAVE_FIONBIO OR @@ -1010,6 +1014,11 @@ if(WIN32) add_definitions(-D_WIN32_WINNT=0x0501) endif(WIN32) +# For windows, all compilers used by cmake should support large files +if(WIN32) + set(USE_WIN32_LARGE_FILES ON) +endif(WIN32) + if(MSVC) add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) endif(MSVC) @@ -1061,8 +1070,10 @@ _add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL) _add_if("IPv6" ENABLE_IPV6) _add_if("unix-sockets" USE_UNIX_SOCKETS) _add_if("libz" HAVE_LIBZ) -_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX) -_add_if("IDN" HAVE_LIBIDN) +_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32) +_add_if("IDN" HAVE_LIBIDN2) +_add_if("Largefile" (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND + ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES)) # TODO SSP1 (WinSSL) check is missing _add_if("SSPI" USE_WINDOWS_SSPI) _add_if("GSS-API" HAVE_GSSAPI) @@ -1128,9 +1139,7 @@ set(CURL_CA_BUNDLE "") set(CURLVERSION "${CURL_VERSION}") set(ENABLE_SHARED "yes") if(CURL_STATICLIB) - # Broken: LIBCURL_LIBS below; .a lib is not built - message(WARNING "Static linking is broken!") - set(ENABLE_STATIC "no") + set(ENABLE_STATIC "yes") else() set(ENABLE_STATIC "no") endif() @@ -1139,9 +1148,12 @@ set(includedir "\${prefix}/include") set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}") set(LIBCURL_LIBS "") set(libdir "${CMAKE_INSTALL_PREFIX}/lib") -# TODO CURL_LIBS also contains absolute paths which don't work with static -l... foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS}) - set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") + if(_lib MATCHES ".*/.*") + set(LIBCURL_LIBS "${LIBCURL_LIBS} ${_lib}") + else() + set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}") + endif() endforeach() # "a" (Linux) or "lib" (Windows) string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}") diff --git a/include/curl/curl.h b/include/curl/curl.h index 7fd6d1f..9c09cb9 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -30,6 +30,10 @@ * https://cool.haxx.se/mailman/listinfo/curl-library/ */ +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + #include "curlver.h" /* libcurl version defines */ #include "curlbuild.h" /* libcurl build definitions */ #include "curlrules.h" /* libcurl rules enforcement */ @@ -431,7 +435,7 @@ typedef enum { CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ CURLE_COULDNT_RESOLVE_HOST, /* 6 */ CURLE_COULDNT_CONNECT, /* 7 */ - CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server due to lack of access - when login fails this is not returned. */ @@ -562,6 +566,7 @@ typedef enum { /* compatibility with older names */ #define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY /* The following were added in 7.21.5, April 2011 */ #define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION @@ -1695,6 +1700,10 @@ typedef enum { /* Set TCP Fast Open */ CINIT(TCP_FASTOPEN, LONG, 244), + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/include/curl/curlver.h b/include/curl/curlver.h index 81563f2..3bb0235 100644 --- a/include/curl/curlver.h +++ b/include/curl/curlver.h @@ -30,13 +30,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.50.1-DEV" +#define LIBCURL_VERSION "7.51.0-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 50 -#define LIBCURL_VERSION_PATCH 1 +#define LIBCURL_VERSION_MINOR 51 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -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 0x073201 +#define LIBCURL_VERSION_NUM 0x073300 /* * This is the date and time when the full source package was created. The diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 49a3409..eb2de6d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -87,6 +87,11 @@ endif() set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL) +if(HIDES_CURL_PRIVATE_SYMBOLS) + set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") + set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE}) +endif() + # Remove the "lib" prefix since the library is already named "libcurl". set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "") diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 0ed998c..1328cad 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -40,13 +40,13 @@ LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.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 \ ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ - getinfo.c transfer.c strequal.c easy.c security.c curl_fnmatch.c \ + getinfo.c transfer.c strcase.c easy.c security.c curl_fnmatch.c \ fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.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 rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ + ssh.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 \ @@ -58,13 +58,13 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.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 \ speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ - strequal.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ + strcase.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.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 rawstr.h curl_addrinfo.h curl_sspi.h \ + socks.h ssh.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 \ diff --git a/lib/amigaos.c b/lib/amigaos.c index 5591d22..4f55b30 100644 --- a/lib/amigaos.c +++ b/lib/amigaos.c @@ -57,7 +57,7 @@ bool Curl_amiga_init() } if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, - SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "cURL", + SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", TAG_DONE)) { __request("SocketBaseTags ERROR"); return FALSE; diff --git a/lib/base64.c b/lib/base64.c index ad25459..204a227 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -190,6 +190,11 @@ static CURLcode base64_encode(const char *table64, if(!insize) insize = strlen(indata); +#if SIZEOF_SIZE_T == 4 + if(insize > UINT_MAX/4) + return CURLE_OUT_OF_MEMORY; +#endif + base64data = output = malloc(insize * 4 / 3 + 4); if(!output) return CURLE_OUT_OF_MEMORY; diff --git a/lib/conncache.c b/lib/conncache.c index 32a7030..01b1b44 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -30,7 +30,6 @@ #include "progress.h" #include "multiif.h" #include "sendf.h" -#include "rawstr.h" #include "conncache.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" diff --git a/lib/connect.c b/lib/connect.c index 0047f9a..3df34d9 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -762,7 +762,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, #endif /* check socket for connect */ - rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); + rc = SOCKET_WRITABLE(conn->tempsock[i], 0); if(rc == 0) { /* no connection yet */ error = 0; @@ -1368,25 +1368,26 @@ CURLcode Curl_socket(struct connectdata *conn, } -#ifdef CURLDEBUG /* - * Curl_conncontrol() is used to set the conn->bits.close bit on or off. It - * MUST be called with the connclose() or connkeep() macros with a stated - * reason. The reason is only shown in debug builds but helps to figure out - * decision paths when connections are or aren't re-used as expected. + * Curl_conncontrol() marks streams or connection for closure. */ -void Curl_conncontrol(struct connectdata *conn, bool closeit, - const char *reason) -{ -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) reason; +void Curl_conncontrol(struct connectdata *conn, + int ctrl /* see defines in header */ +#ifdef DEBUGBUILD + , const char *reason #endif - if(closeit != conn->bits.close) { - infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", - reason); - + ) +{ + /* close if a connection, or a stream that isn't multiplexed */ + bool closeit = (ctrl == CONNCTRL_CONNECTION) || + ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM)); + if((ctrl == CONNCTRL_STREAM) && + (conn->handler->flags & PROTOPT_STREAM)) + DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); + else if(closeit != conn->bits.close) { + DEBUGF(infof(conn->data, "Marked for [%s]: %s\n", + closeit?"closure":"keep alive", reason)); conn->bits.close = closeit; /* the only place in the source code that should assign this bit */ } } -#endif diff --git a/lib/connect.h b/lib/connect.h index 6d60e0d..a7cbc9b 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -104,21 +104,37 @@ CURLcode Curl_socket(struct connectdata *conn, void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd); -#ifdef CURLDEBUG /* - * Curl_connclose() sets the bit.close bit to TRUE with an explanation. - * Nothing else. + * Curl_conncontrol() marks the end of a connection/stream. The 'closeit' + * argument specifies if it is the end of a connection or a stream. + * + * For stream-based protocols (such as HTTP/2), a stream close will not cause + * a connection close. Other protocols will close the connection for both + * cases. + * + * It sets the bit.close bit to TRUE (with an explanation for debug builds), + * when the connection will close. */ -void Curl_conncontrol(struct connectdata *conn, - bool closeit, - const char *reason); -#define connclose(x,y) Curl_conncontrol(x,TRUE, y) -#define connkeep(x,y) Curl_conncontrol(x, FALSE, y) -#else /* if !CURLDEBUG */ -#define connclose(x,y) (x)->bits.close = TRUE -#define connkeep(x,y) (x)->bits.close = FALSE +#define CONNCTRL_KEEP 0 /* undo a marked closure */ +#define CONNCTRL_CONNECTION 1 +#define CONNCTRL_STREAM 2 +void Curl_conncontrol(struct connectdata *conn, + int closeit +#ifdef DEBUGBUILD + , const char *reason +#endif + ); + +#ifdef DEBUGBUILD +#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y) +#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y) +#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y) +#else /* if !CURLDEBUG */ +#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM) +#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION) +#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP) #endif #endif /* HEADER_CURL_CONNECT_H */ diff --git a/lib/cookie.c b/lib/cookie.c index d5a83fd..1b3e645 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -90,13 +90,12 @@ Example set of cookies: #include "urldata.h" #include "cookie.h" -#include "strequal.h" #include "strtok.h" #include "sendf.h" #include "slist.h" #include "share.h" #include "strtoofft.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memrchr.h" #include "inet_pton.h" @@ -126,7 +125,7 @@ static bool tailmatch(const char *cooke_domain, const char *hostname) if(hostname_len < cookie_domain_len) return FALSE; - if(!Curl_raw_equal(cooke_domain, hostname+hostname_len-cookie_domain_len)) + if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len)) return FALSE; /* A lead char of cookie_domain is not '.'. @@ -469,9 +468,9 @@ Curl_cookie_add(struct Curl_easy *data, /* this was a "=" with no content, and we must allow 'secure' and 'httponly' specified this weirdly */ done = TRUE; - if(Curl_raw_equal("secure", name)) + if(strcasecompare("secure", name)) co->secure = TRUE; - else if(Curl_raw_equal("httponly", name)) + else if(strcasecompare("httponly", name)) co->httponly = TRUE; else if(sep) /* there was a '=' so we're not done parsing this field */ @@ -479,7 +478,7 @@ Curl_cookie_add(struct Curl_easy *data, } if(done) ; - else if(Curl_raw_equal("path", name)) { + else if(strcasecompare("path", name)) { strstore(&co->path, whatptr); if(!co->path) { badcookie = TRUE; /* out of memory bad */ @@ -491,7 +490,7 @@ Curl_cookie_add(struct Curl_easy *data, break; } } - else if(Curl_raw_equal("domain", name)) { + else if(strcasecompare("domain", name)) { bool is_ip; const char *dotp; @@ -529,14 +528,14 @@ Curl_cookie_add(struct Curl_easy *data, whatptr); } } - else if(Curl_raw_equal("version", name)) { + else if(strcasecompare("version", name)) { strstore(&co->version, whatptr); if(!co->version) { badcookie = TRUE; break; } } - else if(Curl_raw_equal("max-age", name)) { + else if(strcasecompare("max-age", name)) { /* Defined in RFC2109: Optional. The Max-Age attribute defines the lifetime of the @@ -552,7 +551,7 @@ Curl_cookie_add(struct Curl_easy *data, break; } } - else if(Curl_raw_equal("expires", name)) { + else if(strcasecompare("expires", name)) { strstore(&co->expirestr, whatptr); if(!co->expirestr) { badcookie = TRUE; @@ -713,7 +712,7 @@ Curl_cookie_add(struct Curl_easy *data, As far as I can see, it is set to true when the cookie says .domain.com and to false when the domain is complete www.domain.com */ - co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; + co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE; break; case 2: /* It turns out, that sometimes the file format allows the path @@ -742,7 +741,7 @@ Curl_cookie_add(struct Curl_easy *data, fields++; /* add a field and fall down to secure */ /* FALLTHROUGH */ case 3: - co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; + co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE; break; case 4: co->expires = curlx_strtoofft(ptr, NULL, 10); @@ -813,11 +812,12 @@ Curl_cookie_add(struct Curl_easy *data, clist = c->cookies; replace_old = FALSE; while(clist) { - if(Curl_raw_equal(clist->name, co->name)) { + if(strcasecompare(clist->name, co->name)) { /* the names are identical */ if(clist->domain && co->domain) { - if(Curl_raw_equal(clist->domain, co->domain)) + if(strcasecompare(clist->domain, co->domain) && + (clist->tailmatch == co->tailmatch)) /* The domains are identical */ replace_old=TRUE; } @@ -828,7 +828,7 @@ Curl_cookie_add(struct Curl_easy *data, /* the domains were identical */ if(clist->spath && co->spath) { - if(Curl_raw_equal(clist->spath, co->spath)) { + if(strcasecompare(clist->spath, co->spath)) { replace_old = TRUE; } else @@ -902,6 +902,35 @@ Curl_cookie_add(struct Curl_easy *data, return co; } +/* + * get_line() makes sure to only return complete whole lines that fit in 'len' + * bytes and end with a newline. + */ +static char *get_line(char *buf, int len, FILE *input) +{ + bool partial = FALSE; + while(1) { + char *b = fgets(buf, len, input); + if(b) { + size_t rlen = strlen(b); + if(rlen && (b[rlen-1] == '\n')) { + if(partial) { + partial = FALSE; + continue; + } + return b; + } + else + /* read a partial, discard the next piece that ends with newline */ + partial = TRUE; + } + else + break; + } + return NULL; +} + + /***************************************************************************** * * Curl_cookie_init() @@ -938,7 +967,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, } c->running = FALSE; /* this is not running, this is init */ - if(file && strequal(file, "-")) { + if(file && !strcmp(file, "-")) { fp = stdin; fromfile=FALSE; } @@ -958,7 +987,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, line = malloc(MAX_COOKIE_LINE); if(!line) goto fail; - while(fgets(line, MAX_COOKIE_LINE, fp)) { + while(get_line(line, MAX_COOKIE_LINE, fp)) { if(checkprefix("Set-Cookie:", line)) { /* This is a cookie line, get it! */ lineptr=&line[11]; @@ -1023,6 +1052,40 @@ static int cookie_sort(const void *p1, const void *p2) return 0; } +#define CLONE(field) \ + do { \ + if(src->field) { \ + dup->field = strdup(src->field); \ + if(!dup->field) \ + goto fail; \ + } \ + } while(0) + +static struct Cookie *dup_cookie(struct Cookie *src) +{ + struct Cookie *dup = calloc(sizeof(struct Cookie), 1); + if(dup) { + CLONE(expirestr); + CLONE(domain); + CLONE(path); + CLONE(spath); + CLONE(name); + CLONE(value); + CLONE(maxage); + CLONE(version); + dup->expires = src->expires; + dup->tailmatch = src->tailmatch; + dup->secure = src->secure; + dup->livecookie = src->livecookie; + dup->httponly = src->httponly; + } + return dup; + + fail: + freecookie(dup); + return NULL; +} + /***************************************************************************** * * Curl_cookie_getlist() @@ -1067,7 +1130,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* now check if the domain is correct */ if(!co->domain || (co->tailmatch && !is_ip && tailmatch(co->domain, host)) || - ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) { + ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { /* the right part of the host matches the domain stuff in the cookie data */ @@ -1078,11 +1141,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* and now, we know this is a match and we should create an entry for the return-linked-list */ - newco = malloc(sizeof(struct Cookie)); + newco = dup_cookie(co); if(newco) { - /* first, copy the whole source cookie: */ - memcpy(newco, co, sizeof(struct Cookie)); - /* then modify our next */ newco->next = mainco; @@ -1094,12 +1154,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, else { fail: /* failure, clear up the allocated chain and return NULL */ - while(mainco) { - co = mainco->next; - free(mainco); - mainco = co; - } - + Curl_cookie_freelist(mainco); return NULL; } } @@ -1151,7 +1206,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, void Curl_cookie_clearall(struct CookieInfo *cookies) { if(cookies) { - Curl_cookie_freelist(cookies->cookies, TRUE); + Curl_cookie_freelist(cookies->cookies); cookies->cookies = NULL; cookies->numcookies = 0; } @@ -1163,21 +1218,14 @@ void Curl_cookie_clearall(struct CookieInfo *cookies) * * Free a list of cookies previously returned by Curl_cookie_getlist(); * - * The 'cookiestoo' argument tells this function whether to just free the - * list or actually also free all cookies within the list as well. - * ****************************************************************************/ -void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo) +void Curl_cookie_freelist(struct Cookie *co) { struct Cookie *next; while(co) { next = co->next; - if(cookiestoo) - freecookie(co); - else - free(co); /* we only free the struct since the "members" are all just - pointed out in the main cookie list! */ + freecookie(co); co = next; } } @@ -1232,7 +1280,7 @@ void Curl_cookie_cleanup(struct CookieInfo *c) { if(c) { free(c->filename); - Curl_cookie_freelist(c->cookies, TRUE); + Curl_cookie_freelist(c->cookies); free(c); /* free the base struct as well */ } } @@ -1290,7 +1338,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) /* at first, remove expired cookies */ remove_expired(c); - if(strequal("-", dumphere)) { + if(!strcmp("-", dumphere)) { /* use stdout */ out = stdout; use_stdout=TRUE; diff --git a/lib/cookie.h b/lib/cookie.h index cd7c54a..a9a4578 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -82,7 +82,7 @@ struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *, const char *, bool); -void Curl_cookie_freelist(struct Cookie *cookies, bool cookiestoo); +void Curl_cookie_freelist(struct Cookie *cookies); void Curl_cookie_clearall(struct CookieInfo *cookies); void Curl_cookie_clearsess(struct CookieInfo *cookies); diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index 65a414b..33c15cb 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -67,7 +67,7 @@ #cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1 /* to make a symbol visible */ -#cmakedefine CURL_EXTERN_SYMBOL 1 +#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL} /* Ensure using CURL_EXTERN_SYMBOL is possible */ #ifndef CURL_EXTERN_SYMBOL #define CURL_EXTERN_SYMBOL @@ -906,6 +906,9 @@ /* Define if you want to enable POSIX threaded DNS lookup */ #cmakedefine USE_THREADS_POSIX 1 +/* Define if you want to enable WIN32 threaded DNS lookup */ +#cmakedefine USE_THREADS_WIN32 1 + /* Define to disable non-blocking sockets. */ #cmakedefine USE_BLOCKING_SOCKETS 1 @@ -933,11 +936,13 @@ /* if OpenSSL is in use */ #cmakedefine USE_OPENSSL 1 +/* to enable NGHTTP2 */ +#cmakedefine USE_NGHTTP2 1 + /* if Unix domain sockets are enabled */ #cmakedefine USE_UNIX_SOCKETS -/* Define to 1 if you are building a Windows target without large file - support. */ +/* Define to 1 if you are building a Windows target with large file support. */ #cmakedefine USE_WIN32_LARGE_FILES 1 /* to enable SSPI support */ diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c index f3fb013..812a073 100644 --- a/lib/curl_ntlm_core.c +++ b/lib/curl_ntlm_core.c @@ -76,6 +76,11 @@ # define MD5_DIGEST_LENGTH 16 # define MD4_DIGEST_LENGTH 16 +#elif defined(USE_MBEDTLS) + +# include +# include + #elif defined(USE_NSS) # include @@ -100,7 +105,7 @@ #include "urldata.h" #include "non-ascii.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_ntlm_core.h" #include "curl_md5.h" #include "curl_hmac.h" @@ -188,6 +193,26 @@ static void setup_des_key(const unsigned char *key_56, gcry_cipher_setkey(*des, key, sizeof(key)); } +#elif defined(USE_MBEDTLS) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + mbedtls_des_context ctx; + char key[8]; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + mbedtls_des_key_set_parity((unsigned char *) key); + + /* Perform the encryption */ + mbedtls_des_init(&ctx); + mbedtls_des_setkey_enc(&ctx, (unsigned char *) key); + return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; +} + #elif defined(USE_NSS) /* @@ -400,8 +425,8 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, setup_des_key(keys + 14, &des); gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ - || defined(USE_WIN32_CRYPTO) +#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \ + || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(plaintext, results, keys); encrypt_des(plaintext, results + 8, keys + 7); encrypt_des(plaintext, results + 16, keys + 14); @@ -464,8 +489,8 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, setup_des_key(pw + 7, &des); gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ - || defined(USE_WIN32_CRYPTO) +#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \ + || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(magic, lmbuffer, pw); encrypt_des(magic, lmbuffer + 8, pw + 7); #endif @@ -543,6 +568,8 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, gcry_md_write(MD4pw, pw, 2 * len); memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH); gcry_md_close(MD4pw); +#elif defined(USE_MBEDTLS) + mbedtls_md4(pw, 2 * len, ntbuffer); #elif defined(USE_NSS) || defined(USE_OS400CRYPTO) Curl_md4it(ntbuffer, pw, 2 * len); #elif defined(USE_DARWINSSL) diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c index 35e9fea..6b86962 100644 --- a/lib/curl_sasl.c +++ b/lib/curl_sasl.c @@ -42,8 +42,6 @@ #include "curl_sasl.h" #include "warnless.h" #include "strtok.h" -#include "strequal.h" -#include "rawstr.h" #include "sendf.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ /* The last 3 #include files should be in this order */ @@ -159,7 +157,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, sasl->prefmech = SASL_AUTH_NONE; } - if(strnequal(value, "*", len)) + if(!strncmp(value, "*", len)) sasl->prefmech = SASL_AUTH_DEFAULT; else { mechbit = Curl_sasl_decode_mech(value, len, &mechlen); @@ -288,7 +286,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, } else if(conn->bits.user_passwd) { #if defined(USE_KERBEROS5) - if(enabledmechs & SASL_MECH_GSSAPI) { + if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() && + Curl_auth_user_contains_domain(conn->user)) { sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ mech = SASL_MECH_STRING_GSSAPI; state1 = SASL_GSSAPI; @@ -308,7 +307,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, else #endif #ifndef CURL_DISABLE_CRYPTO_AUTH - if(enabledmechs & SASL_MECH_DIGEST_MD5) { + if((enabledmechs & SASL_MECH_DIGEST_MD5) && + Curl_auth_is_digest_supported()) { mech = SASL_MECH_STRING_DIGEST_MD5; state1 = SASL_DIGESTMD5; sasl->authused = SASL_MECH_DIGEST_MD5; @@ -321,7 +321,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, else #endif #ifdef USE_NTLM - if(enabledmechs & SASL_MECH_NTLM) { + if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) { mech = SASL_MECH_STRING_NTLM; state1 = SASL_NTLM; state2 = SASL_NTLM_TYPE2MSG; diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 7dcc4c4..9619a1e 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -599,10 +599,9 @@ int netware_init(void); #endif #endif -#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H) -/* The lib was present and the tld.h header (which is missing in libidn 0.3.X - but we only work with libidn 0.4.1 or later) */ -#define USE_LIBIDN +#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) +/* The lib and header are present */ +#define USE_LIBIDN2 #endif #ifndef SIZEOF_TIME_T @@ -638,6 +637,13 @@ int netware_init(void); defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) #define USE_NTLM + +#elif defined(USE_MBEDTLS) +# include +# if defined(MBEDTLS_MD4_C) +#define USE_NTLM +# endif + #endif #endif @@ -746,4 +752,14 @@ endings either CRLF or LF so 't' is appropriate. # endif #endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ +/* Detect Windows App environment which has a restricted access + * to the Win32 APIs. */ +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ + !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define CURL_WINDOWS_APP +# endif +# endif + #endif /* HEADER_CURL_SETUP_H */ diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index ee3f1b1..11a7120 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -64,6 +64,12 @@ PSecurityFunctionTable s_pSecFn = NULL; * * Once this function has been executed, Windows SSPI functions can be * called through the Security Service Provider Interface dispatch table. + * + * Parameters: + * + * None. + * + * Returns CURLE_OK on success. */ CURLcode Curl_sspi_global_init(void) { @@ -102,8 +108,11 @@ CURLcode Curl_sspi_global_init(void) * Curl_sspi_global_cleanup() * * This deinitializes the Security Service Provider Interface from libcurl. + * + * Parameters: + * + * None. */ - void Curl_sspi_global_cleanup(void) { if(s_hSecDll) { @@ -205,6 +214,15 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, return CURLE_OK; } +/* + * Curl_sspi_free_identity() + * + * This is used to free the contents of a SSPI identifier structure. + * + * Parameters: + * + * identity [in/out] - The identity structure. + */ void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) { if(identity) { diff --git a/lib/curlx.h b/lib/curlx.h index 448a34f..6168dc1 100644 --- a/lib/curlx.h +++ b/lib/curlx.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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,8 +34,8 @@ functions while they still are offered publicly. They will be made library- private one day */ -#include "strequal.h" -/* "strequal.h" provides the strequal protos */ +#include "strcase.h" +/* "strcase.h" provides the strcasecompare protos */ #include "strtoofft.h" /* "strtoofft.h" provides this function: curlx_strtoofft(), returns a @@ -67,15 +67,12 @@ be removed from a future libcurl official API: curlx_getenv curlx_mprintf (and its variations) - curlx_strequal - curlx_strnequal + curlx_strcasecompare + curlx_strncasecompare */ #define curlx_getenv curl_getenv -#define curlx_strequal curl_strequal -#define curlx_strnequal curl_strnequal -#define curlx_raw_equal Curl_raw_equal #define curlx_mvsnprintf curl_mvsnprintf #define curlx_msnprintf curl_msnprintf #define curlx_maprintf curl_maprintf diff --git a/lib/dict.c b/lib/dict.c index a7b5965..69defc4 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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,11 +52,10 @@ #include #include "transfer.h" #include "sendf.h" - +#include "escape.h" #include "progress.h" -#include "strequal.h" #include "dict.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -96,12 +95,12 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff) char *newp; char *dictp; char *ptr; - int len; + size_t len; char ch; int olen=0; - newp = curl_easy_unescape(data, inputbuff, 0, &len); - if(!newp) + CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE); + if(!newp || result) return NULL; dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */ @@ -145,9 +144,9 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) /* AUTH is missing */ } - if(Curl_raw_nequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || - Curl_raw_nequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || - Curl_raw_nequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { + if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || + strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || + strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { word = strchr(path, ':'); if(word) { @@ -203,9 +202,9 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL); /* no upload */ } - else if(Curl_raw_nequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || - Curl_raw_nequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || - Curl_raw_nequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { + else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || + strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || + strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { word = strchr(path, ':'); if(word) { diff --git a/lib/easy.c b/lib/easy.c index dc7139f..eee1061 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -50,7 +50,6 @@ #include #endif -#include "strequal.h" #include "urldata.h" #include #include "transfer.h" @@ -144,28 +143,6 @@ static CURLcode win32_init(void) return CURLE_OK; } -#ifdef USE_LIBIDN -/* - * Initialise use of IDNA library. - * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for - * idna_to_ascii_lz(). - */ -static void idna_init (void) -{ -#ifdef WIN32 - char buf[60]; - UINT cp = GetACP(); - - if(!getenv("CHARSET") && cp > 0) { - snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp); - putenv(buf); - } -#else - /* to do? */ -#endif -} -#endif /* USE_LIBIDN */ - /* true globals -- for curl_global_init() and curl_global_cleanup() */ static unsigned int initialized; static long init_flags; @@ -217,7 +194,7 @@ curl_calloc_callback Curl_ccalloc; #endif /** - * curl_global_init() globally initializes cURL given a bitwise set of the + * curl_global_init() globally initializes curl given a bitwise set of the * different features of what to initialize. */ static CURLcode global_init(long flags, bool memoryfuncs) @@ -262,10 +239,6 @@ static CURLcode global_init(long flags, bool memoryfuncs) } #endif -#ifdef USE_LIBIDN - idna_init(); -#endif - if(Curl_resolver_global_init()) { DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); return CURLE_FAILED_INIT; @@ -292,7 +265,7 @@ static CURLcode global_init(long flags, bool memoryfuncs) /** - * curl_global_init() globally initializes cURL given a bitwise set of the + * curl_global_init() globally initializes curl given a bitwise set of the * different features of what to initialize. */ CURLcode curl_global_init(long flags) @@ -301,7 +274,7 @@ CURLcode curl_global_init(long flags) } /* - * curl_global_init_mem() globally initializes cURL and also registers the + * curl_global_init_mem() globally initializes curl and also registers the * user provided callback routines. */ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, @@ -333,7 +306,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, } /** - * curl_global_cleanup() globally cleanups cURL, uses the value of + * curl_global_cleanup() globally cleanups curl, uses the value of * "init_flags" to determine what needs to be cleaned up and what doesn't. */ void curl_global_cleanup(void) @@ -995,6 +968,9 @@ void curl_easy_reset(struct Curl_easy *data) /* zero out Progress data: */ memset(&data->progress, 0, sizeof(struct Progress)); + /* zero out PureInfo data: */ + Curl_initinfo(data); + data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ } @@ -1044,7 +1020,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) if(!result && ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) ) - Curl_expire(data, 1); /* get this handle going again */ + Curl_expire(data, 0); /* get this handle going again */ return result; } diff --git a/lib/escape.c b/lib/escape.c index 04230b4..6657007 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -78,15 +78,21 @@ char *curl_unescape(const char *string, int length) char *curl_easy_escape(struct Curl_easy *data, const char *string, int inlength) { - size_t alloc = (inlength?(size_t)inlength:strlen(string))+1; + size_t alloc; char *ns; char *testing_ptr = NULL; unsigned char in; /* we need to treat the characters unsigned */ - size_t newlen = alloc; + size_t newlen; size_t strindex=0; size_t length; CURLcode result; + if(inlength < 0) + return NULL; + + alloc = (inlength?(size_t)inlength:strlen(string))+1; + newlen = alloc; + ns = malloc(alloc); if(!ns) return NULL; @@ -211,14 +217,22 @@ char *curl_easy_unescape(struct Curl_easy *data, const char *string, int length, int *olen) { char *str = NULL; - size_t inputlen = length; - size_t outputlen; - CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, - FALSE); - if(res) - return NULL; - if(olen) - *olen = curlx_uztosi(outputlen); + if(length >= 0) { + size_t inputlen = length; + size_t outputlen; + CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, + FALSE); + if(res) + return NULL; + + if(olen) { + if(outputlen <= (size_t) INT_MAX) + *olen = curlx_uztosi(outputlen); + else + /* too large to return in an int, fail! */ + Curl_safefree(str); + } + } return str; } diff --git a/lib/file.c b/lib/file.c index b534ec1..272289e 100644 --- a/lib/file.c +++ b/lib/file.c @@ -190,14 +190,15 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) struct FILEPROTO *file = data->req.protop; int fd; #ifdef DOS_FILESYSTEM - int i; + size_t i; char *actual_path; #endif - int real_path_len; + size_t real_path_len; - real_path = curl_easy_unescape(data, data->state.path, 0, &real_path_len); - if(!real_path) - return CURLE_OUT_OF_MEMORY; + CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path, + &real_path_len, FALSE); + if(result) + return result; #ifdef DOS_FILESYSTEM /* If the first character is a slash, and there's diff --git a/lib/formdata.c b/lib/formdata.c index 673759d..785f1a6 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -33,7 +33,7 @@ #include "urldata.h" /* for struct Curl_easy */ #include "formdata.h" #include "vtls/vtls.h" -#include "strequal.h" +#include "strcase.h" #include "sendf.h" #include "strdup.h" /* The last 3 #include files should be in this order */ @@ -201,9 +201,9 @@ static const char *ContentTypeForFilename(const char *filename, if(filename) { /* in case a NULL was passed in */ for(i=0; i= strlen(ctts[i].extension)) { - if(strequal(filename + - strlen(filename) - strlen(ctts[i].extension), - ctts[i].extension)) { + if(strcasecompare(filename + + strlen(filename) - strlen(ctts[i].extension), + ctts[i].extension)) { contenttype = ctts[i].type; break; } @@ -845,16 +845,23 @@ static CURLcode AddFormData(struct FormData **formp, goto error; } #endif + if(type != FORM_DATAMEM) { + newform->line = malloc((size_t)length+1); + if(!newform->line) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + alloc2 = newform->line; + memcpy(newform->line, line, (size_t)length); - newform->line = malloc((size_t)length+1); - if(!newform->line) { - result = CURLE_OUT_OF_MEMORY; - goto error; + /* zero terminate for easier debugging */ + newform->line[(size_t)length]=0; + } + else { + newform->line = (char *)line; + type = FORM_DATA; /* in all other aspects this is just FORM_DATA */ } - alloc2 = newform->line; - memcpy(newform->line, line, (size_t)length); newform->length = (size_t)length; - newform->line[(size_t)length]=0; /* zero terminate for easier debugging */ } else /* For callbacks and files we don't have any actual data so we just keep a @@ -863,13 +870,6 @@ static CURLcode AddFormData(struct FormData **formp, newform->type = type; - if(*formp) { - (*formp)->next = newform; - *formp = newform; - } - else - *formp = newform; - if(size) { if(type != FORM_FILE) /* for static content as well as callback data we add the size given @@ -878,7 +878,7 @@ static CURLcode AddFormData(struct FormData **formp, else { /* Since this is a file to be uploaded here, add the size of the actual file */ - if(!strequal("-", newform->line)) { + if(strcmp("-", newform->line)) { struct_stat file; if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) *size += filesize(newform->line, file); @@ -889,6 +889,14 @@ static CURLcode AddFormData(struct FormData **formp, } } } + + if(*formp) { + (*formp)->next = newform; + *formp = newform; + } + else + *formp = newform; + return CURLE_OK; error: if(newform) @@ -906,13 +914,21 @@ static CURLcode AddFormDataf(struct FormData **formp, curl_off_t *size, const char *fmt, ...) { - char s[4096]; + char *s; + CURLcode result; va_list ap; va_start(ap, fmt); - vsnprintf(s, sizeof(s), fmt, ap); + s = curl_mvaprintf(fmt, ap); va_end(ap); - return AddFormData(formp, FORM_DATA, s, 0, size); + if(!s) + return CURLE_OUT_OF_MEMORY; + + result = AddFormData(formp, FORM_DATAMEM, s, 0, size); + if(result) + free(s); + + return result; } /* @@ -1289,7 +1305,7 @@ CURLcode Curl_getformdata(struct Curl_easy *data, /* we should include the contents from the specified file */ FILE *fileread; - fileread = strequal("-", file->contents)? + fileread = !strcmp("-", file->contents)? stdin:fopen(file->contents, "rb"); /* binary read for win32 */ /* diff --git a/lib/formdata.h b/lib/formdata.h index 6eb7c6c..200470b 100644 --- a/lib/formdata.h +++ b/lib/formdata.h @@ -23,6 +23,7 @@ ***************************************************************************/ enum formtype { + FORM_DATAMEM, /* already allocated FORM_DATA memory */ FORM_DATA, /* form metadata (convert to network encoding if necessary) */ FORM_CONTENT, /* form content (never convert) */ FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback diff --git a/lib/ftp.c b/lib/ftp.c index 8af6531..b231731 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -61,7 +61,7 @@ #include "ftplistparser.h" #include "curl_sec.h" #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" @@ -72,7 +72,7 @@ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "speedcheck.h" #include "warnless.h" #include "http_proxy.h" @@ -475,7 +475,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) if(ftpcode/100 > 3) return CURLE_FTP_ACCEPT_FAILED; - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } break; @@ -741,7 +741,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ */ } else { - switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) { + switch (SOCKET_READABLE(sockfd, interval_ms)) { case -1: /* select() error, stop reading */ failf(data, "FTP response aborted due to select/poll error: %d", SOCKERRNO); @@ -911,7 +911,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, } else { socks[1] = conn->sock[SECONDARYSOCKET]; - bits |= GETSOCK_WRITESOCK(1); + bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1); } return bits; @@ -1835,7 +1835,7 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn) if(conn->bits.ipv6) { /* We can't disable EPSV when doing IPv6, so this is instead a fail */ failf(conn->data, "Failed EPSV attempt, exiting\n"); - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); @@ -2742,7 +2742,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) else if(ftpcode != 220) { failf(data, "Got a %03d ftp-server response when 220 was expected", ftpcode); - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } /* We have received a 220 response fine, now we proceed. */ @@ -2999,7 +2999,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* Check for special servers here. */ - if(strequal(os, "OS/400")) { + if(strcasecompare(os, "OS/400")) { /* Force OS400 name format 1. */ result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); if(result) { @@ -3165,7 +3165,7 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn, struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE); - /* Check for the state outside of the Curl_socket_ready() return code checks + /* Check for the state outside of the Curl_socket_check() return code checks since at times we are in fact already in this state when this function gets called. */ *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; @@ -3250,7 +3250,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, ssize_t nread; int ftpcode; CURLcode result = CURLE_OK; - bool was_ctl_valid = ftpc->ctl_valid; char *path; const char *path_to_use = data->state.path; @@ -3274,10 +3273,9 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* the connection stays alive fine even though this happened */ /* fall-through */ case CURLE_OK: /* doesn't affect the control connection's status */ - if(!premature) { - ftpc->ctl_valid = was_ctl_valid; + if(!premature) break; - } + /* until we cope better with prematurely ended requests, let them * fallback as if in complete failure */ default: /* by default, an error means the control connection is @@ -3300,13 +3298,12 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, ftpc->known_filesize = -1; } - /* get the "raw" path */ - path = curl_easy_unescape(data, path_to_use, 0, NULL); - if(!path) { - /* out of memory, but we can limp along anyway (and should try to - * since we may already be in the out of memory cleanup path) */ - if(!result) - result = CURLE_OUT_OF_MEMORY; + if(!result) + /* get the "raw" path */ + result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE); + 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 */ ftpc->prevpath = NULL; /* no path remembering */ @@ -4093,8 +4090,7 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done) } -CURLcode Curl_ftpsendf(struct connectdata *conn, - const char *fmt, ...) +CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd) { ssize_t bytes_written; #define SBUF_SIZE 1024 @@ -4106,10 +4102,9 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, enum protection_level data_sec = conn->data_prot; #endif - va_list ap; - va_start(ap, fmt); - write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap); - va_end(ap); + write_len = strlen(cmd); + if(write_len > (sizeof(s) -3)) + return CURLE_BAD_FUNCTION_ARGUMENT; strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ write_len +=2; @@ -4291,6 +4286,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) 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) @@ -4299,12 +4295,13 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) if(!dirlen) dirlen++; - ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/", - slash_pos ? curlx_uztosi(dirlen) : 1, - NULL); - if(!ftpc->dirs[0]) { + result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/", + slash_pos ? dirlen : 1, + &ftpc->dirs[0], NULL, + FALSE); + if(result) { freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; + return result; } ftpc->dirdepth = 1; /* we consider it to be a single dir */ filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */ @@ -4322,7 +4319,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; /* we have a special case for listing the root dir only */ - if(strequal(path_to_use, "/")) { + if(!strcmp(path_to_use, "/")) { cur_pos++; /* make it point to the zero byte */ ftpc->dirs[0] = strdup("/"); ftpc->dirdepth++; @@ -4339,18 +4336,15 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) /* 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. */ - int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir); - ftpc->dirs[ftpc->dirdepth] = - curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL); - if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */ - failf(data, "no memory"); - freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; - } - if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) { + 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) { free(ftpc->dirs[ftpc->dirdepth]); freedirs(ftpc); - return CURLE_URL_MALFORMAT; + return result; } } else { @@ -4386,15 +4380,12 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) } /* switch */ if(filename && *filename) { - ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL); - if(NULL == ftpc->file) { - freedirs(ftpc); - failf(data, "no memory"); - return CURLE_OUT_OF_MEMORY; - } - if(isBadFtpString(ftpc->file)) { + CURLcode result = + Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE); + + if(result) { freedirs(ftpc); - return CURLE_URL_MALFORMAT; + return result; } } else @@ -4412,16 +4403,18 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) if(ftpc->prevpath) { /* prevpath is "raw" so we convert the input path before we compare the strings */ - int dlen; - char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen); - if(!path) { + size_t dlen; + char *path; + CURLcode result = + Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE); + if(result) { freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; + return result; } - dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0; - if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) && - strnequal(path, ftpc->prevpath, dlen)) { + dlen -= ftpc->file?strlen(ftpc->file):0; + if((dlen == strlen(ftpc->prevpath)) && + !strncmp(path, ftpc->prevpath, dlen)) { infof(data, "Request has same path as previous transfer\n"); ftpc->cwddone = TRUE; } diff --git a/lib/ftp.h b/lib/ftp.h index 2ed5b43..dbd8567 100644 --- a/lib/ftp.h +++ b/lib/ftp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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,7 +31,7 @@ extern const struct Curl_handler Curl_handler_ftp; extern const struct Curl_handler Curl_handler_ftps; #endif -CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...); +CURLcode Curl_ftpsend(struct connectdata *, const char *cmd); CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn, int *ftpcode); #endif /* CURL_DISABLE_FTP */ diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index abbf76e..747dbba 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -45,7 +45,6 @@ #include "fileinfo.h" #include "llist.h" #include "strtoofft.h" -#include "rawstr.h" #include "ftp.h" #include "ftplistparser.h" #include "curl_fnmatch.h" diff --git a/lib/getenv.c b/lib/getenv.c index 50bb79f..89d181d 100644 --- a/lib/getenv.c +++ b/lib/getenv.c @@ -30,7 +30,8 @@ static char *GetEnv(const char *variable) { -#ifdef _WIN32_WCE +#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) + (void)variable; return NULL; #else #ifdef WIN32 diff --git a/lib/getinfo.c b/lib/getinfo.c index 262cd93..9641d79 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -36,8 +36,8 @@ #include "memdebug.h" /* - * This is supposed to be called in the beginning of a perform() session - * and should reset all session-info variables + * This is supposed to be called in the beginning of a perform() session and + * in curl_easy_reset() and should reset all session-info variables. */ CURLcode Curl_initinfo(struct Curl_easy *data) { @@ -58,18 +58,27 @@ CURLcode Curl_initinfo(struct Curl_easy *data) info->filetime = -1; /* -1 is an illegal time and thus means unknown */ info->timecond = FALSE; - free(info->contenttype); - info->contenttype = NULL; - info->header_size = 0; info->request_size = 0; + info->proxyauthavail = 0; + info->httpauthavail = 0; info->numconnects = 0; + free(info->contenttype); + info->contenttype = NULL; + + free(info->wouldredirect); + info->wouldredirect = NULL; + info->conn_primary_ip[0] = '\0'; info->conn_local_ip[0] = '\0'; info->conn_primary_port = 0; info->conn_local_port = 0; +#ifdef USE_SSL + Curl_ssl_free_certinfo(data); +#endif + return CURLE_OK; } diff --git a/lib/gopher.c b/lib/gopher.c index f1efb60..a073d0b 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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,13 +28,11 @@ #include #include "transfer.h" #include "sendf.h" - #include "progress.h" -#include "strequal.h" #include "gopher.h" -#include "rawstr.h" #include "select.h" #include "url.h" +#include "escape.h" #include "warnless.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -83,7 +81,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) char *sel; char *sel_org = NULL; ssize_t amount, k; - int len; + size_t len; *done = TRUE; /* unconditionally */ @@ -107,7 +105,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) newp[i] = '\x09'; /* ... and finally unescape */ - sel = curl_easy_unescape(data, newp, 0, &len); + result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE); if(!sel) return CURLE_OUT_OF_MEMORY; sel_org = sel; @@ -121,20 +119,17 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) result = Curl_write(conn, sockfd, sel, k, &amount); if(!result) { /* Which may not have written it all! */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount); - if(result) { - free(sel_org); - return result; - } + if(result) + break; + k -= amount; sel += amount; if(k < 1) break; /* but it did write it all */ } - else { - failf(data, "Failed sending Gopher request"); - free(sel_org); - return result; - } + else + break; + /* Don't busyloop. The entire loop thing is a work-around as it causes a BLOCKING behavior which is a NO-NO. This function should rather be split up in a do and a doing piece where the pieces that aren't @@ -144,14 +139,18 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) Wait a while for the socket to be writable. Note that this doesn't acknowledge the timeout. */ - Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 100); + if(SOCKET_WRITABLE(sockfd, 100) < 0) { + result = CURLE_SEND_ERROR; + break; + } } free(sel_org); - /* We can use Curl_sendf to send the terminal \r\n relatively safely and - save allocing another string/doing another _write loop. */ - result = Curl_sendf(sockfd, conn, "\r\n"); + if(!result) + /* We can use Curl_sendf to send the terminal \r\n relatively safely and + save allocing another string/doing another _write loop. */ + result = Curl_sendf(sockfd, conn, "\r\n"); if(result) { failf(data, "Failed sending Gopher request"); return result; diff --git a/lib/hostcheck.c b/lib/hostcheck.c index 4db9e6b..f545254 100644 --- a/lib/hostcheck.c +++ b/lib/hostcheck.c @@ -30,7 +30,7 @@ #endif #include "hostcheck.h" -#include "rawstr.h" +#include "strcase.h" #include "inet_pton.h" #include "curl_memory.h" @@ -77,7 +77,7 @@ static int hostmatch(char *hostname, char *pattern) pattern_wildcard = strchr(pattern, '*'); if(pattern_wildcard == NULL) - return Curl_raw_equal(pattern, hostname) ? + return strcasecompare(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; /* detect IP address as hostname and fail the match if so */ @@ -94,16 +94,16 @@ static int hostmatch(char *hostname, char *pattern) pattern_label_end = strchr(pattern, '.'); if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || pattern_wildcard > pattern_label_end || - Curl_raw_nequal(pattern, "xn--", 4)) { + strncasecompare(pattern, "xn--", 4)) { wildcard_enabled = 0; } if(!wildcard_enabled) - return Curl_raw_equal(pattern, hostname) ? + return strcasecompare(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; hostname_label_end = strchr(hostname, '.'); if(hostname_label_end == NULL || - !Curl_raw_equal(pattern_label_end, hostname_label_end)) + !strcasecompare(pattern_label_end, hostname_label_end)) return CURL_HOST_NOMATCH; /* The wildcard must match at least one character, so the left-most @@ -114,8 +114,8 @@ static int hostmatch(char *hostname, char *pattern) prefixlen = pattern_wildcard - pattern; suffixlen = pattern_label_end - (pattern_wildcard+1); - return Curl_raw_nequal(pattern, hostname, prefixlen) && - Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen, + return strncasecompare(pattern, hostname, prefixlen) && + strncasecompare(pattern_wildcard+1, hostname_label_end - suffixlen, suffixlen) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; } diff --git a/lib/hostip.c b/lib/hostip.c index f2d9841..24a922e 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -603,11 +603,14 @@ int Curl_resolv_timeout(struct connectdata *conn, /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */ return Curl_resolv(conn, hostname, port, entry); - if(timeout < 1000) + if(timeout < 1000) { /* The alarm() function only provides integer second resolution, so if we want to wait less than one second we must bail out already now. */ + failf(data, + "remaining timeout of %ld too small to resolve via SIGALRM method", + timeout); return CURLRESOLV_TIMEDOUT; - + } /* This allows us to time-out from the name resolver, as the timeout will generate a signal and we will siglongjmp() from that here. This technique has problems (see alarmfunc). diff --git a/lib/http.c b/lib/http.c index 378d8f7..e7788e7 100644 --- a/lib/http.c +++ b/lib/http.c @@ -53,7 +53,6 @@ #include "progress.h" #include "curl_base64.h" #include "cookie.h" -#include "strequal.h" #include "vauth/vauth.h" #include "vtls/vtls.h" #include "http_digest.h" @@ -68,7 +67,7 @@ #include "parsedate.h" /* for the week day and month names */ #include "strtoofft.h" #include "multiif.h" -#include "rawstr.h" +#include "strcase.h" #include "content_encoding.h" #include "http_proxy.h" #include "warnless.h" @@ -182,7 +181,7 @@ char *Curl_checkheaders(const struct connectdata *conn, struct Curl_easy *data = conn->data; for(head = data->set.headers;head; head=head->next) { - if(Curl_raw_nequal(head->data, thisheader, thislen)) + if(strncasecompare(head->data, thisheader, thislen)) return head->data; } @@ -208,7 +207,7 @@ char *Curl_checkProxyheaders(const struct connectdata *conn, for(head = (conn->bits.proxy && data->set.sep_headers) ? data->set.proxyheaders : data->set.headers; head; head=head->next) { - if(Curl_raw_nequal(head->data, thisheader, thislen)) + if(strncasecompare(head->data, thisheader, thislen)) return head->data; } @@ -462,7 +461,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) #endif /* This is not NTLM or many bytes left to send: close */ - connclose(conn, "Mid-auth HTTP and much data left to send"); + streamclose(conn, "Mid-auth HTTP and much data left to send"); data->req.size = 0; /* don't download any more than 0 bytes */ /* There still is data left to send, but this connection is marked for @@ -726,7 +725,7 @@ Curl_http_output_auth(struct connectdata *conn, conn->bits.netrc || !data->state.first_host || data->set.http_disable_hostname_check_before_authentication || - Curl_raw_equal(data->state.first_host, conn->host.name)) { + strcasecompare(data->state.first_host, conn->host.name)) { result = output_auth_headers(conn, authhost, request, path, FALSE); } else @@ -784,23 +783,27 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, while(*auth) { #ifdef USE_SPNEGO if(checkprefix("Negotiate", auth)) { - *availp |= CURLAUTH_NEGOTIATE; - authp->avail |= CURLAUTH_NEGOTIATE; - - if(authp->picked == CURLAUTH_NEGOTIATE) { - if(negdata->state == GSS_AUTHSENT || negdata->state == GSS_AUTHNONE) { - CURLcode result = Curl_input_negotiate(conn, proxy, auth); - if(!result) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->change.url); - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - data->state.authproblem = FALSE; - /* we received a GSS auth token and we dealt with it fine */ - negdata->state = GSS_AUTHRECV; + if((authp->avail & CURLAUTH_NEGOTIATE) || + Curl_auth_is_spnego_supported()) { + *availp |= CURLAUTH_NEGOTIATE; + authp->avail |= CURLAUTH_NEGOTIATE; + + if(authp->picked == CURLAUTH_NEGOTIATE) { + if(negdata->state == GSS_AUTHSENT || + negdata->state == GSS_AUTHNONE) { + CURLcode result = Curl_input_negotiate(conn, proxy, auth); + if(!result) { + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->change.url); + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + data->state.authproblem = FALSE; + /* we received a GSS auth token and we dealt with it fine */ + negdata->state = GSS_AUTHRECV; + } + else + data->state.authproblem = TRUE; } - else - data->state.authproblem = TRUE; } } } @@ -809,39 +812,44 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, #ifdef USE_NTLM /* NTLM support requires the SSL crypto libs */ if(checkprefix("NTLM", auth)) { - *availp |= CURLAUTH_NTLM; - authp->avail |= CURLAUTH_NTLM; - if(authp->picked == CURLAUTH_NTLM || - authp->picked == CURLAUTH_NTLM_WB) { - /* NTLM authentication is picked and activated */ - CURLcode result = Curl_input_ntlm(conn, proxy, auth); - if(!result) { - data->state.authproblem = FALSE; + if((authp->avail & CURLAUTH_NTLM) || + (authp->avail & CURLAUTH_NTLM_WB) || + Curl_auth_is_ntlm_supported()) { + *availp |= CURLAUTH_NTLM; + authp->avail |= CURLAUTH_NTLM; + + if(authp->picked == CURLAUTH_NTLM || + authp->picked == CURLAUTH_NTLM_WB) { + /* NTLM authentication is picked and activated */ + CURLcode result = Curl_input_ntlm(conn, proxy, auth); + if(!result) { + data->state.authproblem = FALSE; #ifdef NTLM_WB_ENABLED - if(authp->picked == CURLAUTH_NTLM_WB) { - *availp &= ~CURLAUTH_NTLM; - authp->avail &= ~CURLAUTH_NTLM; - *availp |= CURLAUTH_NTLM_WB; - authp->avail |= CURLAUTH_NTLM_WB; - - /* Get the challenge-message which will be passed to - * ntlm_auth for generating the type 3 message later */ - while(*auth && ISSPACE(*auth)) - auth++; - if(checkprefix("NTLM", auth)) { - auth += strlen("NTLM"); + if(authp->picked == CURLAUTH_NTLM_WB) { + *availp &= ~CURLAUTH_NTLM; + authp->avail &= ~CURLAUTH_NTLM; + *availp |= CURLAUTH_NTLM_WB; + authp->avail |= CURLAUTH_NTLM_WB; + + /* Get the challenge-message which will be passed to + * ntlm_auth for generating the type 3 message later */ while(*auth && ISSPACE(*auth)) auth++; - if(*auth) - if((conn->challenge_header = strdup(auth)) == NULL) - return CURLE_OUT_OF_MEMORY; + if(checkprefix("NTLM", auth)) { + auth += strlen("NTLM"); + while(*auth && ISSPACE(*auth)) + auth++; + if(*auth) + if((conn->challenge_header = strdup(auth)) == NULL) + return CURLE_OUT_OF_MEMORY; + } } - } #endif - } - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; + } + else { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } } } } @@ -849,18 +857,18 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, #endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(checkprefix("Digest", auth)) { - if((authp->avail & CURLAUTH_DIGEST) != 0) { + if((authp->avail & CURLAUTH_DIGEST) != 0) infof(data, "Ignoring duplicate digest auth header.\n"); - } - else { + else if(Curl_auth_is_digest_supported()) { CURLcode result; + *availp |= CURLAUTH_DIGEST; authp->avail |= CURLAUTH_DIGEST; /* We call this function on input Digest headers even if Digest * authentication isn't activated yet, as we need to store the - * incoming data from this header in case we are gonna use - * Digest. */ + * incoming data from this header in case we are going to use + * Digest */ result = Curl_input_digest(conn, proxy, auth); if(result) { infof(data, "Authentication problem. Ignoring this.\n"); @@ -1296,7 +1304,7 @@ Curl_compareheader(const char *headerline, /* line to check */ const char *start; const char *end; - if(!Curl_raw_nequal(headerline, header, hlen)) + if(!strncasecompare(headerline, header, hlen)) return FALSE; /* doesn't start with header */ /* pass the header */ @@ -1322,7 +1330,7 @@ Curl_compareheader(const char *headerline, /* line to check */ /* find the content string in the rest of the line */ for(;len>=clen;len--, start++) { - if(Curl_raw_nequal(start, content, clen)) + if(strncasecompare(start, content, clen)) return TRUE; /* match! */ } @@ -1443,9 +1451,8 @@ CURLcode Curl_http_done(struct connectdata *conn, { struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; -#ifdef USE_NGHTTP2 - struct http_conn *httpc = &conn->proto.httpc; -#endif + + infof(data, "Curl_http_done: called premature == %d\n", premature); Curl_unencode_cleanup(conn); @@ -1458,7 +1465,7 @@ CURLcode Curl_http_done(struct connectdata *conn, * Do not close CONNECT_ONLY connections. */ if((data->req.httpcode != 401) && (data->req.httpcode != 407) && !data->set.connect_only) - connclose(conn, "Negotiate transfer completed"); + streamclose(conn, "Negotiate transfer completed"); Curl_cleanup_negotiate(data); } #endif @@ -1475,27 +1482,7 @@ CURLcode Curl_http_done(struct connectdata *conn, http->send_buffer = NULL; /* clear the pointer */ } -#ifdef USE_NGHTTP2 - if(http->header_recvbuf) { - DEBUGF(infof(data, "free header_recvbuf!!\n")); - Curl_add_buffer_free(http->header_recvbuf); - http->header_recvbuf = NULL; /* clear the pointer */ - Curl_add_buffer_free(http->trailer_recvbuf); - http->trailer_recvbuf = NULL; /* clear the pointer */ - if(http->push_headers) { - /* if they weren't used and then freed before */ - for(; http->push_headers_used > 0; --http->push_headers_used) { - free(http->push_headers[http->push_headers_used - 1]); - } - free(http->push_headers); - http->push_headers = NULL; - } - } - if(http->stream_id) { - nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); - http->stream_id = 0; - } -#endif + Curl_http2_done(conn, premature); if(HTTPREQ_POST_FORM == data->set.httpreq) { data->req.bytecount = http->readbytecount + http->writebytecount; @@ -1660,6 +1647,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, Connection: */ checkprefix("Connection", headers->data)) ; + else if((conn->httpversion == 20) && + checkprefix("Transfer-Encoding:", headers->data)) + /* HTTP/2 doesn't support chunked requests */ + ; else { CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data); @@ -1946,47 +1937,42 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif - if(conn->httpversion == 20) - /* In HTTP2 forbids Transfer-Encoding: chunked */ - ptr = NULL; + ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); + if(ptr) { + /* Some kind of TE is requested, check if 'chunked' is chosen */ + data->req.upload_chunky = + Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); + } else { - ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); - if(ptr) { - /* Some kind of TE is requested, check if 'chunked' is chosen */ - data->req.upload_chunky = - Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); - } - else { - if((conn->handler->protocol&PROTO_FAMILY_HTTP) && - data->set.upload && - (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; - } - else { - failf(data, "Chunky upload is not supported by HTTP 1.0"); - return CURLE_UPLOAD_FAILED; - } + if((conn->handler->protocol&PROTO_FAMILY_HTTP) && + data->set.upload && + (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; } else { - /* else, no chunky upload */ - data->req.upload_chunky = FALSE; + failf(data, "Chunky upload is not supported by HTTP 1.0"); + return CURLE_UPLOAD_FAILED; } - - if(data->req.upload_chunky) - te = "Transfer-Encoding: chunked\r\n"; } + else { + /* else, no chunky upload */ + data->req.upload_chunky = FALSE; + } + + if(data->req.upload_chunky) + te = "Transfer-Encoding: chunked\r\n"; } Curl_safefree(conn->allocptr.host); ptr = Curl_checkheaders(conn, "Host:"); if(ptr && (!data->state.this_is_a_follow || - Curl_raw_equal(data->state.first_host, conn->host.name))) { + strcasecompare(data->state.first_host, conn->host.name))) { #if !defined(CURL_DISABLE_COOKIES) /* If we have a given custom Host: header, we extract the host name in order to possibly use it for cookie reasons later on. We only allow the @@ -2305,6 +2291,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) "%s" /* TE: */ "%s" /* accept-encoding */ "%s" /* referer */ + "%s" /* Proxy-Connection */ "%s",/* transfer-encoding */ ftp_typecode, @@ -2327,6 +2314,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.accept_encoding:"", (data->change.referer && conn->allocptr.ref)? conn->allocptr.ref:"" /* Referer: */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkProxyheaders(conn, "Proxy-Connection:"))? + "Proxy-Connection: Keep-Alive\r\n":"", te ); @@ -2392,7 +2383,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } co = co->next; /* next cookie please */ } - Curl_cookie_freelist(store, FALSE); /* free the cookie list */ + Curl_cookie_freelist(store); } if(addcookies && !result) { if(!count) @@ -2768,6 +2759,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } + if((conn->httpversion == 20) && data->req.upload_chunky) + /* upload_chunky was set above to set up the request in a chunky fashion, + but is disabled here again to avoid that the chunked encoded version is + actually used when sending the request body over h2 */ + data->req.upload_chunky = FALSE; return result; } @@ -3040,19 +3036,19 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #endif /* CURL_DOES_CONVERSIONS */ if(100 <= k->httpcode && 199 >= k->httpcode) { - /* - * We have made a HTTP PUT or POST and this is 1.1-lingo - * that tells us that the server is OK with this and ready - * to receive the data. - * However, we'll get more headers now so we must get - * back into the header-parsing state! - */ - k->header = TRUE; - k->headerline = 0; /* restart the header line counter */ - /* "A user agent MAY ignore unexpected 1xx status responses." */ switch(k->httpcode) { case 100: + /* + * We have made a HTTP PUT or POST and this is 1.1-lingo + * that tells us that the server is OK with this and ready + * to receive the data. + * However, we'll get more headers now so we must get + * back into the header-parsing state! + */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + /* if we did wait for this do enable write now! */ if(k->exp100 > EXP100_SEND_DATA) { k->exp100 = EXP100_SEND_DATA; @@ -3062,9 +3058,14 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, case 101: /* Switching Protocols */ if(k->upgr101 == UPGR101_REQUESTED) { + /* Switching to HTTP/2 */ infof(data, "Received 101\n"); k->upgr101 = UPGR101_RECEIVED; + /* we'll get more headers (HTTP/2 response) */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + /* switch to http2 now. The bytes after response headers are also processed here, otherwise they are lost. */ result = Curl_http2_switched(conn, k->str, *nread); @@ -3072,8 +3073,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return result; *nread = 0; } + else { + /* Switching to another protocol (e.g. WebSocket) */ + k->header = FALSE; /* no more header to parse! */ + } break; default: + /* the status code 1xx indicates a provisional response, so + we'll get another set of headers */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ break; } } @@ -3091,7 +3100,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, signal the end of the document. */ infof(data, "no chunk, no close, no size. Assume close to " "signal end\n"); - connclose(conn, "HTTP: No end-of-message indicator"); + streamclose(conn, "HTTP: No end-of-message indicator"); } } @@ -3171,12 +3180,21 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * connection for closure after we've read the entire response. */ if(!k->upload_done) { - infof(data, "HTTP error before end of send, stop sending\n"); - connclose(conn, "Stop sending data before everything sent"); - k->upload_done = TRUE; - k->keepon &= ~KEEP_SEND; /* don't send */ - if(data->state.expect100header) - k->exp100 = EXP100_FAILED; + 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; + k->keepon |= KEEP_SEND; + } + } + else { + infof(data, "HTTP error before end of send, stop sending\n"); + streamclose(conn, "Stop sending data before everything sent"); + k->upload_done = TRUE; + k->keepon &= ~KEEP_SEND; /* don't send */ + if(data->state.expect100header) + k->exp100 = EXP100_FAILED; + } } break; @@ -3476,7 +3494,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* Negative Content-Length is really odd, and we know it happens for example when older Apache servers send large files */ - connclose(conn, "negative content-length"); + streamclose(conn, "negative content-length"); infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T ", closing after transfer\n", contentlength); } @@ -3549,7 +3567,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * the connection will close when this request has been * served. */ - connclose(conn, "Connection: close used"); + streamclose(conn, "Connection: close used"); } else if(checkprefix("Transfer-Encoding:", k->p)) { /* One or more encodings. We check for chunked and/or a compression diff --git a/lib/http.h b/lib/http.h index 6529005..9fb669c 100644 --- a/lib/http.h +++ b/lib/http.h @@ -168,6 +168,7 @@ struct HTTP { 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 */ uint32_t error_code; /* HTTP/2 error code */ char *mem; /* points to a buffer in memory to store received data */ diff --git a/lib/http2.c b/lib/http2.c index efc082d..cfdb327 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -29,7 +29,7 @@ #include "http.h" #include "sendf.h" #include "curl_base64.h" -#include "rawstr.h" +#include "strcase.h" #include "multiif.h" #include "conncache.h" #include "url.h" @@ -92,8 +92,9 @@ static int http2_perform_getsock(const struct connectdata *conn, because of renegotiation. */ sock[0] = conn->sock[FIRSTSOCKET]; - if(nghttp2_session_want_read(c->h2)) - bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); + /* in a HTTP/2 connection we can basically always get a frame so we should + always be ready for one */ + bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); if(nghttp2_session_want_write(c->h2)) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); @@ -150,6 +151,7 @@ void Curl_http2_setup_req(struct Curl_easy *data) http->pauselen = 0; http->error_code = NGHTTP2_NO_ERROR; http->closed = FALSE; + http->close_handled = FALSE; http->mem = data->state.buffer; http->len = BUFSIZE; http->memlen = 0; @@ -184,7 +186,7 @@ const struct Curl_handler Curl_handler_http2 = { ZERO_NULL, /* readwrite */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ + PROTOPT_STREAM /* flags */ }; const struct Curl_handler Curl_handler_http2_ssl = { @@ -204,7 +206,7 @@ const struct Curl_handler Curl_handler_http2_ssl = { ZERO_NULL, /* readwrite */ PORT_HTTP, /* defport */ CURLPROTO_HTTPS, /* protocol */ - PROTOPT_SSL /* flags */ + PROTOPT_SSL | PROTOPT_STREAM /* flags */ }; /* @@ -317,7 +319,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) the middle of header, it could be matched in middle of the value, this is because we do prefix match.*/ if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || - Curl_raw_equal(header, ":") || strchr(header + 1, ':')) + !strcmp(header, ":") || strchr(header + 1, ':')) return NULL; else { struct HTTP *stream = h->data->req.protop; @@ -488,8 +490,11 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, } stream = data_s->req.protop; - if(!stream) + if(!stream) { + DEBUGF(infof(conn->data, "No proto pointer for stream: %x\n", + stream_id)); return NGHTTP2_ERR_CALLBACK_FAILURE; + } DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", frame->hd.type, stream_id)); @@ -547,7 +552,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, /* if we receive data for another handle, wake that up */ if(conn_s->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); } break; case NGHTTP2_PUSH_PROMISE: @@ -621,8 +626,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for - immediately? */ + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "%zu data received for stream %u " "(%zu left in buffer %p, total %zu)\n", @@ -883,7 +887,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, Curl_add_buffer(stream->header_recvbuf, " \r\n", 3); /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n", stream->status_code, data_s)); @@ -899,7 +903,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, value)); @@ -941,11 +945,12 @@ static ssize_t data_source_read_callback(nghttp2_session *session, memcpy(buf, stream->upload_mem, nread); stream->upload_mem += nread; stream->upload_len -= nread; - stream->upload_left -= nread; + if(data_s->state.infilesize != -1) + stream->upload_left -= nread; } if(stream->upload_left == 0) - *data_flags = 1; + *data_flags = NGHTTP2_DATA_FLAG_EOF; else if(nread == 0) return NGHTTP2_ERR_DEFERRED; @@ -979,6 +984,43 @@ static int error_callback(nghttp2_session *session, } #endif +void Curl_http2_done(struct connectdata *conn, bool premature) +{ + struct Curl_easy *data = conn->data; + struct HTTP *http = data->req.protop; + struct http_conn *httpc = &conn->proto.httpc; + + if(http->header_recvbuf) { + DEBUGF(infof(data, "free header_recvbuf!!\n")); + Curl_add_buffer_free(http->header_recvbuf); + http->header_recvbuf = NULL; /* clear the pointer */ + Curl_add_buffer_free(http->trailer_recvbuf); + http->trailer_recvbuf = NULL; /* clear the pointer */ + if(http->push_headers) { + /* if they weren't used and then freed before */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); + } + free(http->push_headers); + http->push_headers = NULL; + } + } + + if(premature) { + /* RST_STREAM */ + nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id, + NGHTTP2_STREAM_CLOSED); + if(http->stream_id == httpc->pause_stream_id) { + infof(data, "stopped the pause stream!\n"); + httpc->pause_stream_id = 0; + } + } + if(http->stream_id) { + nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); + http->stream_id = 0; + } +} + /* * Initialize nghttp2 for a Curl connection */ @@ -1091,9 +1133,10 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, /* * Returns nonzero if current HTTP/2 session should be closed. */ -static int should_close_session(struct http_conn *httpc) { +static int should_close_session(struct http_conn *httpc) +{ return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) && - !nghttp2_session_want_write(httpc->h2); + !nghttp2_session_want_write(httpc->h2); } static int h2_session_send(struct Curl_easy *data, @@ -1107,7 +1150,8 @@ static int h2_session_send(struct Curl_easy *data, */ static int h2_process_pending_input(struct Curl_easy *data, struct http_conn *httpc, - CURLcode *err) { + CURLcode *err) +{ ssize_t nread; char *inbuf; ssize_t rv; @@ -1155,9 +1199,41 @@ static int h2_process_pending_input(struct Curl_easy *data, return 0; } +/* + * Called from transfer.c:done_sending when we stop uploading. + */ +CURLcode Curl_http2_done_sending(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if((conn->handler == &Curl_handler_http2_ssl) || + (conn->handler == &Curl_handler_http2)) { + /* make sure this is only attempted for HTTP/2 transfers */ + + struct HTTP *stream = conn->data->req.protop; + + if(stream->upload_left) { + /* If the stream still thinks there's data left to upload. */ + struct http_conn *httpc = &conn->proto.httpc; + nghttp2_session *h2 = httpc->h2; + + stream->upload_left = 0; /* DONE! */ + + /* resume sending here to trigger the callback to get called again so + that it can signal EOF to nghttp2 */ + (void)nghttp2_session_resume_data(h2, stream->stream_id); + + (void)h2_process_pending_input(conn->data, httpc, &result); + } + } + return result; +} + + static ssize_t http2_handle_stream_close(struct connectdata *conn, struct Curl_easy *data, - struct HTTP *stream, CURLcode *err) { + struct HTTP *stream, CURLcode *err) +{ char *trailer_pos, *trailer_end; CURLcode result; struct http_conn *httpc = &conn->proto.httpc; @@ -1178,8 +1254,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, DEBUGASSERT(data->state.drain == 0); - /* Reset to FALSE to prevent infinite loop in readwrite_data - function. */ + /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ stream->closed = FALSE; if(stream->error_code != NGHTTP2_NO_ERROR) { failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)", @@ -1216,6 +1291,8 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, } } + stream->close_handled = TRUE; + DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); return 0; } @@ -1268,10 +1345,6 @@ static int h2_session_send(struct Curl_easy *data, return nghttp2_session_send(h2); } -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ static ssize_t http2_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { @@ -1382,6 +1455,8 @@ 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. */ + DEBUGF(infof(data, "stream %x is paused, pause id: %x\n", + stream->stream_id, httpc->pause_stream_id)); *err = CURLE_AGAIN; return -1; } @@ -1497,7 +1572,6 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, #define HEADER_OVERFLOW(x) \ (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen) -/* return number of received (decrypted) bytes */ static ssize_t http2_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { @@ -1525,6 +1599,14 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, DEBUGF(infof(conn->data, "http2_send len=%zu\n", len)); if(stream->stream_id != -1) { + if(stream->close_handled) { + infof(conn->data, "stream %d closed\n", stream->stream_id); + *err = CURLE_HTTP2_STREAM; + return -1; + } + else if(stream->closed) { + return http2_handle_stream_close(conn, conn->data, stream, err); + } /* If stream_id != -1, we have dispatched request HEADERS, and now are going to send or sending request body in DATA frame */ stream->upload_mem = mem; @@ -1661,12 +1743,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, goto fail; hlen = end - hdbuf; - if(hlen == 10 && Curl_raw_nequal("connection", hdbuf, 10)) { + if(hlen == 10 && strncasecompare("connection", hdbuf, 10)) { /* skip Connection: headers! */ skip = 1; --nheader; } - else if(hlen == 4 && Curl_raw_nequal("host", hdbuf, 4)) { + else if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; nva[i].namelen = strlen((char *)nva[i].name); @@ -1687,28 +1769,6 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, failf(conn->data, "Failed sending HTTP request: Header overflow"); goto fail; } - /* Inspect Content-Length header field and retrieve the request - entity length so that we can set END_STREAM to the last DATA - frame. */ - if(nva[i].namelen == 14 && - Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { - size_t j; - stream->upload_left = 0; - if(!nva[i].valuelen) - goto fail; - for(j = 0; j < nva[i].valuelen; ++j) { - if(nva[i].value[j] < '0' || nva[i].value[j] > '9') - goto fail; - if(stream->upload_left >= CURL_OFF_T_MAX / 10) - goto fail; - stream->upload_left *= 10; - stream->upload_left += nva[i].value[j] - '0'; - } - DEBUGF(infof(conn->data, - "request content-length=%" - CURL_FORMAT_CURL_OFF_T - "\n", stream->upload_left)); - } ++i; } } @@ -1736,6 +1796,10 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, if(nva[i].valuelen > max_acc - acc) break; acc += nva[i].valuelen; + + DEBUGF(infof(conn->data, "h2 header: %.*s:%.*s\n", + nva[i].namelen, nva[i].name, + nva[i].valuelen, nva[i].value)); } if(i != nheader) { @@ -1751,6 +1815,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_PUT: + if(conn->data->state.infilesize != -1) + stream->upload_left = conn->data->state.infilesize; + else + /* data sending without specifying the data amount up front */ + stream->upload_left = -1; /* unknown, but not zero */ + data_prd.read_callback = data_source_read_callback; data_prd.source.ptr = NULL; stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, @@ -1850,10 +1920,6 @@ CURLcode Curl_http2_setup(struct connectdata *conn) infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); Curl_multi_connchanged(conn->data->multi); - /* switch on TCP_NODELAY as we need to send off packets without delay for - maximum throughput */ - Curl_tcpnodelay(conn, conn->sock[FIRSTSOCKET]); - return CURLE_OK; } diff --git a/lib/http2.h b/lib/http2.h index bedbebf..8917535 100644 --- a/lib/http2.h +++ b/lib/http2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,6 +51,8 @@ CURLcode Curl_http2_switched(struct connectdata *conn, /* called from Curl_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); +CURLcode Curl_http2_done_sending(struct connectdata *conn); #else /* USE_NGHTTP2 */ #define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL @@ -61,6 +63,8 @@ void Curl_http2_setup_req(struct Curl_easy *data); #define Curl_http2_setup_req(x) #define Curl_http2_init_state(x) #define Curl_http2_init_userset(x) +#define Curl_http2_done(x,y) +#define Curl_http2_done_sending(x) #endif #endif /* HEADER_CURL_HTTP2_H */ diff --git a/lib/http_digest.c b/lib/http_digest.c index 97230e7..184d00b 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -25,7 +25,7 @@ #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) #include "urldata.h" -#include "rawstr.h" +#include "strcase.h" #include "vauth/vauth.h" #include "http_digest.h" /* The last 3 #include files should be in this order */ diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index c39d6f3..eb17ed4 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -26,7 +26,6 @@ #include "urldata.h" #include "sendf.h" -#include "rawstr.h" #include "http_negotiate.h" #include "vauth/vauth.h" diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index 935df25..e424040 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -35,7 +35,7 @@ #include "urldata.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "http_ntlm.h" #include "curl_ntlm_wb.h" #include "vauth/vauth.h" diff --git a/lib/http_proxy.c b/lib/http_proxy.c index c6b05e3..8f5e9b4 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -31,7 +31,6 @@ #include "http.h" #include "url.h" #include "select.h" -#include "rawstr.h" #include "progress.h" #include "non-ascii.h" #include "connect.h" @@ -160,6 +159,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(!result) { char *host=(char *)""; + const char *proxyconn=""; const char *useragent=""; const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; @@ -185,6 +185,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } } + if(!Curl_checkProxyheaders(conn, "Proxy-Connection:")) + proxyconn = "Proxy-Connection: Keep-Alive\r\n"; + if(!Curl_checkProxyheaders(conn, "User-Agent:") && data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; @@ -194,13 +197,15 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, "CONNECT %s HTTP/%s\r\n" "%s" /* Host: */ "%s" /* Proxy-Authorization */ - "%s", /* User-Agent */ + "%s" /* User-Agent */ + "%s", /* Proxy-Connection */ hostheader, http, host, conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", - useragent); + useragent, + proxyconn); if(host && *host) free(host); @@ -239,7 +244,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } if(!blocking) { - if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) + if(0 == SOCKET_READABLE(tunnelsocket, 0)) /* return so we'll be called again polling-style */ return CURLE_OK; else { @@ -274,8 +279,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } /* loop every second at least, less if the timeout is near */ - switch (Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, - check<1000L?check:1000)) { + switch (SOCKET_READABLE(tunnelsocket, check<1000L?check:1000)) { case -1: /* select() error, stop reading */ error = SELECT_ERROR; failf(data, "Proxy CONNECT aborted due to select/poll error"); @@ -568,7 +572,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, free(data->req.newurl); data->req.newurl = NULL; /* failure, close this connection to avoid re-use */ - connclose(conn, "proxy CONNECT failure"); + streamclose(conn, "proxy CONNECT failure"); Curl_closesocket(conn, conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; } diff --git a/lib/if2ip.c b/lib/if2ip.c index 2f92b2d..e6faa4b 100644 --- a/lib/if2ip.c +++ b/lib/if2ip.c @@ -51,7 +51,7 @@ #endif #include "inet_ntop.h" -#include "strequal.h" +#include "strcase.h" #include "if2ip.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -102,7 +102,7 @@ bool Curl_if_is_interface_name(const char *interf) if(getifaddrs(&head) >= 0) { for(iface=head; iface != NULL; iface=iface->ifa_next) { - if(curl_strequal(iface->ifa_name, interf)) { + if(strcasecompare(iface->ifa_name, interf)) { result = TRUE; break; } @@ -132,7 +132,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, for(iface = head; iface != NULL; iface=iface->ifa_next) { if(iface->ifa_addr != NULL) { if(iface->ifa_addr->sa_family == af) { - if(curl_strequal(iface->ifa_name, interf)) { + if(strcasecompare(iface->ifa_name, interf)) { void *addr; char *ip; char scope[12] = ""; @@ -180,7 +180,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, } } else if((res == IF2IP_NOT_FOUND) && - curl_strequal(iface->ifa_name, interf)) { + strcasecompare(iface->ifa_name, interf)) { res = IF2IP_AF_NOT_SUPPORTED; } } diff --git a/lib/imap.c b/lib/imap.c index 123ea3b..4aa7dcc 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -68,16 +68,15 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "imap.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_sasl.h" #include "warnless.h" @@ -271,7 +270,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd) /* Does the command name match and is it followed by a space character or at the end of line? */ - if(line + cmd_len <= end && Curl_raw_nequal(line, cmd, cmd_len) && + if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) && (line[cmd_len] == ' ' || line + cmd_len + 2 == end)) return TRUE; @@ -846,7 +845,7 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn, if(imapcode != 'O') { failf(data, "Got unexpected imap-server response"); - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + result = CURLE_WEIRD_SERVER_REPLY; } else result = imap_perform_capability(conn); @@ -1179,7 +1178,7 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, else { /* We don't know how to parse this line */ failf(pp->conn->data, "Failed to parse FETCH response."); - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + result = CURLE_WEIRD_SERVER_REPLY; } /* End of DO phase */ @@ -1198,7 +1197,7 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, (void)instate; /* No use for this yet */ if(imapcode != 'O') - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: Fix error code */ + result = CURLE_WEIRD_SERVER_REPLY; else /* End of DONE phase */ state(conn, IMAP_STOP); @@ -1275,7 +1274,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn) /* Was there an error parsing the response line? */ if(imapcode == -1) - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; if(!imapcode) break; @@ -1935,7 +1934,7 @@ static CURLcode imap_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) + if(strncasecompare(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&imapc->sasl, value, ptr - value); else @@ -2031,28 +2030,28 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) PARTIAL) stripping of the trailing slash character if it is present. Note: Unknown parameters trigger a URL_MALFORMAT error. */ - if(Curl_raw_equal(name, "UIDVALIDITY") && !imap->uidvalidity) { + if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uidvalidity = value; value = NULL; } - else if(Curl_raw_equal(name, "UID") && !imap->uid) { + else if(strcasecompare(name, "UID") && !imap->uid) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uid = value; value = NULL; } - else if(Curl_raw_equal(name, "SECTION") && !imap->section) { + else if(strcasecompare(name, "SECTION") && !imap->section) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->section = value; value = NULL; } - else if(Curl_raw_equal(name, "PARTIAL") && !imap->partial) { + else if(strcasecompare(name, "PARTIAL") && !imap->partial) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; diff --git a/lib/krb5.c b/lib/krb5.c index 87ce8ee..5d5c003 100644 --- a/lib/krb5.c +++ b/lib/krb5.c @@ -182,7 +182,7 @@ krb5_auth(void *app_data, struct connectdata *conn) for(;;) { /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { - result = Curl_ftpsendf(conn, "AUTH GSSAPI"); + result = Curl_ftpsend(conn, "AUTH GSSAPI"); if(result) return -2; @@ -243,16 +243,22 @@ krb5_auth(void *app_data, struct connectdata *conn) } if(output_buffer.length != 0) { + char *cmd; + result = Curl_base64_encode(data, (char *)output_buffer.value, output_buffer.length, &p, &base64_sz); if(result) { Curl_infof(data, "base64-encoding: %s\n", curl_easy_strerror(result)); - ret = AUTH_CONTINUE; + ret = AUTH_ERROR; break; } - result = Curl_ftpsendf(conn, "ADAT %s", p); + cmd = aprintf("ADAT %s", p); + if(cmd) + result = Curl_ftpsend(conn, cmd); + else + result = CURLE_OUT_OF_MEMORY; free(p); diff --git a/lib/ldap.c b/lib/ldap.c index a164627..7dbc1b0 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -69,12 +69,11 @@ #include "escape.h" #include "progress.h" #include "transfer.h" -#include "strequal.h" +#include "strcase.h" #include "strtok.h" #include "curl_ldap.h" #include "curl_multibyte.h" #include "curl_base64.h" -#include "rawstr.h" #include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -284,7 +283,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) /* Novell SDK supports DER or BASE64 files. */ int cert_type = LDAPSSL_CERT_FILETYPE_B64; if((data->set.str[STRING_CERT_TYPE]) && - (Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "DER"))) + (strcasecompare(data->set.str[STRING_CERT_TYPE], "DER"))) cert_type = LDAPSSL_CERT_FILETYPE_DER; if(!ldap_ca) { failf(data, "LDAP local: ERROR %s CA cert not set!", @@ -325,7 +324,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(data->set.ssl.verifypeer) { /* OpenLDAP SDK supports BASE64 files. */ if((data->set.str[STRING_CERT_TYPE]) && - (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) { + (!strcasecompare(data->set.str[STRING_CERT_TYPE], "PEM"))) { failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); result = CURLE_SSL_CERTPROBLEM; goto quit; @@ -708,16 +707,16 @@ static void _ldap_trace (const char *fmt, ...) */ static int str2scope (const char *p) { - if(strequal(p, "one")) - return LDAP_SCOPE_ONELEVEL; - if(strequal(p, "onetree")) - return LDAP_SCOPE_ONELEVEL; - if(strequal(p, "base")) - return LDAP_SCOPE_BASE; - if(strequal(p, "sub")) - return LDAP_SCOPE_SUBTREE; - if(strequal(p, "subtree")) - return LDAP_SCOPE_SUBTREE; + if(strcasecompare(p, "one")) + return LDAP_SCOPE_ONELEVEL; + if(strcasecompare(p, "onetree")) + return LDAP_SCOPE_ONELEVEL; + if(strcasecompare(p, "base")) + return LDAP_SCOPE_BASE; + if(strcasecompare(p, "sub")) + return LDAP_SCOPE_SUBTREE; + if(strcasecompare(p, "subtree")) + return LDAP_SCOPE_SUBTREE; return (-1); } @@ -767,7 +766,7 @@ static bool split_str(char *str, char ***out, size_t *count) * * Defined in RFC4516 section 2. */ -static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) +static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) { int rc = LDAP_SUCCESS; char *path; @@ -776,9 +775,9 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) size_t i; if(!conn->data || - !conn->data->state.path || - conn->data->state.path[0] != '/' || - !checkprefix("LDAP", conn->data->change.url)) + !conn->data->state.path || + conn->data->state.path[0] != '/' || + !checkprefix("LDAP", conn->data->change.url)) return LDAP_INVALID_SYNTAX; ludp->lud_scope = LDAP_SCOPE_BASE; @@ -798,12 +797,13 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) if(*p) { char *dn = p; char *unescaped; + CURLcode result; LDAP_TRACE (("DN '%s'\n", dn)); /* Unescape the DN */ - unescaped = curl_easy_unescape(conn->data, dn, 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE); + if(result) { rc = LDAP_NO_MEMORY; goto quit; @@ -862,12 +862,14 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) for(i = 0; i < count; i++) { char *unescaped; + CURLcode result; LDAP_TRACE (("attr[%d] '%s'\n", i, attributes[i])); /* Unescape the attribute */ - unescaped = curl_easy_unescape(conn->data, attributes[i], 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL, + FALSE); + if(result) { free(attributes); rc = LDAP_NO_MEMORY; @@ -930,12 +932,13 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) if(*p) { char *filter = p; char *unescaped; + CURLcode result; LDAP_TRACE (("filter '%s'\n", filter)); /* Unescape the filter */ - unescaped = curl_easy_unescape(conn->data, filter, 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE); + if(result) { rc = LDAP_NO_MEMORY; goto quit; @@ -971,8 +974,8 @@ quit: return rc; } -static int _ldap_url_parse (const struct connectdata *conn, - LDAPURLDesc **ludpp) +static int _ldap_url_parse(const struct connectdata *conn, + LDAPURLDesc **ludpp) { LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); int rc; @@ -981,7 +984,7 @@ static int _ldap_url_parse (const struct connectdata *conn, if(!ludp) return LDAP_NO_MEMORY; - rc = _ldap_url_parse2 (conn, ludp); + rc = _ldap_url_parse2(conn, ludp); if(rc != LDAP_SUCCESS) { _ldap_free_urldesc(ludp); ludp = NULL; @@ -990,7 +993,7 @@ static int _ldap_url_parse (const struct connectdata *conn, return (rc); } -static void _ldap_free_urldesc (LDAPURLDesc *ludp) +static void _ldap_free_urldesc(LDAPURLDesc *ludp) { size_t i; diff --git a/lib/libcurl.rc b/lib/libcurl.rc index 50b365d..c1efbad 100644 --- a/lib/libcurl.rc +++ b/lib/libcurl.rc @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,12 +44,12 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "The cURL library, https://curl.haxx.se/\0" + VALUE "CompanyName", "The curl library, https://curl.haxx.se/\0" VALUE "FileDescription", "libcurl Shared Library\0" VALUE "FileVersion", LIBCURL_VERSION "\0" VALUE "InternalName", "libcurl\0" VALUE "OriginalFilename", "libcurl.dll\0" - VALUE "ProductName", "The cURL library\0" + VALUE "ProductName", "The curl library\0" VALUE "ProductVersion", LIBCURL_VERSION "\0" VALUE "LegalCopyright", "© " LIBCURL_COPYRIGHT "\0" VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" diff --git a/lib/md5.c b/lib/md5.c index 84adb99..f818d32 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -124,7 +124,7 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) CC_MD5_Final(digest, ctx); } -#elif defined(_WIN32) +#elif defined(_WIN32) && !defined(CURL_WINDOWS_APP) #include #include "curl_memory.h" diff --git a/lib/mprintf.c b/lib/mprintf.c index 73f854b..2c88aa8 100644 --- a/lib/mprintf.c +++ b/lib/mprintf.c @@ -227,10 +227,12 @@ static bool dprintf_IsQualifierNoDollar(const char *fmt) * Create an index with the type of each parameter entry and its * value (may vary in size) * + * Returns zero on success. + * ******************************************************************/ -static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, - va_list arglist) +static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, + va_list arglist) { char *fmt = (char *)format; int param_num = 0; @@ -393,6 +395,10 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, i = this_param - 1; + if((i < 0) || (i >= MAX_PARAMETERS)) + /* out of allowed range */ + return 1; + switch (*fmt) { case 'S': flags |= FLAGS_ALT; @@ -549,7 +555,7 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, } } - return max_param; + return 0; } @@ -587,7 +593,8 @@ static int dprintf_formatf( char *workend = &work[sizeof(work) - 2]; /* Do the actual %-code parsing */ - dprintf_Pass1(format, vto, endpos, ap_save); + if(dprintf_Pass1(format, vto, endpos, ap_save)) + return -1; end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1() created for us */ @@ -992,7 +999,7 @@ int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, info.max = maxlength; retcode = dprintf_formatf(&info, addbyter, format, ap_save); - if(info.max) { + if((retcode != -1) && info.max) { /* we terminate this with a zero byte */ if(info.max == info.length) /* we're at maximum, scrap the last letter */ @@ -1029,16 +1036,19 @@ static int alloc_addbyter(int output, FILE *data) infop->len =0; } else if(infop->len+1 >= infop->alloc) { - char *newptr; + char *newptr = NULL; + size_t newsize = infop->alloc*2; - newptr = realloc(infop->buffer, infop->alloc*2); + /* detect wrap-around or other overflow problems */ + if(newsize > infop->alloc) + newptr = realloc(infop->buffer, newsize); if(!newptr) { infop->fail = 1; return -1; /* fail */ } infop->buffer = newptr; - infop->alloc *= 2; + infop->alloc = newsize; } infop->buffer[ infop->len ] = outc; diff --git a/lib/multi.c b/lib/multi.c index 8bb9366..2432b15 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -42,6 +42,7 @@ #include "multihandle.h" #include "pipeline.h" #include "sigpipe.h" +#include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -442,7 +443,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, sockets that time-out or have actions will be dealt with. Since this handle has no action yet, we make sure it times out to get things to happen. */ - Curl_expire(data, 1); + Curl_expire(data, 0); /* increase the node-counter */ multi->num_easy++; @@ -462,6 +463,14 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, handle is added */ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + /* The closure handle only ever has default timeouts set. To improve the + state somewhat we clone the timeouts from each added handle so that the + closure handle always has the same timeouts as the most recently added + easy handle. */ + multi->closure_handle->set.timeout = data->set.timeout; + multi->closure_handle->set.server_response_timeout = + data->set.server_response_timeout; + update_timer(multi); return CURLM_OK; } @@ -569,12 +578,12 @@ static CURLcode multi_done(struct connectdata **connp, result = CURLE_ABORTED_BY_CALLBACK; } - if((!premature && - conn->send_pipe->size + conn->recv_pipe->size != 0 && - !data->set.reuse_forbid && - !conn->bits.close)) { + if(conn->send_pipe->size + conn->recv_pipe->size != 0 && + !data->set.reuse_forbid && + !conn->bits.close) { /* Stop if pipeline is not empty and we do not have to close connection. */ + data->easy_conn = NULL; DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n")); return CURLE_OK; } @@ -685,7 +694,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* If the handle is in a pipeline and has started sending off its request but not received its response yet, we need to close connection. */ - connclose(data->easy_conn, "Removed with partial response"); + streamclose(data->easy_conn, "Removed with partial response"); /* Set connection owner so that the DONE function closes it. We can safely do this here since connection is killed. */ data->easy_conn->data = easy; @@ -695,7 +704,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* The timer must be shut down before data->multi is set to NULL, else the timenode will remain in the splay tree after curl_easy_cleanup is called. */ - Curl_expire(data, 0); + Curl_expire_clear(data); if(data->dns.hostcachetype == HCACHE_MULTI) { /* stop using the multi handle's DNS cache */ @@ -1298,7 +1307,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, return CURLM_BAD_EASY_HANDLE; do { - bool disconnect_conn = FALSE; + /* A "stream" here is a logical stream if the protocol can handle that + (HTTP/2), or the full connection for older protocols */ + bool stream_error = FALSE; rc = CURLM_OK; /* Handle the case when the pipe breaks, i.e., the connection @@ -1376,8 +1387,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Force connection closed if the connection has indeed been used */ if(data->mstate > CURLM_STATE_DO) { - connclose(data->easy_conn, "Disconnected with pending data"); - disconnect_conn = TRUE; + streamclose(data->easy_conn, "Disconnected with pending data"); + stream_error = TRUE; } result = CURLE_OPERATION_TIMEDOUT; (void)multi_done(&data->easy_conn, result, TRUE); @@ -1426,7 +1437,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Add this handle to the send or pend pipeline */ result = Curl_add_handle_to_pipeline(data, data->easy_conn); if(result) - disconnect_conn = TRUE; + stream_error = TRUE; else { if(async) /* We're now waiting for an asynchronous name lookup */ @@ -1518,7 +1529,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(result) { /* failure detected */ - disconnect_conn = TRUE; + stream_error = TRUE; break; } } @@ -1558,7 +1569,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(result) { /* failure detected */ /* Just break, the cleaning up is handled all in one place */ - disconnect_conn = TRUE; + stream_error = TRUE; break; } break; @@ -1578,7 +1589,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, TRUE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1595,7 +1606,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, TRUE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1670,7 +1681,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(drc) { /* a failure here pretty much implies an out of memory */ result = drc; - disconnect_conn = TRUE; + stream_error = TRUE; } else retry = (newurl)?TRUE:FALSE; @@ -1703,7 +1714,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } else { /* Have error handler disconnect conn if we can't retry */ - disconnect_conn = TRUE; + stream_error = TRUE; free(newurl); } } @@ -1712,7 +1723,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_posttransfer(data); if(data->easy_conn) multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } } break; @@ -1734,7 +1745,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1763,7 +1774,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1800,9 +1811,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, result = Curl_speedcheck(data, now); if(( (data->set.max_send_speed == 0) || - (data->progress.ulspeed < data->set.max_send_speed)) && + (Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now) <= 0)) && ( (data->set.max_recv_speed == 0) || - (data->progress.dlspeed < data->set.max_recv_speed))) + (Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now) <= 0))) multistate(data, CURLM_STATE_PERFORM); break; @@ -1810,41 +1829,38 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, { char *newurl = NULL; bool retry = FALSE; + bool comeback = FALSE; /* check if over send speed */ - if((data->set.max_send_speed > 0) && - (data->progress.ulspeed > data->set.max_send_speed)) { - int buffersize; - - multistate(data, CURLM_STATE_TOOFAST); - - /* calculate upload rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - timeout_ms = Curl_sleep_time(data->set.max_send_speed, - data->progress.ulspeed, buffersize); - Curl_expire_latest(data, timeout_ms); - break; + if(data->set.max_send_speed > 0) { + timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now); + if(timeout_ms > 0) { + multistate(data, CURLM_STATE_TOOFAST); + Curl_expire_latest(data, timeout_ms); + break; + } } /* check if over recv speed */ - if((data->set.max_recv_speed > 0) && - (data->progress.dlspeed > data->set.max_recv_speed)) { - int buffersize; - - multistate(data, CURLM_STATE_TOOFAST); - - /* Calculate download rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - timeout_ms = Curl_sleep_time(data->set.max_recv_speed, - data->progress.dlspeed, buffersize); - Curl_expire_latest(data, timeout_ms); - break; + if(data->set.max_recv_speed > 0) { + timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now); + if(timeout_ms > 0) { + multistate(data, CURLM_STATE_TOOFAST); + Curl_expire_latest(data, timeout_ms); + break; + } } /* read/write data if it is ready to do so */ - result = Curl_readwrite(data->easy_conn, data, &done); + result = Curl_readwrite(data->easy_conn, data, &done, &comeback); k = &data->req; @@ -1884,10 +1900,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) && result != CURLE_HTTP2_STREAM) - connclose(data->easy_conn, "Transfer returned error"); + streamclose(data->easy_conn, "Transfer returned error"); Curl_posttransfer(data); - multi_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, TRUE); } else if(done) { followtype follow=FOLLOW_NONE; @@ -1900,7 +1916,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* expire the new receiving pipeline head */ if(data->easy_conn->recv_pipe->head) - Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 1); + Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 0); /* Check if we can move pending requests to send pipe */ Curl_multi_process_pending_handles(multi); @@ -1943,13 +1959,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!result) newurl = NULL; /* allocation was handed over Curl_follow() */ else - disconnect_conn = TRUE; + stream_error = TRUE; } multistate(data, CURLM_STATE_DONE); rc = CURLM_CALL_MULTI_PERFORM; } } + else if(comeback) + rc = CURLM_CALL_MULTI_PERFORM; free(newurl); break; @@ -2008,7 +2026,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, that could be freed anytime */ data->easy_conn = NULL; - Curl_expire(data, 0); /* stop all timers */ + Curl_expire_clear(data); /* stop all timers */ break; case CURLM_STATE_MSGSENT: @@ -2042,7 +2060,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_removeHandleFromPipeline(data, data->easy_conn->send_pipe); Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); - if(disconnect_conn) { + if(stream_error) { /* Don't attempt to send data over a connection that timed out */ bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; /* disconnect properly */ @@ -2066,7 +2084,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* aborted due to progress callback return code must close the connection */ result = CURLE_ABORTED_BY_CALLBACK; - connclose(data->easy_conn, "Aborted by callback"); + streamclose(data->easy_conn, "Aborted by callback"); /* if not yet in DONE state, go there, otherwise COMPLETED */ multistate(data, (data->mstate < CURLM_STATE_DONE)? @@ -2160,6 +2178,7 @@ static void close_all_connections(struct Curl_multi *multi) conn->data->easy_conn = NULL; /* clear the easy handle's connection pointer */ /* This will remove the connection from the cache */ + connclose(conn, "kill all"); (void)Curl_disconnect(conn, FALSE); sigpipe_restore(&pipe_st); @@ -2876,92 +2895,59 @@ multi_addtimeout(struct curl_llist *timeoutlist, * given a number of milliseconds from now to use to set the 'act before * this'-time for the transfer, to be extracted by curl_multi_timeout() * - * Note that the timeout will be added to a queue of timeouts if it defines a - * moment in time that is later than the current head of queue. - * - * Pass zero to clear all timeout values for this handle. -*/ + * The timeout will be added to a queue of timeouts if it defines a moment in + * time that is later than the current head of queue. + */ void Curl_expire(struct Curl_easy *data, long milli) { struct Curl_multi *multi = data->multi; struct timeval *nowp = &data->state.expiretime; int rc; + struct timeval set; /* this is only interesting while there is still an associated multi struct remaining! */ if(!multi) return; - if(!milli) { - /* No timeout, clear the time data. */ - if(nowp->tv_sec || nowp->tv_usec) { - /* Since this is an cleared time, we must remove the previous entry from - the splay tree */ - struct curl_llist *list = data->state.timeoutlist; - - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error clearing splay node = %d\n", rc); - - /* flush the timeout list too */ - while(list->size > 0) - Curl_llist_remove(list, list->tail, NULL); + set = Curl_tvnow(); + set.tv_sec += milli/1000; + set.tv_usec += (milli%1000)*1000; -#ifdef DEBUGBUILD - infof(data, "Expire cleared\n"); -#endif - nowp->tv_sec = 0; - nowp->tv_usec = 0; - } + if(set.tv_usec >= 1000000) { + set.tv_sec++; + set.tv_usec -= 1000000; } - else { - struct timeval set; - - set = Curl_tvnow(); - set.tv_sec += milli/1000; - set.tv_usec += (milli%1000)*1000; - - if(set.tv_usec >= 1000000) { - set.tv_sec++; - set.tv_usec -= 1000000; - } - - if(nowp->tv_sec || nowp->tv_usec) { - /* This means that the struct is added as a node in the splay tree. - Compare if the new time is earlier, and only remove-old/add-new if it - is. */ - long diff = curlx_tvdiff(set, *nowp); - if(diff > 0) { - /* the new expire time was later so just add it to the queue - and get out */ - multi_addtimeout(data->state.timeoutlist, &set); - return; - } - /* the new time is newer than the presently set one, so add the current - to the queue and update the head */ - multi_addtimeout(data->state.timeoutlist, nowp); - - /* Since this is an updated time, we must remove the previous entry from - the splay tree first and then re-add the new value */ - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error removing splay node = %d\n", rc); + if(nowp->tv_sec || nowp->tv_usec) { + /* This means that the struct is added as a node in the splay tree. + Compare if the new time is earlier, and only remove-old/add-new if it + is. */ + long diff = curlx_tvdiff(set, *nowp); + if(diff > 0) { + /* the new expire time was later so just add it to the queue + and get out */ + multi_addtimeout(data->state.timeoutlist, &set); + return; } - *nowp = set; - data->state.timenode.payload = data; - multi->timetree = Curl_splayinsert(*nowp, - multi->timetree, - &data->state.timenode); + /* the new time is newer than the presently set one, so add the current + to the queue and update the head */ + multi_addtimeout(data->state.timeoutlist, nowp); + + /* Since this is an updated time, we must remove the previous entry from + the splay tree first and then re-add the new value */ + rc = Curl_splayremovebyaddr(multi->timetree, + &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error removing splay node = %d\n", rc); } -#if 0 - Curl_splayprint(multi->timetree, 0, TRUE); -#endif + + *nowp = set; + data->state.timenode.payload = data; + multi->timetree = Curl_splayinsert(*nowp, multi->timetree, + &data->state.timenode); } /* @@ -3004,6 +2990,49 @@ void Curl_expire_latest(struct Curl_easy *data, long milli) Curl_expire(data, milli); } + +/* + * Curl_expire_clear() + * + * Clear ALL timeout values for this handle. + */ +void Curl_expire_clear(struct Curl_easy *data) +{ + struct Curl_multi *multi = data->multi; + struct timeval *nowp = &data->state.expiretime; + int rc; + + /* this is only interesting while there is still an associated multi struct + remaining! */ + if(!multi) + return; + + if(nowp->tv_sec || nowp->tv_usec) { + /* Since this is an cleared time, we must remove the previous entry from + the splay tree */ + struct curl_llist *list = data->state.timeoutlist; + + rc = Curl_splayremovebyaddr(multi->timetree, + &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error clearing splay node = %d\n", rc); + + /* flush the timeout list too */ + while(list->size > 0) + Curl_llist_remove(list, list->tail, NULL); + +#ifdef DEBUGBUILD + infof(data, "Expire cleared\n"); +#endif + nowp->tv_sec = 0; + nowp->tv_usec = 0; + } +} + + + + CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s, void *hashp) { @@ -3064,7 +3093,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) Curl_llist_remove(multi->pending, e, NULL); /* Make sure that the handle will be processed soonish. */ - Curl_expire_latest(data, 1); + Curl_expire_latest(data, 0); } e = next; /* operate on next handle */ diff --git a/lib/multiif.h b/lib/multiif.h index fd2df55..eaff496 100644 --- a/lib/multiif.h +++ b/lib/multiif.h @@ -26,6 +26,7 @@ * Prototypes for library-wide functions provided by multi.c */ void Curl_expire(struct Curl_easy *data, long milli); +void Curl_expire_clear(struct Curl_easy *data); void Curl_expire_latest(struct Curl_easy *data, long milli); bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits); void Curl_multi_handlePipeBreak(struct Curl_easy *data); diff --git a/lib/netrc.c b/lib/netrc.c index 46f427a..996711d 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -28,10 +28,8 @@ #include #include "netrc.h" - -#include "strequal.h" #include "strtok.h" -#include "rawstr.h" +#include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -130,20 +128,20 @@ int Curl_parsenetrc(const char *host, switch(state) { case NOTHING: - if(Curl_raw_equal("machine", tok)) { + if(strcasecompare("machine", tok)) { /* the next tok is the machine name, this is in itself the delimiter that starts the stuff entered for this machine, after this we need to search for 'login' and 'password'. */ state=HOSTFOUND; } - else if(Curl_raw_equal("default", tok)) { + else if(strcasecompare("default", tok)) { state=HOSTVALID; retcode=0; /* we did find our host */ } break; case HOSTFOUND: - if(Curl_raw_equal(host, tok)) { + if(strcasecompare(host, tok)) { /* and yes, this is our host! */ state=HOSTVALID; retcode=0; /* we did find our host */ @@ -156,7 +154,7 @@ int Curl_parsenetrc(const char *host, /* we are now parsing sub-keywords concerning "our" host */ if(state_login) { if(specific_login) { - state_our_login = Curl_raw_equal(*loginp, tok); + state_our_login = strcasecompare(*loginp, tok); } else { free(*loginp); @@ -179,11 +177,11 @@ int Curl_parsenetrc(const char *host, } state_password=0; } - else if(Curl_raw_equal("login", tok)) + else if(strcasecompare("login", tok)) state_login=1; - else if(Curl_raw_equal("password", tok)) + else if(strcasecompare("password", tok)) state_password=1; - else if(Curl_raw_equal("machine", tok)) { + else if(strcasecompare("machine", tok)) { /* ok, there's machine here go => */ state = HOSTFOUND; state_our_login = FALSE; diff --git a/lib/parsedate.c b/lib/parsedate.c index dfcf855..3c783be 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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 @@ #endif #include -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "parsedate.h" @@ -211,7 +211,7 @@ static int checkday(const char *check, size_t len) else what = &Curl_wkday[0]; for(i=0; i<7; i++) { - if(Curl_raw_equal(check, what[0])) { + if(strcasecompare(check, what[0])) { found=TRUE; break; } @@ -228,7 +228,7 @@ static int checkmonth(const char *check) what = &Curl_month[0]; for(i=0; i<12; i++) { - if(Curl_raw_equal(check, what[0])) { + if(strcasecompare(check, what[0])) { found=TRUE; break; } @@ -248,7 +248,7 @@ static int checktz(const char *check) what = tz; for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) { - if(Curl_raw_equal(check, what->name)) { + if(strcasecompare(check, what->name)) { found=TRUE; break; } @@ -386,15 +386,17 @@ static int parsedate(const char *date, time_t *output) /* a digit */ int val; char *end; + int len=0; if((secnum == -1) && - (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { + (3 == sscanf(date, "%02d:%02d:%02d%n", + &hournum, &minnum, &secnum, &len))) { /* time stamp! */ - date += 8; + date += len; } else if((secnum == -1) && - (2 == sscanf(date, "%02d:%02d", &hournum, &minnum))) { + (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) { /* time stamp without seconds */ - date += 5; + date += len; secnum = 0; } else { diff --git a/lib/pingpong.c b/lib/pingpong.c index 92ff84b..bf2c8fd 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -108,7 +108,8 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) /* We are receiving and there is data ready in the SSL library */ rc = 1; else - rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + CURL_SOCKET_BAD, pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ interval_ms); diff --git a/lib/pipeline.c b/lib/pipeline.c index 0ff82f0..40a5e82 100644 --- a/lib/pipeline.c +++ b/lib/pipeline.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2013, Linus Nielsen Feltzing, - * Copyright (C) 2013-2015, Daniel Stenberg, , et al. + * Copyright (C) 2013-2016, Daniel Stenberg, , 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,7 +31,7 @@ #include "multiif.h" #include "pipeline.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -114,7 +114,7 @@ CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { /* this is a new one as head, expire it */ Curl_pipeline_leave_write(conn); /* not in use yet */ - Curl_expire(conn->send_pipe->head->ptr, 1); + Curl_expire(conn->send_pipe->head->ptr, 0); } #if 0 /* enable for pipeline debugging */ @@ -149,7 +149,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, infof(conn->data, "%p is at send pipe head B!\n", (void *)conn->send_pipe->head->ptr); #endif - Curl_expire(conn->send_pipe->head->ptr, 1); + Curl_expire(conn->send_pipe->head->ptr, 0); } /* The receiver's list is not really interesting here since either this @@ -177,7 +177,7 @@ bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct site_blacklist_entry *site; site = curr->ptr; - if(Curl_raw_equal(site->hostname, conn->host.name) && + if(strcasecompare(site->hostname, conn->host.name) && site->port == conn->remote_port) { infof(handle, "Site %s:%d is pipeline blacklisted\n", conn->host.name, conn->remote_port); @@ -269,7 +269,7 @@ bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *bl_server_name; bl_server_name = curr->ptr; - if(Curl_raw_nequal(bl_server_name, server_name, + if(strncasecompare(bl_server_name, server_name, strlen(bl_server_name))) { infof(handle, "Server %s is blacklisted\n", server_name); return TRUE; diff --git a/lib/pop3.c b/lib/pop3.c index 591e877..8486519 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -70,16 +70,14 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "pop3.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" @@ -663,7 +661,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, if(pop3code != '+') { failf(data, "Got unexpected pop3-server response"); - result = CURLE_FTP_WEIRD_SERVER_REPLY; + result = CURLE_WEIRD_SERVER_REPLY; } else { /* Does the server support APOP authentication? */ @@ -1412,11 +1410,11 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) { + if(strncasecompare(key, "AUTH=", 5)) { result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, value, ptr - value); - if(result && strnequal(value, "+APOP", ptr - value)) { + if(result && strncasecompare(value, "+APOP", ptr - value)) { pop3c->preftype = POP3_TYPE_APOP; pop3c->sasl.prefmech = SASL_AUTH_NONE; result = CURLE_OK; diff --git a/lib/progress.c b/lib/progress.c index 760ca1c..0f67ef2 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -216,18 +216,93 @@ void Curl_pgrsStartNow(struct Curl_easy *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_tvnow(); + data->progress.ul_limit_start.tv_sec = 0; + data->progress.ul_limit_start.tv_usec = 0; + data->progress.dl_limit_start.tv_sec = 0; + data->progress.dl_limit_start.tv_usec = 0; /* clear all bits except HIDE and HEADERS_OUT */ data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; } +/* + * This is used to handle speed limits, calculating how much milliseconds we + * need to wait until we're back under the speed limit, if needed. + * + * The way it works is by having a "starting point" (time & amount of data + * transfered by then) used in the speed computation, to be used instead of the + * start of the transfer. + * This starting point is regularly moved as transfer goes on, to keep getting + * accurate values (instead of average over the entire tranfer). + * + * This function takes the current amount of data transfered, the amount at the + * starting point, the limit (in bytes/s), the time of the starting point and + * the current time. + * + * Returns -1 if no waiting is needed (not enough data transfered since + * starting point yet), 0 when no waiting is needed but the starting point + * should be reset (to current), or the number of milliseconds to wait to get + * back under the speed limit. + */ +long Curl_pgrsLimitWaitTime(curl_off_t cursize, + curl_off_t startsize, + curl_off_t limit, + struct timeval start, + struct timeval now) +{ + curl_off_t size = cursize - startsize; + long minimum, actual; + + /* we don't have a starting point yet -- return 0 so it gets (re)set */ + if(start.tv_sec == 0 && start.tv_usec == 0) + return 0; + + /* not enough data yet */ + if(size < limit) + return -1; + + minimum = (long) (CURL_OFF_T_C(1000) * size / limit); + actual = Curl_tvdiff(now, start); + + if(actual < minimum) + return minimum - actual; + else + return 0; +} + void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) { + struct timeval now = Curl_tvnow(); + data->progress.downloaded = size; + + /* download speed limit */ + if((data->set.max_recv_speed > 0) && + (Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now) == 0)) { + data->progress.dl_limit_start = now; + data->progress.dl_limit_size = size; + } } void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size) { + struct timeval now = Curl_tvnow(); + data->progress.uploaded = size; + + /* upload speed limit */ + if((data->set.max_send_speed > 0) && + (Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now) == 0)) { + data->progress.ul_limit_start = now; + data->progress.ul_limit_size = size; + } } void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size) diff --git a/lib/progress.h b/lib/progress.h index a77b7ce..155ff04 100644 --- a/lib/progress.h +++ b/lib/progress.h @@ -49,7 +49,11 @@ void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); int Curl_pgrsUpdate(struct connectdata *); void Curl_pgrsResetTimesSizes(struct Curl_easy *data); void Curl_pgrsTime(struct Curl_easy *data, timerid timer); - +long Curl_pgrsLimitWaitTime(curl_off_t cursize, + curl_off_t startsize, + curl_off_t limit, + struct timeval start, + struct timeval now); /* Don't show progress for sizes smaller than: */ #define LEAST_SIZE_PROGRESS BUFSIZE diff --git a/lib/rawstr.c b/lib/rawstr.c deleted file mode 100644 index 5665ebd..0000000 --- a/lib/rawstr.c +++ /dev/null @@ -1,148 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#include "rawstr.h" - -/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because - its behavior is altered by the current locale. */ -char Curl_raw_toupper(char in) -{ -#if !defined(CURL_DOES_CONVERSIONS) - if(in >= 'a' && in <= 'z') - return (char)('A' + in - 'a'); -#else - switch (in) { - case 'a': - return 'A'; - case 'b': - return 'B'; - case 'c': - return 'C'; - case 'd': - return 'D'; - case 'e': - return 'E'; - case 'f': - return 'F'; - case 'g': - return 'G'; - case 'h': - return 'H'; - case 'i': - return 'I'; - case 'j': - return 'J'; - case 'k': - return 'K'; - case 'l': - return 'L'; - case 'm': - return 'M'; - case 'n': - return 'N'; - case 'o': - return 'O'; - case 'p': - return 'P'; - case 'q': - return 'Q'; - case 'r': - return 'R'; - case 's': - return 'S'; - case 't': - return 'T'; - case 'u': - return 'U'; - case 'v': - return 'V'; - case 'w': - return 'W'; - case 'x': - return 'X'; - case 'y': - return 'Y'; - case 'z': - return 'Z'; - } -#endif - - return in; -} - -/* - * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant - * to be locale independent and only compare strings we know are safe for - * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for - * some further explanation to why this function is necessary. - * - * The function is capable of comparing a-z case insensitively even for - * non-ascii. - */ - -int Curl_raw_equal(const char *first, const char *second) -{ - while(*first && *second) { - if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) - /* get out of the loop as soon as they don't match */ - break; - first++; - second++; - } - /* we do the comparison here (possibly again), just to make sure that if the - loop above is skipped because one of the strings reached zero, we must not - return this as a successful match */ - return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); -} - -int Curl_raw_nequal(const char *first, const char *second, size_t max) -{ - while(*first && *second && max) { - if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { - break; - } - max--; - first++; - second++; - } - if(0 == max) - return 1; /* they are equal this far */ - - return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); -} - -/* Copy an upper case version of the string from src to dest. The - * strings may overlap. No more than n characters of the string are copied - * (including any NUL) and the destination string will NOT be - * NUL-terminated if that limit is reached. - */ -void Curl_strntoupper(char *dest, const char *src, size_t n) -{ - if(n < 1) - return; - - do { - *dest++ = Curl_raw_toupper(*src); - } while(*src++ && --n); -} diff --git a/lib/rawstr.h b/lib/rawstr.h deleted file mode 100644 index 4af00f1..0000000 --- a/lib/rawstr.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef HEADER_CURL_RAWSTR_H -#define HEADER_CURL_RAWSTR_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -/* - * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant - * to be locale independent and only compare strings we know are safe for - * this. - * - * The function is capable of comparing a-z case insensitively even for - * non-ascii. - */ -int Curl_raw_equal(const char *first, const char *second); -int Curl_raw_nequal(const char *first, const char *second, size_t max); - -char Curl_raw_toupper(char in); - -/* checkprefix() is a shorter version of the above, used when the first - argument is zero-byte terminated */ -#define checkprefix(a,b) Curl_raw_nequal(a,b,strlen(a)) - -void Curl_strntoupper(char *dest, const char *src, size_t n); - -#endif /* HEADER_CURL_RAWSTR_H */ - diff --git a/lib/rtsp.c b/lib/rtsp.c index 27955bc..d1bad19 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -33,7 +33,7 @@ #include "url.h" #include "progress.h" #include "rtsp.h" -#include "rawstr.h" +#include "strcase.h" #include "select.h" #include "connect.h" /* The last 3 #include files should be in this order */ @@ -147,7 +147,7 @@ bool Curl_rtsp_connisdead(struct connectdata *check) int sval; bool ret_val = TRUE; - sval = Curl_socket_ready(check->sock[FIRSTSOCKET], CURL_SOCKET_BAD, 0); + sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0); if(sval == 0) { /* timeout */ ret_val = FALSE; @@ -796,19 +796,15 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn, } } else { - /* If the Session ID is not set, and we find it in a response, then - set it */ - - /* The session ID can be an alphanumeric or a 'safe' character + /* If the Session ID is not set, and we find it in a response, then set + * it. * - * RFC 2326 15.1 Base Syntax: - * safe = "\$" | "-" | "_" | "." | "+" - * */ + * Allow any non whitespace content, up to the field seperator or end of + * line. RFC 2326 isn't 100% clear on the session ID and for example + * gstreamer does url-encoded session ID's not covered by the standard. + */ char *end = start; - while(*end && - (ISALNUM(*end) || *end == '-' || *end == '_' || *end == '.' || - *end == '+' || - (*end == '\\' && *(end + 1) && *(end + 1) == '$' && (++end, 1)))) + while(*end && *end != ';' && !ISSPACE(*end)) end++; /* Copy the id substring into a new buffer */ diff --git a/lib/security.c b/lib/security.c index a0bcaea..ff26066 100644 --- a/lib/security.c +++ b/lib/security.c @@ -60,7 +60,7 @@ #include "curl_sec.h" #include "ftp.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" /* The last #include file should be: */ @@ -122,7 +122,7 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) vsnprintf(print_buffer, sizeof(print_buffer), message, args); va_end(args); - if(Curl_ftpsendf(conn, print_buffer)) { + if(Curl_ftpsend(conn, print_buffer)) { ftp_code = -1; } else { @@ -192,15 +192,18 @@ static CURLcode read_data(struct connectdata *conn, struct krb5buffer *buf) { int len; - void* tmp; + void *tmp = NULL; CURLcode result; result = socket_read(fd, &len, sizeof(len)); if(result) return result; - len = ntohl(len); - tmp = realloc(buf->data, len); + if(len) { + /* only realloc if there was a length */ + len = ntohl(len); + tmp = realloc(buf->data, len); + } if(tmp == NULL) return CURLE_OUT_OF_MEMORY; diff --git a/lib/select.c b/lib/select.c index abf55d8..26302d9 100644 --- a/lib/select.c +++ b/lib/select.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,15 +51,14 @@ #include "warnless.h" /* Convenience local macros */ - -#define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) +#define ELAPSED_MS() (int)curlx_tvdiff(curlx_tvnow(), initial_tv) int Curl_ack_eintr = 0; -#define error_not_EINTR (Curl_ack_eintr || error != EINTR) +#define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR) /* * Internal function used for waiting a specific amount of ms - * in Curl_socket_ready() and Curl_poll() when no file descriptor + * in Curl_socket_check() and Curl_poll() when no file descriptor * is provided to wait on, just being used to delay execution. * WinSock select() and poll() timeout mechanisms need a valid * socket descriptor in a not null file descriptor set to work. @@ -109,9 +108,9 @@ int Curl_wait_ms(int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; - pending_ms = timeout_ms - elapsed_ms; + pending_ms = timeout_ms - ELAPSED_MS(); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -165,6 +164,12 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ int r; int ret; +#if SIZEOF_LONG != SIZEOF_INT + /* wrap-around precaution */ + if(timeout_ms >= INT_MAX) + timeout_ms = INT_MAX; +#endif + if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { /* no sockets, just wait */ @@ -213,10 +218,10 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - elapsed_ms); + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -328,10 +333,10 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -434,10 +439,10 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -521,10 +526,10 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = timeout_ms - ELAPSED_MS(); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; diff --git a/lib/select.h b/lib/select.h index 695bb69..1d26f49 100644 --- a/lib/select.h +++ b/lib/select.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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,9 +75,10 @@ int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, curl_socket_t writefd, long timeout_ms); -/* provide the former API internally */ -#define Curl_socket_ready(x,y,z) \ - Curl_socket_check(x, CURL_SOCKET_BAD, y, z) +#define SOCKET_READABLE(x,z) \ + Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z) +#define SOCKET_WRITABLE(x,z) \ + Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z) int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); diff --git a/lib/smb.c b/lib/smb.c index 56a38c2..7cb0c96 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -673,7 +673,7 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done) switch(smbc->state) { case SMB_NEGOTIATE: - if(h->status) { + if(h->status || smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) { connclose(conn, "SMB: negotiation failed"); return CURLE_COULDNT_CONNECT; } @@ -712,6 +712,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) { struct smb_request *req = conn->data->req.protop; struct smb_header *h; + struct smb_conn *smbc = &conn->proto.smbc; enum smb_req_state next_state = SMB_DONE; unsigned short len; unsigned short off; @@ -754,7 +755,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_OPEN: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { req->result = CURLE_REMOTE_FILE_NOT_FOUND; next_state = SMB_TREE_DISCONNECT; break; @@ -775,7 +776,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_DOWNLOAD: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_header) + 14) { req->result = CURLE_RECV_ERROR; next_state = SMB_CLOSE; break; @@ -785,7 +786,6 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) off = Curl_read16_le(((unsigned char *) msg) + sizeof(struct smb_header) + 13); if(len > 0) { - struct smb_conn *smbc = &conn->proto.smbc; if(off + sizeof(unsigned int) + len > smbc->got) { failf(conn->data, "Invalid input packet"); result = CURLE_RECV_ERROR; @@ -807,7 +807,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_UPLOAD: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_header) + 6) { req->result = CURLE_UPLOAD_FAILED; next_state = SMB_CLOSE; break; diff --git a/lib/smtp.c b/lib/smtp.c index d203b53..a4fc2c2 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -69,16 +69,14 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "smtp.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" #include "curl_gethostname.h" #include "curl_sasl.h" #include "warnless.h" @@ -674,7 +672,7 @@ static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, if(smtpcode/100 != 2) { failf(data, "Got unexpected smtp-server response: %d", smtpcode); - result = CURLE_FTP_WEIRD_SERVER_REPLY; + result = CURLE_WEIRD_SERVER_REPLY; } else result = smtp_perform_ehlo(conn); @@ -1512,7 +1510,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) + if(strncasecompare(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, value, ptr - value); else diff --git a/lib/socks.c b/lib/socks.c index fccb16d..742d411 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -33,7 +33,6 @@ #include "urldata.h" #include "sendf.h" -#include "strequal.h" #include "select.h" #include "connect.h" #include "timeval.h" @@ -67,7 +66,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ result = CURLE_OPERATION_TIMEDOUT; break; } - if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, timeleft) <= 0) { + if(SOCKET_READABLE(sockfd, timeleft) <= 0) { result = ~CURLE_OK; break; } @@ -170,24 +169,26 @@ CURLcode Curl_SOCKS4(const char *proxy_name, hp=dns->addr; if(hp) { char buf[64]; - unsigned short ip[4]; Curl_printable_address(hp, buf, sizeof(buf)); - if(4 == sscanf(buf, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { - /* Set DSTIP */ - socksreq[4] = (unsigned char)ip[0]; - socksreq[5] = (unsigned char)ip[1]; - socksreq[6] = (unsigned char)ip[2]; - socksreq[7] = (unsigned char)ip[3]; + if(hp->ai_family == AF_INET) { + struct sockaddr_in *saddr_in; + + saddr_in = (struct sockaddr_in*)(void*)hp->ai_addr; + socksreq[4] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[0]; + socksreq[5] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[1]; + socksreq[6] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[2]; + socksreq[7] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[3]; + + infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf); } - else + else { hp = NULL; /* fail! */ - infof(data, "SOCKS4 connect to %s (locally resolved)\n", buf); + failf(data, "SOCKS4 connection to %s not supported\n", buf); + } Curl_resolv_unlock(data, dns); /* not used anymore from now on */ - } if(!hp) { failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", @@ -399,7 +400,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, TRUE); /* wait until socket gets connected */ - result = Curl_socket_ready(CURL_SOCKET_BAD, sock, timeout); + result = SOCKET_WRITABLE(sock, timeout); if(-1 == result) { failf(conn->data, "SOCKS5: no connection here"); @@ -429,6 +430,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, FALSE); + infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port); + code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), &written); if(code || (written != (2 + (int)socksreq[1]))) { @@ -438,7 +441,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, TRUE); - result = Curl_socket_ready(sock, CURL_SOCKET_BAD, timeout); + result = SOCKET_READABLE(sock, timeout); if(-1 == result) { failf(conn->data, "SOCKS5 nothing to read"); @@ -594,34 +597,40 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(dns) hp=dns->addr; if(hp) { - struct sockaddr_in *saddr_in; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 *saddr_in6; -#endif int i; + char buf[64]; + Curl_printable_address(hp, buf, sizeof(buf)); if(hp->ai_family == AF_INET) { + struct sockaddr_in *saddr_in; socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ saddr_in = (struct sockaddr_in*)(void*)hp->ai_addr; for(i = 0; i < 4; i++) { socksreq[len++] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[i]; - infof(data, "%d\n", socksreq[len-1]); } + + infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", buf); } #ifdef ENABLE_IPV6 else if(hp->ai_family == AF_INET6) { + struct sockaddr_in6 *saddr_in6; socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ saddr_in6 = (struct sockaddr_in6*)(void*)hp->ai_addr; for(i = 0; i < 16; i++) { socksreq[len++] = ((unsigned char*)&saddr_in6->sin6_addr.s6_addr)[i]; } + + infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", buf); } #endif - else + else { hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported\n", buf); + } + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ } if(!hp) { @@ -668,39 +677,6 @@ CURLcode Curl_SOCKS5(const char *proxy_name, "SOCKS5 reply has wrong version, version should be 5."); return CURLE_COULDNT_CONNECT; } - if(socksreq[1] != 0) { /* Anything besides 0 is an error */ - if(socksreq[3] == 1) { - failf(data, - "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - else if(socksreq[3] == 3) { - failf(data, - "Can't complete SOCKS5 connection to %s:%d. (%d)", - hostname, - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - else if(socksreq[3] == 4) { - failf(data, - "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:" - "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned char)socksreq[8], (unsigned char)socksreq[9], - (unsigned char)socksreq[10], (unsigned char)socksreq[11], - (unsigned char)socksreq[12], (unsigned char)socksreq[13], - (unsigned char)socksreq[14], (unsigned char)socksreq[15], - (unsigned char)socksreq[16], (unsigned char)socksreq[17], - (unsigned char)socksreq[18], (unsigned char)socksreq[19], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - return CURLE_COULDNT_CONNECT; - } /* Fix: in general, returned BND.ADDR is variable length parameter by RFC 1928, so the reply packet should be read until the end to avoid errors at @@ -735,10 +711,9 @@ CURLcode Curl_SOCKS5(const char *proxy_name, /* decrypt_gssapi_blockread already read the whole packet */ #endif if(len > 10) { - len -= 10; result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], - len, &actualread); - if(result || (len != actualread)) { + len - 10, &actualread); + if(result || ((len - 10) != actualread)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -747,6 +722,49 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } #endif + if(socksreq[1] != 0) { /* Anything besides 0 is an error */ + if(socksreq[3] == 1) { + failf(data, + "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (((unsigned char)socksreq[8] << 8) | + (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); + } + else if(socksreq[3] == 3) { + unsigned char port_upper = (unsigned char)socksreq[len - 2]; + socksreq[len - 2] = 0; + failf(data, + "Can't complete SOCKS5 connection to %s:%d. (%d)", + (char *)&socksreq[5], + ((port_upper << 8) | + (unsigned char)socksreq[len - 1]), + (unsigned char)socksreq[1]); + socksreq[len - 2] = port_upper; + } + else if(socksreq[3] == 4) { + failf(data, + "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned char)socksreq[8], (unsigned char)socksreq[9], + (unsigned char)socksreq[10], (unsigned char)socksreq[11], + (unsigned char)socksreq[12], (unsigned char)socksreq[13], + (unsigned char)socksreq[14], (unsigned char)socksreq[15], + (unsigned char)socksreq[16], (unsigned char)socksreq[17], + (unsigned char)socksreq[18], (unsigned char)socksreq[19], + (((unsigned char)socksreq[20] << 8) | + (unsigned char)socksreq[21]), + (unsigned char)socksreq[1]); + } + return CURLE_COULDNT_CONNECT; + } + else { + infof(data, "SOCKS5 request granted.\n"); + } + (void)curlx_nonblock(sock, TRUE); return CURLE_OK; /* Proxy was successful! */ } diff --git a/lib/ssh.c b/lib/ssh.c index 7bc3136..43c8283 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -72,7 +72,7 @@ #include "speedcheck.h" #include "getinfo.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" @@ -416,12 +416,12 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, struct Curl_easy *data = conn->data; char *real_path = NULL; char *working_path; - int working_path_len; - - working_path = curl_easy_unescape(data, data->state.path, 0, - &working_path_len); - if(!working_path) - return CURLE_OUT_OF_MEMORY; + size_t working_path_len; + CURLcode result = + Curl_urldecode(data, data->state.path, 0, &working_path, + &working_path_len, FALSE); + if(result) + return result; /* Check for /~/, indicating relative to the user's home directory */ if(conn->handler->protocol & CURLPROTO_SCP) { @@ -676,7 +676,7 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn) * against a known fingerprint, if available. */ if(pubkey_md5 && strlen(pubkey_md5) == 32) { - if(!fingerprint || !strequal(md5buffer, pubkey_md5)) { + if(!fingerprint || strcmp(md5buffer, pubkey_md5)) { if(fingerprint) failf(data, "Denied establishing ssh session: mismatch md5 fingerprint. " @@ -1233,7 +1233,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->acceptfail = TRUE; } - if(curl_strequal("pwd", cmd)) { + if(strcasecompare("pwd", cmd)) { /* output debug output if that is requested */ char *tmp = aprintf("257 \"%s\" is current directory.\n", sftp_scp->path); @@ -1297,9 +1297,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) * OpenSSH's sftp program and call the appropriate libssh2 * functions. */ - if(curl_strnequal(cmd, "chgrp ", 6) || - curl_strnequal(cmd, "chmod ", 6) || - curl_strnequal(cmd, "chown ", 6) ) { + if(strncasecompare(cmd, "chgrp ", 6) || + strncasecompare(cmd, "chmod ", 6) || + strncasecompare(cmd, "chown ", 6) ) { /* attribute change */ /* sshc->quote_path1 contains the mode to set */ @@ -1321,8 +1321,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_STAT); break; } - else if(curl_strnequal(cmd, "ln ", 3) || - curl_strnequal(cmd, "symlink ", 8)) { + else if(strncasecompare(cmd, "ln ", 3) || + strncasecompare(cmd, "symlink ", 8)) { /* symbolic linking */ /* sshc->quote_path1 is the source */ /* get the destination */ @@ -1342,12 +1342,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_SYMLINK); break; } - else if(curl_strnequal(cmd, "mkdir ", 6)) { + else if(strncasecompare(cmd, "mkdir ", 6)) { /* create dir */ state(conn, SSH_SFTP_QUOTE_MKDIR); break; } - else if(curl_strnequal(cmd, "rename ", 7)) { + else if(strncasecompare(cmd, "rename ", 7)) { /* rename file */ /* first param is the source path */ /* second param is the dest. path */ @@ -1366,17 +1366,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_RENAME); break; } - else if(curl_strnequal(cmd, "rmdir ", 6)) { + else if(strncasecompare(cmd, "rmdir ", 6)) { /* delete dir */ state(conn, SSH_SFTP_QUOTE_RMDIR); break; } - else if(curl_strnequal(cmd, "rm ", 3)) { + else if(strncasecompare(cmd, "rm ", 3)) { state(conn, SSH_SFTP_QUOTE_UNLINK); break; } #ifdef HAS_STATVFS_SUPPORT - else if(curl_strnequal(cmd, "statvfs ", 8)) { + else if(strncasecompare(cmd, "statvfs ", 8)) { state(conn, SSH_SFTP_QUOTE_STATVFS); break; } @@ -1431,7 +1431,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->acceptfail = TRUE; } - if(!curl_strnequal(cmd, "chmod", 5)) { + if(!strncasecompare(cmd, "chmod", 5)) { /* Since chown and chgrp only set owner OR group but libssh2 wants to * set them both at once, we need to obtain the current ownership * first. This takes an extra protocol round trip. @@ -1457,7 +1457,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } /* Now set the new attributes... */ - if(curl_strnequal(cmd, "chgrp", 5)) { + if(strncasecompare(cmd, "chgrp", 5)) { sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && @@ -1471,7 +1471,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } } - else if(curl_strnequal(cmd, "chmod", 5)) { + else if(strncasecompare(cmd, "chmod", 5)) { sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; /* permissions are octal */ @@ -1486,7 +1486,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } } - else if(curl_strnequal(cmd, "chown", 5)) { + else if(strncasecompare(cmd, "chown", 5)) { sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && @@ -1895,7 +1895,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short timeout here */ - Curl_expire(data, 1); + Curl_expire(data, 0); state(conn, SSH_STOP); } @@ -2860,7 +2860,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) fd_write = sock; /* wait for the socket to become ready */ - Curl_socket_ready(fd_read, fd_write, + Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, left>1000?1000:left); /* ignore result */ } #endif @@ -3109,7 +3109,6 @@ static CURLcode scp_done(struct connectdata *conn, CURLcode status, } -/* return number of received (decrypted) bytes */ static ssize_t scp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { @@ -3134,10 +3133,6 @@ static ssize_t scp_send(struct connectdata *conn, int sockindex, return nwrite; } -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ static ssize_t scp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { diff --git a/lib/strcase.c b/lib/strcase.c new file mode 100644 index 0000000..807689e --- /dev/null +++ b/lib/strcase.c @@ -0,0 +1,166 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "strcase.h" + +/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because + its behavior is altered by the current locale. */ +char Curl_raw_toupper(char in) +{ +#if !defined(CURL_DOES_CONVERSIONS) + if(in >= 'a' && in <= 'z') + return (char)('A' + in - 'a'); +#else + switch (in) { + case 'a': + return 'A'; + case 'b': + return 'B'; + case 'c': + return 'C'; + case 'd': + return 'D'; + case 'e': + return 'E'; + case 'f': + return 'F'; + case 'g': + return 'G'; + case 'h': + return 'H'; + case 'i': + return 'I'; + case 'j': + return 'J'; + case 'k': + return 'K'; + case 'l': + return 'L'; + case 'm': + return 'M'; + case 'n': + return 'N'; + case 'o': + return 'O'; + case 'p': + return 'P'; + case 'q': + return 'Q'; + case 'r': + return 'R'; + case 's': + return 'S'; + case 't': + return 'T'; + case 'u': + return 'U'; + case 'v': + return 'V'; + case 'w': + return 'W'; + case 'x': + return 'X'; + case 'y': + return 'Y'; + case 'z': + return 'Z'; + } +#endif + + return in; +} + +/* + * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant + * to be locale independent and only compare strings we know are safe for + * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for + * some further explanation to why this function is necessary. + * + * The function is capable of comparing a-z case insensitively even for + * non-ascii. + * + * @unittest: 1301 + */ + +int Curl_strcasecompare(const char *first, const char *second) +{ + while(*first && *second) { + if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) + /* get out of the loop as soon as they don't match */ + break; + first++; + second++; + } + /* we do the comparison here (possibly again), just to make sure that if the + loop above is skipped because one of the strings reached zero, we must not + return this as a successful match */ + return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); +} + +/* + * @unittest: 1301 + */ +int Curl_strncasecompare(const char *first, const char *second, size_t max) +{ + while(*first && *second && max) { + if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { + break; + } + max--; + first++; + second++; + } + if(0 == max) + return 1; /* they are equal this far */ + + return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); +} + +/* Copy an upper case version of the string from src to dest. The + * strings may overlap. No more than n characters of the string are copied + * (including any NUL) and the destination string will NOT be + * NUL-terminated if that limit is reached. + */ +void Curl_strntoupper(char *dest, const char *src, size_t n) +{ + if(n < 1) + return; + + do { + *dest++ = Curl_raw_toupper(*src); + } while(*src++ && --n); +} + +/* --- public functions --- */ + +int curl_strequal(const char *first, const char *second) +{ + return Curl_strcasecompare(first, second); +} +int curl_strnequal(const char *first, const char *second, size_t max) +{ + return Curl_strncasecompare(first, second, max); +} diff --git a/lib/strcase.h b/lib/strcase.h new file mode 100644 index 0000000..bf057b1 --- /dev/null +++ b/lib/strcase.h @@ -0,0 +1,50 @@ +#ifndef HEADER_CURL_STRCASE_H +#define HEADER_CURL_STRCASE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +/* + * Only "raw" case insensitive strings. This is meant to be locale independent + * and only compare strings we know are safe for this. + * + * The function is capable of comparing a-z case insensitively even for + * non-ascii. + */ + +#define strcasecompare(a,b) Curl_strcasecompare(a,b) +#define strncasecompare(a,b,c) Curl_strncasecompare(a,b,c) + +int Curl_strcasecompare(const char *first, const char *second); +int Curl_strncasecompare(const char *first, const char *second, size_t max); + +char Curl_raw_toupper(char in); + +/* checkprefix() is a shorter version of the above, used when the first + argument is zero-byte terminated */ +#define checkprefix(a,b) curl_strnequal(a,b,strlen(a)) + +void Curl_strntoupper(char *dest, const char *src, size_t n); +char Curl_raw_toupper(char in); + +#endif /* HEADER_CURL_STRCASE_H */ diff --git a/lib/strdup.c b/lib/strdup.c index 23f554e..5a15c2b 100644 --- a/lib/strdup.c +++ b/lib/strdup.c @@ -65,9 +65,9 @@ char *curlx_strdup(const char *str) * Returns the new pointer or NULL on failure. * ***************************************************************************/ -char *Curl_memdup(const char *src, size_t length) +void *Curl_memdup(const void *src, size_t length) { - char *buffer = malloc(length); + void *buffer = malloc(length); if(!buffer) return NULL; /* fail */ diff --git a/lib/strdup.h b/lib/strdup.h index 4c48ca4..c74a3b7 100644 --- a/lib/strdup.h +++ b/lib/strdup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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,6 +26,6 @@ #ifndef HAVE_STRDUP extern char *curlx_strdup(const char *str); #endif -char *Curl_memdup(const char *src, size_t buffer_length); +void *Curl_memdup(const void *src, size_t buffer_length); #endif /* HEADER_CURL_STRDUP_H */ diff --git a/lib/strequal.c b/lib/strequal.c deleted file mode 100644 index 01c3784..0000000 --- a/lib/strequal.c +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_STRINGS_H -#include -#endif - -#include "strequal.h" - -/* - * @unittest: 1301 - */ -int curl_strequal(const char *first, const char *second) -{ -#if defined(HAVE_STRCASECMP) - return !(strcasecmp)(first, second); -#elif defined(HAVE_STRCMPI) - return !(strcmpi)(first, second); -#elif defined(HAVE_STRICMP) - return !(stricmp)(first, second); -#else - while(*first && *second) { - if(toupper(*first) != toupper(*second)) { - break; - } - first++; - second++; - } - return toupper(*first) == toupper(*second); -#endif -} - -/* - * @unittest: 1301 - */ -int curl_strnequal(const char *first, const char *second, size_t max) -{ -#if defined(HAVE_STRNCASECMP) - return !strncasecmp(first, second, max); -#elif defined(HAVE_STRNCMPI) - return !strncmpi(first, second, max); -#elif defined(HAVE_STRNICMP) - return !strnicmp(first, second, max); -#else - while(*first && *second && max) { - if(toupper(*first) != toupper(*second)) { - break; - } - max--; - first++; - second++; - } - if(0 == max) - return 1; /* they are equal this far */ - - return toupper(*first) == toupper(*second); -#endif -} diff --git a/lib/strequal.h b/lib/strequal.h deleted file mode 100644 index ff56df5..0000000 --- a/lib/strequal.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef HEADER_CURL_STREQUAL_H -#define HEADER_CURL_STREQUAL_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include - -#define strequal(a,b) curl_strequal(a,b) -#define strnequal(a,b,c) curl_strnequal(a,b,c) - -#endif /* HEADER_CURL_STREQUAL_H */ - diff --git a/lib/strerror.c b/lib/strerror.c index 0e268d5..db50c7d 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -35,8 +35,8 @@ #include -#ifdef USE_LIBIDN -#include +#ifdef USE_LIBIDN2 +#include #endif #ifdef USE_WINDOWS_SSPI @@ -79,8 +79,8 @@ curl_easy_strerror(CURLcode error) case CURLE_COULDNT_CONNECT: return "Couldn't connect to server"; - case CURLE_FTP_WEIRD_SERVER_REPLY: - return "FTP: weird server reply"; + case CURLE_WEIRD_SERVER_REPLY: + return "Weird server reply"; case CURLE_REMOTE_ACCESS_DENIED: return "Access denied to remote resource"; @@ -427,7 +427,7 @@ curl_share_strerror(CURLSHcode error) #ifdef USE_WINSOCK -/* This function handles most / all (?) Winsock errors cURL is able to produce. +/* This function handles most / all (?) Winsock errors curl is able to produce. */ static const char * get_winsock_error (int err, char *buf, size_t len) @@ -726,83 +726,6 @@ const char *Curl_strerror(struct connectdata *conn, int err) return buf; } -#ifdef USE_LIBIDN -/* - * Return error-string for libidn status as returned from idna_to_ascii_lz(). - */ -const char *Curl_idn_strerror (struct connectdata *conn, int err) -{ -#ifdef HAVE_IDNA_STRERROR - (void)conn; - return idna_strerror((Idna_rc) err); -#else - const char *str; - char *buf; - size_t max; - - DEBUGASSERT(conn); - - buf = conn->syserr_buf; - max = sizeof(conn->syserr_buf)-1; - *buf = '\0'; - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch ((Idna_rc)err) { - case IDNA_SUCCESS: - str = "No error"; - break; - case IDNA_STRINGPREP_ERROR: - str = "Error in string preparation"; - break; - case IDNA_PUNYCODE_ERROR: - str = "Error in Punycode operation"; - break; - case IDNA_CONTAINS_NON_LDH: - str = "Illegal ASCII characters"; - break; - case IDNA_CONTAINS_MINUS: - str = "Contains minus"; - break; - case IDNA_INVALID_LENGTH: - str = "Invalid output length"; - break; - case IDNA_NO_ACE_PREFIX: - str = "No ACE prefix (\"xn--\")"; - break; - case IDNA_ROUNDTRIP_VERIFY_ERROR: - str = "Round trip verify error"; - break; - case IDNA_CONTAINS_ACE_PREFIX: - str = "Already have ACE prefix (\"xn--\")"; - break; - case IDNA_ICONV_ERROR: - str = "Locale conversion failed"; - break; - case IDNA_MALLOC_ERROR: - str = "Allocation failed"; - break; - case IDNA_DLOPEN_ERROR: - str = "dlopen() error"; - break; - default: - snprintf(buf, max, "error %d", err); - str = NULL; - break; - } -#else - if((Idna_rc)err == IDNA_SUCCESS) - str = "No error"; - else - str = "Error"; -#endif - if(str) - strncpy(buf, str, max); - buf[max] = '\0'; - return (buf); -#endif -} -#endif /* USE_LIBIDN */ - #ifdef USE_WINDOWS_SSPI const char *Curl_sspi_strerror (struct connectdata *conn, int err) { diff --git a/lib/strerror.h b/lib/strerror.h index ae8c96b..627273e 100644 --- a/lib/strerror.h +++ b/lib/strerror.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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,7 +26,7 @@ const char *Curl_strerror (struct connectdata *conn, int err); -#ifdef USE_LIBIDN +#ifdef USE_LIBIDN2 const char *Curl_idn_strerror (struct connectdata *conn, int err); #endif diff --git a/lib/system_win32.c b/lib/system_win32.c index d6a998b..7873759 100644 --- a/lib/system_win32.c +++ b/lib/system_win32.c @@ -83,7 +83,39 @@ bool Curl_verify_windows_version(const unsigned int majorVersion, { bool matched = FALSE; -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ +#if defined(CURL_WINDOWS_APP) + /* We have no way to determine the Windows version from Windows apps, + so let's assume we're running on the target Windows version. */ + const WORD fullVersion = MAKEWORD(minorVersion, majorVersion); + const WORD targetVersion = (WORD)_WIN32_WINNT; + + switch(condition) { + case VERSION_LESS_THAN: + matched = targetVersion < fullVersion; + break; + + case VERSION_LESS_THAN_EQUAL: + matched = targetVersion <= fullVersion; + break; + + case VERSION_EQUAL: + matched = targetVersion == fullVersion; + break; + + case VERSION_GREATER_THAN_EQUAL: + matched = targetVersion >= fullVersion; + break; + + case VERSION_GREATER_THAN: + matched = targetVersion > fullVersion; + break; + } + + if(matched && (platform == PLATFORM_WINDOWS)) { + /* we're always running on PLATFORM_WINNT */ + matched = FALSE; + } +#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ (_WIN32_WINNT < _WIN32_WINNT_WIN2K) OSVERSIONINFO osver; @@ -128,7 +160,7 @@ bool Curl_verify_windows_version(const unsigned int majorVersion, } /* Verify the platform identifier (if necessary) */ - if(matched && platform != PLATFORM_DONT_CARE) { + if(matched) { switch(platform) { case PLATFORM_WINDOWS: if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) @@ -138,6 +170,9 @@ bool Curl_verify_windows_version(const unsigned int majorVersion, case PLATFORM_WINNT: if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT) matched = FALSE; + + default: /* like platform == PLATFORM_DONT_CARE */ + break; } } } diff --git a/lib/telnet.c b/lib/telnet.c index cc705cf..c37242d 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -58,8 +58,7 @@ #include "arpa_telnet.h" #include "select.h" -#include "strequal.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" /* The last 3 #include files should be in this order */ @@ -846,7 +845,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) option_keyword, option_arg) == 2) { /* Terminal type */ - if(Curl_raw_equal(option_keyword, "TTYPE")) { + if(strcasecompare(option_keyword, "TTYPE")) { strncpy(tn->subopt_ttype, option_arg, 31); tn->subopt_ttype[31] = 0; /* String termination */ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; @@ -854,7 +853,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Display variable */ - if(Curl_raw_equal(option_keyword, "XDISPLOC")) { + if(strcasecompare(option_keyword, "XDISPLOC")) { strncpy(tn->subopt_xdisploc, option_arg, 127); tn->subopt_xdisploc[127] = 0; /* String termination */ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; @@ -862,7 +861,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Environment variable */ - if(Curl_raw_equal(option_keyword, "NEW_ENV")) { + if(strcasecompare(option_keyword, "NEW_ENV")) { beg = curl_slist_append(tn->telnet_vars, option_arg); if(!beg) { result = CURLE_OUT_OF_MEMORY; @@ -874,7 +873,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Window Size */ - if(Curl_raw_equal(option_keyword, "WS")) { + if(strcasecompare(option_keyword, "WS")) { if(sscanf(option_arg, "%hu%*[xX]%hu", &tn->subopt_wsx, &tn->subopt_wsy) == 2) tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; @@ -887,7 +886,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* To take care or not of the 8th bit in data exchange */ - if(Curl_raw_equal(option_keyword, "BINARY")) { + if(strcasecompare(option_keyword, "BINARY")) { binary_option=atoi(option_arg); if(binary_option!=1) { tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; diff --git a/lib/tftp.c b/lib/tftp.c index d7ff94f..deee394 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -55,9 +55,10 @@ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "speedcheck.h" #include "select.h" +#include "escape.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -484,10 +485,10 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) /* As RFC3617 describes the separator slash is not actually part of the file name so we skip the always-present first letter of the path string. */ - filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0, - NULL); - if(!filename) - return CURLE_OUT_OF_MEMORY; + result = Curl_urldecode(data, &state->conn->data->state.path[1], 0, + &filename, NULL, FALSE); + if(result) + return result; snprintf((char *)state->spacket.data+2, state->blksize, @@ -705,6 +706,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) int rblock; CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; + int cb; /* Bytes currently read */ switch(event) { @@ -762,9 +764,20 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) return CURLE_OK; } - result = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); - if(result) - return result; + /* TFTP considers data block size < 512 bytes as an end of session. So + * in some cases we must wait for additional data to build full (512 bytes) + * data block. + * */ + state->sbytes = 0; + state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4; + do { + result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes, + &cb); + if(result) + return result; + state->sbytes += cb; + state->conn->data->req.upload_fromhere += cb; + } while(state->sbytes < state->blksize && cb != 0); sbytes = sendto(state->sockfd, (void *) state->spacket.data, 4 + state->sbytes, SEND_4TH_ARG, @@ -1221,7 +1234,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) } else { /* no timeouts to handle, check our socket */ - rc = Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD, 0); + rc = SOCKET_READABLE(state->sockfd, 0); if(rc == -1) { /* bail out */ diff --git a/lib/transfer.c b/lib/transfer.c index f5987fe..6245ee4 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -21,10 +21,7 @@ ***************************************************************************/ #include "curl_setup.h" - #include "strtoofft.h" -#include "strequal.h" -#include "rawstr.h" #ifdef HAVE_NETINET_IN_H #include @@ -75,6 +72,7 @@ #include "multiif.h" #include "connect.h" #include "non-ascii.h" +#include "http2.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -384,11 +382,15 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) * Go ahead and do a read if we have a readable socket or if * the stream was rewound (in which case we have data in a * buffer) + * + * return '*comeback' TRUE if we didn't properly drain the socket so this + * function should get called again without select() or similar in between! */ static CURLcode readwrite_data(struct Curl_easy *data, struct connectdata *conn, struct SingleRequest *k, - int *didwhat, bool *done) + int *didwhat, bool *done, + bool *comeback) { CURLcode result = CURLE_OK; ssize_t nread; /* number of bytes read */ @@ -398,6 +400,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, int maxloops = 100; *done = FALSE; + *comeback = FALSE; /* This is where we loop until we have read everything there is to read or we get a CURLE_AGAIN */ @@ -529,6 +532,13 @@ static CURLcode readwrite_data(struct Curl_easy *data, is non-headers. */ if(k->str && !k->header && (nread > 0 || is_empty_data)) { + if(data->set.opt_no_body) { + /* data arrives although we want none, bail out */ + streamclose(conn, "ignoring body"); + *done = TRUE; + return CURLE_WEIRD_SERVER_REPLY; + } + #ifndef CURL_DISABLE_HTTP if(0 == k->bodywrites && !is_empty_data) { /* These checks are only made the first time we are about to @@ -804,6 +814,12 @@ static CURLcode readwrite_data(struct Curl_easy *data, } while(data_pending(conn) && maxloops--); + if(maxloops <= 0) { + /* we mark it as read-again-please */ + conn->cselect_bits = CURL_CSELECT_IN; + *comeback = TRUE; + } + if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && conn->bits.close) { /* When we've read the entire thing and the close bit is set, the server @@ -821,6 +837,8 @@ static CURLcode done_sending(struct connectdata *conn, { k->keepon &= ~KEEP_SEND; /* we're done writing */ + Curl_http2_done_sending(conn); + if(conn->bits.rewindaftersend) { CURLcode result = Curl_readrewind(conn); if(result) @@ -1029,10 +1047,14 @@ static CURLcode readwrite_upload(struct Curl_easy *data, /* * Curl_readwrite() is the low-level function to be called when data is to * be read and written to/from the connection. + * + * return '*comeback' TRUE if we didn't properly drain the socket so this + * function should get called again without select() or similar in between! */ CURLcode Curl_readwrite(struct connectdata *conn, struct Curl_easy *data, - bool *done) + bool *done, + bool *comeback) { struct SingleRequest *k = &data->req; CURLcode result; @@ -1064,7 +1086,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, if(!select_res) /* Call for select()/poll() only, if read/write/error status is not known. */ - select_res = Curl_socket_ready(fd_read, fd_write, 0); + select_res = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0); if(select_res == CURL_CSELECT_ERR) { failf(data, "select/poll returned error"); @@ -1077,7 +1099,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, if((k->keepon & KEEP_RECV) && ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { - result = readwrite_data(data, conn, k, &didwhat, done); + result = readwrite_data(data, conn, k, &didwhat, done, comeback); if(result || *done) return result; } @@ -1249,60 +1271,6 @@ int Curl_single_getsock(const struct connectdata *conn, return bitmap; } -/* - * Determine optimum sleep time based on configured rate, current rate, - * and packet size. - * Returns value in milliseconds. - * - * The basic idea is to adjust the desired rate up/down in this method - * based on whether we are running too slow or too fast. Then, calculate - * how many milliseconds to wait for the next packet to achieve this new - * rate. - */ -long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, - int pkt_size) -{ - curl_off_t min_sleep = 0; - curl_off_t rv = 0; - - if(rate_bps == 0) - return 0; - - /* If running faster than about .1% of the desired speed, slow - * us down a bit. Use shift instead of division as the 0.1% - * cutoff is arbitrary anyway. - */ - if(cur_rate_bps > (rate_bps + (rate_bps >> 10))) { - /* running too fast, decrease target rate by 1/64th of rate */ - rate_bps -= rate_bps >> 6; - min_sleep = 1; - } - else if(cur_rate_bps < (rate_bps - (rate_bps >> 10))) { - /* running too slow, increase target rate by 1/64th of rate */ - rate_bps += rate_bps >> 6; - } - - /* Determine number of milliseconds to wait until we do - * the next packet at the adjusted rate. We should wait - * longer when using larger packets, for instance. - */ - rv = ((curl_off_t)(pkt_size * 1000) / rate_bps); - - /* Catch rounding errors and always slow down at least 1ms if - * we are running too fast. - */ - if(rv < min_sleep) - rv = min_sleep; - - /* Bound value to fit in 'long' on 32-bit platform. That's - * plenty long enough anyway! - */ - if(rv > 0x7fffffff) - rv = 0x7fffffff; - - return (long)rv; -} - /* Curl_init_CONNECT() gets called each time the handle switches to CONNECT which means this gets called once for each subsequent redirect etc */ void Curl_init_CONNECT(struct Curl_easy *data) @@ -1875,13 +1843,12 @@ CURLcode Curl_retry_request(struct connectdata *conn, return CURLE_OK; if((data->req.bytecount + data->req.headerbytecount == 0) && - conn->bits.reuse && - !data->set.opt_no_body && - (data->set.rtspreq != RTSPREQ_RECEIVE)) { - /* We got no data, we attempted to re-use a connection and yet we want a - "body". This might happen if the connection was left alive when we were - done using it before, but that was closed when we wanted to read from - it again. Bad luck. Retry the same request on a fresh connect! */ + conn->bits.reuse && + (data->set.rtspreq != RTSPREQ_RECEIVE)) { + /* We didn't get a single byte when we attempted to re-use a + connection. This might happen if the connection was left alive when we + were done using it before, but that was closed when we wanted to use it + again. Bad luck. Retry the same request on a fresh connect! */ infof(conn->data, "Connection died, retrying a fresh connect\n"); *url = strdup(conn->data->change.url); if(!*url) diff --git a/lib/transfer.h b/lib/transfer.h index 0e253e3..5189672 100644 --- a/lib/transfer.h +++ b/lib/transfer.h @@ -40,10 +40,9 @@ typedef enum { CURLcode Curl_follow(struct Curl_easy *data, char *newurl, followtype type); - - CURLcode Curl_readwrite(struct connectdata *conn, - struct Curl_easy *data, bool *done); + struct Curl_easy *data, bool *done, + bool *comeback); int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *socks, int numsocks); @@ -65,8 +64,5 @@ Curl_setup_transfer (struct connectdata *data, curl_off_t *writecountp /* return number of bytes written */ ); -long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, - int pkt_size); - #endif /* HEADER_CURL_TRANSFER_H */ diff --git a/lib/url.c b/lib/url.c index e547e5c..b997f41 100644 --- a/lib/url.c +++ b/lib/url.c @@ -59,24 +59,13 @@ #include #endif -#ifdef USE_LIBIDN -#include -#include -#include -#ifdef HAVE_IDN_FREE_H -#include -#else -/* prototype from idn-free.h, not provided by libidn 0.4.5's make install! */ -void idn_free (void *ptr); -#endif -#ifndef HAVE_IDN_FREE -/* if idn_free() was not found in this version of libidn use free() instead */ -#define idn_free(x) (free)(x) -#endif +#ifdef USE_LIBIDN2 +#include + #elif defined(USE_WIN32_IDN) /* prototype for curl_win32_idn_to_ascii() */ bool curl_win32_idn_to_ascii(const char *in, char **out); -#endif /* USE_LIBIDN */ +#endif /* USE_LIBIDN2 */ #include "urldata.h" #include "netrc.h" @@ -88,7 +77,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "sendf.h" #include "progress.h" #include "cookie.h" -#include "strequal.h" +#include "strcase.h" #include "strerror.h" #include "escape.h" #include "strtok.h" @@ -100,7 +89,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "multiif.h" #include "easyif.h" #include "speedcheck.h" -#include "rawstr.h" #include "warnless.h" #include "non-ascii.h" #include "inet_pton.h" @@ -405,7 +393,7 @@ CURLcode Curl_close(struct Curl_easy *data) if(!data) return CURLE_OK; - Curl_expire(data, 0); /* shut off timers */ + Curl_expire_clear(data); /* shut off timers */ m = data->multi; @@ -602,6 +590,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->tcp_keepintvl = 60; set->tcp_keepidle = 60; set->tcp_fastopen = FALSE; + set->tcp_nodelay = TRUE; set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; @@ -781,6 +770,10 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, */ data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE; break; + case CURLOPT_KEEP_SENDING_ON_ERROR: + data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ? + TRUE : FALSE; + break; case CURLOPT_UPLOAD: case CURLOPT_PUT: /* @@ -1225,23 +1218,23 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, if(argptr == NULL) break; - if(Curl_raw_equal(argptr, "ALL")) { + if(strcasecompare(argptr, "ALL")) { /* clear all cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearall(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } - else if(Curl_raw_equal(argptr, "SESS")) { + else if(strcasecompare(argptr, "SESS")) { /* clear session cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearsess(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } - else if(Curl_raw_equal(argptr, "FLUSH")) { + else if(strcasecompare(argptr, "FLUSH")) { /* flush cookies to file, takes care of the locking */ Curl_flush_cookies(data, 0); } - else if(Curl_raw_equal(argptr, "RELOAD")) { + else if(strcasecompare(argptr, "RELOAD")) { /* reload cookies from file */ Curl_cookie_loadfiles(data); break; @@ -2614,7 +2607,7 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; case CURLOPT_TLSAUTH_TYPE: - if(strnequal((char *)va_arg(param, char *), "SRP", strlen("SRP"))) + if(strncasecompare((char *)va_arg(param, char *), "SRP", strlen("SRP"))) data->set.ssl.authtype = CURL_TLSAUTH_SRP; else data->set.ssl.authtype = CURL_TLSAUTH_NONE; @@ -2829,6 +2822,17 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) return CURLE_OK; } + /* + * If this connection isn't marked to force-close, leave it open if there + * are other users of it + */ + if(!conn->bits.close && + (conn->send_pipe->size + conn->recv_pipe->size)) { + DEBUGF(infof(data, "Curl_disconnect, usecounter: %d\n", + conn->send_pipe->size + conn->recv_pipe->size)); + return CURLE_OK; + } + if(conn->dns_entry != NULL) { Curl_resolv_unlock(data, conn->dns_entry); conn->dns_entry = NULL; @@ -2876,7 +2880,7 @@ static bool SocketIsDead(curl_socket_t sock) int sval; bool ret_val = TRUE; - sval = Curl_socket_ready(sock, CURL_SOCKET_BAD, 0); + sval = SOCKET_READABLE(sock, 0); if(sval == 0) /* timeout */ ret_val = FALSE; @@ -2892,7 +2896,8 @@ static bool IsPipeliningPossible(const struct Curl_easy *handle, const struct connectdata *conn) { /* If a HTTP protocol and pipelining is enabled */ - if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (!conn->bits.protoconnstart || !conn->bits.close)) { if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && @@ -3267,6 +3272,8 @@ ConnectionExists(struct Curl_easy *data, pipeLen = check->send_pipe->size + check->recv_pipe->size; if(canPipeline) { + if(check->bits.protoconnstart && check->bits.close) + continue; if(!check->bits.multiplex) { /* If not multiplexing, make sure the pipe has only GET requests */ @@ -3341,7 +3348,7 @@ ConnectionExists(struct Curl_easy *data, (needle->proxytype != check->proxytype || needle->bits.httpproxy != check->bits.httpproxy || needle->bits.tunnel_proxy != check->bits.tunnel_proxy || - !Curl_raw_equal(needle->proxy.name, check->proxy.name) || + !strcasecompare(needle->proxy.name, check->proxy.name) || needle->port != check->port)) /* don't mix connections that use different proxies */ continue; @@ -3384,8 +3391,8 @@ ConnectionExists(struct Curl_easy *data, if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { /* This protocol requires credentials per connection, so verify that we're using the same name and password as well */ - if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) { + if(strcmp(needle->user, check->user) || + strcmp(needle->passwd, check->passwd)) { /* one of them was different */ continue; } @@ -3396,14 +3403,14 @@ ConnectionExists(struct Curl_easy *data, /* The requested connection does not use a HTTP proxy or it uses SSL or it is a non-SSL protocol tunneled over the same HTTP proxy name and port number */ - if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) || + if((strcasecompare(needle->handler->scheme, check->handler->scheme) || (get_protocol_family(check->handler->protocol) == needle->handler->protocol && check->tls_upgraded)) && - (!needle->bits.conn_to_host || Curl_raw_equal( + (!needle->bits.conn_to_host || strcasecompare( needle->conn_to_host.name, check->conn_to_host.name)) && (!needle->bits.conn_to_port || needle->conn_to_port == check->conn_to_port) && - Curl_raw_equal(needle->host.name, check->host.name) && + strcasecompare(needle->host.name, check->host.name) && needle->remote_port == check->remote_port) { /* The schemes match or the the protocol family is the same and the previous connection was TLS upgraded, and the hostname and host @@ -3445,8 +3452,8 @@ ConnectionExists(struct Curl_easy *data, possible. (Especially we must not reuse the same connection if partway through a handshake!) */ if(wantNTLMhttp) { - if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) + if(strcmp(needle->user, check->user) || + strcmp(needle->passwd, check->passwd)) continue; } else if(check->ntlm.state != NTLMSTATE_NONE) { @@ -3460,8 +3467,8 @@ ConnectionExists(struct Curl_easy *data, if(!check->proxyuser || !check->proxypasswd) continue; - if(!strequal(needle->proxyuser, check->proxyuser) || - !strequal(needle->proxypasswd, check->proxypasswd)) + if(strcmp(needle->proxyuser, check->proxyuser) || + strcmp(needle->proxypasswd, check->proxypasswd)) continue; } else if(check->proxyntlm.state != NTLMSTATE_NONE) { @@ -3752,58 +3759,15 @@ static bool is_ASCII_name(const char *hostname) return TRUE; } -#ifdef USE_LIBIDN -/* - * Check if characters in hostname is allowed in Top Level Domain. - */ -static bool tld_check_name(struct Curl_easy *data, - const char *ace_hostname) -{ - size_t err_pos; - char *uc_name = NULL; - int rc; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - const char *tld_errmsg = ""; -#else - (void)data; -#endif - - /* Convert (and downcase) ACE-name back into locale's character set */ - rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0); - if(rc != IDNA_SUCCESS) - return FALSE; - - /* Warning: err_pos receives "the decoded character offset rather than the - byte position in the string." And as of libidn 1.32 that character offset - is for UTF-8, even if the passed in string is another locale. */ - rc = tld_check_lz(uc_name, &err_pos, NULL); -#ifndef CURL_DISABLE_VERBOSE_STRINGS -#ifdef HAVE_TLD_STRERROR - if(rc != TLD_SUCCESS) - tld_errmsg = tld_strerror((Tld_rc)rc); -#endif - if(rc != TLD_SUCCESS) - infof(data, "WARNING: TLD check for %s failed; %s\n", - uc_name, tld_errmsg); -#endif /* CURL_DISABLE_VERBOSE_STRINGS */ - if(uc_name) - idn_free(uc_name); - if(rc != TLD_SUCCESS) - return FALSE; - - return TRUE; -} -#endif - /* * Perform any necessary IDN conversion of hostname */ -static void fix_hostname(struct Curl_easy *data, - struct connectdata *conn, struct hostname *host) +static void fix_hostname(struct connectdata *conn, struct hostname *host) { size_t len; + struct Curl_easy *data = conn->data; -#ifndef USE_LIBIDN +#ifndef USE_LIBIDN2 (void)data; (void)conn; #elif defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -3821,25 +3785,18 @@ static void fix_hostname(struct Curl_easy *data, /* Check name for non-ASCII and convert hostname to ACE form if we can */ if(!is_ASCII_name(host->name)) { -#ifdef USE_LIBIDN - if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { +#ifdef USE_LIBIDN2 + if(idn2_check_version(IDN2_VERSION)) { char *ace_hostname = NULL; - - int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); - infof(data, "Input domain encoded as `%s'\n", - stringprep_locale_charset()); - if(rc == IDNA_SUCCESS) { - /* tld_check_name() displays a warning if the host name contains - "illegal" characters for this TLD */ - (void)tld_check_name(data, ace_hostname); - - host->encalloc = ace_hostname; + int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, 0); + if(rc == IDN2_OK) { + host->encalloc = (char *)ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; } else infof(data, "Failed to convert %s to ACE; %s\n", host->name, - Curl_idn_strerror(conn, rc)); + idn2_strerror(rc)); } #elif defined(USE_WIN32_IDN) char *ace_hostname = NULL; @@ -3862,9 +3819,9 @@ static void fix_hostname(struct Curl_easy *data, */ static void free_fixed_hostname(struct hostname *host) { -#if defined(USE_LIBIDN) +#if defined(USE_LIBIDN2) if(host->encalloc) { - idn_free(host->encalloc); /* must be freed with idn_free() since this was + idn2_free(host->encalloc); /* must be freed with idn2_free() since this was allocated by libidn */ host->encalloc = NULL; } @@ -4022,7 +3979,7 @@ static CURLcode findprotocol(struct Curl_easy *data, variables based on the URL. Now that the handler may be changed later when the protocol specific setup function is called. */ for(pp = protocols; (p = *pp) != NULL; pp++) { - if(Curl_raw_equal(p->scheme, protostr)) { + if(strcasecompare(p->scheme, protostr)) { /* Protocol found in table. Check if allowed */ if(!(data->set.allowed_protocols & p->protocol)) /* nope, get out */ @@ -4091,7 +4048,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, ************************************************************/ if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]", protobuf, path)) && - Curl_raw_equal(protobuf, "file")) { + strcasecompare(protobuf, "file")) { if(path[0] == '/' && path[1] == '/') { /* Allow omitted hostname (e.g. file:/). This is not strictly * speaking a valid file: URL by RFC 1738, but treating file:/ as @@ -4145,7 +4102,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, path[0]=0; rc = sscanf(data->change.url, - "%15[^\n:]:%3[/]%[^\n/?]%[^\n]", + "%15[^\n:]:%3[/]%[^\n/?#]%[^\n]", protobuf, slashbuf, conn->host.name, path); if(2 == rc) { failf(data, "Bad URL"); @@ -4157,7 +4114,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, * The URL was badly formatted, let's try the browser-style _without_ * protocol specified like 'http://'. */ - rc = sscanf(data->change.url, "%[^\n/?]%[^\n]", conn->host.name, path); + rc = sscanf(data->change.url, "%[^\n/?#]%[^\n]", conn->host.name, path); if(1 > rc) { /* * We couldn't even get this format. @@ -4262,10 +4219,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, } /* If the URL is malformatted (missing a '/' after hostname before path) we - * insert a slash here. The only letter except '/' we accept to start a path - * is '?'. + * insert a slash here. The only letters except '/' that can start a path is + * '?' and '#' - as controlled by the two sscanf() patterns above. */ - if(path[0] == '?') { + if(path[0] != '/') { /* We need this function to deal with overlapping memory areas. We know that the memory area 'path' points to is 'urllen' bytes big and that is bigger than the path. Use +1 to move the zero byte too. */ @@ -4531,7 +4488,7 @@ static bool check_noproxy(const char* name, const char* no_proxy) char *endptr; if(no_proxy && no_proxy[0]) { - if(Curl_raw_equal("*", no_proxy)) { + if(strcasecompare("*", no_proxy)) { return TRUE; } @@ -4569,7 +4526,7 @@ static bool check_noproxy(const char* name, const char* no_proxy) if((tok_end - tok_start) <= namelen) { /* Match the last part of the name to the domain we are checking. */ const char *checkn = name + namelen - (tok_end - tok_start); - if(Curl_raw_nequal(no_proxy + tok_start, checkn, + if(strncasecompare(no_proxy + tok_start, checkn, tok_end - tok_start)) { if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') { /* We either have an exact match, or the previous character is a . @@ -4648,7 +4605,7 @@ static char *detect_proxy(struct connectdata *conn) * This can cause 'internal' http/ftp requests to be * arbitrarily redirected by any external attacker. */ - if(!prox && !Curl_raw_equal("http_proxy", proxy_env)) { + if(!prox && !strcasecompare("http_proxy", proxy_env)) { /* There was no lowercase variable, try the uppercase version: */ Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); prox=curl_getenv(proxy_env); @@ -4705,7 +4662,13 @@ static CURLcode parse_proxy(struct Curl_easy *data, conn->proxytype = CURLPROXY_SOCKS4A; else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy)) conn->proxytype = CURLPROXY_SOCKS4; - /* Any other xxx:// : change to http proxy */ + else if(checkprefix("http:", proxy)) + ; /* leave it as HTTP or HTTP/1.0 */ + else { + /* Any other xxx:// reject! */ + failf(data, "Unsupported proxy scheme for \'%s\'", proxy); + return CURLE_COULDNT_CONNECT; + } } else proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */ @@ -4725,21 +4688,24 @@ static CURLcode parse_proxy(struct Curl_easy *data, them. */ Curl_safefree(conn->proxyuser); if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH) - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); - else + result = Curl_urldecode(data, proxyuser, 0, &conn->proxyuser, NULL, + FALSE); + else { conn->proxyuser = strdup(""); + if(!conn->proxyuser) + result = CURLE_OUT_OF_MEMORY; + } - if(!conn->proxyuser) - result = CURLE_OUT_OF_MEMORY; - else { + if(!result) { Curl_safefree(conn->proxypasswd); if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - else + result = Curl_urldecode(data, proxypasswd, 0, + &conn->proxypasswd, NULL, FALSE); + else { conn->proxypasswd = strdup(""); - - if(!conn->proxypasswd) - result = CURLE_OUT_OF_MEMORY; + if(!conn->proxypasswd) + result = CURLE_OUT_OF_MEMORY; + } } if(!result) { @@ -4846,6 +4812,7 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data, { char proxyuser[MAX_CURL_USER_LENGTH]=""; char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; + CURLcode result; if(data->set.str[STRING_PROXYUSERNAME] != NULL) { strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME], @@ -4858,15 +4825,11 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data, proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ } - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); - if(!conn->proxyuser) - return CURLE_OUT_OF_MEMORY; - - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - if(!conn->proxypasswd) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; + result = Curl_urldecode(data, proxyuser, 0, &conn->proxyuser, NULL, FALSE); + if(!result) + result = Curl_urldecode(data, proxypasswd, 0, &conn->proxypasswd, NULL, + FALSE); + return result; } #endif /* CURL_DISABLE_PROXY */ @@ -4940,9 +4903,8 @@ static CURLcode parse_url_login(struct Curl_easy *data, conn->bits.user_passwd = TRUE; /* enable user+password */ /* Decode the user */ - newname = curl_easy_unescape(data, userp, 0, NULL); - if(!newname) { - result = CURLE_OUT_OF_MEMORY; + result = Curl_urldecode(data, userp, 0, &newname, NULL, FALSE); + if(result) { goto out; } @@ -4952,9 +4914,9 @@ static CURLcode parse_url_login(struct Curl_easy *data, if(passwdp) { /* We have a password in the URL so decode it */ - char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL); - if(!newpasswd) { - result = CURLE_OUT_OF_MEMORY; + char *newpasswd; + result = Curl_urldecode(data, passwdp, 0, &newpasswd, NULL, FALSE); + if(result) { goto out; } @@ -4964,9 +4926,9 @@ static CURLcode parse_url_login(struct Curl_easy *data, if(optionsp) { /* We have an options list in the URL so decode it */ - char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL); - if(!newoptions) { - result = CURLE_OUT_OF_MEMORY; + char *newoptions; + result = Curl_urldecode(data, optionsp, 0, &newoptions, NULL, FALSE); + if(result) { goto out; } @@ -5457,7 +5419,8 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data, if(!hostname_to_match) return CURLE_OUT_OF_MEMORY; hostname_to_match_len = strlen(hostname_to_match); - host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len); + host_match = strncasecompare(ptr, hostname_to_match, + hostname_to_match_len); free(hostname_to_match); ptr += hostname_to_match_len; @@ -6021,18 +5984,18 @@ static CURLcode create_conn(struct Curl_easy *data, /************************************************************* * IDN-fix the hostnames *************************************************************/ - fix_hostname(data, conn, &conn->host); + fix_hostname(conn, &conn->host); if(conn->bits.conn_to_host) - fix_hostname(data, conn, &conn->conn_to_host); + fix_hostname(conn, &conn->conn_to_host); if(conn->proxy.name && *conn->proxy.name) - fix_hostname(data, conn, &conn->proxy); + fix_hostname(conn, &conn->proxy); /************************************************************* * Check whether the host and the "connect to host" are equal. * Do this after the hostnames have been IDN-fixed . *************************************************************/ if(conn->bits.conn_to_host && - Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) { + strcasecompare(conn->conn_to_host.name, conn->host.name)) { conn->bits.conn_to_host = FALSE; } diff --git a/lib/urldata.h b/lib/urldata.h index 3cf7ed9..7c7bf1b 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -330,6 +330,7 @@ struct ssl_connect_data { CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ + bool use_alpn; /* true if ALPN is used for this connection */ #elif defined(USE_DARWINSSL) SSLContextRef ssl_ctx; curl_socket_t ssl_sockfd; @@ -373,6 +374,7 @@ struct ssl_config_data { struct curl_ssl_session { char *name; /* host name for which this ID was used */ char *conn_to_host; /* host name for the connection (may be NULL) */ + const char *scheme; /* protocol scheme used */ void *sessionid; /* as returned from the SSL layer */ size_t idsize; /* if known, otherwise 0 */ long age; /* just a number, the higher the more recent */ @@ -817,6 +819,7 @@ struct Curl_handler { #define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per request instead of per connection */ #define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ +#define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -1102,9 +1105,10 @@ struct connectdata { /* * Struct to keep statistical and informational data. + * All variables in this struct must be reset in Curl_initinfo(). */ struct PureInfo { - int httpcode; /* Recent HTTP, FTP, or RTSP response code */ + int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */ int httpproxycode; /* response code from proxy when received separate */ int httpversion; /* the http version number X.Y = X*10+Y */ long filetime; /* If requested, this is might get set. Set to -1 if the time @@ -1171,6 +1175,14 @@ struct Progress { struct timeval t_startsingle; struct timeval t_startop; struct timeval t_acceptdata; + + /* upload speed limit */ + struct timeval ul_limit_start; + curl_off_t ul_limit_size; + /* download speed limit */ + struct timeval dl_limit_start; + curl_off_t dl_limit_size; + #define CURR_TIME (5+1) /* 6 entries for 5 seconds */ curl_off_t speeder[ CURR_TIME ]; @@ -1600,6 +1612,7 @@ struct UserDefined { bool ftp_use_port; /* use the FTP PORT command */ bool hide_progress; /* don't use the progress meter */ bool http_fail_on_error; /* fail on HTTP error codes >= 400 */ + bool http_keep_sending_on_error; /* for HTTP status codes >= 300 */ bool http_follow_location; /* follow HTTP redirects */ bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */ bool http_disable_hostname_check_before_authentication; diff --git a/lib/vauth/cleartext.c b/lib/vauth/cleartext.c index 4e906bc..6df419a 100644 --- a/lib/vauth/cleartext.c +++ b/lib/vauth/cleartext.c @@ -33,8 +33,6 @@ #include "curl_md5.h" #include "warnless.h" #include "strtok.h" -#include "strequal.h" -#include "rawstr.h" #include "sendf.h" #include "curl_printf.h" diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c index 26ea7b5..0a11a30 100644 --- a/lib/vauth/digest.c +++ b/lib/vauth/digest.c @@ -37,7 +37,7 @@ #include "vtls/vtls.h" #include "warnless.h" #include "strtok.h" -#include "rawstr.h" +#include "strcase.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ #include "curl_printf.h" @@ -217,11 +217,11 @@ static CURLcode auth_digest_get_qop_values(const char *options, int *value) token = strtok_r(tmp, ",", &tok_buf); while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) + if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) *value |= DIGEST_QOP_VALUE_AUTH; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) *value |= DIGEST_QOP_VALUE_AUTH_INT; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) *value |= DIGEST_QOP_VALUE_AUTH_CONF; token = strtok_r(NULL, ",", &tok_buf); @@ -306,6 +306,20 @@ static CURLcode auth_decode_digest_md5_message(const char *chlg64, } /* + * Curl_auth_is_digest_supported() + * + * This is used to evaluate if DIGEST is supported. + * + * Parameters: None + * + * Returns TRUE as DIGEST as handled by libcurl. + */ +bool Curl_auth_is_digest_supported(void) +{ + return TRUE; +} + +/* * Curl_auth_create_digest_md5_message() * * This is used to generate an already encoded DIGEST-MD5 response message @@ -524,31 +538,31 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "nonce")) { + if(strcasecompare(value, "nonce")) { free(digest->nonce); digest->nonce = strdup(content); if(!digest->nonce) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "stale")) { - if(Curl_raw_equal(content, "true")) { + else if(strcasecompare(value, "stale")) { + if(strcasecompare(content, "true")) { digest->stale = TRUE; digest->nc = 1; /* we make a new nonce now */ } } - else if(Curl_raw_equal(value, "realm")) { + else if(strcasecompare(value, "realm")) { free(digest->realm); digest->realm = strdup(content); if(!digest->realm) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "opaque")) { + else if(strcasecompare(value, "opaque")) { free(digest->opaque); digest->opaque = strdup(content); if(!digest->opaque) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "qop")) { + else if(strcasecompare(value, "qop")) { char *tok_buf; /* Tokenize the list and choose auth if possible, use a temporary clone of the buffer since strtok_r() ruins it */ @@ -558,10 +572,10 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, token = strtok_r(tmp, ",", &tok_buf); while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { + if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { foundAuth = TRUE; } - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { foundAuthInt = TRUE; } token = strtok_r(NULL, ",", &tok_buf); @@ -583,15 +597,15 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, return CURLE_OUT_OF_MEMORY; } } - else if(Curl_raw_equal(value, "algorithm")) { + else if(strcasecompare(value, "algorithm")) { free(digest->algorithm); digest->algorithm = strdup(content); if(!digest->algorithm) return CURLE_OUT_OF_MEMORY; - if(Curl_raw_equal(content, "MD5-sess")) + if(strcasecompare(content, "MD5-sess")) digest->algo = CURLDIGESTALGO_MD5SESS; - else if(Curl_raw_equal(content, "MD5")) + else if(strcasecompare(content, "MD5")) digest->algo = CURLDIGESTALGO_MD5; else return CURLE_BAD_CONTENT_ENCODING; @@ -730,7 +744,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, md5this = (unsigned char *) aprintf("%s:%s", request, uripath); - if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { + if(digest->qop && strcasecompare(digest->qop, "auth-int")) { /* We don't support auth-int for PUT or POST at the moment. TODO: replace md5 of empty string with entity-body for PUT/POST */ unsigned char *md5this2 = (unsigned char *) @@ -806,7 +820,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, digest->qop, request_digest); - if(Curl_raw_equal(digest->qop, "auth")) + if(strcasecompare(digest->qop, "auth")) digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded which tells to the server how many times you are using the same nonce in the qop=auth mode */ diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index 6a7315e..29526fc 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -37,13 +37,34 @@ #include "curl_multibyte.h" #include "sendf.h" #include "strdup.h" -#include "rawstr.h" +#include "strcase.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" /* +* Curl_auth_is_digest_supported() +* +* This is used to evaluate if DIGEST is supported. +* +* Parameters: None +* +* Returns TRUE if DIGEST is supported by Windows SSPI. +*/ +bool Curl_auth_is_digest_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Digest */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* * Curl_auth_create_digest_md5_message() * * This is used to generate an already encoded DIGEST-MD5 response message @@ -256,7 +277,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "realm")) { + if(strcasecompare(value, "realm")) { /* Setup identity's domain and length */ domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); diff --git a/lib/vauth/krb5_gssapi.c b/lib/vauth/krb5_gssapi.c index 31c8c7d..c754fae 100644 --- a/lib/vauth/krb5_gssapi.c +++ b/lib/vauth/krb5_gssapi.c @@ -42,6 +42,20 @@ #include "memdebug.h" /* + * Curl_auth_is_gssapi_supported() + * + * This is used to evaluate if GSSAPI (Kerberos V5) is supported. + * + * Parameters: None + * + * Returns TRUE if Kerberos V5 is supported by the GSS-API library. + */ +bool Curl_auth_is_gssapi_supported(void) +{ + return TRUE; +} + +/* * Curl_auth_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c index 08774f6..151794e 100644 --- a/lib/vauth/krb5_sspi.c +++ b/lib/vauth/krb5_sspi.c @@ -40,6 +40,28 @@ #include "memdebug.h" /* + * Curl_auth_is_gssapi_supported() + * + * This is used to evaluate if GSSAPI (Kerberos V5) is supported. + * + * Parameters: None + * + * Returns TRUE if Kerberos V5 is supported by Windows SSPI. + */ +bool Curl_auth_is_gssapi_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Kerberos */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* * Curl_auth_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c index c85fe42..b484a01 100644 --- a/lib/vauth/ntlm.c +++ b/lib/vauth/ntlm.c @@ -217,6 +217,20 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, */ /* + * Curl_auth_is_ntlm_supported() + * + * This is used to evaluate if NTLM is supported. + * + * Parameters: None + * + * Returns TRUE as NTLM as handled by libcurl. + */ +bool Curl_auth_is_ntlm_supported(void) +{ + return TRUE; +} + +/* * Curl_auth_decode_ntlm_type2_message() * * This is used to decode an already encoded NTLM type-2 message. The message diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c index 982a9d3..c330517 100644 --- a/lib/vauth/ntlm_sspi.c +++ b/lib/vauth/ntlm_sspi.c @@ -38,6 +38,27 @@ #include "memdebug.h" /* + * Curl_auth_is_ntlm_supported() + * + * This is used to evaluate if NTLM is supported. + * + * Parameters: None + * + * Returns TRUE if NTLM is supported by Windows SSPI. + */ +bool Curl_auth_is_ntlm_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* * Curl_auth_create_ntlm_type1_message() * * This is used to generate an already encoded NTLM type-1 message ready for diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c index b256ee6..8840db8 100644 --- a/lib/vauth/spnego_gssapi.c +++ b/lib/vauth/spnego_gssapi.c @@ -41,6 +41,20 @@ #include "memdebug.h" /* + * Curl_auth_is_spnego_supported() + * + * This is used to evaluate if SPNEGO (Negotiate) is supported. + * + * Parameters: None + * + * Returns TRUE if Negotiate supported by the GSS-API library. + */ +bool Curl_auth_is_spnego_supported(void) +{ + return TRUE; +} + +/* * Curl_auth_decode_spnego_message() * * This is used to decode an already encoded SPNEGO (Negotiate) challenge diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index b6176ec..672b43f 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -40,6 +40,28 @@ #include "memdebug.h" /* + * Curl_auth_is_spnego_supported() + * + * This is used to evaluate if SPNEGO (Negotiate) is supported. + * + * Parameters: None + * + * Returns TRUE if Negotiate is supported by Windows SSPI. + */ +bool Curl_auth_is_spnego_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Negotiate */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + +/* * Curl_auth_decode_spnego_message() * * This is used to decode an already encoded SPNEGO (Negotiate) challenge @@ -249,8 +271,10 @@ CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, if(result) return result; - if(!*outptr || !*outlen) + if(!*outptr || !*outlen) { + free(*outptr); return CURLE_REMOTE_ACCESS_DENIED; + } return CURLE_OK; } diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c index 702e2d4..b995f34 100644 --- a/lib/vauth/vauth.c +++ b/lib/vauth/vauth.c @@ -104,3 +104,44 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, } #endif /* USE_WINDOWS_SSPI */ +/* +* Curl_auth_user_contains_domain() +* +* This is used to test if the specified user contains a Windows domain name as +* follows: +* +* User\Domain (Down-level Logon Name) +* User/Domain (curl Down-level format - for compatibility with existing code) +* User@Domain (User Principal Name) +* +* Note: The user name may be empty when using a GSS-API library or Windows SSPI +* as the user and domain are either obtained from the credientals cache when +* using GSS-API or via the currently logged in user's credientals when using +* Windows SSPI. +* +* Parameters: +* +* user [in] - The user name. +* +* Returns TRUE on success; otherwise FALSE. +*/ +bool Curl_auth_user_contains_domain(const char *user) +{ + bool valid = FALSE; + + if(user && *user) { + /* Check we have a domain name or UPN present */ + char *p = strpbrk(user, "\\/@"); + + valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE : + FALSE); + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else + /* User and domain are obtained from the GSS-API credientials cache or the + currently logged in user from Windows */ + valid = TRUE; +#endif + + return valid; +} diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index 38806ee..9d61228 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -55,6 +55,9 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, const char *realm); #endif +/* This is used to test if the user contains a Windows domain name */ +bool Curl_auth_user_contains_domain(const char *user); + /* This is used to generate a base64 encoded PLAIN cleartext message */ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, const char *userp, @@ -83,6 +86,9 @@ CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, const char *passwdp, char **outptr, size_t *outlen); +/* This is used to evaluate if DIGEST is supported */ +bool Curl_auth_is_digest_supported(void); + /* This is used to generate a base64 encoded DIGEST-MD5 response message */ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, const char *chlg64, @@ -109,6 +115,9 @@ void Curl_auth_digest_cleanup(struct digestdata *digest); #endif /* !CURL_DISABLE_CRYPTO_AUTH */ #if defined(USE_NTLM) +/* This is used to evaluate if NTLM is supported */ +bool Curl_auth_is_ntlm_supported(void); + /* This is used to generate a base64 encoded NTLM type-1 message */ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, const char *passwdp, @@ -140,6 +149,9 @@ CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, const char *bearer, char **outptr, size_t *outlen); #if defined(USE_KERBEROS5) +/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */ +bool Curl_auth_is_gssapi_supported(void); + /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token message */ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, @@ -165,6 +177,9 @@ void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5); #endif /* USE_KERBEROS5 */ #if defined(USE_SPNEGO) +/* This is used to evaluate if SPNEGO (Negotiate) is supported */ +bool Curl_auth_is_spnego_supported(void); + /* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge message */ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, diff --git a/lib/version.c b/lib/version.c index 1292445..a434a62 100644 --- a/lib/version.c +++ b/lib/version.c @@ -36,8 +36,8 @@ # include #endif -#ifdef USE_LIBIDN -#include +#ifdef USE_LIBIDN2 +#include #endif #ifdef USE_LIBPSL @@ -111,9 +111,9 @@ char *curl_version(void) left -= len; ptr += len; #endif -#ifdef USE_LIBIDN - if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { - len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL)); +#ifdef USE_LIBIDN2 + if(idn2_check_version(IDN2_VERSION)) { + len = snprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); left -= len; ptr += len; } @@ -365,10 +365,10 @@ curl_version_info_data *curl_version_info(CURLversion stamp) version_info.ares_num = aresnum; } #endif -#ifdef USE_LIBIDN +#ifdef USE_LIBIDN2 /* This returns a version string if we use the given version or later, otherwise it returns NULL */ - version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION); + version_info.libidn = idn2_check_version(IDN2_VERSION); if(version_info.libidn) version_info.features |= CURL_VERSION_IDN; #elif defined(USE_WIN32_IDN) diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c index b6c69ad..85b8bc4 100644 --- a/lib/vtls/axtls.c +++ b/lib/vtls/axtls.c @@ -579,8 +579,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) */ if(connssl->ssl) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server. buf is managed internally by diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c index 7994b3e..5d6dbfb 100644 --- a/lib/vtls/cyassl.c +++ b/lib/vtls/cyassl.c @@ -55,7 +55,7 @@ and that's a problem since options.h hasn't been included yet. */ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" @@ -118,9 +118,9 @@ static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; return -1; } @@ -803,7 +803,8 @@ cyassl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c index ebb9e30..66e74f1 100644 --- a/lib/vtls/darwinssl.c +++ b/lib/vtls/darwinssl.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, . - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -920,7 +920,7 @@ static OSStatus CopyIdentityWithLabel(char *label, #if CURL_SUPPORT_MAC_10_6 /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */ status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key); -#endif /* CURL_SUPPORT_MAC_10_7 */ +#endif /* CURL_SUPPORT_MAC_10_6 */ } #elif CURL_SUPPORT_MAC_10_6 /* For developers building on older cats, we have no choice but to fall back @@ -955,7 +955,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath, /* Here we go: */ status = SecPKCS12Import(pkcs_data, options, &items); - if(status == noErr && items && CFArrayGetCount(items)) { + if(status == errSecSuccess && items && CFArrayGetCount(items)) { CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L); const void *temp_identity = CFDictionaryGetValue(identity_and_trust, kSecImportItemIdentity); @@ -1438,6 +1438,16 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* Disable IDEA: */ case SSL_RSA_WITH_IDEA_CBC_SHA: case SSL_RSA_WITH_IDEA_CBC_MD5: + /* Disable RC4: */ + case SSL_RSA_WITH_RC4_128_MD5: + case SSL_RSA_WITH_RC4_128_SHA: + case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */ + case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/ + case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */ + case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */ + case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */ + case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */ + case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */ break; default: /* enable everything else */ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i]; @@ -2140,7 +2150,8 @@ darwinssl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -2262,8 +2273,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) rc = 0; - what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); for(;;) { if(what < 0) { @@ -2291,7 +2301,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) if(nread <= 0) break; - what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + what = SOCKET_READABLE(conn->sock[sockindex], 0); } return rc; diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c index 55a55ef..3b0cfd5 100644 --- a/lib/vtls/gskit.c +++ b/lib/vtls/gskit.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , 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,7 +72,7 @@ #include "vtls.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "strequal.h" +#include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" @@ -1001,8 +1001,8 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) close_one(connssl, data); rc = 0; - what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); for(;;) { if(what < 0) { @@ -1031,7 +1031,7 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) if(nread <= 0) break; - what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + what = SOCKET_READABLE(conn->sock[sockindex], 0); } return rc; diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 1c3e6b1..5c87c7f 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -52,7 +52,7 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "x509asn1.h" #include "curl_printf.h" @@ -289,7 +289,7 @@ static CURLcode handshake(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0: timeout_ms?timeout_ms:1000); if(what < 0) { @@ -356,9 +356,9 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type) { if(!type || !type[0]) return GNUTLS_X509_FMT_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return GNUTLS_X509_FMT_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return GNUTLS_X509_FMT_DER; return -1; } @@ -1445,8 +1445,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) if(conn->ssl[sockindex].session) { while(!done) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index a1e7d23..24249dd 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -31,7 +31,7 @@ #ifdef USE_MBEDTLS -#include +#include #include #include #include @@ -50,7 +50,6 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" #include "polarssl_threadlock.h" /* The last 3 #include files should be in this order */ @@ -420,7 +419,15 @@ mbed_connect_step1(struct connectdata *conn, #endif #ifdef MBEDTLS_DEBUG + /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ mbedtls_ssl_conf_dbg(&connssl->config, mbed_debug, data); + /* - 0 No debug + * - 1 Error + * - 2 State change + * - 3 Informational + * - 4 Verbose + */ + mbedtls_debug_set_threshold(4); #endif connssl->connecting_state = ssl_connect_2; @@ -765,7 +772,8 @@ mbed_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c index ad33f25..dff1575 100644 --- a/lib/vtls/nss.c +++ b/lib/vtls/nss.c @@ -34,7 +34,7 @@ #include "formdata.h" /* for the boundary function */ #include "url.h" /* for the ssl config check function */ #include "connect.h" -#include "strequal.h" +#include "strcase.h" #include "select.h" #include "vtls.h" #include "llist.h" @@ -64,7 +64,7 @@ #include #endif -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "x509asn1.h" @@ -78,13 +78,12 @@ #define SLOTSIZE 13 PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd); - -PRLock * nss_initlock = NULL; -PRLock * nss_crllock = NULL; -struct curl_llist *nss_crl_list = NULL; -NSSInitContext * nss_context = NULL; - -volatile int initialized = 0; +static PRLock *nss_initlock = NULL; +static PRLock *nss_crllock = NULL; +static PRLock *nss_findslot_lock = NULL; +static struct curl_llist *nss_crl_list = NULL; +static NSSInitContext *nss_context = NULL; +static volatile int initialized = 0; typedef struct { const char *name; @@ -150,7 +149,7 @@ static const cipher_s cipherlist[] = { {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}, {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA}, {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA}, - {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, + {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, @@ -180,10 +179,29 @@ static const cipher_s cipherlist[] = { {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256}, #endif +#ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + /* cipher suites using SHA384 */ + {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384}, + {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384}, + {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384}, + {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384}, + {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, + {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384}, + {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, +#endif +#ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + /* chacha20-poly1305 cipher suites */ + {"ecdhe_rsa_chacha20_poly1305_sha_256", + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, + {"ecdhe_ecdsa_chacha20_poly1305_sha_256", + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256}, + {"dhe_rsa_chacha20_poly1305_sha_256", + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, +#endif }; static const char* pem_library = "libnsspem.so"; -SECMODModule* mod = NULL; +static SECMODModule* mod = NULL; /* NSPR I/O layer we use to detect blocking direction during SSL handshake */ static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER; @@ -243,7 +261,7 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, found = PR_FALSE; for(i=0; i. + */ +static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name) +{ + PK11SlotInfo *slot; + PR_Lock(nss_initlock); + slot = PK11_FindSlotByName(slot_name); + PR_Unlock(nss_initlock); + return slot; +} + /* Call PK11_CreateGenericObject() with the given obj_class and filename. If * the call succeeds, append the object handle to the list of objects so that * the object can be destroyed in Curl_nss_close(). */ @@ -362,7 +393,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, if(!slot_name) return CURLE_OUT_OF_MEMORY; - slot = PK11_FindSlotByName(slot_name); + slot = nss_find_slot_by_name(slot_name); free(slot_name); if(!slot) return result; @@ -563,7 +594,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, return result; } - slot = PK11_FindSlotByName("PEM Token #1"); + slot = nss_find_slot_by_name("PEM Token #1"); if(!slot) return CURLE_SSL_CERTPROBLEM; @@ -1004,16 +1035,16 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; struct Curl_easy *data = connssl->data; const char *nickname = connssl->client_nickname; + static const char pem_slotname[] = "PEM Token #1"; if(connssl->obj_clicert) { /* use the cert/key provided by PEM reader */ - static const char pem_slotname[] = "PEM Token #1"; SECItem cert_der = { 0, NULL, 0 }; void *proto_win = SSL_RevealPinArg(sock); struct CERTCertificateStr *cert; struct SECKEYPrivateKeyStr *key; - PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname); + PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname); if(NULL == slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; @@ -1069,6 +1100,12 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, if(NULL == nickname) nickname = "[unknown]"; + if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) { + failf(data, "NSS: refusing previously loaded certificate from file: %s", + nickname); + return SECFailure; + } + if(NULL == *pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; @@ -1243,6 +1280,7 @@ int Curl_nss_init(void) PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); nss_initlock = PR_NewLock(); nss_crllock = PR_NewLock(); + nss_findslot_lock = PR_NewLock(); } /* We will actually initialize NSS later */ @@ -1297,6 +1335,7 @@ void Curl_nss_cleanup(void) PR_DestroyLock(nss_initlock); PR_DestroyLock(nss_crllock); + PR_DestroyLock(nss_findslot_lock); nss_initlock = NULL; initialized = 0; @@ -1882,8 +1921,11 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, const bool blocking = (done == NULL); CURLcode result; - if(connssl->state == ssl_connection_complete) + if(connssl->state == ssl_connection_complete) { + if(!blocking) + *done = TRUE; return CURLE_OK; + } if(connssl->connecting_state == ssl_connect_1) { result = nss_setup_connect(conn, sockindex); diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 3027ca3..c040928 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -46,10 +46,9 @@ #include "openssl.h" #include "connect.h" #include "slist.h" -#include "strequal.h" #include "select.h" #include "vtls.h" -#include "rawstr.h" +#include "strcase.h" #include "hostcheck.h" #include "curl_printf.h" @@ -95,11 +94,6 @@ #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) #define HAVE_ERR_REMOVE_THREAD_STATE 1 -#if (OPENSSL_VERSION_NUMBER >= 0x10100004L) && \ - !defined(LIBRESSL_VERSION_NUMBER) -/* OpenSSL 1.1.0 deprecates the function */ -#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 -#endif #endif #if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ @@ -110,11 +104,28 @@ #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ !defined(LIBRESSL_VERSION_NUMBER) -#define SSLeay_add_ssl_algorithms() SSL_library_init() #define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER #define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ #define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ #define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ +#define CONST_EXTS const +#define CONST_ASN1_BIT_STRING const +#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 +#else +/* For OpenSSL before 1.1.0 */ +#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) +#define X509_get0_notBefore(x) X509_get_notBefore(x) +#define X509_get0_notAfter(x) X509_get_notAfter(x) +#define CONST_EXTS /* nope */ +#define CONST_ASN1_BIT_STRING /* nope */ +#ifdef LIBRESSL_VERSION_NUMBER +static unsigned long OpenSSL_version_num(void) +{ + return LIBRESSL_VERSION_NUMBER; +} +#else +#define OpenSSL_version_num() SSLeay() +#endif #endif #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ @@ -278,13 +289,13 @@ static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; - if(Curl_raw_equal(type, "ENG")) + if(strcasecompare(type, "ENG")) return SSL_FILETYPE_ENGINE; - if(Curl_raw_equal(type, "P12")) + if(strcasecompare(type, "P12")) return SSL_FILETYPE_PKCS12; return -1; } @@ -711,6 +722,10 @@ int Curl_ossl_init(void) CONF_MFLAGS_DEFAULT_SECTION| CONF_MFLAGS_IGNORE_MISSING_FILE); +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !defined(LIBRESSL_VERSION_NUMBER) + /* OpenSSL 1.1.0+ takes care of initialization itself */ +#else /* Lets get nice error messages */ SSL_load_error_strings(); @@ -719,6 +734,7 @@ int Curl_ossl_init(void) return 0; OpenSSL_add_all_algorithms(); +#endif return 1; } @@ -726,6 +742,11 @@ int Curl_ossl_init(void) /* Global cleanup */ void Curl_ossl_cleanup(void) { +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !defined(LIBRESSL_VERSION_NUMBER) + /* OpenSSL 1.1 deprecates all these cleanup functions and + turns them into no-ops in OpenSSL 1.0 compatibility mode */ +#else /* Free ciphers and digests lists */ EVP_cleanup(); @@ -734,18 +755,11 @@ void Curl_ossl_cleanup(void) ENGINE_cleanup(); #endif -#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA - /* Free OpenSSL ex_data table */ - CRYPTO_cleanup_all_ex_data(); -#endif - /* Free OpenSSL error strings */ ERR_free_strings(); /* Free thread local error state, destroying hash upon zero refcount */ -#ifdef HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED - -#elif defined(HAVE_ERR_REMOVE_THREAD_STATE) +#ifdef HAVE_ERR_REMOVE_THREAD_STATE ERR_remove_thread_state(NULL); #else ERR_remove_state(0); @@ -757,6 +771,7 @@ void Curl_ossl_cleanup(void) #ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS SSL_COMP_free_compression_methods(); #endif +#endif } /* @@ -949,8 +964,8 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) if(connssl->handle) { buffsize = (int)sizeof(buf); while(!done) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); if(what > 0) { ERR_clear_error(); @@ -1043,6 +1058,14 @@ void Curl_ossl_close_all(struct Curl_easy *data) #else (void)data; #endif +#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \ + defined(HAVE_ERR_REMOVE_THREAD_STATE) + /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread + so we need to clean it here in case the thread will be killed. All OpenSSL + code should extract the error in association with the error so clearing + this queue here should be harmless at worst. */ + ERR_remove_thread_state(NULL); +#endif } /* ====================================================== */ @@ -1083,6 +1106,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) #endif CURLcode result = CURLE_OK; bool dNSName = FALSE; /* if a dNSName field exists in the cert */ + bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1115,15 +1139,15 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) /* get a handle to alternative name number i */ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); - /* If a subjectAltName extension of type dNSName is present, that MUST - be used as the identity. / RFC2818 section 3.1 */ if(check->type == GEN_DNS) dNSName = TRUE; + else if(check->type == GEN_IPADD) + iPAddress = TRUE; /* only check alternatives of the same type the target is */ if(check->type == target) { /* get data and length */ - const char *altptr = (char *)ASN1_STRING_data(check->d.ia5); + const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5); size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5); switch(target) { @@ -1164,18 +1188,14 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) } GENERAL_NAMES_free(altnames); - if(dnsmatched || (!dNSName && ipmatched)) { - /* count as a match if the dnsname matched or if there was no dnsname - fields at all AND there was an IP field match */ + if(dnsmatched || ipmatched) matched = TRUE; - } } if(matched) /* an alternative name matched */ ; - else if(dNSName) { - /* an dNSName field existed, but didn't match and then we MUST fail */ + else if(dNSName || iPAddress) { infof(data, " subjectAltName does not match %s\n", conn->host.dispname); failf(data, "SSL: no alternative certificate subject name matches " "target host name '%s'", conn->host.dispname); @@ -1215,7 +1235,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if(j >= 0) { peer_CN = OPENSSL_malloc(j+1); if(peer_CN) { - memcpy(peer_CN, ASN1_STRING_data(tmp), j); + memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j); peer_CN[j] = '\0'; } } @@ -2178,6 +2198,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) lerr = SSL_get_verify_result(connssl->handle); if(lerr != X509_V_OK) { + data->set.ssl.certverifyresult = lerr; snprintf(error_buffer, sizeof(error_buffer), "SSL certificate problem: %s", X509_verify_cert_error_string(lerr)); @@ -2309,7 +2330,7 @@ do { \ static int X509V3_ext(struct Curl_easy *data, int certnum, - STACK_OF(X509_EXTENSION) *exts) + CONST_EXTS STACK_OF(X509_EXTENSION) *exts) { int i; size_t j; @@ -2391,7 +2412,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, EVP_PKEY *pubkey=NULL; int j; char *ptr; - ASN1_BIT_STRING *psig = NULL; + CONST_ASN1_BIT_STRING ASN1_BIT_STRING *psig = NULL; X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); push_certinfo("Subject", i); @@ -2411,7 +2432,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, #if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) { - X509_ALGOR *palg = NULL; + const X509_ALGOR *palg = NULL; ASN1_STRING *a = ASN1_STRING_new(); if(a) { X509_get0_signature(&psig, &palg, x); @@ -2442,10 +2463,10 @@ static CURLcode get_cert_chain(struct connectdata *conn, } #endif - ASN1_TIME_print(mem, X509_get_notBefore(x)); + ASN1_TIME_print(mem, X509_get0_notBefore(x)); push_certinfo("Start date", i); - ASN1_TIME_print(mem, X509_get_notAfter(x)); + ASN1_TIME_print(mem, X509_get0_notAfter(x)); push_certinfo("Expire date", i); pubkey = X509_get_pubkey(x); @@ -2629,7 +2650,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, break; /* failed */ /* https://www.openssl.org/docs/crypto/buffer.html */ - buff1 = temp = OPENSSL_malloc(len1); + buff1 = temp = malloc(len1); if(!buff1) break; /* failed */ @@ -2652,7 +2673,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, /* https://www.openssl.org/docs/crypto/buffer.html */ if(buff1) - OPENSSL_free(buff1); + free(buff1); return result; } @@ -2698,12 +2719,12 @@ static CURLcode servercert(struct connectdata *conn, buffer, BUFSIZE); infof(data, " subject: %s\n", rc?"[NONE]":buffer); - ASN1_TIME_print(mem, X509_get_notBefore(connssl->server_cert)); + ASN1_TIME_print(mem, X509_get0_notBefore(connssl->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " start date: %.*s\n", len, ptr); rc = BIO_reset(mem); - ASN1_TIME_print(mem, X509_get_notAfter(connssl->server_cert)); + ASN1_TIME_print(mem, X509_get0_notAfter(connssl->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " expire date: %.*s\n", len, ptr); rc = BIO_reset(mem); @@ -2945,7 +2966,8 @@ static CURLcode ossl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -3142,7 +3164,7 @@ size_t Curl_ossl_version(char *buffer, size_t size) unsigned long ssleay_value; sub[2]='\0'; sub[1]='\0'; - ssleay_value=SSLeay(); + ssleay_value=OpenSSL_version_num(); if(ssleay_value < 0x906000) { ssleay_value=SSLEAY_VERSION_NUMBER; sub[0]='\0'; diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c index d33f548..18b564e 100644 --- a/lib/vtls/polarssl.c +++ b/lib/vtls/polarssl.c @@ -54,7 +54,7 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "polarssl_threadlock.h" #include "curl_printf.h" #include "curl_memory.h" @@ -75,6 +75,11 @@ #define THREADING_SUPPORT #endif +#ifndef POLARSSL_ERROR_C +#define error_strerror(x,y,z) +#endif /* POLARSSL_ERROR_C */ + + #if defined(THREADING_SUPPORT) static entropy_context entropy; @@ -96,13 +101,13 @@ static void entropy_init_mutex(entropy_context *ctx) /* start of entropy_func_mutex() */ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) { - int ret; - /* lock 1 = entropy_func_mutex() */ - Curl_polarsslthreadlock_lock_function(1); - ret = entropy_func(data, output, len); - Curl_polarsslthreadlock_unlock_function(1); + int ret; + /* lock 1 = entropy_func_mutex() */ + Curl_polarsslthreadlock_lock_function(1); + ret = entropy_func(data, output, len); + Curl_polarsslthreadlock_unlock_function(1); - return ret; + return ret; } /* end of entropy_func_mutex() */ @@ -138,18 +143,11 @@ static Curl_send polarssl_send; static CURLcode polarssl_connect_step1(struct connectdata *conn, - int sockindex) + int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - - bool sni = TRUE; /* default is SNI enabled */ int ret = -1; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif char errorbuf[128]; errorbuf[0]=0; @@ -158,30 +156,24 @@ polarssl_connect_step1(struct connectdata *conn, failf(data, "PolarSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } - else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) - sni = FALSE; /* SSLv3 has no SNI */ #ifdef THREADING_SUPPORT entropy_init_mutex(&entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy, NULL, 0)) != 0) { -#ifdef POLARSSL_ERROR_C - error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); + error_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); } #else entropy_init(&connssl->entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy, NULL, 0)) != 0) { -#ifdef POLARSSL_ERROR_C - error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); + error_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); } #endif /* THREADING_SUPPORT */ @@ -193,9 +185,7 @@ polarssl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CAFILE]); if(ret<0) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_SSL_CAFILE], -ret, errorbuf); @@ -209,9 +199,7 @@ polarssl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CAPATH]); if(ret<0) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_SSL_CAPATH], -ret, errorbuf); @@ -228,9 +216,7 @@ polarssl_connect_step1(struct connectdata *conn, data->set.str[STRING_CERT]); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_CERT], -ret, errorbuf); @@ -253,9 +239,7 @@ polarssl_connect_step1(struct connectdata *conn, pk_free(&pk); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_KEY], -ret, errorbuf); @@ -271,9 +255,7 @@ polarssl_connect_step1(struct connectdata *conn, data->set.str[STRING_SSL_CRLFILE]); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s", data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf); @@ -344,13 +326,14 @@ polarssl_connect_step1(struct connectdata *conn, Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { ret = ssl_set_session(&connssl->ssl, old_session); - Curl_ssl_sessionid_unlock(conn); if(ret) { + Curl_ssl_sessionid_unlock(conn); failf(data, "ssl_set_session returned -0x%x", -ret); return CURLE_SSL_CONNECT_ERROR; } infof(data, "PolarSSL re-using session\n"); } + Curl_ssl_sessionid_unlock(conn); } ssl_set_ca_chain(&connssl->ssl, @@ -401,7 +384,7 @@ polarssl_connect_step1(struct connectdata *conn, static CURLcode polarssl_connect_step2(struct connectdata *conn, - int sockindex) + int sockindex) { int ret; struct Curl_easy *data = conn->data; @@ -429,9 +412,7 @@ polarssl_connect_step2(struct connectdata *conn, return CURLE_OK; default: -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; @@ -538,9 +519,9 @@ polarssl_connect_step2(struct connectdata *conn, } else #endif - if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } + if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } } else infof(data, "ALPN, server did not agree to a protocol\n"); @@ -555,7 +536,7 @@ polarssl_connect_step2(struct connectdata *conn, static CURLcode polarssl_connect_step3(struct connectdata *conn, - int sockindex) + int sockindex) { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -727,7 +708,8 @@ polarssl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -786,8 +768,8 @@ polarssl_connect_common(struct connectdata *conn, CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) + int sockindex, + bool *done) { return polarssl_connect_common(conn, sockindex, TRUE, done); } @@ -795,7 +777,7 @@ Curl_polarssl_connect_nonblocking(struct connectdata *conn, CURLcode Curl_polarssl_connect(struct connectdata *conn, - int sockindex) + int sockindex) { CURLcode result; bool done = FALSE; diff --git a/lib/vtls/polarssl_threadlock.c b/lib/vtls/polarssl_threadlock.c index 3b0ebf8..b1eb7b7 100644 --- a/lib/vtls/polarssl_threadlock.c +++ b/lib/vtls/polarssl_threadlock.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013-2015, Daniel Stenberg, , et al. + * Copyright (C) 2013-2016, Daniel Stenberg, , et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which @@ -52,7 +52,7 @@ int Curl_polarsslthreadlock_thread_setup(void) int i; int ret; - mutex_buf = malloc(NUMT * sizeof(POLARSSL_MUTEX_T)); + mutex_buf = calloc(NUMT * sizeof(POLARSSL_MUTEX_T), 1); if(!mutex_buf) return 0; /* error, no number of threads defined */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index f991ec9..f731eeb 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -127,6 +127,18 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", conn->host.name, conn->remote_port); +#ifdef HAS_ALPN + /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. + Also it doesn't seem to be supported for Wine, see curl bug #983. */ + connssl->use_alpn = conn->bits.tls_enable_alpn && + !GetProcAddress(GetModuleHandleA("ntdll"), + "wine_get_version") && + Curl_verify_windows_version(6, 3, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL); +#else + connssl->use_alpn = false; +#endif + connssl->cred = NULL; /* check for an existing re-usable credential handle */ @@ -250,10 +262,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) } #ifdef HAS_ALPN - /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */ - if(conn->bits.tls_enable_alpn && - Curl_verify_windows_version(6, 3, PLATFORM_WINNT, - VERSION_GREATER_THAN_EQUAL)) { + if(connssl->use_alpn) { int cur = 0; int list_start_index = 0; unsigned int* extension_len = NULL; @@ -328,11 +337,17 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) if(!host_name) return CURLE_OUT_OF_MEMORY; - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ + /* Schannel InitializeSecurityContext: + https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx + At the moment we don't pass inbuf unless we're using ALPN since we only + use it for that, and Wine (for which we currently disable ALPN) is giving + us problems with inbuf regardless. https://github.com/curl/curl/issues/983 + */ sspi_status = s_pSecFn->InitializeSecurityContext( - &connssl->cred->cred_handle, NULL, host_name, - connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle, + &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0, + (connssl->use_alpn ? &inbuf_desc : NULL), + 0, &connssl->ctxt->ctxt_handle, &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); Curl_unicodefree(host_name); @@ -651,10 +666,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } #ifdef HAS_ALPN - /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above */ - if(conn->bits.tls_enable_alpn && - Curl_verify_windows_version(6, 3, PLATFORM_WINNT, - VERSION_GREATER_THAN_EQUAL)) { + if(connssl->use_alpn) { sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); @@ -803,7 +815,8 @@ schannel_connect_common(struct connectdata *conn, int sockindex, curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); @@ -959,8 +972,7 @@ schannel_send(struct connectdata *conn, int sockindex, break; } - what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex], - timeleft); + what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft); if(what < 0) { /* fatal error */ failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 3863777..56a8823 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -61,7 +61,7 @@ #include "vtls.h" /* generic SSL protos etc */ #include "slist.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "url.h" #include "progress.h" #include "share.h" @@ -84,7 +84,7 @@ static bool safe_strequal(char* str1, char* str2) { if(str1 && str2) /* both pointers point to something then compare them */ - return (0 != Curl_raw_equal(str1, str2)) ? TRUE : FALSE; + return (0 != strcasecompare(str1, str2)) ? TRUE : FALSE; else /* if both pointers are NULL then treat them as equal */ return (!str1 && !str2) ? TRUE : FALSE; @@ -100,8 +100,6 @@ Curl_ssl_config_matches(struct ssl_config_data* data, safe_strequal(data->CApath, needle->CApath) && safe_strequal(data->CAfile, needle->CAfile) && safe_strequal(data->clientcert, needle->clientcert) && - safe_strequal(data->random_file, needle->random_file) && - safe_strequal(data->egdsocket, needle->egdsocket) && safe_strequal(data->cipher_list, needle->cipher_list)) return TRUE; @@ -392,14 +390,15 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, if(!check->sessionid) /* not session ID means blank entry */ continue; - if(Curl_raw_equal(conn->host.name, check->name) && + if(strcasecompare(conn->host.name, check->name) && ((!conn->bits.conn_to_host && !check->conn_to_host) || - (conn->bits.conn_to_host && check->conn_to_host && - Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) && + (conn->bits.conn_to_host && check->conn_to_host && + strcasecompare(conn->conn_to_host.name, check->conn_to_host))) && ((!conn->bits.conn_to_port && check->conn_to_port == -1) || - (conn->bits.conn_to_port && check->conn_to_port != -1 && - conn->conn_to_port == check->conn_to_port)) && + (conn->bits.conn_to_port && check->conn_to_port != -1 && + conn->conn_to_port == check->conn_to_port)) && (conn->remote_port == check->remote_port) && + strcasecompare(conn->handler->scheme, check->scheme) && Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ (*general_age)++; /* increase general age */ @@ -530,6 +529,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ store->conn_to_port = conn_to_port; /* connect to port number */ store->remote_port = conn->remote_port; /* port number */ + store->scheme = conn->handler->scheme; if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ diff --git a/lib/x509asn1.c b/lib/x509asn1.c index e17bcd9..74a511b 100644 --- a/lib/x509asn1.c +++ b/lib/x509asn1.c @@ -27,7 +27,7 @@ #include #include "urldata.h" -#include "strequal.h" +#include "strcase.h" #include "hostcheck.h" #include "vtls/vtls.h" #include "sendf.h" @@ -178,7 +178,7 @@ static const curl_OID * searchOID(const char * oid) Return the table entry pointer or NULL if not found. */ for(op = OIDtable; op->numoid; op++) - if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid)) + if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid)) return op; return (const curl_OID *) NULL; @@ -817,7 +817,7 @@ static void do_pubkey(struct Curl_easy * data, int certnum, /* Get the public key (single element). */ Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end); - if(curl_strequal(algo, "rsaEncryption")) { + if(strcasecompare(algo, "rsaEncryption")) { p = Curl_getASN1Element(&elem, pk.beg, pk.end); /* Compute key length. */ for(q = elem.beg; !*q && q < elem.end; q++) @@ -842,7 +842,7 @@ static void do_pubkey(struct Curl_easy * data, int certnum, Curl_getASN1Element(&elem, p, pk.end); do_pubkey_field(data, certnum, "rsa(e)", &elem); } - else if(curl_strequal(algo, "dsa")) { + else if(strcasecompare(algo, "dsa")) { p = Curl_getASN1Element(&elem, param->beg, param->end); do_pubkey_field(data, certnum, "dsa(p)", &elem); p = Curl_getASN1Element(&elem, p, param->end); @@ -851,7 +851,7 @@ static void do_pubkey(struct Curl_easy * data, int certnum, do_pubkey_field(data, certnum, "dsa(g)", &elem); do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); } - else if(curl_strequal(algo, "dhpublicnumber")) { + else if(strcasecompare(algo, "dhpublicnumber")) { p = Curl_getASN1Element(&elem, param->beg, param->end); do_pubkey_field(data, certnum, "dh(p)", &elem); Curl_getASN1Element(&elem, param->beg, param->end); @@ -859,7 +859,7 @@ static void do_pubkey(struct Curl_easy * data, int certnum, do_pubkey_field(data, certnum, "dh(pub_key)", &pk); } #if 0 /* Patent-encumbered. */ - else if(curl_strequal(algo, "ecPublicKey")) { + else if(strcasecompare(algo, "ecPublicKey")) { /* Left TODO. */ } #endif -- cgit v0.12