curl 2018-10-30 (19667715)

Code extracted from:

    https://github.com/curl/curl.git

at commit 196677150f711a96c38ed123e621f1d4e995b2e5 (curl-7_62_0).
This commit is contained in:
Curl Upstream
2018-10-31 09:41:28 -04:00
committed by Brad King
parent 18812a9c3d
commit 9835e90750
124 changed files with 5064 additions and 2065 deletions
-1
View File
@@ -1,2 +1 @@
@CMAKE_CONFIGURABLE_FILE_CONTENT@
+16
View File
@@ -549,3 +549,19 @@ main() {
return 0;
}
#endif
#ifdef HAVE_CLOCK_GETTIME_MONOTONIC
#include <time.h>
int
main() {
struct timespec ts = {0, 0};
clock_gettime(CLOCK_MONOTONIC, &ts);
return 0;
}
#endif
#ifdef HAVE_BUILTIN_AVAILABLE
int
main() {
if(__builtin_available(macOS 10.12, *)) {}
return 0;
}
#endif
+8 -60
View File
@@ -1,64 +1,12 @@
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
if(NOT CURL_FIND_COMPONENTS)
set(CURL_FIND_COMPONENTS curl libcurl)
if(CURL_FIND_REQUIRED)
set(CURL_FIND_REQUIRED_curl TRUE)
set(CURL_FIND_REQUIRED_libcurl TRUE)
endif()
endif()
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
if(CURL_FIND_REQUIRED_libcurl)
find_dependency(OpenSSL "@OPENSSL_VERSION_MAJOR@")
if(@USE_OPENSSL@)
find_dependency(OpenSSL @OPENSSL_VERSION_MAJOR@)
endif()
if(@USE_ZLIB@)
find_dependency(ZLIB @ZLIB_VERSION_MAJOR@)
endif()
set(_curl_missing_components)
foreach(_comp ${CURL_FIND_COMPONENTS})
if(EXISTS "${_DIR}/${_comp}-target.cmake")
include("${_DIR}/${_comp}-target.cmake")
set(CURL_${_comp}_FOUND TRUE)
else()
set(CURL_${_comp}_FOUND FALSE)
if(CURL_FIND_REQUIRED_${_comp})
set(CURL_FOUND FALSE)
list(APPEND _curl_missing_components ${_comp})
endif()
endif()
endforeach()
if(_curl_missing_components)
set(CURL_NOT_FOUND_MESSAGE "Following required components not found: " ${_curl_missing_components})
else()
if(TARGET CURL::libcurl)
string(TOUPPER "${CMAKE_BUILD_TYPE}" _curl_current_config)
if(NOT _curl_current_config)
set(_curl_current_config "NOCONFIG")
endif()
get_target_property(_curl_configurations CURL::libcurl IMPORTED_CONFIGURATIONS)
list(FIND _curl_configurations "${_curl_current_config}" _i)
if(_i LESS 0)
set(_curl_config "RELEASE")
list(FIND _curl_configurations "${_curl_current_config}" _i)
if(_i LESS 0)
set(_curl_config "NOCONFIG")
list(FIND _curl_configurations "${_curl_current_config}" _i)
endif()
endif()
if(_i LESS 0)
set(_curl_current_config "") # let CMake pick config at random
else()
set(_curl_current_config "_${_curl_current_config}")
endif()
get_target_property(CURL_INCLUDE_DIRS CURL::libcurl INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(CURL_LIBRARIES CURL::libcurl "LOCATION${_curl_current_config}")
set(_curl_current_config)
set(_curl_configurations)
set(_i)
endif()
endif()
unset(_curl_missing_components)
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
check_required_components("@PROJECT_NAME@")
+54 -46
View File
@@ -38,7 +38,7 @@
# To check:
# (From Daniel Stenberg) The cmake build selected to run gcc with -fPIC on my box while the plain configure script did not.
# (From Daniel Stenberg) The gcc command line use neither -g nor any -O options. As a developer, I also treasure our configure scripts's --enable-debug option that sets a long range of "picky" compiler options.
cmake_minimum_required(VERSION 3.4 FATAL_ERROR)
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
include(Utilities)
include(Macros)
@@ -92,7 +92,7 @@ option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OF
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
if(PICKY_COMPILER)
foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers)
foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers -Wno-pedantic-ms-format)
# surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
# test result in.
check_c_compiler_flag(${_CCOPT} OPT${_CCOPT})
@@ -352,7 +352,16 @@ if(CMAKE_USE_OPENSSL)
set(USE_OPENSSL ON)
set(HAVE_LIBCRYPTO ON)
set(HAVE_LIBSSL ON)
list(APPEND CURL_LIBS OpenSSL::SSL OpenSSL::Crypto)
# Depend on OpenSSL via imported targets if supported by the running
# version of CMake. This allows our dependents to get our dependencies
# transitively.
if(NOT CMAKE_VERSION VERSION_LESS 3.4)
list(APPEND CURL_LIBS OpenSSL::SSL OpenSSL::Crypto)
else()
list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
include_directories(${OPENSSL_INCLUDE_DIR})
endif()
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
check_include_file("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H)
@@ -499,15 +508,23 @@ check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
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)
set(USE_ZLIB OFF)
if(CURL_ZLIB)
find_package(ZLIB QUIET)
if(ZLIB_FOUND)
set(HAVE_ZLIB_H ON)
set(HAVE_ZLIB ON)
set(HAVE_LIBZ ON)
list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
include_directories(${ZLIB_INCLUDE_DIRS})
set(USE_ZLIB ON)
# Depend on ZLIB via imported targets if supported by the running
# version of CMake. This allows our dependents to get our dependencies
# transitively.
if(NOT CMAKE_VERSION VERSION_LESS 3.4)
list(APPEND CURL_LIBS ZLIB::ZLIB)
else()
list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
include_directories(${ZLIB_INCLUDE_DIRS})
endif()
list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
endif()
endif()
@@ -947,7 +964,6 @@ foreach(CURL_TEST
HAVE_GETHOSTBYNAME_R_3_REENTRANT
HAVE_GETHOSTBYNAME_R_5_REENTRANT
HAVE_GETHOSTBYNAME_R_6_REENTRANT
HAVE_SOCKLEN_T
HAVE_IN_ADDR_T
HAVE_BOOL_T
STDC_HEADERS
@@ -1017,6 +1033,12 @@ if(HAVE_INET_NTOA_R_DECL_REENTRANT)
set(NEED_REENTRANT 1)
endif()
# Check clock_gettime(CLOCK_MONOTONIC, x) support
curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC)
# Check compiler support of __builtin_available()
curl_internal_test(HAVE_BUILTIN_AVAILABLE)
# Some other minor tests
if(NOT HAVE_IN_ADDR_T)
@@ -1066,24 +1088,6 @@ if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
endif()
endif()
if(HAVE_SOCKLEN_T)
set(CURL_TYPEOF_CURL_SOCKLEN_T "socklen_t")
if(WIN32)
set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h;ws2tcpip.h")
elseif(HAVE_SYS_SOCKET_H)
set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
endif()
check_type_size("socklen_t" CURL_SIZEOF_CURL_SOCKLEN_T)
set(CMAKE_EXTRA_INCLUDE_FILES)
if(NOT HAVE_CURL_SIZEOF_CURL_SOCKLEN_T)
message(FATAL_ERROR
"Check for sizeof socklen_t failed, see CMakeFiles/CMakerror.log")
endif()
else()
set(CURL_TYPEOF_CURL_SOCKLEN_T int)
set(CURL_SIZEOF_CURL_SOCKLEN_T ${SIZEOF_INT})
endif()
# TODO test which of these headers are required
if(WIN32)
set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H})
@@ -1144,11 +1148,13 @@ function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE)
endfunction()
if(WIN32 AND NOT CYGWIN)
set(CURL_INSTALL_CMAKE_DIR CMake)
else()
set(CURL_INSTALL_CMAKE_DIR lib/cmake/curl)
endif()
include(GNUInstallDirs)
set(CURL_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake")
set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake")
if(USE_MANUAL)
add_subdirectory(docs)
@@ -1282,7 +1288,7 @@ set(VERSIONNUM "${CURL_VERSION_NUM}")
configure_file("${CURL_SOURCE_DIR}/curl-config.in"
"${CURL_BINARY_DIR}/curl-config" @ONLY)
install(FILES "${CURL_BINARY_DIR}/curl-config"
DESTINATION bin
DESTINATION ${CMAKE_INSTALL_BINDIR}
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
@@ -1292,34 +1298,36 @@ install(FILES "${CURL_BINARY_DIR}/curl-config"
configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in"
"${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
install(FILES "${CURL_BINARY_DIR}/libcurl.pc"
DESTINATION lib/pkgconfig)
# This needs to be run very last so other parts of the scripts can take advantage of this.
if(NOT CURL_CONFIG_HAS_BEEN_RUN_BEFORE)
set(CURL_CONFIG_HAS_BEEN_RUN_BEFORE 1 CACHE INTERNAL "Flag to track whether this is the first time running CMake or if CMake has been configured before")
endif()
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
# install headers
install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl"
DESTINATION include
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h")
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/curl-config-version.cmake"
"${version_config}"
VERSION ${CURL_VERSION}
COMPATIBILITY SameMajorVersion
)
configure_file(CMake/curl-config.cmake.in
"${PROJECT_BINARY_DIR}/curl-config.cmake"
@ONLY
# Use:
# * TARGETS_EXPORT_NAME
# * PROJECT_NAME
configure_package_config_file(CMake/curl-config.cmake.in
"${project_config}"
INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR}
)
install(
FILES ${PROJECT_BINARY_DIR}/curl-config.cmake
${PROJECT_BINARY_DIR}/curl-config-version.cmake
EXPORT "${TARGETS_EXPORT_NAME}"
NAMESPACE "${PROJECT_NAME}::"
DESTINATION ${CURL_INSTALL_CMAKE_DIR}
)
install(
FILES ${version_config} ${project_config}
DESTINATION ${CURL_INSTALL_CMAKE_DIR}
)
+21 -4
View File
@@ -146,7 +146,8 @@ typedef enum {
CURLSSLBACKEND_SCHANNEL = 8,
CURLSSLBACKEND_DARWINSSL = 9,
CURLSSLBACKEND_AXTLS = 10,
CURLSSLBACKEND_MBEDTLS = 11
CURLSSLBACKEND_MBEDTLS = 11,
CURLSSLBACKEND_MESALINK = 12
} curl_sslbackend;
/* aliases for library clones and renames */
@@ -517,8 +518,7 @@ typedef enum {
CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */
CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */
CURLE_OBSOLETE50, /* 50 - NOT USED */
CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint
wasn't verified fine */
CURLE_OBSOLETE51, /* 51 - NOT USED */
CURLE_GOT_NOTHING, /* 52 - when this is a specific error */
CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */
CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as
@@ -528,7 +528,8 @@ typedef enum {
CURLE_OBSOLETE57, /* 57 - NOT IN USE */
CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */
CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */
CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */
CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
wasn't verified fine */
CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */
CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */
CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */
@@ -584,6 +585,9 @@ typedef enum {
CURL_LAST /* never use! */
} CURLcode;
/* added in 7.62.0 */
#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
the obsolete stuff removed! */
@@ -800,6 +804,9 @@ typedef enum {
this value, keep them in sync. */
#define CURL_HET_DEFAULT 200L
/* The default connection upkeep interval in milliseconds. */
#define CURL_UPKEEP_INTERVAL_DEFAULT 60000L
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
the obsolete stuff removed! */
@@ -1856,6 +1863,15 @@ typedef enum {
/* Disallow specifying username/login in URL. */
CINIT(DISALLOW_USERNAME_IN_URL, LONG, 278),
/* DNS-over-HTTPS URL */
CINIT(DOH_URL, STRINGPOINT, 279),
/* Preferred buffer size to use for uploads */
CINIT(UPLOAD_BUFFERSIZE, LONG, 280),
/* Time in ms between connection upkeep calls for long-lived connections. */
CINIT(UPKEEP_INTERVAL_MS, LONG, 281),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@@ -2779,6 +2795,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
stuff before they can be included! */
#include "easy.h" /* nothing in curl is fun without the easy stuff */
#include "multi.h"
#include "urlapi.h"
/* the typechecker doesn't work in C++ (yet) */
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
+4 -4
View File
@@ -30,13 +30,13 @@
/* This is the version number of the libcurl package from which this header
file origins: */
#define LIBCURL_VERSION "7.61.1-DEV"
#define LIBCURL_VERSION "7.62.0-DEV"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 7
#define LIBCURL_VERSION_MINOR 61
#define LIBCURL_VERSION_PATCH 1
#define LIBCURL_VERSION_MINOR 62
#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 0x073D01
#define LIBCURL_VERSION_NUM 0x073E00
/*
* This is the date and time when the full source package was created. The
+10
View File
@@ -95,6 +95,16 @@ CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen,
CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
size_t buflen, size_t *n);
/*
* NAME curl_easy_upkeep()
*
* DESCRIPTION
*
* Performs connection upkeep for the given session handle.
*/
CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl);
#ifdef __cplusplus
}
#endif
+1 -1
View File
@@ -298,7 +298,7 @@
# define CURL_PULL_SYS_TYPES_H 1
# define CURL_PULL_SYS_SOCKET_H 1
#elif defined(__SUNPRO_C) /* Oracle Solaris Studio */
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */
# if !defined(__LP64) && (defined(__ILP32) || \
defined(__i386) || \
defined(__sparcv8) || \
+4 -2
View File
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -269,6 +269,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_DNS_LOCAL_IP4 || \
(option) == CURLOPT_DNS_LOCAL_IP6 || \
(option) == CURLOPT_DNS_SERVERS || \
(option) == CURLOPT_DOH_URL || \
(option) == CURLOPT_EGDSOCKET || \
(option) == CURLOPT_FTPPORT || \
(option) == CURLOPT_FTP_ACCOUNT || \
@@ -500,7 +501,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_off_t,
/* evaluates to true if expr can be passed as POST data (void* or char*) */
#define _curl_is_postfields(expr) \
(_curl_is_ptr((expr), void) || \
_curl_is_arr((expr), char))
_curl_is_arr((expr), char) || \
_curl_is_arr((expr), unsigned char))
/* FIXME: the whole callback checking is messy...
* The idea is to tolerate char vs. void and const vs. not const
+120
View File
@@ -0,0 +1,120 @@
#ifndef __CURL_URLAPI_H
#define __CURL_URLAPI_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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.
*
***************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/* the error codes for the URL API */
typedef enum {
CURLUE_OK,
CURLUE_BAD_HANDLE, /* 1 */
CURLUE_BAD_PARTPOINTER, /* 2 */
CURLUE_MALFORMED_INPUT, /* 3 */
CURLUE_BAD_PORT_NUMBER, /* 4 */
CURLUE_UNSUPPORTED_SCHEME, /* 5 */
CURLUE_URLDECODE, /* 6 */
CURLUE_OUT_OF_MEMORY, /* 7 */
CURLUE_USER_NOT_ALLOWED, /* 8 */
CURLUE_UNKNOWN_PART, /* 9 */
CURLUE_NO_SCHEME, /* 10 */
CURLUE_NO_USER, /* 11 */
CURLUE_NO_PASSWORD, /* 12 */
CURLUE_NO_OPTIONS, /* 13 */
CURLUE_NO_HOST, /* 14 */
CURLUE_NO_PORT, /* 15 */
CURLUE_NO_QUERY, /* 16 */
CURLUE_NO_FRAGMENT /* 17 */
} CURLUcode;
typedef enum {
CURLUPART_URL,
CURLUPART_SCHEME,
CURLUPART_USER,
CURLUPART_PASSWORD,
CURLUPART_OPTIONS,
CURLUPART_HOST,
CURLUPART_PORT,
CURLUPART_PATH,
CURLUPART_QUERY,
CURLUPART_FRAGMENT
} CURLUPart;
#define CURLU_DEFAULT_PORT (1<<0) /* return default port number */
#define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set,
if the port number matches the
default for the scheme */
#define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if
missing */
#define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */
#define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */
#define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */
#define CURLU_URLDECODE (1<<6) /* URL decode on get */
#define CURLU_URLENCODE (1<<7) /* URL encode on set */
#define CURLU_APPENDQUERY (1<<8) /* append a form style part */
#define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */
typedef struct Curl_URL CURLU;
/*
* curl_url() creates a new CURLU handle and returns a pointer to it.
* Must be freed with curl_url_cleanup().
*/
CURL_EXTERN CURLU *curl_url(void);
/*
* curl_url_cleanup() frees the CURLU handle and related resources used for
* the URL parsing. It will not free strings previously returned with the URL
* API.
*/
CURL_EXTERN void curl_url_cleanup(CURLU *handle);
/*
* curl_url_dup() duplicates a CURLU handle and returns a new copy. The new
* handle must also be freed with curl_url_cleanup().
*/
CURL_EXTERN CURLU *curl_url_dup(CURLU *in);
/*
* curl_url_get() extracts a specific part of the URL from a CURLU
* handle. Returns error code. The returned pointer MUST be freed with
* curl_free() afterwards.
*/
CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
char **part, unsigned int flags);
/*
* curl_url_set() sets a specific part of the URL in a CURLU handle. Returns
* error code. The passed in string will be copied. Passing a NULL instead of
* a part string, clears that part.
*/
CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
const char *part, unsigned int flags);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif
+6 -12
View File
@@ -105,23 +105,17 @@ if(WIN32)
endif()
target_include_directories(${LIB_NAME} INTERFACE
$<INSTALL_INTERFACE:include>)
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
install(TARGETS ${LIB_NAME}
EXPORT libcurl-target
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
EXPORT ${TARGETS_EXPORT_NAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
export(TARGETS ${LIB_NAME}
APPEND FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake
NAMESPACE CURL::
)
install(EXPORT libcurl-target
FILE libcurl-target.cmake
NAMESPACE CURL::
DESTINATION ${CURL_INSTALL_CMAKE_DIR}
)
+5 -4
View File
@@ -30,12 +30,12 @@ LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h
LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \
vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \
vtls/cyassl.c vtls/schannel.c vtls/schannel_verify.c \
vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.c
vtls/darwinssl.c vtls/gskit.c vtls/mbedtls.c vtls/mesalink.c
LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \
vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \
vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \
vtls/mbedtls.h
vtls/mbedtls.h vtls/mesalink.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 \
@@ -54,7 +54,8 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \
curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \
x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \
mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c
mime.c sha256.c setopt.c curl_path.c curl_ctype.c curl_range.c psl.c \
doh.c urlapi.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 \
@@ -74,7 +75,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \
x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
curl_printf.h system_win32.h rand.h mime.h curl_sha256.h setopt.h \
curl_path.h curl_ctype.h curl_range.h psl.h
curl_path.h curl_ctype.h curl_range.h psl.h doh.h urlapi-int.h
LIB_RCFILES = libcurl.rc
-1
View File
@@ -36,4 +36,3 @@ void Curl_amiga_cleanup();
#endif
#endif /* HEADER_CURL_AMIGAOS_H */
+5 -1
View File
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -37,6 +37,7 @@
#define CURL_NEW_ENV_VAR 0
#define CURL_NEW_ENV_VALUE 1
#ifndef CURL_DISABLE_VERBOSE_STRINGS
/*
* The telnet options represented as strings
*/
@@ -53,6 +54,7 @@ static const char * const telnetoptions[]=
"TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC",
"OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON"
};
#endif
#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
@@ -76,6 +78,7 @@ static const char * const telnetoptions[]=
#define CURL_DONT 254 /* DON'T use this option! */
#define CURL_IAC 255 /* Interpret As Command */
#ifndef CURL_DISABLE_VERBOSE_STRINGS
/*
* Then those numbers represented as strings:
*/
@@ -86,6 +89,7 @@ static const char * const telnetcmds[]=
"AYT", "EC", "EL", "GA", "SB",
"WILL", "WONT", "DO", "DONT", "IAC"
};
#endif
#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */
+11 -15
View File
@@ -1218,7 +1218,6 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
{
struct Cookie *newco;
struct Cookie *co;
time_t now = time(NULL);
struct Cookie *mainco = NULL;
size_t matches = 0;
bool is_ip;
@@ -1236,11 +1235,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
co = c->cookies[myhash];
while(co) {
/* only process this cookie if it is not expired or had no expire
date AND that if the cookie requires we're secure we must only
continue if we are! */
if((!co->expires || (co->expires > now)) &&
(co->secure?secure:TRUE)) {
/* if the cookie requires we're secure we must only continue if we are! */
if(co->secure?secure:TRUE) {
/* now check if the domain is correct */
if(!co->domain ||
@@ -1266,12 +1262,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
matches++;
}
else {
fail:
/* failure, clear up the allocated chain and return NULL */
Curl_cookie_freelist(mainco);
return NULL;
}
else
goto fail;
}
}
}
@@ -1309,6 +1301,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
}
return mainco; /* return the new list */
fail:
/* failure, clear up the allocated chain and return NULL */
Curl_cookie_freelist(mainco);
return NULL;
}
/*****************************************************************************
@@ -1508,10 +1505,9 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere)
format_ptr = get_netscape_format(array[i]);
if(format_ptr == NULL) {
fprintf(out, "#\n# Fatal libcurl error\n");
if(!use_stdout) {
free(array);
free(array);
if(!use_stdout)
fclose(out);
}
return 1;
}
fprintf(out, "%s\n", format_ptr);
+3 -3
View File
@@ -127,6 +127,9 @@
/* Define to 1 if bool is an available type. */
#cmakedefine HAVE_BOOL_T 1
/* Define to 1 if you have the __builtin_available function. */
#cmakedefine HAVE_BUILTIN_AVAILABLE 1
/* Define to 1 if you have the clock_gettime function and monotonic timer. */
#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1
@@ -900,9 +903,6 @@
/* The size of `time_t', as computed by sizeof. */
#cmakedefine SIZEOF_TIME_T ${SIZEOF_TIME_T}
/* The size of `void*', as computed by sizeof. */
#cmakedefine SIZEOF_VOIDP ${SIZEOF_VOIDP}
/* Define to 1 if you have the ANSI C header files. */
#cmakedefine STDC_HEADERS 1
-1
View File
@@ -32,4 +32,3 @@ extern const struct Curl_handler Curl_handler_ldaps;
#endif
#endif /* HEADER_CURL_LDAP_H */
+17 -1
View File
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -249,6 +249,9 @@ done:
return CURLE_REMOTE_ACCESS_DENIED;
}
/* if larger than this, something is seriously wrong */
#define MAX_NTLM_WB_RESPONSE 100000
static CURLcode ntlm_wb_response(struct connectdata *conn,
const char *input, curlntlm state)
{
@@ -289,6 +292,13 @@ static CURLcode ntlm_wb_response(struct connectdata *conn,
buf[len_out - 1] = '\0';
break;
}
if(len_out > MAX_NTLM_WB_RESPONSE) {
failf(conn->data, "too large ntlm_wb response!");
free(buf);
return CURLE_OUT_OF_MEMORY;
}
newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE);
if(!newbuf)
return CURLE_OUT_OF_MEMORY;
@@ -314,6 +324,8 @@ static CURLcode ntlm_wb_response(struct connectdata *conn,
conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3);
free(buf);
if(!conn->response_header)
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
done:
free(buf);
@@ -389,6 +401,8 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
conn->response_header);
DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
free(conn->response_header);
if(!*allocuserpwd)
return CURLE_OUT_OF_MEMORY;
conn->response_header = NULL;
break;
case NTLMSTATE_TYPE2:
@@ -409,6 +423,8 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
authp->done = TRUE;
Curl_ntlm_wb_cleanup(conn);
if(!*allocuserpwd)
return CURLE_OUT_OF_MEMORY;
break;
case NTLMSTATE_TYPE3:
/* connection is already authenticated,
+2 -2
View File
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -39,7 +39,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
char *working_path;
size_t working_path_len;
CURLcode result =
Curl_urldecode(data, data->state.path, 0, &working_path,
Curl_urldecode(data, data->state.up.path, 0, &working_path,
&working_path_len, FALSE);
if(result)
return result;
+1 -1
View File
@@ -44,4 +44,4 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
char **path);
CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir);
#endif
#endif /* HEADER_CURL_PATH_H */
+3 -1
View File
@@ -37,9 +37,11 @@
/* The last #include file should be: */
#include "memdebug.h"
#ifdef _WIN32
#if defined(WIN32) && !defined(USE_LWIPSOCK)
#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
#define SET_RCVTIMEO(tv,s) int tv = s*1000
#elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD)
#define SET_RCVTIMEO(tv,s) int tv = s*1000
#else
#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0}
#endif
+4 -1
View File
@@ -44,6 +44,9 @@
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifndef NOGDI
# define NOGDI
# endif
#endif
/*
@@ -645,7 +648,7 @@ int netware_init(void);
#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \
defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
defined(USE_DARWINSSL) || defined(USE_GSKIT)
defined(USE_DARWINSSL) || defined(USE_GSKIT) || defined(USE_MESALINK)
#define USE_SSL /* SSL support has been enabled */
#endif
-1
View File
@@ -515,4 +515,3 @@ typedef int sig_atomic_t;
#endif /* HEADER_CURL_SETUP_ONCE_H */
+4 -3
View File
@@ -90,8 +90,9 @@ CURLcode Curl_sspi_global_init(void)
return CURLE_FAILED_INIT;
/* Get address of the InitSecurityInterfaceA function from the SSPI dll */
pInitSecurityInterface = (INITSECURITYINTERFACE_FN)
GetProcAddress(s_hSecDll, SECURITYENTRYPOINT);
pInitSecurityInterface =
CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN,
(GetProcAddress(s_hSecDll, SECURITYENTRYPOINT)));
if(!pInitSecurityInterface)
return CURLE_FAILED_INIT;
@@ -131,7 +132,7 @@ void Curl_sspi_global_cleanup(void)
* Parameters:
*
* userp [in] - The user name in the format User or Domain\User.
* passdwp [in] - The user's password.
* passwdp [in] - The user's password.
* identity [in/out] - The identity structure.
*
* Returns CURLE_OK on success.
+12 -4
View File
@@ -104,13 +104,21 @@ int Curl_thread_join(curl_thread_t *hnd)
curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
void *arg)
{
curl_thread_t t;
#ifdef _WIN32_WCE
t = CreateThread(NULL, 0, func, arg, 0, NULL);
typedef HANDLE curl_win_thread_handle_t;
#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
typedef unsigned long curl_win_thread_handle_t;
#else
uintptr_t thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
t = (curl_thread_t)thread_handle;
typedef uintptr_t curl_win_thread_handle_t;
#endif
curl_thread_t t;
curl_win_thread_handle_t thread_handle;
#ifdef _WIN32_WCE
thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
#else
thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
#endif
t = (curl_thread_t)thread_handle;
if((t == 0) || (t == LongToHandle(-1L))) {
#ifdef _WIN32_WCE
DWORD gle = GetLastError();
+2 -1
View File
@@ -38,7 +38,8 @@
# define curl_thread_t HANDLE
# define curl_thread_t_null (HANDLE)0
# if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
(_WIN32_WINNT < _WIN32_WINNT_VISTA)
(_WIN32_WINNT < _WIN32_WINNT_VISTA) || \
(defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
# define Curl_mutex_init(m) InitializeCriticalSection(m)
# else
# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1)
-1
View File
@@ -102,4 +102,3 @@
#endif /* ENABLE_CURLX_PRINTF */
#endif /* HEADER_CURL_CURLX_H */
+1 -1
View File
@@ -136,7 +136,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
char *path = data->state.path;
char *path = data->state.up.path;
curl_off_t *bytecount = &data->req.bytecount;
*done = TRUE; /* unconditionally */
+920
View File
@@ -0,0 +1,920 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 "urldata.h"
#include "curl_addrinfo.h"
#include "doh.h"
#ifdef USE_NGHTTP2
#include "sendf.h"
#include "multiif.h"
#include "url.h"
#include "share.h"
#include "curl_base64.h"
#include "connect.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
#define DNS_CLASS_IN 0x01
#define DOH_MAX_RESPONSE_SIZE 3000 /* bytes */
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char * const errors[]={
"",
"Bad label",
"Out of range",
"Label loop",
"Too small",
"Out of memory",
"RDATA length",
"Malformat",
"Bad RCODE",
"Unexpected TYPE",
"Unexpected CLASS",
"No content",
"Bad ID"
};
static const char *doh_strerror(DOHcode code)
{
if((code >= DOH_OK) && (code <= DOH_DNS_BAD_ID))
return errors[code];
return "bad error code";
}
#endif
#ifdef DEBUGBUILD
#define UNITTEST
#else
#define UNITTEST static
#endif
UNITTEST DOHcode doh_encode(const char *host,
DNStype dnstype,
unsigned char *dnsp, /* buffer */
size_t len, /* buffer size */
size_t *olen) /* output length */
{
size_t hostlen = strlen(host);
unsigned char *orig = dnsp;
const char *hostp = host;
if(len < (12 + hostlen + 4))
return DOH_TOO_SMALL_BUFFER;
*dnsp++ = 0; /* 16 bit id */
*dnsp++ = 0;
*dnsp++ = 0x01; /* |QR| Opcode |AA|TC|RD| Set the RD bit */
*dnsp++ = '\0'; /* |RA| Z | RCODE | */
*dnsp++ = '\0';
*dnsp++ = 1; /* QDCOUNT (number of entries in the question section) */
*dnsp++ = '\0';
*dnsp++ = '\0'; /* ANCOUNT */
*dnsp++ = '\0';
*dnsp++ = '\0'; /* NSCOUNT */
*dnsp++ = '\0';
*dnsp++ = '\0'; /* ARCOUNT */
/* store a QNAME */
do {
char *dot = strchr(hostp, '.');
size_t labellen;
bool found = false;
if(dot) {
found = true;
labellen = dot - hostp;
}
else
labellen = strlen(hostp);
if(labellen > 63) {
/* too long label, error out */
*olen = 0;
return DOH_DNS_BAD_LABEL;
}
*dnsp++ = (unsigned char)labellen;
memcpy(dnsp, hostp, labellen);
dnsp += labellen;
hostp += labellen + 1;
if(!found) {
*dnsp++ = 0; /* terminating zero */
break;
}
} while(1);
*dnsp++ = '\0'; /* upper 8 bit TYPE */
*dnsp++ = (unsigned char)dnstype;
*dnsp++ = '\0'; /* upper 8 bit CLASS */
*dnsp++ = DNS_CLASS_IN; /* IN - "the Internet" */
*olen = dnsp - orig;
return DOH_OK;
}
static size_t
doh_write_cb(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct dohresponse *mem = (struct dohresponse *)userp;
if((mem->size + realsize) > DOH_MAX_RESPONSE_SIZE)
/* suspiciously much for us */
return 0;
mem->memory = realloc(mem->memory, mem->size + realsize);
if(mem->memory == NULL)
/* out of memory! */
return 0;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
return realsize;
}
/* called from multi.c when this DOH transfer is complete */
static int Curl_doh_done(struct Curl_easy *doh, CURLcode result)
{
struct Curl_easy *data = doh->set.dohfor;
/* so one of the DOH request done for the 'data' transfer is now complete! */
data->req.doh.pending--;
infof(data, "a DOH request is completed, %d to go\n", data->req.doh.pending);
if(result)
infof(data, "DOH request %s\n", curl_easy_strerror(result));
if(!data->req.doh.pending) {
/* DOH completed */
curl_slist_free_all(data->req.doh.headers);
data->req.doh.headers = NULL;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
return 0;
}
#define ERROR_CHECK_SETOPT(x,y) result = curl_easy_setopt(doh, x, y); \
if(result) goto error
static CURLcode dohprobe(struct Curl_easy *data,
struct dnsprobe *p, DNStype dnstype,
const char *host,
const char *url, CURLM *multi,
struct curl_slist *headers)
{
struct Curl_easy *doh = NULL;
char *nurl = NULL;
CURLcode result = CURLE_OK;
timediff_t timeout_ms;
DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
&p->dohlen);
if(d) {
failf(data, "Failed to encode DOH packet [%d]\n", d);
return CURLE_OUT_OF_MEMORY;
}
p->dnstype = dnstype;
p->serverdoh.memory = NULL;
/* the memory will be grown as needed by realloc in the doh_write_cb
function */
p->serverdoh.size = 0;
/* Note: this is code for sending the DoH request with GET but there's still
no logic that actually enables this. We should either add that ability or
yank out the GET code. Discuss! */
if(data->set.doh_get) {
char *b64;
size_t b64len;
result = Curl_base64url_encode(data, (char *)p->dohbuffer, p->dohlen,
&b64, &b64len);
if(result)
goto error;
nurl = aprintf("%s?dns=%s", url, b64);
free(b64);
if(!nurl) {
result = CURLE_OUT_OF_MEMORY;
goto error;
}
url = nurl;
}
timeout_ms = Curl_timeleft(data, NULL, TRUE);
/* Curl_open() is the internal version of curl_easy_init() */
result = Curl_open(&doh);
if(!result) {
/* pass in the struct pointer via a local variable to please coverity and
the gcc typecheck helpers */
struct dohresponse *resp = &p->serverdoh;
ERROR_CHECK_SETOPT(CURLOPT_URL, url);
ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
if(!data->set.doh_get) {
ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
}
ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
#ifndef CURLDEBUG
/* enforce HTTPS if not debug */
ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
#endif
ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
doh->set.fmultidone = Curl_doh_done;
doh->set.dohfor = data; /* identify for which transfer this is done */
p->easy = doh;
/* add this transfer to the multi handle */
if(curl_multi_add_handle(multi, doh))
goto error;
}
else
goto error;
free(nurl);
return CURLE_OK;
error:
free(nurl);
Curl_close(doh);
return result;
}
/*
* Curl_doh() resolves a name using DOH. It resolves a name and returns a
* 'Curl_addrinfo *' with the address information.
*/
Curl_addrinfo *Curl_doh(struct connectdata *conn,
const char *hostname,
int port,
int *waitp)
{
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
*waitp = TRUE; /* this never returns synchronously */
(void)conn;
(void)hostname;
(void)port;
/* start clean, consider allocating this struct on demand */
memset(&data->req.doh, 0, sizeof(struct dohdata));
data->req.doh.host = hostname;
data->req.doh.port = port;
data->req.doh.headers =
curl_slist_append(NULL,
"Content-Type: application/dns-message");
if(!data->req.doh.headers)
goto error;
if(conn->ip_version != CURL_IPRESOLVE_V6) {
/* create IPv4 DOH request */
result = dohprobe(data, &data->req.doh.probe[0], DNS_TYPE_A,
hostname, data->set.str[STRING_DOH],
data->multi, data->req.doh.headers);
if(result)
goto error;
data->req.doh.pending++;
}
if(conn->ip_version != CURL_IPRESOLVE_V4) {
/* create IPv6 DOH request */
result = dohprobe(data, &data->req.doh.probe[1], DNS_TYPE_AAAA,
hostname, data->set.str[STRING_DOH],
data->multi, data->req.doh.headers);
if(result)
goto error;
data->req.doh.pending++;
}
return NULL;
error:
curl_slist_free_all(data->req.doh.headers);
data->req.doh.headers = NULL;
curl_easy_cleanup(data->req.doh.probe[0].easy);
data->req.doh.probe[0].easy = NULL;
curl_easy_cleanup(data->req.doh.probe[1].easy);
data->req.doh.probe[1].easy = NULL;
return NULL;
}
static DOHcode skipqname(unsigned char *doh, size_t dohlen,
unsigned int *indexp)
{
unsigned char length;
do {
if(dohlen < (*indexp + 1))
return DOH_DNS_OUT_OF_RANGE;
length = doh[*indexp];
if((length & 0xc0) == 0xc0) {
/* name pointer, advance over it and be done */
if(dohlen < (*indexp + 2))
return DOH_DNS_OUT_OF_RANGE;
*indexp += 2;
break;
}
if(length & 0xc0)
return DOH_DNS_BAD_LABEL;
if(dohlen < (*indexp + 1 + length))
return DOH_DNS_OUT_OF_RANGE;
*indexp += 1 + length;
} while(length);
return DOH_OK;
}
static unsigned short get16bit(unsigned char *doh, int index)
{
return (unsigned short)((doh[index] << 8) | doh[index + 1]);
}
static unsigned int get32bit(unsigned char *doh, int index)
{
return (doh[index] << 24) | (doh[index + 1] << 16) |
(doh[index + 2] << 8) | doh[index + 3];
}
static DOHcode store_a(unsigned char *doh, int index, struct dohentry *d)
{
/* silently ignore addresses over the limit */
if(d->numaddr < DOH_MAX_ADDR) {
struct dohaddr *a = &d->addr[d->numaddr];
a->type = DNS_TYPE_A;
memcpy(&a->ip.v4, &doh[index], 4);
d->numaddr++;
}
return DOH_OK;
}
static DOHcode store_aaaa(unsigned char *doh, int index, struct dohentry *d)
{
/* silently ignore addresses over the limit */
if(d->numaddr < DOH_MAX_ADDR) {
struct dohaddr *a = &d->addr[d->numaddr];
a->type = DNS_TYPE_AAAA;
memcpy(&a->ip.v6, &doh[index], 16);
d->numaddr++;
}
return DOH_OK;
}
static DOHcode cnameappend(struct cnamestore *c,
unsigned char *src,
size_t len)
{
if(!c->alloc) {
c->allocsize = len + 1;
c->alloc = malloc(c->allocsize);
if(!c->alloc)
return DOH_OUT_OF_MEM;
}
else if(c->allocsize < (c->allocsize + len + 1)) {
char *ptr;
c->allocsize += len + 1;
ptr = realloc(c->alloc, c->allocsize);
if(!ptr) {
free(c->alloc);
return DOH_OUT_OF_MEM;
}
c->alloc = ptr;
}
memcpy(&c->alloc[c->len], src, len);
c->len += len;
c->alloc[c->len] = 0; /* keep it zero terminated */
return DOH_OK;
}
static DOHcode store_cname(unsigned char *doh,
size_t dohlen,
unsigned int index,
struct dohentry *d)
{
struct cnamestore *c;
unsigned int loop = 128; /* a valid DNS name can never loop this much */
unsigned char length;
if(d->numcname == DOH_MAX_CNAME)
return DOH_OK; /* skip! */
c = &d->cname[d->numcname++];
do {
if(index >= dohlen)
return DOH_DNS_OUT_OF_RANGE;
length = doh[index];
if((length & 0xc0) == 0xc0) {
int newpos;
/* name pointer, get the new offset (14 bits) */
if((index + 1) >= dohlen)
return DOH_DNS_OUT_OF_RANGE;
/* move to the the new index */
newpos = (length & 0x3f) << 8 | doh[index + 1];
index = newpos;
continue;
}
else if(length & 0xc0)
return DOH_DNS_BAD_LABEL; /* bad input */
else
index++;
if(length) {
DOHcode rc;
if(c->len) {
rc = cnameappend(c, (unsigned char *)".", 1);
if(rc)
return rc;
}
if((index + length) > dohlen)
return DOH_DNS_BAD_LABEL;
rc = cnameappend(c, &doh[index], length);
if(rc)
return rc;
index += length;
}
} while(length && --loop);
if(!loop)
return DOH_DNS_LABEL_LOOP;
return DOH_OK;
}
static DOHcode rdata(unsigned char *doh,
size_t dohlen,
unsigned short rdlength,
unsigned short type,
int index,
struct dohentry *d)
{
/* RDATA
- A (TYPE 1): 4 bytes
- AAAA (TYPE 28): 16 bytes
- NS (TYPE 2): N bytes */
DOHcode rc;
switch(type) {
case DNS_TYPE_A:
if(rdlength != 4)
return DOH_DNS_RDATA_LEN;
rc = store_a(doh, index, d);
if(rc)
return rc;
break;
case DNS_TYPE_AAAA:
if(rdlength != 16)
return DOH_DNS_RDATA_LEN;
rc = store_aaaa(doh, index, d);
if(rc)
return rc;
break;
case DNS_TYPE_CNAME:
rc = store_cname(doh, dohlen, index, d);
if(rc)
return rc;
break;
default:
/* unsupported type, just skip it */
break;
}
return DOH_OK;
}
static void init_dohentry(struct dohentry *de)
{
memset(de, 0, sizeof(*de));
de->ttl = INT_MAX;
}
UNITTEST DOHcode doh_decode(unsigned char *doh,
size_t dohlen,
DNStype dnstype,
struct dohentry *d)
{
unsigned char rcode;
unsigned short qdcount;
unsigned short ancount;
unsigned short type = 0;
unsigned short class;
unsigned short rdlength;
unsigned short nscount;
unsigned short arcount;
unsigned int index = 12;
DOHcode rc;
if(dohlen < 12)
return DOH_TOO_SMALL_BUFFER; /* too small */
if(doh[0] || doh[1])
return DOH_DNS_BAD_ID; /* bad ID */
rcode = doh[3] & 0x0f;
if(rcode)
return DOH_DNS_BAD_RCODE; /* bad rcode */
qdcount = get16bit(doh, 4);
while(qdcount) {
rc = skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
if(dohlen < (index + 4))
return DOH_DNS_OUT_OF_RANGE;
index += 4; /* skip question's type and class */
qdcount--;
}
ancount = get16bit(doh, 6);
while(ancount) {
unsigned int ttl;
rc = skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
type = get16bit(doh, index);
if((type != DNS_TYPE_CNAME) && (type != dnstype))
/* Not the same type as was asked for nor CNAME */
return DOH_DNS_UNEXPECTED_TYPE;
index += 2;
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
class = get16bit(doh, index);
if(DNS_CLASS_IN != class)
return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */
index += 2;
if(dohlen < (index + 4))
return DOH_DNS_OUT_OF_RANGE;
ttl = get32bit(doh, index);
if(ttl < d->ttl)
d->ttl = ttl;
index += 4;
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
rdlength = get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
rc = rdata(doh, dohlen, rdlength, type, index, d);
if(rc)
return rc; /* bad rdata */
index += rdlength;
ancount--;
}
nscount = get16bit(doh, 8);
while(nscount) {
rc = skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
if(dohlen < (index + 8))
return DOH_DNS_OUT_OF_RANGE;
index += 2 + 2 + 4; /* type, class and ttl */
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
rdlength = get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
index += rdlength;
nscount--;
}
arcount = get16bit(doh, 10);
while(arcount) {
rc = skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
if(dohlen < (index + 8))
return DOH_DNS_OUT_OF_RANGE;
index += 2 + 2 + 4; /* type, class and ttl */
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
rdlength = get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
index += rdlength;
arcount--;
}
if(index != dohlen)
return DOH_DNS_MALFORMAT; /* something is wrong */
if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr)
/* nothing stored! */
return DOH_NO_CONTENT;
return DOH_OK; /* ok */
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void showdoh(struct Curl_easy *data,
struct dohentry *d)
{
int i;
infof(data, "TTL: %u seconds\n", d->ttl);
for(i = 0; i < d->numaddr; i++) {
struct dohaddr *a = &d->addr[i];
if(a->type == DNS_TYPE_A) {
infof(data, "DOH A: %u.%u.%u.%u\n",
a->ip.v4[0], a->ip.v4[1],
a->ip.v4[2], a->ip.v4[3]);
}
else if(a->type == DNS_TYPE_AAAA) {
int j;
char buffer[128];
char *ptr;
size_t len;
snprintf(buffer, 128, "DOH AAAA: ");
ptr = &buffer[10];
len = 118;
for(j = 0; j < 16; j += 2) {
size_t l;
snprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j],
d->addr[i].ip.v6[j + 1]);
l = strlen(ptr);
len -= l;
ptr += l;
}
infof(data, "%s\n", buffer);
}
}
for(i = 0; i < d->numcname; i++) {
infof(data, "CNAME: %s\n", d->cname[i].alloc);
}
}
#else
#define showdoh(x,y)
#endif
/*
* doh2ai()
*
* This function returns a pointer to the first element of a newly allocated
* Curl_addrinfo struct linked list filled with the data from a set of DOH
* lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
* a IPv6 stack, but usable also for IPv4, all hosts and environments.
*
* The memory allocated by this function *MUST* be free'd later on calling
* Curl_freeaddrinfo(). For each successful call to this function there
* must be an associated call later to Curl_freeaddrinfo().
*/
static Curl_addrinfo *
doh2ai(const struct dohentry *de, const char *hostname, int port)
{
Curl_addrinfo *ai;
Curl_addrinfo *prevai = NULL;
Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
#ifdef ENABLE_IPV6
struct sockaddr_in6 *addr6;
#endif
CURLcode result = CURLE_OK;
int i;
if(!de)
/* no input == no output! */
return NULL;
for(i = 0; i < de->numaddr; i++) {
size_t ss_size;
CURL_SA_FAMILY_T addrtype;
if(de->addr[i].type == DNS_TYPE_AAAA) {
#ifndef ENABLE_IPV6
/* we can't handle IPv6 addresses */
continue;
#else
ss_size = sizeof(struct sockaddr_in6);
addrtype = AF_INET6;
#endif
}
else {
ss_size = sizeof(struct sockaddr_in);
addrtype = AF_INET;
}
ai = calloc(1, sizeof(Curl_addrinfo));
if(!ai) {
result = CURLE_OUT_OF_MEMORY;
break;
}
ai->ai_canonname = strdup(hostname);
if(!ai->ai_canonname) {
result = CURLE_OUT_OF_MEMORY;
free(ai);
break;
}
ai->ai_addr = calloc(1, ss_size);
if(!ai->ai_addr) {
result = CURLE_OUT_OF_MEMORY;
free(ai->ai_canonname);
free(ai);
break;
}
if(!firstai)
/* store the pointer we want to return from this function */
firstai = ai;
if(prevai)
/* make the previous entry point to this */
prevai->ai_next = ai;
ai->ai_family = addrtype;
/* we return all names as STREAM, so when using this address for TFTP
the type must be ignored and conn->socktype be used instead! */
ai->ai_socktype = SOCK_STREAM;
ai->ai_addrlen = (curl_socklen_t)ss_size;
/* leave the rest of the struct filled with zero */
switch(ai->ai_family) {
case AF_INET:
addr = (void *)ai->ai_addr; /* storage area for this info */
DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
addr->sin_family = (CURL_SA_FAMILY_T)addrtype;
addr->sin_port = htons((unsigned short)port);
break;
#ifdef ENABLE_IPV6
case AF_INET6:
addr6 = (void *)ai->ai_addr; /* storage area for this info */
DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
addr6->sin6_family = (CURL_SA_FAMILY_T)addrtype;
addr6->sin6_port = htons((unsigned short)port);
break;
#endif
}
prevai = ai;
}
if(result) {
Curl_freeaddrinfo(firstai);
firstai = NULL;
}
return firstai;
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char *type2name(DNStype dnstype)
{
return (dnstype == DNS_TYPE_A)?"A":"AAAA";
}
#endif
UNITTEST void de_cleanup(struct dohentry *d)
{
int i = 0;
for(i = 0; i < d->numcname; i++) {
free(d->cname[i].alloc);
}
}
CURLcode Curl_doh_is_resolved(struct connectdata *conn,
struct Curl_dns_entry **dnsp)
{
struct Curl_easy *data = conn->data;
*dnsp = NULL; /* defaults to no response */
if(!data->req.doh.probe[0].easy && !data->req.doh.probe[1].easy) {
failf(data, "Could not DOH-resolve: %s", conn->async.hostname);
return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
else if(!data->req.doh.pending) {
DOHcode rc;
DOHcode rc2;
struct dohentry de;
struct Curl_dns_entry *dns;
struct Curl_addrinfo *ai;
/* remove DOH handles from multi handle and close them */
curl_multi_remove_handle(data->multi, data->req.doh.probe[0].easy);
Curl_close(data->req.doh.probe[0].easy);
curl_multi_remove_handle(data->multi, data->req.doh.probe[1].easy);
Curl_close(data->req.doh.probe[1].easy);
/* parse the responses, create the struct and return it! */
init_dohentry(&de);
rc = doh_decode(data->req.doh.probe[0].serverdoh.memory,
data->req.doh.probe[0].serverdoh.size,
data->req.doh.probe[0].dnstype,
&de);
free(data->req.doh.probe[0].serverdoh.memory);
if(rc) {
infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc),
type2name(data->req.doh.probe[0].dnstype),
data->req.doh.host);
}
rc2 = doh_decode(data->req.doh.probe[1].serverdoh.memory,
data->req.doh.probe[1].serverdoh.size,
data->req.doh.probe[1].dnstype,
&de);
free(data->req.doh.probe[1].serverdoh.memory);
if(rc2) {
infof(data, "DOG: %s type %s for %s\n", doh_strerror(rc2),
type2name(data->req.doh.probe[1].dnstype),
data->req.doh.host);
}
if(!rc || !rc2) {
infof(data, "DOH Host name: %s\n", data->req.doh.host);
showdoh(data, &de);
ai = doh2ai(&de, data->req.doh.host, data->req.doh.port);
if(!ai) {
de_cleanup(&de);
return CURLE_OUT_OF_MEMORY;
}
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
/* we got a response, store it in the cache */
dns = Curl_cache_addr(data, ai, data->req.doh.host, data->req.doh.port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
de_cleanup(&de);
if(!dns)
/* returned failure, bail out nicely */
Curl_freeaddrinfo(ai);
else {
conn->async.dns = dns;
*dnsp = dns;
return CURLE_OK;
}
}
de_cleanup(&de);
return CURLE_COULDNT_RESOLVE_HOST;
}
return CURLE_OK;
}
#else /* !USE_NGHTTP2 */
/*
*/
Curl_addrinfo *Curl_doh(struct connectdata *conn,
const char *hostname,
int port,
int *waitp)
{
(void)conn;
(void)hostname;
(void)port;
(void)waitp;
return NULL;
}
CURLcode Curl_doh_is_resolved(struct connectdata *conn,
struct Curl_dns_entry **dnsp)
{
(void)conn;
(void)dnsp;
return CURLE_NOT_BUILT_IN;
}
#endif /* USE_NGHTTP2 */
+105
View File
@@ -0,0 +1,105 @@
#ifndef HEADER_CURL_DOH_H
#define HEADER_CURL_DOH_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 "urldata.h"
#include "curl_addrinfo.h"
/*
* Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name
* and returns a 'Curl_addrinfo *' with the address information.
*/
Curl_addrinfo *Curl_doh(struct connectdata *conn,
const char *hostname,
int port,
int *waitp);
CURLcode Curl_doh_is_resolved(struct connectdata *conn,
struct Curl_dns_entry **dns);
int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks,
int numsocks);
typedef enum {
DOH_OK,
DOH_DNS_BAD_LABEL, /* 1 */
DOH_DNS_OUT_OF_RANGE, /* 2 */
DOH_DNS_LABEL_LOOP, /* 3 */
DOH_TOO_SMALL_BUFFER, /* 4 */
DOH_OUT_OF_MEM, /* 5 */
DOH_DNS_RDATA_LEN, /* 6 */
DOH_DNS_MALFORMAT, /* 7 */
DOH_DNS_BAD_RCODE, /* 8 - no such name */
DOH_DNS_UNEXPECTED_TYPE, /* 9 */
DOH_DNS_UNEXPECTED_CLASS, /* 10 */
DOH_NO_CONTENT, /* 11 */
DOH_DNS_BAD_ID /* 12 */
} DOHcode;
typedef enum {
DNS_TYPE_A = 1,
DNS_TYPE_NS = 2,
DNS_TYPE_CNAME = 5,
DNS_TYPE_AAAA = 28
} DNStype;
#define DOH_MAX_ADDR 24
#define DOH_MAX_CNAME 4
struct cnamestore {
size_t len; /* length of cname */
char *alloc; /* allocated pointer */
size_t allocsize; /* allocated size */
};
struct dohaddr {
int type;
union {
unsigned char v4[4]; /* network byte order */
unsigned char v6[16];
} ip;
};
struct dohentry {
unsigned int ttl;
int numaddr;
struct dohaddr addr[DOH_MAX_ADDR];
int numcname;
struct cnamestore cname[DOH_MAX_CNAME];
};
#ifdef DEBUGBUILD
DOHcode doh_encode(const char *host,
DNStype dnstype,
unsigned char *dnsp, /* buffer */
size_t len, /* buffer size */
size_t *olen); /* output length */
DOHcode doh_decode(unsigned char *doh,
size_t dohlen,
DNStype dnstype,
struct dohentry *d);
void de_cleanup(struct dohentry *d);
#endif
#endif /* HEADER_CURL_DOH_H */
+2
View File
@@ -62,6 +62,8 @@ char *Curl_dedotdotify(const char *input)
if(!out)
return NULL; /* out of memory */
*out = 0; /* zero terminates, for inputs like "./" */
/* get a cloned copy of the input */
clone = strdup(input);
if(!clone) {
+1 -1
View File
@@ -22,4 +22,4 @@
*
***************************************************************************/
char *Curl_dedotdotify(const char *input);
#endif
#endif /* HEADER_CURL_DOTDOT_H */
+19 -4
View File
@@ -1002,10 +1002,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
*/
void curl_easy_reset(struct Curl_easy *data)
{
Curl_safefree(data->state.pathbuffer);
data->state.path = NULL;
Curl_free_request_state(data);
/* zero out UserDefined data: */
@@ -1197,3 +1193,22 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
return result;
}
/*
* Performs connection upkeep for the given session handle.
*/
CURLcode curl_easy_upkeep(struct Curl_easy *data)
{
/* Verify that we got an easy handle we can work with. */
if(!GOOD_EASY_HANDLE(data))
return CURLE_BAD_FUNCTION_ARGUMENT;
if(data->multi_easy) {
/* Use the common function to keep connections alive. */
return Curl_upkeep(&data->multi_easy->conn_cache, data);
}
else {
/* No connections, so just return success */
return CURLE_OK;
}
}
-1
View File
@@ -30,4 +30,3 @@ CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
#endif
#endif /* HEADER_CURL_EASYIF_H */
+12 -8
View File
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -41,7 +41,7 @@
its behavior is altered by the current locale.
See https://tools.ietf.org/html/rfc3986#section-2.3
*/
static bool Curl_isunreserved(unsigned char in)
bool Curl_isunreserved(unsigned char in)
{
switch(in) {
case '0': case '1': case '2': case '3': case '4':
@@ -141,6 +141,8 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
* Returns a pointer to a malloced string in *ostring with length given in
* *olen. If length == 0, the length is assumed to be strlen(string).
*
* 'data' can be set to NULL but then this function can't convert network
* data to host for non-ascii.
*/
CURLcode Curl_urldecode(struct Curl_easy *data,
const char *string, size_t length,
@@ -151,7 +153,7 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
char *ns = malloc(alloc);
size_t strindex = 0;
unsigned long hex;
CURLcode result;
CURLcode result = CURLE_OK;
if(!ns)
return CURLE_OUT_OF_MEMORY;
@@ -171,11 +173,13 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
result = Curl_convert_from_network(data, (char *)&in, 1);
if(result) {
/* Curl_convert_from_network calls failf if unsuccessful */
free(ns);
return result;
if(data) {
result = Curl_convert_from_network(data, (char *)&in, 1);
if(result) {
/* Curl_convert_from_network calls failf if unsuccessful */
free(ns);
return result;
}
}
string += 2;
+2 -2
View File
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -24,10 +24,10 @@
/* Escape and unescape URL encoding in strings. The functions return a new
* allocated string or NULL if an error occurred. */
bool Curl_isunreserved(unsigned char in);
CURLcode Curl_urldecode(struct Curl_easy *data,
const char *string, size_t length,
char **ostring, size_t *olen,
bool reject_crlf);
#endif /* HEADER_CURL_ESCAPE_H */
+16 -17
View File
@@ -143,7 +143,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
#endif
size_t real_path_len;
CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path,
CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &real_path,
&real_path_len, FALSE);
if(result)
return result;
@@ -197,7 +197,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
file->fd = fd;
if(!data->set.upload && (fd == -1)) {
failf(data, "Couldn't open file %s", data->state.path);
failf(data, "Couldn't open file %s", data->state.up.path);
file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
return CURLE_FILE_COULDNT_READ_FILE;
}
@@ -307,7 +307,7 @@ static CURLcode file_upload(struct connectdata *conn)
size_t nread;
size_t nwrite;
size_t readcount;
result = Curl_fillreadbuffer(conn, (int)data->set.buffer_size, &readcount);
result = Curl_fillreadbuffer(conn, data->set.buffer_size, &readcount);
if(result)
break;
@@ -386,7 +386,6 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
*done = TRUE; /* unconditionally */
Curl_initinfo(data);
Curl_pgrsStartNow(data);
if(data->set.upload)
@@ -413,21 +412,18 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
}
}
/* If we have selected NOBODY and HEADER, it means that we only want file
information. Which for FILE can't be much more than the file size and
date. */
if(data->set.opt_no_body && data->set.include_header && fstated) {
if(fstated) {
time_t filetime;
struct tm buffer;
const struct tm *tm = &buffer;
char header[80];
snprintf(header, sizeof(header),
"Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size);
result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0);
result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
if(result)
return result;
result = Curl_client_write(conn, CLIENTWRITE_BOTH,
result = Curl_client_write(conn, CLIENTWRITE_HEADER,
(char *)"Accept-ranges: bytes\r\n", 0);
if(result)
return result;
@@ -439,19 +435,22 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
snprintf(header, sizeof(header),
"Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
"Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
tm->tm_mday,
Curl_month[tm->tm_mon],
tm->tm_year + 1900,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0);
if(!result)
/* set the file size to make it available post transfer */
Curl_pgrsSetDownloadSize(data, expected_size);
return result;
tm->tm_sec,
data->set.opt_no_body ? "": "\r\n");
result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
if(result)
return result;
/* set the file size to make it available post transfer */
Curl_pgrsSetDownloadSize(data, expected_size);
if(data->set.opt_no_body)
return result;
}
/* Check whether file range has been specified */
-1
View File
@@ -38,4 +38,3 @@ extern const struct Curl_handler Curl_handler_file;
#endif
#endif /* HEADER_CURL_FILE_H */
+27 -21
View File
@@ -1444,6 +1444,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
struct FTP *ftp = data->req.protop;
/* If this output is to be machine-parsed, the NLST command might be better
to use, since the LIST command output is not specified or standard in any
@@ -1460,7 +1461,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
then just do LIST (in that case: nothing to do here)
*/
char *cmd, *lstArg, *slashPos;
const char *inpath = data->state.path;
const char *inpath = ftp->path;
lstArg = NULL;
if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
@@ -3141,7 +3142,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
int ftpcode;
CURLcode result = CURLE_OK;
char *path = NULL;
const char *path_to_use = data->state.path;
if(!ftp)
return CURLE_OK;
@@ -3193,7 +3193,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
if(!result)
/* get the "raw" path */
result = Curl_urldecode(data, path_to_use, 0, &path, NULL, TRUE);
result = Curl_urldecode(data, ftp->path, 0, &path, NULL, TRUE);
if(result) {
/* We can limp along anyway (and should try to since we may already be in
* the error path) */
@@ -3213,9 +3213,11 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
ftpc->prevpath[dlen] = 0; /* terminate */
}
else {
free(path);
/* we never changed dir */
ftpc->prevpath = strdup("");
free(path);
if(!ftpc->prevpath)
return CURLE_OUT_OF_MEMORY;
}
if(ftpc->prevpath)
infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
@@ -3346,7 +3348,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
/* Send any post-transfer QUOTE strings? */
if(!status && !result && !premature && data->set.postquote)
result = ftp_sendquote(conn, data->set.postquote);
Curl_safefree(ftp->pathalloc);
return result;
}
@@ -3695,12 +3697,13 @@ static void wc_data_dtor(void *ptr)
static CURLcode init_wc_data(struct connectdata *conn)
{
char *last_slash;
char *path = conn->data->state.path;
struct FTP *ftp = conn->data->req.protop;
char *path = ftp->path;
struct WildcardData *wildcard = &(conn->data->wildcard);
CURLcode result = CURLE_OK;
struct ftp_wc *ftpwc = NULL;
last_slash = strrchr(conn->data->state.path, '/');
last_slash = strrchr(ftp->path, '/');
if(last_slash) {
last_slash++;
if(last_slash[0] == '\0') {
@@ -3757,7 +3760,7 @@ static CURLcode init_wc_data(struct connectdata *conn)
goto fail;
}
wildcard->path = strdup(conn->data->state.path);
wildcard->path = strdup(ftp->path);
if(!wildcard->path) {
result = CURLE_OUT_OF_MEMORY;
goto fail;
@@ -3828,16 +3831,15 @@ static CURLcode wc_statemach(struct connectdata *conn)
/* filelist has at least one file, lets get first one */
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
struct FTP *ftp = conn->data->req.protop;
char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
if(!tmp_path)
return CURLE_OUT_OF_MEMORY;
/* switch default "state.pathbuffer" and tmp_path, good to see
ftp_parse_url_path function to understand this trick */
Curl_safefree(conn->data->state.pathbuffer);
conn->data->state.pathbuffer = tmp_path;
conn->data->state.path = tmp_path;
/* switch default ftp->path and tmp_path */
free(ftp->pathalloc);
ftp->pathalloc = ftp->path = tmp_path;
infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
if(conn->data->set.chunk_bgn) {
@@ -3963,10 +3965,14 @@ CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
enum protection_level data_sec = conn->data_prot;
#endif
write_len = strlen(cmd);
if(write_len > (sizeof(s) -3))
if(!cmd)
return CURLE_BAD_FUNCTION_ARGUMENT;
write_len = strlen(cmd);
if(!write_len || write_len > (sizeof(s) -3))
return CURLE_BAD_FUNCTION_ARGUMENT;
memcpy(&s, cmd, write_len);
strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
write_len += 2;
bytes_written = 0;
@@ -4101,7 +4107,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
struct FTP *ftp = data->req.protop;
struct ftp_conn *ftpc = &conn->proto.ftpc;
const char *slash_pos; /* position of the first '/' char in curpos */
const char *path_to_use = data->state.path;
const char *path_to_use = ftp->path;
const char *cur_pos;
const char *filename = NULL;
@@ -4187,7 +4193,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
/* parse the URL path into separate path components */
while((slash_pos = strchr(cur_pos, '/')) != NULL) {
/* 1 or 0 pointer offset to indicate absolute directory */
ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
ssize_t absolute_dir = ((cur_pos - ftp->path > 0) &&
(ftpc->dirdepth == 0))?1:0;
/* seek out the next path component */
@@ -4264,7 +4270,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
size_t dlen;
char *path;
CURLcode result =
Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, TRUE);
Curl_urldecode(conn->data, ftp->path, 0, &path, &dlen, TRUE);
if(result) {
freedirs(ftpc);
return result;
@@ -4384,16 +4390,16 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
char *type;
struct FTP *ftp;
conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1);
if(NULL == ftp)
return CURLE_OUT_OF_MEMORY;
data->state.path++; /* don't include the initial slash */
ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
data->state.slash_removed = TRUE; /* we've skipped the slash */
/* FTP URLs support an extension like ";type=<typecode>" that
* we'll try to get now! */
type = strstr(data->state.path, ";type=");
type = strstr(ftp->path, ";type=");
if(!type)
type = strstr(conn->host.rawalloc, ";type=");
+2
View File
@@ -105,6 +105,8 @@ struct FTP {
curl_off_t *bytecountp;
char *user; /* user name string */
char *passwd; /* password string */
char *path; /* points to the urlpieces struct field */
char *pathalloc; /* if non-NULL a pointer to an allocated path */
/* transfer a file/body or not, done as a typedefed enum just to make
debuggers display the full symbol and not just the numerical value */
-1
View File
@@ -85,7 +85,6 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
#ifdef USE_SSL
Curl_ssl_free_certinfo(data);
#endif
return CURLE_OK;
}
+1 -1
View File
@@ -78,7 +78,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
curl_off_t *bytecount = &data->req.bytecount;
char *path = data->state.path;
char *path = data->state.up.path;
char *sel = NULL;
char *sel_org = NULL;
ssize_t amount, k;
-25
View File
@@ -111,31 +111,6 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
return result;
}
/* Call this function after Curl_connect() has returned async=TRUE and
then a successful name resolve has been received.
Note: this function disconnects and frees the conn data in case of
resolve failure */
CURLcode Curl_async_resolved(struct connectdata *conn,
bool *protocol_done)
{
CURLcode result;
if(conn->async.dns) {
conn->dns_entry = conn->async.dns;
conn->async.dns = NULL;
}
result = Curl_setup_conn(conn, protocol_done);
if(result)
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
Curl_disconnect(conn->data, conn, TRUE); /* close the connection */
return result;
}
/*
* Curl_getaddrinfo() is the generic low-level name resolve API within this
* source file. There are several versions of this function - for different
-1
View File
@@ -29,4 +29,3 @@
int Curl_cert_hostcheck(const char *match_pattern, const char *hostname);
#endif /* HEADER_CURL_HOSTCHECK_H */
+67 -11
View File
@@ -60,6 +60,7 @@
#include "url.h"
#include "inet_ntop.h"
#include "multiif.h"
#include "doh.h"
#include "warnless.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -454,7 +455,7 @@ Curl_cache_addr(struct Curl_easy *data,
/* shuffle addresses if requested */
if(data->set.dns_shuffle_addresses) {
CURLcode result = Curl_shuffle_addr(data, &addr);
if(!result)
if(result)
return NULL;
}
@@ -565,23 +566,27 @@ int Curl_resolv(struct connectdata *conn,
return CURLRESOLV_ERROR;
}
/* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
non-zero value indicating that we need to wait for the response to the
resolve call */
addr = Curl_getaddrinfo(conn,
if(data->set.doh) {
addr = Curl_doh(conn, hostname, port, &respwait);
}
else {
/* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
non-zero value indicating that we need to wait for the response to the
resolve call */
addr = Curl_getaddrinfo(conn,
#ifdef DEBUGBUILD
(data->set.str[STRING_DEVICE]
&& !strcmp(data->set.str[STRING_DEVICE],
"LocalHost"))?"localhost":
(data->set.str[STRING_DEVICE]
&& !strcmp(data->set.str[STRING_DEVICE],
"LocalHost"))?"localhost":
#endif
hostname, port, &respwait);
hostname, port, &respwait);
}
if(!addr) {
if(respwait) {
/* the response to our resolve call will come asynchronously at
a later time, good or bad */
/* First, check that we haven't received the info by now */
result = Curl_resolver_is_resolved(conn, &dns);
result = Curl_resolv_check(conn, &dns);
if(result) /* error detected */
return CURLRESOLV_ERROR;
if(dns)
@@ -1053,3 +1058,54 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
return CURLE_OK;
}
CURLcode Curl_resolv_check(struct connectdata *conn,
struct Curl_dns_entry **dns)
{
if(conn->data->set.doh)
return Curl_doh_is_resolved(conn, dns);
return Curl_resolver_is_resolved(conn, dns);
}
int Curl_resolv_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks)
{
#ifdef CURLRES_ASYNCH
if(conn->data->set.doh)
/* nothing to wait for during DOH resolve, those handles have their own
sockets */
return GETSOCK_BLANK;
return Curl_resolver_getsock(conn, socks, numsocks);
#else
(void)conn;
(void)socks;
(void)numsocks;
return GETSOCK_BLANK;
#endif
}
/* Call this function after Curl_connect() has returned async=TRUE and
then a successful name resolve has been received.
Note: this function disconnects and frees the conn data in case of
resolve failure */
CURLcode Curl_once_resolved(struct connectdata *conn,
bool *protocol_done)
{
CURLcode result;
if(conn->async.dns) {
conn->dns_entry = conn->async.dns;
conn->async.dns = NULL;
}
result = Curl_setup_conn(conn, protocol_done);
if(result)
/* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */
Curl_disconnect(conn->data, conn, TRUE); /* close the connection */
return result;
}
+7 -6
View File
@@ -145,12 +145,7 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
/* IPv4 threadsafe resolve function used for synch and asynch builds */
Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
CURLcode Curl_async_resolved(struct connectdata *conn,
bool *protocol_connect);
#ifndef CURLRES_ASYNCH
#define Curl_async_resolved(x,y) CURLE_OK
#endif
CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect);
/*
* Curl_addrinfo_callback() is used when we build with any asynch specialty.
@@ -258,4 +253,10 @@ void Curl_hostcache_destroy(struct Curl_easy *data);
*/
CURLcode Curl_loadhostpairs(struct Curl_easy *data);
CURLcode Curl_resolv_check(struct connectdata *conn,
struct Curl_dns_entry **dns);
int Curl_resolv_getsock(struct connectdata *conn,
curl_socket_t *socks,
int numsocks);
#endif /* HEADER_CURL_HOSTIP_H */
+138 -107
View File
@@ -169,7 +169,7 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
data->req.protop = http;
if(!CONN_INUSE(conn))
/* if not alredy multi-using, setup connection details */
/* if not already multi-using, setup connection details */
Curl_http2_setup_conn(conn);
Curl_http2_setup_req(data);
return CURLE_OK;
@@ -537,14 +537,6 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
}
if(pickhost || pickproxy) {
/* In case this is GSS auth, the newurl field is already allocated so
we must make sure to free it before allocating a new one. As figured
out in bug #2284386 */
Curl_safefree(data->req.newurl);
data->req.newurl = strdup(data->change.url); /* clone URL */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
if((data->set.httpreq != HTTPREQ_GET) &&
(data->set.httpreq != HTTPREQ_HEAD) &&
!conn->bits.rewindaftersend) {
@@ -552,6 +544,13 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
if(result)
return result;
}
/* In case this is GSS auth, the newurl field is already allocated so
we must make sure to free it before allocating a new one. As figured
out in bug #2284386 */
Curl_safefree(data->req.newurl);
data->req.newurl = strdup(data->change.url); /* clone URL */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
}
else if((data->req.httpcode < 300) &&
(!data->state.authhost.done) &&
@@ -1094,11 +1093,13 @@ Curl_send_buffer *Curl_add_buffer_init(void)
/*
* Curl_add_buffer_free() frees all associated resources.
*/
void Curl_add_buffer_free(Curl_send_buffer *buff)
void Curl_add_buffer_free(Curl_send_buffer **inp)
{
if(buff) /* deal with NULL input */
free(buff->buffer);
free(buff);
Curl_send_buffer *in = *inp;
if(in) /* deal with NULL input */
free(in->buffer);
free(in);
*inp = NULL;
}
/*
@@ -1107,7 +1108,7 @@ void Curl_add_buffer_free(Curl_send_buffer *buff)
*
* Returns CURLcode
*/
CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
struct connectdata *conn,
/* add the number of sent bytes to this
@@ -1128,6 +1129,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
size_t sendsize;
curl_socket_t sockfd;
size_t headersize;
Curl_send_buffer *in = *inp;
DEBUGASSERT(socketindex <= SECONDARYSOCKET);
@@ -1148,7 +1150,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
/* Curl_convert_to_network calls failf if unsuccessful */
if(result) {
/* conversion failed, free memory and return to the caller */
Curl_add_buffer_free(in);
Curl_add_buffer_free(inp);
return result;
}
@@ -1172,7 +1174,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
result = Curl_get_upload_buffer(data);
if(result) {
/* malloc failed, free memory and return to the caller */
Curl_add_buffer_free(in);
Curl_add_buffer_free(&in);
return result;
}
memcpy(data->state.ulbuf, ptr, sendsize);
@@ -1256,7 +1258,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
Curl_pipeline_leave_write(conn);
}
}
Curl_add_buffer_free(in);
Curl_add_buffer_free(&in);
return result;
}
@@ -1265,31 +1267,35 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
/*
* add_bufferf() add the formatted input to the buffer.
*/
CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...)
{
char *s;
va_list ap;
Curl_send_buffer *in = *inp;
va_start(ap, fmt);
s = vaprintf(fmt, ap); /* this allocs a new string to append */
va_end(ap);
if(s) {
CURLcode result = Curl_add_buffer(in, s, strlen(s));
CURLcode result = Curl_add_buffer(inp, s, strlen(s));
free(s);
return result;
}
/* If we failed, we cleanup the whole buffer and return error */
free(in->buffer);
free(in);
*inp = NULL;
return CURLE_OUT_OF_MEMORY;
}
/*
* add_buffer() appends a memory chunk to the existing buffer
* Curl_add_buffer() appends a memory chunk to the existing buffer
*/
CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr,
size_t size)
{
char *new_rb;
Curl_send_buffer *in = *inp;
if(~size < in->size_used) {
/* If resulting used size of send buffer would wrap size_t, cleanup
@@ -1297,6 +1303,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
size will fit into a single allocatable memory chunk */
Curl_safefree(in->buffer);
free(in);
*inp = NULL;
return CURLE_OUT_OF_MEMORY;
}
@@ -1323,6 +1330,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
if(!new_rb) {
/* If we failed, we cleanup the whole buffer and return error */
free(in);
*inp = NULL;
return CURLE_OUT_OF_MEMORY;
}
@@ -1484,11 +1492,11 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
if(!req_buffer)
return CURLE_OUT_OF_MEMORY;
result = Curl_add_bufferf(req_buffer, proxy_header);
result = Curl_add_bufferf(&req_buffer, proxy_header);
if(result)
return result;
result = Curl_add_buffer_send(req_buffer,
result = Curl_add_buffer_send(&req_buffer,
conn,
&conn->data->info.request_size,
0,
@@ -1561,8 +1569,7 @@ CURLcode Curl_http_done(struct connectdata *conn,
return CURLE_OK;
if(http->send_buffer) {
Curl_add_buffer_free(http->send_buffer);
http->send_buffer = NULL; /* clear the pointer */
Curl_add_buffer_free(&http->send_buffer);
}
Curl_http2_done(conn, premature);
@@ -1653,8 +1660,8 @@ static CURLcode expect100(struct Curl_easy *data,
Curl_compareheader(ptr, "Expect:", "100-continue");
}
else {
result = Curl_add_bufferf(req_buffer,
"Expect: 100-continue\r\n");
result = Curl_add_bufferf(&req_buffer,
"Expect: 100-continue\r\n");
if(!result)
data->state.expect100header = TRUE;
}
@@ -1785,7 +1792,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
!strcasecompare(data->state.first_host, conn->host.name)))
;
else {
result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data);
result = Curl_add_bufferf(&req_buffer, "%s\r\n", headers->data);
}
if(semicolonp)
*semicolonp = ';'; /* put back the semicolon */
@@ -1854,7 +1861,7 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
tm->tm_min,
tm->tm_sec);
result = Curl_add_buffer(req_buffer, datestr, strlen(datestr));
result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr));
return result;
}
@@ -1869,7 +1876,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
struct HTTP *http;
const char *ppath = data->state.path;
const char *path = data->state.up.path;
const char *query = data->state.up.query;
bool paste_ftp_userpwd = FALSE;
char ftp_typecode[sizeof("/;type=?")] = "";
const char *host = conn->host.name;
@@ -1987,7 +1995,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
/* setup the authentication headers */
result = Curl_http_output_auth(conn, request, ppath, FALSE);
result = Curl_http_output_auth(conn, request, path, FALSE);
if(result)
return result;
@@ -2215,47 +2223,59 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* The path sent to the proxy is in fact the entire URL. But if the remote
host is a IDN-name, we must make sure that the request we produce only
uses the encoded host name! */
/* and no fragment part */
CURLUcode uc;
char *url;
CURLU *h = curl_url_dup(data->state.uh);
if(!h)
return CURLE_OUT_OF_MEMORY;
if(conn->host.dispname != conn->host.name) {
char *url = data->change.url;
ptr = strstr(url, conn->host.dispname);
if(ptr) {
/* This is where the display name starts in the URL, now replace this
part with the encoded name. TODO: This method of replacing the host
name is rather crude as I believe there's a slight risk that the
user has entered a user name or password that contain the host name
string. */
size_t currlen = strlen(conn->host.dispname);
size_t newlen = strlen(conn->host.name);
size_t urllen = strlen(url);
char *newurl;
newurl = malloc(urllen + newlen - currlen + 1);
if(newurl) {
/* copy the part before the host name */
memcpy(newurl, url, ptr - url);
/* append the new host name instead of the old */
memcpy(newurl + (ptr - url), conn->host.name, newlen);
/* append the piece after the host name */
memcpy(newurl + newlen + (ptr - url),
ptr + currlen, /* copy the trailing zero byte too */
urllen - (ptr-url) - currlen + 1);
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
data->change.url = newurl;
data->change.url_alloc = TRUE;
}
else
return CURLE_OUT_OF_MEMORY;
uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
}
ppath = data->change.url;
if(checkprefix("ftp://", ppath)) {
uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
if(strcasecompare("http", data->state.up.scheme)) {
/* when getting HTTP, we don't want the userinfo the URL */
uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
}
/* now extract the new version of the URL */
uc = curl_url_get(h, CURLUPART_URL, &url, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
if(data->change.url_alloc)
free(data->change.url);
data->change.url = url;
data->change.url_alloc = TRUE;
curl_url_cleanup(h);
if(strcasecompare("ftp", data->state.up.scheme)) {
if(data->set.proxy_transfer_mode) {
/* when doing ftp, append ;type=<a|i> if not present */
char *type = strstr(ppath, ";type=");
char *type = strstr(path, ";type=");
if(type && type[6] && type[7] == 0) {
switch(Curl_raw_toupper(type[6])) {
case 'A':
@@ -2270,7 +2290,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
char *p = ftp_typecode;
/* avoid sending invalid URLs like ftp://example.com;type=i if the
* user specified ftp://example.com without the slash */
if(!*data->state.path && ppath[strlen(ppath) - 1] != '/') {
if(!*data->state.up.path && path[strlen(path) - 1] != '/') {
*p++ = '/';
}
snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
@@ -2419,25 +2439,36 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* add the main request stuff */
/* GET/HEAD/POST/PUT */
result = Curl_add_bufferf(req_buffer, "%s ", request);
result = Curl_add_bufferf(&req_buffer, "%s ", request);
if(result)
return result;
if(data->set.str[STRING_TARGET])
ppath = data->set.str[STRING_TARGET];
if(data->set.str[STRING_TARGET]) {
path = data->set.str[STRING_TARGET];
query = NULL;
}
/* url */
if(paste_ftp_userpwd)
result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
char *url = data->change.url;
result = Curl_add_buffer(&req_buffer, url, strlen(url));
}
else if(paste_ftp_userpwd)
result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s",
conn->user, conn->passwd,
ppath + sizeof("ftp://") - 1);
else
result = Curl_add_buffer(req_buffer, ppath, strlen(ppath));
path + sizeof("ftp://") - 1);
else {
result = Curl_add_buffer(&req_buffer, path, strlen(path));
if(result)
return result;
if(query)
result = Curl_add_bufferf(&req_buffer, "?%s", query);
}
if(result)
return result;
result =
Curl_add_bufferf(req_buffer,
Curl_add_bufferf(&req_buffer,
"%s" /* ftp typecode (;type=x) */
" HTTP/%s\r\n" /* HTTP version */
"%s" /* host */
@@ -2507,7 +2538,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
co = Curl_cookie_getlist(data->cookies,
conn->allocptr.cookiehost?
conn->allocptr.cookiehost:host,
data->state.path,
data->state.up.path,
(conn->handler->protocol&CURLPROTO_HTTPS)?
TRUE:FALSE);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
@@ -2518,11 +2549,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
while(co) {
if(co->value) {
if(0 == count) {
result = Curl_add_bufferf(req_buffer, "Cookie: ");
result = Curl_add_bufferf(&req_buffer, "Cookie: ");
if(result)
break;
}
result = Curl_add_bufferf(req_buffer,
result = Curl_add_bufferf(&req_buffer,
"%s%s=%s", count?"; ":"",
co->name, co->value);
if(result)
@@ -2535,15 +2566,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
if(addcookies && !result) {
if(!count)
result = Curl_add_bufferf(req_buffer, "Cookie: ");
result = Curl_add_bufferf(&req_buffer, "Cookie: ");
if(!result) {
result = Curl_add_bufferf(req_buffer, "%s%s", count?"; ":"",
result = Curl_add_bufferf(&req_buffer, "%s%s", count?"; ":"",
addcookies);
count++;
}
}
if(count && !result)
result = Curl_add_buffer(req_buffer, "\r\n", 2);
result = Curl_add_buffer(&req_buffer, "\r\n", 2);
if(result)
return result;
@@ -2577,7 +2608,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if((postsize != -1) && !data->req.upload_chunky &&
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
/* only add Content-Length if not uploading chunked */
result = Curl_add_bufferf(req_buffer,
result = Curl_add_bufferf(&req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
"\r\n", postsize);
if(result)
@@ -2590,7 +2621,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result;
}
result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers */
if(result)
return result;
@@ -2598,7 +2629,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_pgrsSetUploadSize(data, postsize);
/* this sends the buffer and frees all the buffer resources */
result = Curl_add_buffer_send(req_buffer, conn,
result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
failf(data, "Failed sending PUT request");
@@ -2616,11 +2647,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* This is form posting using mime data. */
if(conn->bits.authneg) {
/* nothing to post! */
result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
result = Curl_add_bufferf(&req_buffer, "Content-Length: 0\r\n\r\n");
if(result)
return result;
result = Curl_add_buffer_send(req_buffer, conn,
result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
failf(data, "Failed sending POST request");
@@ -2640,7 +2671,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
/* we allow replacing this header if not during auth negotiation,
although it isn't very wise to actually set your own */
result = Curl_add_bufferf(req_buffer,
result = Curl_add_bufferf(&req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
"\r\n", postsize);
if(result)
@@ -2652,7 +2683,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
struct curl_slist *hdr;
for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
result = Curl_add_bufferf(req_buffer, "%s\r\n", hdr->data);
result = Curl_add_bufferf(&req_buffer, "%s\r\n", hdr->data);
if(result)
return result;
}
@@ -2676,7 +2707,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
data->state.expect100header = FALSE;
/* make the request end in a true CRLF */
result = Curl_add_buffer(req_buffer, "\r\n", 2);
result = Curl_add_buffer(&req_buffer, "\r\n", 2);
if(result)
return result;
@@ -2689,7 +2720,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
http->sending = HTTPSEND_BODY;
/* this sends the buffer and frees all the buffer resources */
result = Curl_add_buffer_send(req_buffer, conn,
result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
failf(data, "Failed sending POST request");
@@ -2719,7 +2750,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
/* we allow replacing this header if not during auth negotiation,
although it isn't very wise to actually set your own */
result = Curl_add_bufferf(req_buffer,
result = Curl_add_bufferf(&req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T
"\r\n", postsize);
if(result)
@@ -2727,7 +2758,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
if(!Curl_checkheaders(conn, "Content-Type")) {
result = Curl_add_bufferf(req_buffer,
result = Curl_add_bufferf(&req_buffer,
"Content-Type: application/"
"x-www-form-urlencoded\r\n");
if(result)
@@ -2765,31 +2796,31 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
is no magic limit but only set to prevent really huge POSTs to
get the data duplicated with malloc() and family. */
result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
if(result)
return result;
if(!data->req.upload_chunky) {
/* We're not sending it 'chunked', append it to the request
already now to reduce the number if send() calls */
result = Curl_add_buffer(req_buffer, data->set.postfields,
result = Curl_add_buffer(&req_buffer, data->set.postfields,
(size_t)postsize);
included_body = postsize;
}
else {
if(postsize) {
/* Append the POST data chunky-style */
result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize);
result = Curl_add_bufferf(&req_buffer, "%x\r\n", (int)postsize);
if(!result) {
result = Curl_add_buffer(req_buffer, data->set.postfields,
result = Curl_add_buffer(&req_buffer, data->set.postfields,
(size_t)postsize);
if(!result)
result = Curl_add_buffer(req_buffer, "\r\n", 2);
result = Curl_add_buffer(&req_buffer, "\r\n", 2);
included_body = postsize + 2;
}
}
if(!result)
result = Curl_add_buffer(req_buffer, "\x30\x0d\x0a\x0d\x0a", 5);
result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5);
/* 0 CR LF CR LF */
included_body += 5;
}
@@ -2811,20 +2842,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
if(result)
return result;
}
}
else {
result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
if(result)
return result;
if(data->req.upload_chunky && conn->bits.authneg) {
/* Chunky upload is selected and we're negotiating auth still, send
end-of-data only */
result = Curl_add_buffer(req_buffer,
result = Curl_add_buffer(&req_buffer,
"\x30\x0d\x0a\x0d\x0a", 5);
/* 0 CR LF CR LF */
if(result)
@@ -2845,7 +2876,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
}
/* issue the request */
result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size,
result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size,
(size_t)included_body, FIRSTSOCKET);
if(result)
@@ -2857,12 +2888,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
break;
default:
result = Curl_add_buffer(req_buffer, "\r\n", 2);
result = Curl_add_buffer(&req_buffer, "\r\n", 2);
if(result)
return result;
/* issue the request */
result = Curl_add_buffer_send(req_buffer, conn,
result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result)
@@ -3828,7 +3859,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
here, or else use real peer host name. */
conn->allocptr.cookiehost?
conn->allocptr.cookiehost:conn->host.name,
data->state.path);
data->state.up.path);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
#endif
+11 -8
View File
@@ -58,10 +58,12 @@ struct Curl_send_buffer {
typedef struct Curl_send_buffer Curl_send_buffer;
Curl_send_buffer *Curl_add_buffer_init(void);
void Curl_add_buffer_free(Curl_send_buffer *buff);
CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...);
CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size);
CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
void Curl_add_buffer_free(Curl_send_buffer **inp);
CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...)
WARN_UNUSED_RESULT;
CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr,
size_t size) WARN_UNUSED_RESULT;
CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
struct connectdata *conn,
long *bytes_written,
size_t included_body_bytes,
@@ -154,9 +156,11 @@ struct HTTP {
HTTPSEND_LAST /* never use this */
} sending;
void *send_buffer; /* used if the request couldn't be sent in one chunk,
points to an allocated send_buffer struct */
#ifndef CURL_DISABLE_HTTP
Curl_send_buffer *send_buffer; /* used if the request couldn't be sent in
one chunk, points to an allocated
send_buffer struct */
#endif
#ifdef USE_NGHTTP2
/*********** for HTTP/2 we store stream-local data here *************/
int32_t stream_id; /* stream we are interested in */
@@ -253,4 +257,3 @@ Curl_http_output_auth(struct connectdata *conn,
up the proxy tunnel */
#endif /* HEADER_CURL_HTTP_H */
+101 -34
View File
@@ -141,10 +141,8 @@ static int http2_getsock(struct connectdata *conn,
static void http2_stream_free(struct HTTP *http)
{
if(http) {
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 */
Curl_add_buffer_free(&http->header_recvbuf);
Curl_add_buffer_free(&http->trailer_recvbuf);
for(; http->push_headers_used > 0; --http->push_headers_used) {
free(http->push_headers[http->push_headers_used - 1]);
}
@@ -203,7 +201,7 @@ static bool http2_connisdead(struct connectdata *conn)
dead = !Curl_connalive(conn);
if(!dead) {
/* This happens before we've sent off a request and the connection is
not in use by any other thransfer, there shouldn't be any data here,
not in use by any other transfer, there shouldn't be any data here,
only "protocol frames" */
CURLcode result;
struct http_conn *httpc = &conn->proto.httpc;
@@ -233,12 +231,43 @@ static unsigned int http2_conncheck(struct connectdata *check,
unsigned int checks_to_perform)
{
unsigned int ret_val = CONNRESULT_NONE;
struct http_conn *c = &check->proto.httpc;
int rc;
bool send_frames = false;
if(checks_to_perform & CONNCHECK_ISDEAD) {
if(http2_connisdead(check))
ret_val |= CONNRESULT_DEAD;
}
if(checks_to_perform & CONNCHECK_KEEPALIVE) {
struct curltime now = Curl_now();
time_t elapsed = Curl_timediff(now, check->keepalive);
if(elapsed > check->upkeep_interval_ms) {
/* Perform an HTTP/2 PING */
rc = nghttp2_submit_ping(c->h2, 0, ZERO_NULL);
if(!rc) {
/* Successfully added a PING frame to the session. Need to flag this
so the frame is sent. */
send_frames = true;
}
else {
failf(check->data, "nghttp2_submit_ping() failed: %s(%d)",
nghttp2_strerror(rc), rc);
}
check->keepalive = now;
}
}
if(send_frames) {
rc = nghttp2_session_send(c->h2);
if(rc)
failf(check->data, "nghttp2_session_send() failed: %s(%d)",
nghttp2_strerror(rc), rc);
}
return ret_val;
}
@@ -599,6 +628,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
int rv;
size_t left, ncopy;
int32_t stream_id = frame->hd.stream_id;
CURLcode result;
if(!stream_id) {
/* stream ID zero is for connection-oriented stuff */
@@ -674,7 +704,9 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
stream->status_code = -1;
}
Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
ncopy = CURLMIN(stream->len, left);
@@ -898,6 +930,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
struct Curl_easy *data_s;
int32_t stream_id = frame->hd.stream_id;
struct connectdata *conn = (struct connectdata *)userp;
CURLcode result;
(void)flags;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
@@ -924,6 +957,8 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
stream->push_headers_alloc = 10;
stream->push_headers = malloc(stream->push_headers_alloc *
sizeof(char *));
if(!stream->push_headers)
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
stream->push_headers_used = 0;
}
else if(stream->push_headers_used ==
@@ -952,11 +987,21 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
value));
Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n));
Curl_add_buffer(stream->trailer_recvbuf, name, namelen);
Curl_add_buffer(stream->trailer_recvbuf, ": ", 2);
Curl_add_buffer(stream->trailer_recvbuf, value, valuelen);
Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3);
result = Curl_add_buffer(&stream->trailer_recvbuf, &n, sizeof(n));
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_add_buffer(&stream->trailer_recvbuf, name, namelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_add_buffer(&stream->trailer_recvbuf, ": ", 2);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_add_buffer(&stream->trailer_recvbuf, value, valuelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_add_buffer(&stream->trailer_recvbuf, "\r\n\0", 3);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
return 0;
}
@@ -969,10 +1014,16 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
stream->status_code = decode_status_code(value, valuelen);
DEBUGASSERT(stream->status_code != -1);
Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7);
Curl_add_buffer(stream->header_recvbuf, value, valuelen);
result = Curl_add_buffer(&stream->header_recvbuf, "HTTP/2 ", 7);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* the space character after the status code is mandatory */
Curl_add_buffer(stream->header_recvbuf, " \r\n", 3);
result = Curl_add_buffer(&stream->header_recvbuf, " \r\n", 3);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
if(conn->data != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
@@ -985,10 +1036,18 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* nghttp2 guarantees that namelen > 0, and :status was already
received, and this is not pseudo-header field . */
/* convert to a HTTP1-style header */
Curl_add_buffer(stream->header_recvbuf, name, namelen);
Curl_add_buffer(stream->header_recvbuf, ": ", 2);
Curl_add_buffer(stream->header_recvbuf, value, valuelen);
Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
result = Curl_add_buffer(&stream->header_recvbuf, name, namelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_add_buffer(&stream->header_recvbuf, ": ", 2);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
if(conn->data != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
@@ -1049,7 +1108,8 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
return nread;
}
#ifdef NGHTTP2_HAS_ERROR_CALLBACK
#if defined(NGHTTP2_HAS_ERROR_CALLBACK) && \
!defined(CURL_DISABLE_VERBOSE_STRINGS)
static int error_callback(nghttp2_session *session,
const char *msg,
size_t len,
@@ -1085,17 +1145,11 @@ void Curl_http2_done(struct connectdata *conn, bool premature)
struct HTTP *http = data->req.protop;
struct http_conn *httpc = &conn->proto.httpc;
if(!httpc->h2) /* not HTTP/2 ? */
return;
if(data->state.drain)
drained_transfer(data, httpc);
/* there might be allocated resources done before this got the 'h2' pointer
setup */
if(http->header_recvbuf) {
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 */
Curl_add_buffer_free(&http->header_recvbuf);
Curl_add_buffer_free(&http->trailer_recvbuf);
if(http->push_headers) {
/* if they weren't used and then freed before */
for(; http->push_headers_used > 0; --http->push_headers_used) {
@@ -1106,6 +1160,12 @@ void Curl_http2_done(struct connectdata *conn, bool premature)
}
}
if(!httpc->h2) /* not HTTP/2 ? */
return;
if(data->state.drain)
drained_transfer(data, httpc);
if(premature) {
/* RST_STREAM */
if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
@@ -1167,7 +1227,9 @@ CURLcode Curl_http2_init(struct connectdata *conn)
/* nghttp2_on_header_callback */
nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
#endif
/* The nghttp2 session is not yet setup, do it */
rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
@@ -1204,7 +1266,7 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
httpc->local_settings_num);
if(!binlen) {
failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
Curl_add_buffer_free(req);
Curl_add_buffer_free(&req);
return CURLE_FAILED_INIT;
}
conn->proto.httpc.binlen = binlen;
@@ -1212,11 +1274,11 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
&base64, &blen);
if(result) {
Curl_add_buffer_free(req);
Curl_add_buffer_free(&req);
return result;
}
result = Curl_add_bufferf(req,
result = Curl_add_bufferf(&req,
"Connection: Upgrade, HTTP2-Settings\r\n"
"Upgrade: %s\r\n"
"HTTP2-Settings: %s\r\n",
@@ -2060,8 +2122,11 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
stream->stream_id = -1;
if(!stream->header_recvbuf)
if(!stream->header_recvbuf) {
stream->header_recvbuf = Curl_add_buffer_init();
if(!stream->header_recvbuf)
return CURLE_OUT_OF_MEMORY;
}
if((conn->handler == &Curl_handler_http2_ssl) ||
(conn->handler == &Curl_handler_http2))
@@ -2073,8 +2138,10 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
conn->handler = &Curl_handler_http2;
result = Curl_http2_init(conn);
if(result)
if(result) {
Curl_add_buffer_free(&stream->header_recvbuf);
return result;
}
infof(conn->data, "Using HTTP2, server supports multi-use\n");
stream->upload_left = 0;
-1
View File
@@ -77,4 +77,3 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
#endif
#endif /* HEADER_CURL_HTTP2_H */
-1
View File
@@ -88,4 +88,3 @@ struct Curl_chunker {
};
#endif /* HEADER_CURL_HTTP_CHUNKS_H */
+7 -7
View File
@@ -222,7 +222,7 @@ static CURLcode CONNECT(struct connectdata *conn,
host_port = aprintf("%s:%d", hostname, remote_port);
if(!host_port) {
Curl_add_buffer_free(req_buffer);
Curl_add_buffer_free(&req_buffer);
return CURLE_OUT_OF_MEMORY;
}
@@ -247,7 +247,7 @@ static CURLcode CONNECT(struct connectdata *conn,
aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
remote_port);
if(!hostheader) {
Curl_add_buffer_free(req_buffer);
Curl_add_buffer_free(&req_buffer);
return CURLE_OUT_OF_MEMORY;
}
@@ -255,7 +255,7 @@ static CURLcode CONNECT(struct connectdata *conn,
host = aprintf("Host: %s\r\n", hostheader);
if(!host) {
free(hostheader);
Curl_add_buffer_free(req_buffer);
Curl_add_buffer_free(&req_buffer);
return CURLE_OUT_OF_MEMORY;
}
}
@@ -267,7 +267,7 @@ static CURLcode CONNECT(struct connectdata *conn,
useragent = conn->allocptr.uagent;
result =
Curl_add_bufferf(req_buffer,
Curl_add_bufferf(&req_buffer,
"CONNECT %s HTTP/%s\r\n"
"%s" /* Host: */
"%s" /* Proxy-Authorization */
@@ -290,13 +290,13 @@ static CURLcode CONNECT(struct connectdata *conn,
if(!result)
/* CRLF terminate the request */
result = Curl_add_bufferf(req_buffer, "\r\n");
result = Curl_add_bufferf(&req_buffer, "\r\n");
if(!result) {
/* Send the connect request to the proxy */
/* BLOCKING */
result =
Curl_add_buffer_send(req_buffer, conn,
Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, sockindex);
}
req_buffer = NULL;
@@ -304,7 +304,7 @@ static CURLcode CONNECT(struct connectdata *conn,
failf(data, "Failed sending CONNECT to proxy");
}
Curl_add_buffer_free(req_buffer);
Curl_add_buffer_free(&req_buffer);
if(result)
return result;
+47 -35
View File
@@ -159,7 +159,8 @@ const struct Curl_handler Curl_handler_imaps = {
ZERO_NULL, /* connection_check */
PORT_IMAPS, /* defport */
CURLPROTO_IMAPS, /* protocol */
PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
PROTOPT_CLOSEACTION | PROTOPT_SSL | /* flags */
PROTOPT_URLOPTIONS
};
#endif
@@ -421,7 +422,6 @@ static CURLcode imap_perform_capability(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc;
imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */
imapc->tls_supported = FALSE; /* Clear the TLS capability */
@@ -683,24 +683,37 @@ static CURLcode imap_perform_fetch(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct IMAP *imap = conn->data->req.protop;
/* Check we have a UID */
if(!imap->uid) {
failf(conn->data, "Cannot FETCH without a UID.");
return CURLE_URL_MALFORMAT;
if(imap->uid) {
/* Send the FETCH command */
if(imap->partial)
result = imap_sendf(conn, "UID FETCH %s BODY[%s]<%s>",
imap->uid,
imap->section ? imap->section : "",
imap->partial);
else
result = imap_sendf(conn, "UID FETCH %s BODY[%s]",
imap->uid,
imap->section ? imap->section : "");
}
else if(imap->mindex) {
/* Send the FETCH command */
if(imap->partial)
result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
imap->uid,
imap->section ? imap->section : "",
imap->partial);
else
result = imap_sendf(conn, "FETCH %s BODY[%s]",
imap->uid,
imap->section ? imap->section : "");
/* Send the FETCH command */
if(imap->partial)
result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
imap->mindex,
imap->section ? imap->section : "",
imap->partial);
else
result = imap_sendf(conn, "FETCH %s BODY[%s]",
imap->mindex,
imap->section ? imap->section : "");
}
else {
failf(conn->data, "Cannot FETCH without a UID.");
return CURLE_URL_MALFORMAT;
}
if(!result)
state(conn, IMAP_FETCH);
@@ -1464,9 +1477,10 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
result = status; /* use the already set error code */
}
else if(!data->set.connect_only && !imap->custom &&
(imap->uid || data->set.upload ||
(imap->uid || imap->mindex || data->set.upload ||
data->set.mimepost.kind != MIMEKIND_NONE)) {
/* Handle responses after FETCH or APPEND transfer has finished */
if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
state(conn, IMAP_FETCH_FINAL);
else {
@@ -1490,6 +1504,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
Curl_safefree(imap->mailbox);
Curl_safefree(imap->uidvalidity);
Curl_safefree(imap->uid);
Curl_safefree(imap->mindex);
Curl_safefree(imap->section);
Curl_safefree(imap->partial);
Curl_safefree(imap->query);
@@ -1543,14 +1558,14 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
else if(imap->custom && (selected || !imap->mailbox))
/* Custom command using the same mailbox or no mailbox */
result = imap_perform_list(conn);
else if(!imap->custom && selected && imap->uid)
else if(!imap->custom && selected && (imap->uid || imap->mindex))
/* FETCH from the same mailbox */
result = imap_perform_fetch(conn);
else if(!imap->custom && selected && imap->query)
/* SEARCH the current mailbox */
result = imap_perform_search(conn);
else if(imap->mailbox && !selected &&
(imap->custom || imap->uid || imap->query))
(imap->custom || imap->uid || imap->mindex || imap->query))
/* SELECT the mailbox */
result = imap_perform_select(conn);
else
@@ -1702,8 +1717,6 @@ static CURLcode imap_regular_transfer(struct connectdata *conn,
static CURLcode imap_setup_connection(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
/* Initialise the IMAP layer */
CURLcode result = imap_init(conn);
if(result)
@@ -1711,7 +1724,6 @@ static CURLcode imap_setup_connection(struct connectdata *conn)
/* Clear the TLS upgraded flag */
conn->tls_upgraded = FALSE;
data->state.path++; /* don't include the initial slash */
return CURLE_OK;
}
@@ -1944,7 +1956,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
struct IMAP *imap = data->req.protop;
const char *begin = data->state.path;
const char *begin = &data->state.up.path[1]; /* skip leading slash */
const char *ptr = begin;
/* See how much of the URL is a valid path and decode it */
@@ -2016,6 +2028,13 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
imap->uid = value;
value = NULL;
}
else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
imap->mindex = value;
value = NULL;
}
else if(strcasecompare(name, "SECTION") && !imap->section) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
@@ -2043,17 +2062,10 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
/* Does the URL contain a query parameter? Only valid when we have a mailbox
and no UID as per RFC-5092 */
if(imap->mailbox && !imap->uid && *ptr == '?') {
/* Find the length of the query parameter */
begin = ++ptr;
while(imap_is_bchar(*ptr))
ptr++;
/* Decode the query parameter */
result = Curl_urldecode(data, begin, ptr - begin, &imap->query, NULL,
TRUE);
if(result)
return result;
if(imap->mailbox && !imap->uid && !imap->mindex) {
/* Get the query parameter, URL decoded */
(void)curl_url_get(data->state.uh, CURLUPART_QUERY, &imap->query,
CURLU_URLDECODE);
}
/* Any extra stuff at the end of the URL is an error */
+1
View File
@@ -58,6 +58,7 @@ struct IMAP {
char *mailbox; /* Mailbox to select */
char *uidvalidity; /* UIDVALIDITY to check in select */
char *uid; /* Message UID to fetch */
char *mindex; /* Index in mail box of mail to fetch */
char *section; /* Message SECTION to fetch */
char *partial; /* Message PARTIAL to fetch */
char *query; /* Query to search for */
-1
View File
@@ -35,4 +35,3 @@ char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
#endif
#endif /* HEADER_CURL_INET_NTOP_H */
-1
View File
@@ -37,4 +37,3 @@ int Curl_inet_pton(int, const char *, void *);
#endif
#endif /* HEADER_CURL_INET_PTON_H */
+3 -3
View File
@@ -206,7 +206,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
if(maj != GSS_S_COMPLETE) {
gss_release_name(&min, &gssname);
if(service == srv_host) {
Curl_failf(data, "Error importing service name %s@%s", service, host);
failf(data, "Error importing service name %s@%s", service, host);
return AUTH_ERROR;
}
service = srv_host;
@@ -265,6 +265,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
result = CURLE_OUT_OF_MEMORY;
free(p);
free(cmd);
if(result) {
ret = -2;
@@ -290,8 +291,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
(unsigned char **)&_gssresp.value,
&_gssresp.length);
if(result) {
Curl_failf(data, "base64-decoding: %s",
curl_easy_strerror(result));
failf(data, "base64-decoding: %s", curl_easy_strerror(result));
ret = AUTH_CONTINUE;
break;
}
+12 -6
View File
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -474,7 +474,13 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
#endif
}
if(rc != 0) {
failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc));
#ifdef USE_WIN32_LDAP
failf(data, "LDAP local: bind via ldap_win_bind %s",
ldap_err2string(rc));
#else
failf(data, "LDAP local: bind via ldap_simple_bind_s %s",
ldap_err2string(rc));
#endif
result = CURLE_LDAP_CANNOT_BIND;
goto quit;
}
@@ -838,9 +844,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.up.path ||
conn->data->state.up.path[0] != '/' ||
!strcasecompare("LDAP", conn->data->state.up.scheme))
return LDAP_INVALID_SYNTAX;
ludp->lud_scope = LDAP_SCOPE_BASE;
@@ -848,7 +854,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
ludp->lud_host = conn->host.name;
/* Duplicate the path */
p = path = strdup(conn->data->state.path + 1);
p = path = strdup(conn->data->state.up.path + 1);
if(!path)
return LDAP_NO_MEMORY;
-1
View File
@@ -51,4 +51,3 @@ void Curl_llist_move(struct curl_llist *, struct curl_llist_element *,
struct curl_llist *, struct curl_llist_element *);
#endif /* HEADER_CURL_LLIST_H */
+1 -1
View File
@@ -3,7 +3,7 @@
* MD4 Message-Digest Algorithm (RFC 1320).
*
* Homepage:
http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+1 -1
View File
@@ -177,7 +177,7 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+42 -35
View File
@@ -347,6 +347,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
Curl_llist_init(&multi->pending, multi_freeamsg);
multi->max_pipeline_length = 5;
multi->pipelining = CURLPIPE_MULTIPLEX;
/* -1 means it not set by user, use the default value */
multi->maxconnects = -1;
@@ -491,6 +492,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->state.conn_cache->closure_handle->set.timeout = data->set.timeout;
data->state.conn_cache->closure_handle->set.server_response_timeout =
data->set.server_response_timeout;
data->state.conn_cache->closure_handle->set.no_signal =
data->set.no_signal;
update_timer(multi);
return CURLM_OK;
@@ -541,10 +544,8 @@ static CURLcode multi_done(struct connectdata **connp,
Curl_getoff_all_pipelines(data, conn);
/* Cleanup possible redirect junk */
free(data->req.newurl);
data->req.newurl = NULL;
free(data->req.location);
data->req.location = NULL;
Curl_safefree(data->req.newurl);
Curl_safefree(data->req.location);
switch(status) {
case CURLE_ABORTED_BY_CALLBACK:
@@ -656,7 +657,6 @@ static CURLcode multi_done(struct connectdata **connp,
cache here, and therefore cannot be used from this point on
*/
Curl_free_request_state(data);
return result;
}
@@ -905,7 +905,7 @@ static int multi_getsock(struct Curl_easy *data,
return 0;
case CURLM_STATE_WAITRESOLVE:
return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
return Curl_resolv_getsock(data->easy_conn, socks, numsocks);
case CURLM_STATE_PROTOCONNECT:
case CURLM_STATE_SENDPROTOCONNECT:
@@ -1009,13 +1009,6 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
/* If the internally desired timeout is actually shorter than requested from
the outside, then use the shorter time! But only if the internal timer
is actually larger than -1! */
(void)multi_timeout(multi, &timeout_internal);
if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
timeout_ms = (int)timeout_internal;
/* Count up how many fds we have from the multi handle */
data = multi->easyp;
while(data) {
@@ -1040,6 +1033,13 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
data = data->next; /* check next handle */
}
/* If the internally desired timeout is actually shorter than requested from
the outside, then use the shorter time! But only if the internal timer
is actually larger than -1! */
(void)multi_timeout(multi, &timeout_internal);
if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
timeout_ms = (int)timeout_internal;
curlfds = nfds; /* number of internal file descriptors */
nfds += extra_nfds; /* add the externally provided ones */
@@ -1235,7 +1235,7 @@ static CURLcode multi_reconnect_request(struct connectdata **connp)
return result;
/* Resolved, continue with the connection */
result = Curl_async_resolved(conn, &protocol_done);
result = Curl_once_resolved(conn, &protocol_done);
if(result)
return result;
}
@@ -1511,7 +1511,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!dns)
result = Curl_resolver_is_resolved(data->easy_conn, &dns);
result = Curl_resolv_check(data->easy_conn, &dns);
/* Update sockets here, because the socket(s) may have been
closed and the application thus needs to be told, even if it
@@ -1524,10 +1524,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
/* Perform the next step in the connection phase, and then move on
to the WAITCONNECT state */
result = Curl_async_resolved(data->easy_conn, &protocol_connect);
result = Curl_once_resolved(data->easy_conn, &protocol_connect);
if(result)
/* if Curl_async_resolved() returns failure, the connection struct
/* if Curl_once_resolved() returns failure, the connection struct
is already freed and gone */
data->easy_conn = NULL; /* no more connection */
else {
@@ -1608,7 +1608,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_SENDPROTOCONNECT:
result = Curl_protocol_connect(data->easy_conn, &protocol_connect);
if(!protocol_connect)
if(!result && !protocol_connect)
/* switch to waiting state */
multistate(data, CURLM_STATE_PROTOCONNECT);
else if(!result) {
@@ -1707,7 +1707,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
char *newurl = NULL;
followtype follow = FOLLOW_NONE;
CURLcode drc;
bool retry = FALSE;
drc = Curl_retry_request(data->easy_conn, &newurl);
if(drc) {
@@ -1715,15 +1714,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result = drc;
stream_error = TRUE;
}
else
retry = (newurl)?TRUE:FALSE;
Curl_posttransfer(data);
drc = multi_done(&data->easy_conn, result, FALSE);
/* When set to retry the connection, we must to go back to
* the CONNECT state */
if(retry) {
if(newurl) {
if(!drc || (drc == CURLE_SEND_ERROR)) {
follow = FOLLOW_RETRY;
drc = Curl_follow(data, newurl, follow);
@@ -1993,6 +1990,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_CALL_MULTI_PERFORM;
}
}
free(newurl);
}
else {
/* after the transfer is done, go DONE */
@@ -2004,18 +2002,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
newurl = data->req.location;
data->req.location = NULL;
result = Curl_follow(data, newurl, FOLLOW_FAKE);
if(result)
free(newurl);
if(result) {
stream_error = TRUE;
result = multi_done(&data->easy_conn, result, TRUE);
}
}
multistate(data, CURLM_STATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
if(!result) {
multistate(data, CURLM_STATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
}
}
}
else if(comeback)
rc = CURLM_CALL_MULTI_PERFORM;
free(newurl);
break;
}
@@ -2131,15 +2132,21 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(CURLM_STATE_COMPLETED == data->mstate) {
/* now fill in the Curl_message with this info */
msg = &data->msg;
if(data->set.fmultidone) {
/* signal via callback instead */
data->set.fmultidone(data, result);
}
else {
/* now fill in the Curl_message with this info */
msg = &data->msg;
msg->extmsg.msg = CURLMSG_DONE;
msg->extmsg.easy_handle = data;
msg->extmsg.data.result = result;
msg->extmsg.msg = CURLMSG_DONE;
msg->extmsg.easy_handle = data;
msg->extmsg.data.result = result;
rc = multi_addmsg(multi, msg);
DEBUGASSERT(!data->easy_conn);
rc = multi_addmsg(multi, msg);
DEBUGASSERT(!data->easy_conn);
}
multistate(data, CURLM_STATE_MSGSENT);
}
} while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
@@ -2705,7 +2712,7 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
multi->push_userp = va_arg(param, void *);
break;
case CURLMOPT_PIPELINING:
multi->pipelining = va_arg(param, long);
multi->pipelining = va_arg(param, long) & CURLPIPE_MULTIPLEX;
break;
case CURLMOPT_TIMERFUNCTION:
multi->timer_cb = va_arg(param, curl_multi_timer_callback);
+39 -9
View File
@@ -57,7 +57,11 @@ int Curl_parsenetrc(const char *host,
{
FILE *file;
int retcode = 1;
int specific_login = (*loginp && **loginp != 0);
char *login = *loginp;
char *password = *passwordp;
bool specific_login = (login && *login != 0);
bool login_alloc = FALSE;
bool password_alloc = FALSE;
bool netrc_alloc = FALSE;
enum host_lookup_state state = NOTHING;
@@ -125,7 +129,7 @@ int Curl_parsenetrc(const char *host,
continue;
while(!done && tok) {
if((*loginp && **loginp) && (*passwordp && **passwordp)) {
if((login && *login) && (password && *password)) {
done = TRUE;
break;
}
@@ -158,26 +162,34 @@ int Curl_parsenetrc(const char *host,
/* we are now parsing sub-keywords concerning "our" host */
if(state_login) {
if(specific_login) {
state_our_login = strcasecompare(*loginp, tok);
state_our_login = strcasecompare(login, tok);
}
else {
free(*loginp);
*loginp = strdup(tok);
if(!*loginp) {
if(login_alloc) {
free(login);
login_alloc = FALSE;
}
login = strdup(tok);
if(!login) {
retcode = -1; /* allocation failed */
goto out;
}
login_alloc = TRUE;
}
state_login = 0;
}
else if(state_password) {
if(state_our_login || !specific_login) {
free(*passwordp);
*passwordp = strdup(tok);
if(!*passwordp) {
if(password_alloc) {
free(password);
password_alloc = FALSE;
}
password = strdup(tok);
if(!password) {
retcode = -1; /* allocation failed */
goto out;
}
password_alloc = TRUE;
}
state_password = 0;
}
@@ -198,6 +210,24 @@ int Curl_parsenetrc(const char *host,
} /* while fgets() */
out:
if(!retcode) {
if(login_alloc) {
if(*loginp)
free(*loginp);
*loginp = login;
}
if(password_alloc) {
if(*passwordp)
free(*passwordp);
*passwordp = password;
}
}
else {
if(login_alloc)
free(login);
if(password_alloc)
free(password);
}
fclose(file);
}
+2 -1
View File
@@ -48,7 +48,8 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
int nonblock /* TRUE or FALSE */)
{
#if defined(USE_BLOCKING_SOCKETS)
(void)sockfd;
(void)nonblock;
return 0; /* returns success */
#elif defined(HAVE_FCNTL_O_NONBLOCK)
-1
View File
@@ -28,4 +28,3 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
int nonblock /* TRUE or FALSE */);
#endif /* HEADER_CURL_NONBLOCK_H */
+5 -2
View File
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -195,7 +195,7 @@ int GetOrSetUpData(int id, libdata_t **appData,
if(!app_data->tenbytes || !app_data->lock) {
if(app_data->lock)
NXMutexFree(app_data->lock);
free(app_data->tenbytes);
free(app_data);
app_data = (libdata_t *) NULL;
err = ENOMEM;
@@ -213,6 +213,9 @@ int GetOrSetUpData(int id, libdata_t **appData,
err = set_app_data(gLibId, app_data);
if(err) {
if(app_data->lock)
NXMutexFree(app_data->lock);
free(app_data->tenbytes);
free(app_data);
app_data = (libdata_t *) NULL;
err = ENOMEM;
-1
View File
@@ -28,4 +28,3 @@ extern const char * const Curl_month[12];
CURLcode Curl_gmtime(time_t intime, struct tm *store);
#endif /* HEADER_CURL_PARSEDATE_H */
+1 -4
View File
@@ -1303,8 +1303,6 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn,
static CURLcode pop3_setup_connection(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
/* Initialise the POP3 layer */
CURLcode result = pop3_init(conn);
if(result)
@@ -1312,7 +1310,6 @@ static CURLcode pop3_setup_connection(struct connectdata *conn)
/* Clear the TLS upgraded flag */
conn->tls_upgraded = FALSE;
data->state.path++; /* don't include the initial slash */
return CURLE_OK;
}
@@ -1387,7 +1384,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
/* The POP3 struct is already initialised in pop3_connect() */
struct Curl_easy *data = conn->data;
struct POP3 *pop3 = data->req.protop;
const char *path = data->state.path;
const char *path = &data->state.up.path[1]; /* skip leading path */
/* URL decode the path for the message ID */
return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
-1
View File
@@ -62,4 +62,3 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */
#endif /* HEADER_CURL_PROGRESS_H */
+3 -1
View File
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -174,6 +174,8 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
return result;
while(num) {
/* clang-tidy warns on this line without this comment: */
/* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
*rnd++ = hex[(*bufp & 0xF0)>>4];
*rnd++ = hex[*bufp & 0x0F];
bufp++;
+14 -13
View File
@@ -462,7 +462,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
return CURLE_OUT_OF_MEMORY;
result =
Curl_add_bufferf(req_buffer,
Curl_add_bufferf(&req_buffer,
"%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
"CSeq: %ld\r\n", /* CSeq */
p_request, p_stream_uri, rtsp->CSeq_sent);
@@ -474,7 +474,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
* to make comparison easier
*/
if(p_session_id) {
result = Curl_add_bufferf(req_buffer, "Session: %s\r\n", p_session_id);
result = Curl_add_bufferf(&req_buffer, "Session: %s\r\n", p_session_id);
if(result)
return result;
}
@@ -482,7 +482,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/*
* Shared HTTP-like options
*/
result = Curl_add_bufferf(req_buffer,
result = Curl_add_bufferf(&req_buffer,
"%s" /* transport */
"%s" /* accept */
"%s" /* accept-encoding */
@@ -541,9 +541,10 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/* As stated in the http comments, it is probably not wise to
* actually set a custom Content-Length in the headers */
if(!Curl_checkheaders(conn, "Content-Length")) {
result = Curl_add_bufferf(req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
(data->set.upload ? putsize : postsize));
result =
Curl_add_bufferf(&req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
(data->set.upload ? putsize : postsize));
if(result)
return result;
}
@@ -551,8 +552,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_SET_PARAMETER ||
rtspreq == RTSPREQ_GET_PARAMETER) {
if(!Curl_checkheaders(conn, "Content-Type")) {
result = Curl_add_bufferf(req_buffer,
"Content-Type: text/parameters\r\n");
result = Curl_add_bufferf(&req_buffer,
"Content-Type: text/parameters\r\n");
if(result)
return result;
}
@@ -560,8 +561,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_ANNOUNCE) {
if(!Curl_checkheaders(conn, "Content-Type")) {
result = Curl_add_bufferf(req_buffer,
"Content-Type: application/sdp\r\n");
result = Curl_add_bufferf(&req_buffer,
"Content-Type: application/sdp\r\n");
if(result)
return result;
}
@@ -579,19 +580,19 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/* RTSP never allows chunked transfer */
data->req.forbidchunk = TRUE;
/* Finish the request buffer */
result = Curl_add_buffer(req_buffer, "\r\n", 2);
result = Curl_add_buffer(&req_buffer, "\r\n", 2);
if(result)
return result;
if(postsize > 0) {
result = Curl_add_buffer(req_buffer, data->set.postfields,
result = Curl_add_buffer(&req_buffer, data->set.postfields,
(size_t)postsize);
if(result)
return result;
}
/* issue the request */
result = Curl_add_buffer_send(req_buffer, conn,
result = Curl_add_buffer_send(&req_buffer, conn,
&data->info.request_size, 0, FIRSTSOCKET);
if(result) {
failf(data, "Failed sending RTSP request");
-1
View File
@@ -64,4 +64,3 @@ struct RTSP {
#endif /* HEADER_CURL_RTSP_H */
+4 -2
View File
@@ -61,7 +61,9 @@
#include "strcase.h"
#include "warnless.h"
#include "strdup.h"
/* The last #include file should be: */
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
static const struct {
@@ -422,7 +424,7 @@ static int sec_set_protection_level(struct connectdata *conn)
if(!conn->sec_complete) {
infof(conn->data, "Trying to change the protection level after the"
"completion of the data exchange.\n");
" completion of the data exchange.\n");
return -1;
}
-1
View File
@@ -113,4 +113,3 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
#endif
#endif /* HEADER_CURL_SELECT_H */
+1 -1
View File
@@ -36,7 +36,7 @@ void Curl_failf(struct Curl_easy *, const char *fmt, ...);
#elif defined(HAVE_VARIADIC_MACROS_GCC)
#define infof(x...) Curl_nop_stmt
#else
#define infof (void)
#error "missing VARIADIC macro define, fix and rebuild!"
#endif
#else /* CURL_DISABLE_VERBOSE_STRINGS */
+31
View File
@@ -127,9 +127,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.dns_cache_timeout = arg;
break;
case CURLOPT_DNS_USE_GLOBAL_CACHE:
#if 0 /* deprecated */
/* remember we want this enabled */
arg = va_arg(param, long);
data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
#endif
break;
case CURLOPT_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection */
@@ -841,6 +843,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
#else
if(arg > CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
return CURLE_UNSUPPORTED_PROTOCOL;
if(arg == CURL_HTTP_VERSION_NONE)
arg = CURL_HTTP_VERSION_2TLS;
#endif
data->set.httpversion = arg;
break;
@@ -1936,6 +1940,22 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
break;
case CURLOPT_UPLOAD_BUFFERSIZE:
/*
* The application kindly asks for a differently sized upload buffer.
* Cap it to sensible.
*/
arg = va_arg(param, long);
if(arg > UPLOADBUFFER_MAX)
arg = UPLOADBUFFER_MAX;
else if(arg < UPLOADBUFFER_MIN)
arg = UPLOADBUFFER_MIN;
data->set.upload_buffer_size = arg;
Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */
break;
case CURLOPT_NOSIGNAL:
/*
* The application asks not to set any signal() or alarm() handlers,
@@ -2599,6 +2619,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.disallow_username_in_url =
(0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_DOH_URL:
result = Curl_setstropt(&data->set.str[STRING_DOH],
va_arg(param, char *));
data->set.doh = data->set.str[STRING_DOH]?TRUE:FALSE;
break;
case CURLOPT_UPKEEP_INTERVAL_MS:
arg = va_arg(param, long);
if(arg < 0)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.upkeep_interval_ms = arg;
break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
-1
View File
@@ -142,4 +142,3 @@ void curl_slist_free_all(struct curl_slist *list)
item = next;
} while(next);
}
-1
View File
@@ -37,4 +37,3 @@ struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list,
char *data);
#endif /* HEADER_CURL_SLIST_H */
+3 -2
View File
@@ -610,7 +610,8 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
/* Check if there is data in the transfer buffer */
if(!smbc->send_size && smbc->upload_size) {
size_t nread = smbc->upload_size > UPLOAD_BUFSIZE ? UPLOAD_BUFSIZE :
size_t nread = smbc->upload_size > conn->data->set.upload_buffer_size ?
conn->data->set.upload_buffer_size :
smbc->upload_size;
conn->data->req.upload_fromhere = conn->data->state.ulbuf;
result = Curl_fillreadbuffer(conn, nread, &nread);
@@ -968,7 +969,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
char *slash;
/* URL decode the path */
result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE);
result = Curl_urldecode(data, data->state.up.path, 0, &path, NULL, TRUE);
if(result)
return result;
+3 -6
View File
@@ -1441,7 +1441,6 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn,
static CURLcode smtp_setup_connection(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
CURLcode result;
/* Clear the TLS upgraded flag */
@@ -1452,8 +1451,6 @@ static CURLcode smtp_setup_connection(struct connectdata *conn)
if(result)
return result;
data->state.path++; /* don't include the initial slash */
return CURLE_OK;
}
@@ -1507,7 +1504,7 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
/* The SMTP struct is already initialised in smtp_connect() */
struct Curl_easy *data = conn->data;
struct smtp_conn *smtpc = &conn->proto.smtpc;
const char *path = data->state.path;
const char *path = &data->state.up.path[1]; /* skip leading path */
char localhost[HOSTNAME_MAX + 1];
/* Calculate the path if necessary */
@@ -1563,14 +1560,14 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
if(!scratch || data->set.crlf) {
oldscratch = scratch;
scratch = newscratch = malloc(2 * UPLOAD_BUFSIZE);
scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
if(!newscratch) {
failf(data, "Failed to alloc scratch buffer!");
return CURLE_OUT_OF_MEMORY;
}
}
DEBUGASSERT(UPLOAD_BUFSIZE >= nread);
DEBUGASSERT(data->set.upload_buffer_size >= (size_t)nread);
/* Have we already sent part of the EOB? */
eob_sent = smtp->eob;
-1
View File
@@ -40,4 +40,3 @@ struct Curl_sockaddr_storage {
};
#endif /* HEADER_CURL_SOCKADDR_H */
+1 -2
View File
@@ -98,7 +98,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
* destination server.
*
* Reference :
* http://socks.permeo.com/protocol/socks4.protocol
* https://www.openssh.com/txt/socks4.protocol
*
* Note :
* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
@@ -789,4 +789,3 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
}
#endif /* CURL_DISABLE_PROXY */
-1
View File
@@ -73,4 +73,3 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
#endif /* CURL_DISABLE_PROXY */
#endif /* HEADER_CURL_SOCKS_H */
-1
View File
@@ -274,4 +274,3 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
return 0;
}
+1 -1
View File
@@ -2926,7 +2926,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
int rc;
ssh->kh = libssh2_knownhost_init(ssh->ssh_session);
if(!ssh->kh) {
/* eeek. TODO: free the ssh_session! */
libssh2_session_free(ssh->ssh_session);
return CURLE_FAILED_INIT;
}
+1 -1
View File
@@ -81,7 +81,7 @@ void *Curl_memdup(const void *src, size_t length)
* Curl_saferealloc(ptr, size)
*
* Does a normal realloc(), but will free the data pointer if the realloc
* fails. If 'size' is zero, it will free the data and return a failure.
* fails. If 'size' is non-zero, it will free the data and return a failure.
*
* This convenience function is provided and used to help us avoid a common
* mistake pattern when we could pass in a zero, catch the NULL return and end
+3 -6
View File
@@ -191,9 +191,6 @@ curl_easy_strerror(CURLcode error)
case CURLE_TELNET_OPTION_SYNTAX :
return "Malformed telnet option";
case CURLE_PEER_FAILED_VERIFICATION:
return "SSL peer certificate or SSH remote key was not OK";
case CURLE_GOT_NOTHING:
return "Server returned nothing (no headers, no data)";
@@ -218,9 +215,8 @@ curl_easy_strerror(CURLcode error)
case CURLE_SSL_CIPHER:
return "Couldn't use specified SSL cipher";
case CURLE_SSL_CACERT:
return "Peer certificate cannot be authenticated with given CA "
"certificates";
case CURLE_PEER_FAILED_VERIFICATION:
return "SSL peer certificate or SSH remote key was not OK";
case CURLE_SSL_CACERT_BADFILE:
return "Problem with the SSL CA cert (path? access rights?)";
@@ -324,6 +320,7 @@ curl_easy_strerror(CURLcode error)
case CURLE_OBSOLETE44:
case CURLE_OBSOLETE46:
case CURLE_OBSOLETE50:
case CURLE_OBSOLETE51:
case CURLE_OBSOLETE57:
case CURL_LAST:
break;
-1
View File
@@ -26,4 +26,3 @@ extern const struct Curl_handler Curl_handler_telnet;
#endif
#endif /* HEADER_CURL_TELNET_H */
+2 -2
View File
@@ -485,7 +485,7 @@ 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. */
result = Curl_urldecode(data, &state->conn->data->state.path[1], 0,
result = Curl_urldecode(data, &state->conn->data->state.up.path[1], 0,
&filename, NULL, FALSE);
if(result)
return result;
@@ -1374,7 +1374,7 @@ static CURLcode tftp_setup_connection(struct connectdata * conn)
/* TFTP URLs support an extension like ";mode=<typecode>" that
* we'll try to get now! */
type = strstr(data->state.path, ";mode=");
type = strstr(data->state.up.path, ";mode=");
if(!type)
type = strstr(conn->host.rawalloc, ";mode=");
-1
View File
@@ -26,4 +26,3 @@ extern const struct Curl_handler Curl_handler_tftp;
#endif
#endif /* HEADER_CURL_TFTP_H */
+20 -3
View File
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -33,7 +33,8 @@ struct curltime Curl_now(void)
*/
struct curltime now;
#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
(_WIN32_WINNT < _WIN32_WINNT_VISTA)
(_WIN32_WINNT < _WIN32_WINNT_VISTA) || \
(defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
DWORD milliseconds = GetTickCount();
now.tv_sec = milliseconds / 1000;
now.tv_usec = (milliseconds % 1000) * 1000;
@@ -60,7 +61,23 @@ struct curltime Curl_now(void)
struct timeval now;
struct curltime cnow;
struct timespec tsnow;
if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
/*
** clock_gettime() may be defined by Apple's SDK as weak symbol thus
** code compiles but fails during run-time if clock_gettime() is
** called on unsupported OS version.
*/
#if defined(__APPLE__) && (HAVE_BUILTIN_AVAILABLE == 1)
bool have_clock_gettime = FALSE;
if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
have_clock_gettime = TRUE;
#endif
if(
#if defined(__APPLE__) && (HAVE_BUILTIN_AVAILABLE == 1)
have_clock_gettime &&
#endif
(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
cnow.tv_sec = tsnow.tv_sec;
cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
}
+28 -340
View File
@@ -75,6 +75,7 @@
#include "http2.h"
#include "mime.h"
#include "strcase.h"
#include "urlapi-int.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -362,7 +363,7 @@ static int data_pending(const struct connectdata *conn)
return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
#if defined(USE_NGHTTP2)
Curl_ssl_data_pending(conn, FIRSTSOCKET) ||
/* For HTTP/2, we may read up everything including responde body
/* For HTTP/2, we may read up everything including response body
with header fields in Curl_http_readwrite_headers. If no
content-length is provided, curl waits for the connection
close, which we emulate it using conn->proto.httpc.closed =
@@ -566,7 +567,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
infof(data,
"Rewinding stream by : %zd"
" bytes on url %s (zero-length body)\n",
nread, data->state.path);
nread, data->state.up.path);
read_rewind(conn, (size_t)nread);
}
else {
@@ -574,7 +575,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
"Excess found in a non pipelined read:"
" excess = %zd"
" url = %s (zero-length body)\n",
nread, data->state.path);
nread, data->state.up.path);
}
}
@@ -743,7 +744,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
" bytes on url %s (size = %" CURL_FORMAT_CURL_OFF_T
", maxdownload = %" CURL_FORMAT_CURL_OFF_T
", bytecount = %" CURL_FORMAT_CURL_OFF_T ", nread = %zd)\n",
excess, data->state.path,
excess, data->state.up.path,
k->size, k->maxdownload, k->bytecount, nread);
read_rewind(conn, excess);
}
@@ -878,7 +879,7 @@ static CURLcode done_sending(struct connectdata *conn,
return CURLE_OK;
}
#ifdef WIN32
#if defined(WIN32) && !defined(USE_LWIPSOCK)
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
#endif
@@ -959,7 +960,8 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
sending_http_headers = FALSE;
}
result = Curl_fillreadbuffer(conn, UPLOAD_BUFSIZE, &fillcount);
result = Curl_fillreadbuffer(conn, data->set.upload_buffer_size,
&fillcount);
if(result)
return result;
@@ -991,7 +993,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
(data->set.crlf))) {
/* Do we need to allocate a scratch buffer? */
if(!data->state.scratch) {
data->state.scratch = malloc(2 * UPLOAD_BUFSIZE);
data->state.scratch = malloc(2 * data->set.upload_buffer_size);
if(!data->state.scratch) {
failf(data, "Failed to alloc scratch buffer!");
@@ -1453,314 +1455,11 @@ CURLcode Curl_posttransfer(struct Curl_easy *data)
return CURLE_OK;
}
#ifndef CURL_DISABLE_HTTP
/*
* Find the separator at the end of the host name, or the '?' in cases like
* http://www.url.com?id=2380
*/
static const char *find_host_sep(const char *url)
{
const char *sep;
const char *query;
/* Find the start of the hostname */
sep = strstr(url, "//");
if(!sep)
sep = url;
else
sep += 2;
query = strchr(sep, '?');
sep = strchr(sep, '/');
if(!sep)
sep = url + strlen(url);
if(!query)
query = url + strlen(url);
return sep < query ? sep : query;
}
/*
* Decide in an encoding-independent manner whether a character in an
* URL must be escaped. The same criterion must be used in strlen_url()
* and strcpy_url().
*/
static bool urlchar_needs_escaping(int c)
{
return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
}
/*
* strlen_url() returns the length of the given URL if the spaces within the
* URL were properly URL encoded.
* URL encoding should be skipped for host names, otherwise IDN resolution
* will fail.
*/
static size_t strlen_url(const char *url, bool relative)
{
const unsigned char *ptr;
size_t newlen = 0;
bool left = TRUE; /* left side of the ? */
const unsigned char *host_sep = (const unsigned char *) url;
if(!relative)
host_sep = (const unsigned char *) find_host_sep(url);
for(ptr = (unsigned char *)url; *ptr; ptr++) {
if(ptr < host_sep) {
++newlen;
continue;
}
switch(*ptr) {
case '?':
left = FALSE;
/* FALLTHROUGH */
default:
if(urlchar_needs_escaping(*ptr))
newlen += 2;
newlen++;
break;
case ' ':
if(left)
newlen += 3;
else
newlen++;
break;
}
}
return newlen;
}
/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
* the source URL accordingly.
* URL encoding should be skipped for host names, otherwise IDN resolution
* will fail.
*/
static void strcpy_url(char *output, const char *url, bool relative)
{
/* we must add this with whitespace-replacing */
bool left = TRUE;
const unsigned char *iptr;
char *optr = output;
const unsigned char *host_sep = (const unsigned char *) url;
if(!relative)
host_sep = (const unsigned char *) find_host_sep(url);
for(iptr = (unsigned char *)url; /* read from here */
*iptr; /* until zero byte */
iptr++) {
if(iptr < host_sep) {
*optr++ = *iptr;
continue;
}
switch(*iptr) {
case '?':
left = FALSE;
/* FALLTHROUGH */
default:
if(urlchar_needs_escaping(*iptr)) {
snprintf(optr, 4, "%%%02x", *iptr);
optr += 3;
}
else
*optr++=*iptr;
break;
case ' ':
if(left) {
*optr++='%'; /* add a '%' */
*optr++='2'; /* add a '2' */
*optr++='0'; /* add a '0' */
}
else
*optr++='+'; /* add a '+' here */
break;
}
}
*optr = 0; /* zero terminate output buffer */
}
/*
* Returns true if the given URL is absolute (as opposed to relative)
*/
static bool is_absolute_url(const char *url)
{
char prot[16]; /* URL protocol string storage */
char letter; /* used for a silly sscanf */
return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE;
}
/*
* Concatenate a relative URL to a base URL making it absolute.
* URL-encodes any spaces.
* The returned pointer must be freed by the caller unless NULL
* (returns NULL on out of memory).
*/
static char *concat_url(const char *base, const char *relurl)
{
/***
TRY to append this new path to the old URL
to the right of the host part. Oh crap, this is doomed to cause
problems in the future...
*/
char *newest;
char *protsep;
char *pathsep;
size_t newlen;
bool host_changed = FALSE;
const char *useurl = relurl;
size_t urllen;
/* we must make our own copy of the URL to play with, as it may
point to read-only data */
char *url_clone = strdup(base);
if(!url_clone)
return NULL; /* skip out of this NOW */
/* protsep points to the start of the host name */
protsep = strstr(url_clone, "//");
if(!protsep)
protsep = url_clone;
else
protsep += 2; /* pass the slashes */
if('/' != relurl[0]) {
int level = 0;
/* First we need to find out if there's a ?-letter in the URL,
and cut it and the right-side of that off */
pathsep = strchr(protsep, '?');
if(pathsep)
*pathsep = 0;
/* we have a relative path to append to the last slash if there's one
available, or if the new URL is just a query string (starts with a
'?') we append the new one at the end of the entire currently worked
out URL */
if(useurl[0] != '?') {
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
}
/* Check if there's any slash after the host name, and if so, remember
that position instead */
pathsep = strchr(protsep, '/');
if(pathsep)
protsep = pathsep + 1;
else
protsep = NULL;
/* now deal with one "./" or any amount of "../" in the newurl
and act accordingly */
if((useurl[0] == '.') && (useurl[1] == '/'))
useurl += 2; /* just skip the "./" */
while((useurl[0] == '.') &&
(useurl[1] == '.') &&
(useurl[2] == '/')) {
level++;
useurl += 3; /* pass the "../" */
}
if(protsep) {
while(level--) {
/* cut off one more level from the right of the original URL */
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
else {
*protsep = 0;
break;
}
}
}
}
else {
/* We got a new absolute path for this server */
if((relurl[0] == '/') && (relurl[1] == '/')) {
/* the new URL starts with //, just keep the protocol part from the
original one */
*protsep = 0;
useurl = &relurl[2]; /* we keep the slashes from the original, so we
skip the new ones */
host_changed = TRUE;
}
else {
/* cut off the original URL from the first slash, or deal with URLs
without slash */
pathsep = strchr(protsep, '/');
if(pathsep) {
/* When people use badly formatted URLs, such as
"http://www.url.com?dir=/home/daniel" we must not use the first
slash, if there's a ?-letter before it! */
char *sep = strchr(protsep, '?');
if(sep && (sep < pathsep))
pathsep = sep;
*pathsep = 0;
}
else {
/* There was no slash. Now, since we might be operating on a badly
formatted URL, such as "http://www.url.com?id=2380" which doesn't
use a slash separator as it is supposed to, we need to check for a
?-letter as well! */
pathsep = strchr(protsep, '?');
if(pathsep)
*pathsep = 0;
}
}
}
/* If the new part contains a space, this is a mighty stupid redirect
but we still make an effort to do "right". To the left of a '?'
letter we replace each space with %20 while it is replaced with '+'
on the right side of the '?' letter.
*/
newlen = strlen_url(useurl, !host_changed);
urllen = strlen(url_clone);
newest = malloc(urllen + 1 + /* possible slash */
newlen + 1 /* zero byte */);
if(!newest) {
free(url_clone); /* don't leak this */
return NULL;
}
/* copy over the root url part */
memcpy(newest, url_clone, urllen);
/* check if we need to append a slash */
if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
;
else
newest[urllen++]='/';
/* then append the new piece on the right side */
strcpy_url(&newest[urllen], useurl, !host_changed);
free(url_clone);
return newest;
}
#endif /* CURL_DISABLE_HTTP */
/*
* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
* as given by the remote server and set up the new URL to request.
*
* This function DOES NOT FREE the given url.
*/
CURLcode Curl_follow(struct Curl_easy *data,
char *newurl, /* the Location: string */
@@ -1777,6 +1476,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
/* Location: redirect */
bool disallowport = FALSE;
bool reachedmax = FALSE;
CURLUcode uc;
if(type == FOLLOW_REDIR) {
if((data->set.maxredirs != -1) &&
@@ -1809,33 +1509,18 @@ CURLcode Curl_follow(struct Curl_easy *data,
}
}
if(!is_absolute_url(newurl)) {
/***
*DANG* this is an RFC 2068 violation. The URL is supposed
to be absolute and this doesn't seem to be that!
*/
char *absolute = concat_url(data->change.url, newurl);
if(!absolute)
return CURLE_OUT_OF_MEMORY;
newurl = absolute;
}
else {
/* The new URL MAY contain space or high byte values, that means a mighty
stupid redirect URL but we still make an effort to do "right". */
char *newest;
size_t newlen = strlen_url(newurl, FALSE);
if(Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN))
/* This is an absolute URL, don't allow the custom port number */
disallowport = TRUE;
newest = malloc(newlen + 1); /* get memory for this */
if(!newest)
return CURLE_OUT_OF_MEMORY;
DEBUGASSERT(data->state.uh);
uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, 0);
if(uc)
return Curl_uc_to_curlcode(uc);
strcpy_url(newest, newurl, FALSE); /* create a space-free URL */
newurl = newest; /* use this instead now */
}
uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
if(uc)
return Curl_uc_to_curlcode(uc);
if(type == FOLLOW_FAKE) {
/* we're only figuring out the new url if we would've followed locations
@@ -1852,10 +1537,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
if(disallowport)
data->state.allow_port = FALSE;
if(data->change.url_alloc) {
if(data->change.url_alloc)
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
data->change.url = newurl;
data->change.url_alloc = TRUE;
@@ -2021,8 +1704,13 @@ CURLcode Curl_retry_request(struct connectdata *conn,
if(conn->handler->protocol&PROTO_FAMILY_HTTP) {
struct HTTP *http = data->req.protop;
if(http->writebytecount)
return Curl_readrewind(conn);
if(http->writebytecount) {
CURLcode result = Curl_readrewind(conn);
if(result) {
Curl_safefree(*url);
return result;
}
}
}
}
return CURLE_OK;
-1
View File
@@ -71,4 +71,3 @@ Curl_setup_transfer (struct connectdata *data,
);
#endif /* HEADER_CURL_TRANSFER_H */
+308 -808
View File
@@ -92,6 +92,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "non-ascii.h"
#include "inet_pton.h"
#include "getinfo.h"
#include "urlapi-int.h"
/* And now for the protocols */
#include "ftp.h"
@@ -127,10 +128,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
static void conn_free(struct connectdata *conn);
static void free_fixed_hostname(struct hostname *host);
static CURLcode parse_url_login(struct Curl_easy *data,
struct connectdata *conn,
char **userptr, char **passwdptr,
char **optionsptr);
static unsigned int get_protocol_family(unsigned int protocol);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
@@ -294,6 +291,22 @@ void Curl_freeset(struct Curl_easy *data)
Curl_mime_cleanpart(&data->set.mimepost);
}
/* free the URL pieces */
void Curl_up_free(struct Curl_easy *data)
{
struct urlpieces *up = &data->state.up;
Curl_safefree(up->scheme);
Curl_safefree(up->hostname);
Curl_safefree(up->port);
Curl_safefree(up->user);
Curl_safefree(up->password);
Curl_safefree(up->options);
Curl_safefree(up->path);
Curl_safefree(up->query);
curl_url_cleanup(data->state.uh);
data->state.uh = NULL;
}
/*
* This is the internal function curl_easy_cleanup() calls. This should
* cleanup and free all resources associated with this sessionhandle.
@@ -313,16 +326,17 @@ CURLcode Curl_close(struct Curl_easy *data)
Curl_expire_clear(data); /* shut off timers */
m = data->multi;
if(m)
/* This handle is still part of a multi handle, take care of this first
and detach this handle from there. */
curl_multi_remove_handle(data->multi, data);
if(data->multi_easy)
if(data->multi_easy) {
/* when curl_easy_perform() is used, it creates its own multi handle to
use and this is the one */
curl_multi_cleanup(data->multi_easy);
data->multi_easy = NULL;
}
/* Destroy the timeout list that is held in the easy handle. It is
/normally/ done by curl_multi_remove_handle() but this is "just in
@@ -336,10 +350,6 @@ CURLcode Curl_close(struct Curl_easy *data)
if(data->state.rangestringalloc)
free(data->state.range);
/* Free the pathbuffer */
Curl_safefree(data->state.pathbuffer);
data->state.path = NULL;
/* freed here just in case DONE wasn't called */
Curl_free_request_state(data);
@@ -359,12 +369,7 @@ CURLcode Curl_close(struct Curl_easy *data)
}
data->change.referer = NULL;
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
data->change.url = NULL;
Curl_up_free(data);
Curl_safefree(data->state.buffer);
Curl_safefree(data->state.headerbuff);
Curl_safefree(data->state.ulbuf);
@@ -516,25 +521,28 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->wildcard_enabled = FALSE;
set->chunk_bgn = ZERO_NULL;
set->chunk_end = ZERO_NULL;
/* tcp keepalives are disabled by default, but provide reasonable values for
* the interval and idle times.
*/
set->tcp_keepalive = FALSE;
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;
set->expect_100_timeout = 1000L; /* Wait for a second by default. */
set->sep_headers = TRUE; /* separated header lists by default */
set->buffer_size = READBUFFER_SIZE;
set->upload_buffer_size = UPLOAD_BUFSIZE;
set->upload_buffer_size = UPLOADBUFFER_DEFAULT;
set->happy_eyeballs_timeout = CURL_HET_DEFAULT;
set->fnmatch = ZERO_NULL;
set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
set->httpversion =
#ifdef USE_NGHTTP2
CURL_HTTP_VERSION_2TLS
#else
CURL_HTTP_VERSION_1_1
#endif
;
Curl_http2_init_userset(set);
return result;
}
@@ -594,8 +602,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->progress.flags |= PGRS_HIDE;
data->state.current_speed = -1; /* init to negative == impossible */
data->set.fnmatch = ZERO_NULL;
data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
Curl_http2_init_state(&data->state);
}
@@ -1831,6 +1837,12 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
/* Store creation time to help future close decision making */
conn->created = Curl_now();
/* Store current time to give a baseline to keepalive connection times. */
conn->keepalive = Curl_now();
/* Store off the configured connection upkeep time. */
conn->upkeep_interval_ms = data->set.upkeep_interval_ms;
conn->data = data; /* Setup the association between this connection
and the Curl_easy */
@@ -1937,30 +1949,37 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
return NULL;
}
/* returns the handler if the given scheme is built-in */
const struct Curl_handler *Curl_builtin_scheme(const char *scheme)
{
const struct Curl_handler * const *pp;
const struct Curl_handler *p;
/* Scan protocol handler table and match against 'scheme'. The handler may
be changed later when the protocol specific setup function is called. */
for(pp = protocols; (p = *pp) != NULL; pp++)
if(strcasecompare(p->scheme, scheme))
/* Protocol found in table. Check if allowed */
return p;
return NULL; /* not found */
}
static CURLcode findprotocol(struct Curl_easy *data,
struct connectdata *conn,
const char *protostr)
{
const struct Curl_handler * const *pp;
const struct Curl_handler *p;
const struct Curl_handler *p = Curl_builtin_scheme(protostr);
/* Scan protocol handler table and match against 'protostr' to set a few
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(strcasecompare(p->scheme, protostr)) {
/* Protocol found in table. Check if allowed */
if(!(data->set.allowed_protocols & p->protocol))
/* nope, get out */
break;
/* it is allowed for "normal" request, now do an extra check if this is
the result of a redirect */
if(data->state.this_is_a_follow &&
!(data->set.redir_protocols & p->protocol))
/* nope, get out */
break;
if(p && /* Protocol found in table. Check if allowed */
(data->set.allowed_protocols & p->protocol)) {
/* it is allowed for "normal" request, now do an extra check if this is
the result of a redirect */
if(data->state.this_is_a_follow &&
!(data->set.redir_protocols & p->protocol))
/* nope, get out */
;
else {
/* Perform setup complement if some. */
conn->handler = conn->given = p;
@@ -1969,7 +1988,6 @@ static CURLcode findprotocol(struct Curl_easy *data,
}
}
/* The protocol was not found in the table, but we don't have to assign it
to anything since it is already assigned to a dummy-struct in the
create_conn() function when the connectdata struct is allocated. */
@@ -1979,379 +1997,134 @@ static CURLcode findprotocol(struct Curl_easy *data,
return CURLE_UNSUPPORTED_PROTOCOL;
}
CURLcode Curl_uc_to_curlcode(CURLUcode uc)
{
switch(uc) {
default:
return CURLE_URL_MALFORMAT;
case CURLUE_UNSUPPORTED_SCHEME:
return CURLE_UNSUPPORTED_PROTOCOL;
case CURLUE_OUT_OF_MEMORY:
return CURLE_OUT_OF_MEMORY;
case CURLUE_USER_NOT_ALLOWED:
return CURLE_LOGIN_DENIED;
}
}
/*
* Parse URL and fill in the relevant members of the connection struct.
*/
static CURLcode parseurlandfillconn(struct Curl_easy *data,
struct connectdata *conn,
bool *prot_missing,
char **userp, char **passwdp,
char **optionsp)
struct connectdata *conn)
{
char *at;
char *fragment;
char *path = data->state.path;
char *query;
int rc;
const char *protop = "";
CURLcode result;
bool rebuild_url = FALSE;
bool url_has_scheme = FALSE;
char protobuf[16];
CURLU *uh;
CURLUcode uc;
char *hostname;
*prot_missing = FALSE;
Curl_up_free(data); /* cleanup previous leftovers first */
/* We might pass the entire URL into the request so we need to make sure
* there are no bad characters in there.*/
if(strpbrk(data->change.url, "\r\n")) {
failf(data, "Illegal characters found in URL");
return CURLE_URL_MALFORMAT;
/* parse the URL */
uh = data->state.uh = curl_url();
if(!uh)
return CURLE_OUT_OF_MEMORY;
if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
!Curl_is_absolute_url(data->change.url, NULL, MAX_SCHEME_LEN)) {
char *url;
if(data->change.url_alloc)
free(data->change.url);
url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
data->change.url);
if(!url)
return CURLE_OUT_OF_MEMORY;
data->change.url = url;
data->change.url_alloc = TRUE;
}
/*************************************************************
* Parse the URL.
*
* We need to parse the url even when using the proxy, because we will need
* the hostname and port in case we are trying to SSL connect through the
* proxy -- and we don't know if we will need to use SSL until we parse the
* url ...
************************************************************/
if(data->change.url[0] == ':') {
failf(data, "Bad URL, colon is first character");
return CURLE_URL_MALFORMAT;
uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
CURLU_GUESS_SCHEME |
CURLU_NON_SUPPORT_SCHEME |
(data->set.disallow_username_in_url ?
CURLU_DISALLOW_USER : 0) |
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
if(uc)
return Curl_uc_to_curlcode(uc);
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
if(uc)
return Curl_uc_to_curlcode(uc);
result = findprotocol(data, conn, data->state.up.scheme);
if(result)
return result;
uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user,
CURLU_URLDECODE);
if(!uc) {
conn->user = strdup(data->state.up.user);
if(!conn->user)
return CURLE_OUT_OF_MEMORY;
conn->bits.user_passwd = TRUE;
}
else if(uc != CURLUE_NO_USER)
return Curl_uc_to_curlcode(uc);
uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password,
CURLU_URLDECODE);
if(!uc) {
conn->passwd = strdup(data->state.up.password);
if(!conn->passwd)
return CURLE_OUT_OF_MEMORY;
conn->bits.user_passwd = TRUE;
}
else if(uc != CURLUE_NO_PASSWORD)
return Curl_uc_to_curlcode(uc);
uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
CURLU_URLDECODE);
if(!uc) {
conn->options = strdup(data->state.up.options);
if(!conn->options)
return CURLE_OUT_OF_MEMORY;
}
else if(uc != CURLUE_NO_OPTIONS)
return Curl_uc_to_curlcode(uc);
uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0);
if(uc) {
if(!strcasecompare("file", data->state.up.scheme))
return CURLE_OUT_OF_MEMORY;
}
/* MSDOS/Windows style drive prefix, eg c: in c:foo */
#define STARTS_WITH_DRIVE_PREFIX(str) \
((('a' <= str[0] && str[0] <= 'z') || \
('A' <= str[0] && str[0] <= 'Z')) && \
(str[1] == ':'))
uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, 0);
if(uc)
return Curl_uc_to_curlcode(uc);
/* MSDOS/Windows style drive prefix, optionally with
* a '|' instead of ':', followed by a slash or NUL */
#define STARTS_WITH_URL_DRIVE_PREFIX(str) \
((('a' <= (str)[0] && (str)[0] <= 'z') || \
('A' <= (str)[0] && (str)[0] <= 'Z')) && \
((str)[1] == ':' || (str)[1] == '|') && \
((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0))
/* Don't mistake a drive letter for a scheme if the default protocol is file.
curld --proto-default file c:/foo/bar.txt */
if(STARTS_WITH_DRIVE_PREFIX(data->change.url) &&
data->set.str[STRING_DEFAULT_PROTOCOL] &&
strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file")) {
; /* do nothing */
}
else { /* check for a scheme */
int i;
for(i = 0; i < 16 && data->change.url[i]; ++i) {
if(data->change.url[i] == '/')
break;
if(data->change.url[i] == ':') {
url_has_scheme = TRUE;
break;
}
}
}
/* handle the file: scheme */
if((url_has_scheme && strncasecompare(data->change.url, "file:", 5)) ||
(!url_has_scheme && data->set.str[STRING_DEFAULT_PROTOCOL] &&
strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file"))) {
if(url_has_scheme)
rc = sscanf(data->change.url, "%*15[^\n/:]:%[^\n]", path);
else
rc = sscanf(data->change.url, "%[^\n]", path);
if(rc != 1) {
failf(data, "Bad URL");
return CURLE_URL_MALFORMAT;
}
/* Extra handling URLs with an authority component (i.e. that start with
* "file://")
*
* We allow omitted hostname (e.g. file:/<path>) -- valid according to
* RFC 8089, but not the (current) WHAT-WG URL spec.
*/
if(url_has_scheme && path[0] == '/' && path[1] == '/') {
/* swallow the two slashes */
char *ptr = &path[2];
/*
* According to RFC 8089, a file: URL can be reliably dereferenced if:
*
* o it has no/blank hostname, or
*
* o the hostname matches "localhost" (case-insensitively), or
*
* o the hostname is a FQDN that resolves to this machine.
*
* For brevity, we only consider URLs with empty, "localhost", or
* "127.0.0.1" hostnames as local.
*
* Additionally, there is an exception for URLs with a Windows drive
* letter in the authority (which was accidentally omitted from RFC 8089
* Appendix E, but believe me, it was meant to be there. --MK)
*/
if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
/* the URL includes a host name, it must match "localhost" or
"127.0.0.1" to be valid */
if(!checkprefix("localhost/", ptr) &&
!checkprefix("127.0.0.1/", ptr)) {
failf(data, "Invalid file://hostname/, "
"expected localhost or 127.0.0.1 or none");
return CURLE_URL_MALFORMAT;
}
ptr += 9; /* now points to the slash after the host */
}
/* This cannot be done with strcpy, as the memory chunks overlap! */
memmove(path, ptr, strlen(ptr) + 1);
}
#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
/* Don't allow Windows drive letters when not in Windows.
* This catches both "file:/c:" and "file:c:" */
if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
STARTS_WITH_URL_DRIVE_PREFIX(path)) {
failf(data, "File drive letters are only accepted in MSDOS/Windows.");
return CURLE_URL_MALFORMAT;
}
#else
/* If the path starts with a slash and a drive letter, ditch the slash */
if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) {
/* This cannot be done with strcpy, as the memory chunks overlap! */
memmove(path, &path[1], strlen(&path[1]) + 1);
}
#endif
protop = "file"; /* protocol string */
*prot_missing = !url_has_scheme;
uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port,
CURLU_DEFAULT_PORT);
if(uc) {
if(!strcasecompare("file", data->state.up.scheme))
return CURLE_OUT_OF_MEMORY;
}
else {
/* clear path */
char slashbuf[4];
path[0] = 0;
rc = sscanf(data->change.url,
"%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]",
protobuf, slashbuf, conn->host.name, path);
if(2 == rc) {
failf(data, "Bad URL");
return CURLE_URL_MALFORMAT;
}
if(3 > rc) {
/*
* 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);
if(1 > rc) {
/*
* We couldn't even get this format.
* djgpp 2.04 has a sscanf() bug where 'conn->host.name' is
* assigned, but the return value is EOF!
*/
#if defined(__DJGPP__) && (DJGPP_MINOR == 4)
if(!(rc == -1 && *conn->host.name))
#endif
{
failf(data, "<url> malformed");
return CURLE_URL_MALFORMAT;
}
}
/*
* Since there was no protocol part specified in the URL use the
* user-specified default protocol. If we weren't given a default make a
* guess by matching some protocols against the host's outermost
* sub-domain name. Finally if there was no match use HTTP.
*/
protop = data->set.str[STRING_DEFAULT_PROTOCOL];
if(!protop) {
/* Note: if you add a new protocol, please update the list in
* lib/version.c too! */
if(checkprefix("FTP.", conn->host.name))
protop = "ftp";
else if(checkprefix("DICT.", conn->host.name))
protop = "DICT";
else if(checkprefix("LDAP.", conn->host.name))
protop = "LDAP";
else if(checkprefix("IMAP.", conn->host.name))
protop = "IMAP";
else if(checkprefix("SMTP.", conn->host.name))
protop = "smtp";
else if(checkprefix("POP3.", conn->host.name))
protop = "pop3";
else
protop = "http";
}
*prot_missing = TRUE; /* not given in URL */
}
else {
size_t s = strlen(slashbuf);
protop = protobuf;
if(s != 2) {
infof(data, "Unwillingly accepted illegal URL using %zu slash%s!\n",
s, s>1?"es":"");
if(data->change.url_alloc)
free(data->change.url);
/* repair the URL to use two slashes */
data->change.url = aprintf("%s://%s%s",
protobuf, conn->host.name, path);
if(!data->change.url)
return CURLE_OUT_OF_MEMORY;
data->change.url_alloc = TRUE;
}
}
unsigned long port = strtoul(data->state.up.port, NULL, 10);
conn->remote_port = curlx_ultous(port);
}
/* We search for '?' in the host name (but only on the right side of a
* @-letter to allow ?-letters in username and password) to handle things
* like http://example.com?param= (notice the missing '/').
*/
at = strchr(conn->host.name, '@');
if(at)
query = strchr(at + 1, '?');
else
query = strchr(conn->host.name, '?');
(void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
if(query) {
/* We must insert a slash before the '?'-letter in the URL. If the URL had
a slash after the '?', that is where the path currently begins and the
'?string' is still part of the host name.
hostname = data->state.up.hostname;
if(!hostname)
/* this is for file:// transfers, get a dummy made */
hostname = (char *)"";
We must move the trailing part from the host name and put it first in
the path. And have it all prefixed with a slash.
*/
size_t hostlen = strlen(query);
size_t pathlen = strlen(path);
/* move the existing path plus the zero byte forward, to make room for
the host-name part */
memmove(path + hostlen + 1, path, pathlen + 1);
/* now copy the trailing host part in front of the existing path */
memcpy(path + 1, query, hostlen);
path[0]='/'; /* prepend the missing slash */
rebuild_url = TRUE;
*query = 0; /* now cut off the hostname at the ? */
}
else if(!path[0]) {
/* if there's no path set, use a single slash */
strcpy(path, "/");
rebuild_url = TRUE;
}
/* If the URL is malformatted (missing a '/' after hostname before path) we
* 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] != '/') {
/* 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. */
memmove(&path[1], path, strlen(path) + 1);
path[0] = '/';
rebuild_url = TRUE;
}
else if(!data->set.path_as_is) {
/* sanitise paths and remove ../ and ./ sequences according to RFC3986 */
char *newp = Curl_dedotdotify(path);
if(!newp)
return CURLE_OUT_OF_MEMORY;
if(strcmp(newp, path)) {
rebuild_url = TRUE;
free(data->state.pathbuffer);
data->state.pathbuffer = newp;
data->state.path = newp;
path = newp;
}
else
free(newp);
}
/*
* "rebuild_url" means that one or more URL components have been modified so
* we need to generate an updated full version. We need the corrected URL
* when communicating over HTTP proxy and we don't know at this point if
* we're using a proxy or not.
*/
if(rebuild_url) {
char *reurl;
size_t plen = strlen(path); /* new path, should be 1 byte longer than
the original */
size_t prefixlen = strlen(conn->host.name);
if(!*prot_missing) {
size_t protolen = strlen(protop);
if(curl_strnequal(protop, data->change.url, protolen))
prefixlen += protolen;
else {
failf(data, "<url> malformed");
return CURLE_URL_MALFORMAT;
}
if(curl_strnequal("://", &data->change.url[protolen], 3))
prefixlen += 3;
/* only file: is allowed to omit one or both slashes */
else if(curl_strnequal("file:", data->change.url, 5))
prefixlen += 1 + (data->change.url[5] == '/');
else {
failf(data, "<url> malformed");
return CURLE_URL_MALFORMAT;
}
}
reurl = malloc(prefixlen + plen + 1);
if(!reurl)
return CURLE_OUT_OF_MEMORY;
/* copy the prefix */
memcpy(reurl, data->change.url, prefixlen);
/* append the trailing piece + zerobyte */
memcpy(&reurl[prefixlen], path, plen + 1);
/* possible free the old one */
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
infof(data, "Rebuilt URL to: %s\n", reurl);
data->change.url = reurl;
data->change.url_alloc = TRUE; /* free this later */
}
result = findprotocol(data, conn, protop);
if(result)
return result;
/*
* Parse the login details from the URL and strip them out of
* the host name
*/
result = parse_url_login(data, conn, userp, passwdp, optionsp);
if(result)
return result;
if(conn->host.name[0] == '[') {
if(hostname[0] == '[') {
/* This looks like an IPv6 address literal. See if there is an address
scope if there is no location header */
char *percent = strchr(conn->host.name, '%');
scope. */
char *percent = strchr(++hostname, '%');
conn->bits.ipv6_ip = TRUE;
if(percent) {
unsigned int identifier_offset = 3;
char *endp;
@@ -2399,33 +2172,22 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
infof(data, "Invalid IPv6 address format\n");
}
}
percent = strchr(hostname, ']');
if(percent)
/* terminate IPv6 numerical at end bracket */
*percent = 0;
}
/* make sure the connect struct gets its own copy of the host name */
conn->host.rawalloc = strdup(hostname);
if(!conn->host.rawalloc)
return CURLE_OUT_OF_MEMORY;
conn->host.name = conn->host.rawalloc;
if(data->set.scope_id)
/* Override any scope that was set above. */
conn->scope_id = data->set.scope_id;
/* Remove the fragment part of the path. Per RFC 2396, this is always the
last part of the URI. We are looking for the first '#' so that we deal
gracefully with non conformant URI such as http://example.com#foo#bar. */
fragment = strchr(path, '#');
if(fragment) {
*fragment = 0;
/* we know the path part ended with a fragment, so we know the full URL
string does too and we need to cut it off from there so it isn't used
over proxy */
fragment = strchr(data->change.url, '#');
if(fragment)
*fragment = 0;
}
/*
* So if the URL was A://B/C#D,
* protop is A
* conn->host.name is B
* data->state.path is /C
*/
return CURLE_OK;
}
@@ -2540,11 +2302,8 @@ static bool check_noproxy(const char *name, const char *no_proxy)
if(!endptr)
return FALSE;
name++;
}
else
endptr = strchr(name, ':');
if(endptr)
namelen = endptr - name;
}
else
namelen = strlen(name);
@@ -3076,131 +2835,6 @@ out:
}
#endif /* CURL_DISABLE_PROXY */
/*
* parse_url_login()
*
* Parse the login details (user name, password and options) from the URL and
* strip them out of the host name
*
* Inputs: data->set.use_netrc (CURLOPT_NETRC)
* conn->host.name
*
* Outputs: (almost :- all currently undefined)
* conn->bits.user_passwd - non-zero if non-default passwords exist
* user - non-zero length if defined
* passwd - non-zero length if defined
* options - non-zero length if defined
* conn->host.name - remove user name and password
*/
static CURLcode parse_url_login(struct Curl_easy *data,
struct connectdata *conn,
char **user, char **passwd, char **options)
{
CURLcode result = CURLE_OK;
char *userp = NULL;
char *passwdp = NULL;
char *optionsp = NULL;
/* At this point, we're hoping all the other special cases have
* been taken care of, so conn->host.name is at most
* [user[:password][;options]]@]hostname
*
* We need somewhere to put the embedded details, so do that first.
*/
char *ptr = strchr(conn->host.name, '@');
char *login = conn->host.name;
DEBUGASSERT(!**user);
DEBUGASSERT(!**passwd);
DEBUGASSERT(!**options);
DEBUGASSERT(conn->handler);
if(!ptr)
goto out;
/* We will now try to extract the
* possible login information in a string like:
* ftp://user:password@ftp.my.site:8021/README */
conn->host.name = ++ptr;
/* So the hostname is sane. Only bother interpreting the
* results if we could care. It could still be wasted
* work because it might be overtaken by the programmatically
* set user/passwd, but doing that first adds more cases here :-(
*/
if(data->set.use_netrc == CURL_NETRC_REQUIRED)
goto out;
/* We could use the login information in the URL so extract it. Only parse
options if the handler says we should. */
result =
Curl_parse_login_details(login, ptr - login - 1,
&userp, &passwdp,
(conn->handler->flags & PROTOPT_URLOPTIONS)?
&optionsp:NULL);
if(result)
goto out;
if(userp) {
char *newname;
if(data->set.disallow_username_in_url) {
failf(data, "Option DISALLOW_USERNAME_IN_URL is set "
"and url contains username.");
result = CURLE_LOGIN_DENIED;
goto out;
}
/* We have a user in the URL */
conn->bits.userpwd_in_url = TRUE;
conn->bits.user_passwd = TRUE; /* enable user+password */
/* Decode the user */
result = Curl_urldecode(data, userp, 0, &newname, NULL, FALSE);
if(result) {
goto out;
}
free(*user);
*user = newname;
}
if(passwdp) {
/* We have a password in the URL so decode it */
char *newpasswd;
result = Curl_urldecode(data, passwdp, 0, &newpasswd, NULL, FALSE);
if(result) {
goto out;
}
free(*passwd);
*passwd = newpasswd;
}
if(optionsp) {
/* We have an options list in the URL so decode it */
char *newoptions;
result = Curl_urldecode(data, optionsp, 0, &newoptions, NULL, FALSE);
if(result) {
goto out;
}
free(*options);
*options = newoptions;
}
out:
free(userp);
free(passwdp);
free(optionsp);
return result;
}
/*
* Curl_parse_login_details()
*
@@ -3223,7 +2857,7 @@ static CURLcode parse_url_login(struct Curl_easy *data,
* len [in] - The length of the login string.
* userp [in/out] - The address where a pointer to newly allocated memory
* holding the user will be stored upon completion.
* passdwp [in/out] - The address where a pointer to newly allocated memory
* passwdp [in/out] - The address where a pointer to newly allocated memory
* holding the password will be stored upon completion.
* optionsp [in/out] - The address where a pointer to newly allocated memory
* holding the options will be stored upon completion.
@@ -3334,130 +2968,22 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
* No matter if we use a proxy or not, we have to figure out the remote
* port number of various reasons.
*
* To be able to detect port number flawlessly, we must not confuse them
* IPv6-specified addresses in the [0::1] style. (RFC2732)
*
* The conn->host.name is currently [user:passwd@]host[:port] where host
* could be a hostname, IPv4 address or IPv6 address.
*
* The port number embedded in the URL is replaced, if necessary.
*************************************************************/
static CURLcode parse_remote_port(struct Curl_easy *data,
struct connectdata *conn)
{
char *portptr;
char endbracket;
/* Note that at this point, the IPv6 address cannot contain any scope
suffix as that has already been removed in the parseurlandfillconn()
function */
if((1 == sscanf(conn->host.name, "[%*45[0123456789abcdefABCDEF:.]%c",
&endbracket)) &&
(']' == endbracket)) {
/* this is a RFC2732-style specified IP-address */
conn->bits.ipv6_ip = TRUE;
conn->host.name++; /* skip over the starting bracket */
portptr = strchr(conn->host.name, ']');
if(portptr) {
*portptr++ = '\0'; /* zero terminate, killing the bracket */
if(*portptr) {
if (*portptr != ':') {
failf(data, "IPv6 closing bracket followed by '%c'", *portptr);
return CURLE_URL_MALFORMAT;
}
}
else
portptr = NULL; /* no port number available */
}
}
else {
#ifdef ENABLE_IPV6
struct in6_addr in6;
if(Curl_inet_pton(AF_INET6, conn->host.name, &in6) > 0) {
/* This is a numerical IPv6 address, meaning this is a wrongly formatted
URL */
failf(data, "IPv6 numerical address used in URL without brackets");
return CURLE_URL_MALFORMAT;
}
#endif
portptr = strchr(conn->host.name, ':');
}
if(data->set.use_port && data->state.allow_port) {
/* if set, we use this and ignore the port possibly given in the URL */
/* if set, we use this instead of the port possibly given in the URL */
char portbuf[16];
CURLUcode uc;
conn->remote_port = (unsigned short)data->set.use_port;
if(portptr)
*portptr = '\0'; /* cut off the name there anyway - if there was a port
number - since the port number is to be ignored! */
if(conn->bits.httpproxy) {
/* we need to create new URL with the new port number */
char *url;
char type[12]="";
if(conn->bits.type_set)
snprintf(type, sizeof(type), ";type=%c",
data->set.prefer_ascii?'A':
(data->set.ftp_list_only?'D':'I'));
/*
* This synthesized URL isn't always right--suffixes like ;type=A are
* stripped off. It would be better to work directly from the original
* URL and simply replace the port part of it.
*/
url = aprintf("%s://%s%s%s:%d%s%s%s", conn->given->scheme,
conn->bits.ipv6_ip?"[":"", conn->host.name,
conn->bits.ipv6_ip?"]":"", conn->remote_port,
data->state.slash_removed?"/":"", data->state.path,
type);
if(!url)
return CURLE_OUT_OF_MEMORY;
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
data->change.url = url;
data->change.url_alloc = TRUE;
}
snprintf(portbuf, sizeof(portbuf), "%u", conn->remote_port);
uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
if(uc)
return CURLE_OUT_OF_MEMORY;
}
else if(portptr) {
/* no CURLOPT_PORT given, extract the one from the URL */
char *rest;
long port;
port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */
if((port < 0) || (port > 0xffff)) {
/* Single unix standard says port numbers are 16 bits long */
failf(data, "Port number out of range");
return CURLE_URL_MALFORMAT;
}
if(rest[0]) {
failf(data, "Port number ended with '%c'", rest[0]);
return CURLE_URL_MALFORMAT;
}
if(rest != &portptr[1]) {
*portptr = '\0'; /* cut off the name there */
conn->remote_port = curlx_ultous(port);
}
else {
/* Browser behavior adaptation. If there's a colon with no digits after,
just cut off the name there which makes us ignore the colon and just
use the default port. Firefox and Chrome both do that. */
*portptr = '\0';
}
}
/* only if remote_port was not already parsed off the URL we use the
default port number */
if(conn->remote_port < 0)
conn->remote_port = (unsigned short)conn->given->defport;
return CURLE_OK;
}
@@ -3470,11 +2996,16 @@ static CURLcode override_login(struct Curl_easy *data,
struct connectdata *conn,
char **userp, char **passwdp, char **optionsp)
{
bool user_changed = FALSE;
bool passwd_changed = FALSE;
CURLUcode uc;
if(data->set.str[STRING_USERNAME]) {
free(*userp);
*userp = strdup(data->set.str[STRING_USERNAME]);
if(!*userp)
return CURLE_OUT_OF_MEMORY;
conn->bits.user_passwd = TRUE; /* enable user+password */
user_changed = TRUE;
}
if(data->set.str[STRING_PASSWORD]) {
@@ -3482,6 +3013,8 @@ static CURLcode override_login(struct Curl_easy *data,
*passwdp = strdup(data->set.str[STRING_PASSWORD]);
if(!*passwdp)
return CURLE_OUT_OF_MEMORY;
conn->bits.user_passwd = TRUE; /* enable user+password */
passwd_changed = TRUE;
}
if(data->set.str[STRING_OPTIONS]) {
@@ -3493,9 +3026,16 @@ static CURLcode override_login(struct Curl_easy *data,
conn->bits.netrc = FALSE;
if(data->set.use_netrc != CURL_NETRC_IGNORED) {
int ret = Curl_parsenetrc(conn->host.name,
userp, passwdp,
data->set.str[STRING_NETRC_FILE]);
char *nuser = NULL;
char *npasswd = NULL;
int ret;
if(data->set.use_netrc == CURL_NETRC_OPTIONAL)
nuser = *userp; /* to separate otherwise identical machines */
ret = Curl_parsenetrc(conn->host.name,
&nuser, &npasswd,
data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
infof(data, "Couldn't find host %s in the "
DOT_CHAR "netrc file; using defaults\n",
@@ -3509,55 +3049,85 @@ static CURLcode override_login(struct Curl_easy *data,
file, so that it is safe to use even if we followed a Location: to a
different host or similar. */
conn->bits.netrc = TRUE;
conn->bits.user_passwd = TRUE; /* enable user+password */
if(data->set.use_netrc == CURL_NETRC_OPTIONAL) {
/* prefer credentials outside netrc */
if(nuser && !*userp) {
free(*userp);
*userp = nuser;
user_changed = TRUE;
}
if(npasswd && !*passwdp) {
free(*passwdp);
*passwdp = npasswd;
passwd_changed = TRUE;
}
}
else {
/* prefer netrc credentials */
if(nuser) {
free(*userp);
*userp = nuser;
user_changed = TRUE;
}
if(npasswd) {
free(*passwdp);
*passwdp = npasswd;
passwd_changed = TRUE;
}
}
}
}
/* for updated strings, we update them in the URL */
if(user_changed) {
uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0);
if(uc)
return Curl_uc_to_curlcode(uc);
}
if(passwd_changed) {
uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0);
if(uc)
return Curl_uc_to_curlcode(uc);
}
return CURLE_OK;
}
/*
* Set the login details so they're available in the connection
*/
static CURLcode set_login(struct connectdata *conn,
const char *user, const char *passwd,
const char *options)
static CURLcode set_login(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
const char *setuser = CURL_DEFAULT_USER;
const char *setpasswd = CURL_DEFAULT_PASSWORD;
/* If our protocol needs a password and we have none, use the defaults */
if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) {
/* Store the default user */
conn->user = strdup(CURL_DEFAULT_USER);
/* Store the default password */
if(conn->user)
conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
else
conn->passwd = NULL;
/* This is the default password, so DON'T set conn->bits.user_passwd */
}
if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd)
;
else {
/* Store the user, zero-length if not set */
conn->user = strdup(user);
/* Store the password (only if user is present), zero-length if not set */
if(conn->user)
conn->passwd = strdup(passwd);
else
conn->passwd = NULL;
setuser = "";
setpasswd = "";
}
/* Store the default user */
if(!conn->user) {
conn->user = strdup(setuser);
if(!conn->user)
return CURLE_OUT_OF_MEMORY;
}
if(!conn->user || !conn->passwd)
result = CURLE_OUT_OF_MEMORY;
/* Store the default password */
if(!conn->passwd) {
conn->passwd = strdup(setpasswd);
if(!conn->passwd)
result = CURLE_OUT_OF_MEMORY;
}
/* Store the options, null if not set */
if(!result && options[0]) {
conn->options = strdup(options);
if(!conn->options)
/* if there's a user without password, consider password blank */
if(conn->user && !conn->passwd) {
conn->passwd = strdup("");
if(!conn->passwd)
result = CURLE_OUT_OF_MEMORY;
}
@@ -4009,12 +3579,7 @@ static CURLcode create_conn(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn;
struct connectdata *conn_temp = NULL;
size_t urllen;
char *user = NULL;
char *passwd = NULL;
char *options = NULL;
bool reuse;
bool prot_missing = FALSE;
bool connections_available = TRUE;
bool force_reuse = FALSE;
bool waitpipe = FALSE;
@@ -4026,7 +3591,6 @@ static CURLcode create_conn(struct Curl_easy *data,
/*************************************************************
* Check input data
*************************************************************/
if(!data->change.url) {
result = CURLE_URL_MALFORMAT;
goto out;
@@ -4048,107 +3612,10 @@ static CURLcode create_conn(struct Curl_easy *data,
any failure */
*in_connect = conn;
/* This initing continues below, see the comment "Continue connectdata
* initialization here" */
/***********************************************************
* We need to allocate memory to store the path in. We get the size of the
* full URL to be sure, and we need to make it at least 256 bytes since
* other parts of the code will rely on this fact
***********************************************************/
#define LEAST_PATH_ALLOC 256
urllen = strlen(data->change.url);
if(urllen < LEAST_PATH_ALLOC)
urllen = LEAST_PATH_ALLOC;
/*
* We malloc() the buffers below urllen+2 to make room for 2 possibilities:
* 1 - an extra terminating zero
* 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
*/
Curl_safefree(data->state.pathbuffer);
data->state.path = NULL;
data->state.pathbuffer = malloc(urllen + 2);
if(NULL == data->state.pathbuffer) {
result = CURLE_OUT_OF_MEMORY; /* really bad error */
goto out;
}
data->state.path = data->state.pathbuffer;
conn->host.rawalloc = malloc(urllen + 2);
if(NULL == conn->host.rawalloc) {
Curl_safefree(data->state.pathbuffer);
data->state.path = NULL;
result = CURLE_OUT_OF_MEMORY;
goto out;
}
conn->host.name = conn->host.rawalloc;
conn->host.name[0] = 0;
user = strdup("");
passwd = strdup("");
options = strdup("");
if(!user || !passwd || !options) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd,
&options);
result = parseurlandfillconn(data, conn);
if(result)
goto out;
/*************************************************************
* No protocol part in URL was used, add it!
*************************************************************/
if(prot_missing) {
/* We're guessing prefixes here and if we're told to use a proxy or if
we're going to follow a Location: later or... then we need the protocol
part added so that we have a valid URL. */
char *reurl;
char *ch_lower;
reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url);
if(!reurl) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
/* Change protocol prefix to lower-case */
for(ch_lower = reurl; *ch_lower != ':'; ch_lower++)
*ch_lower = (char)TOLOWER(*ch_lower);
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
data->change.url = reurl;
data->change.url_alloc = TRUE; /* free this later */
}
/*************************************************************
* If the protocol can't handle url query strings, then cut
* off the unhandable part
*************************************************************/
if((conn->given->flags&PROTOPT_NOURLQUERY)) {
char *path_q_sep = strchr(conn->data->state.path, '?');
if(path_q_sep) {
/* according to rfc3986, allow the query (?foo=bar)
also on protocols that can't handle it.
cut the string-part after '?'
*/
/* terminate the string */
path_q_sep[0] = 0;
}
}
if(data->set.str[STRING_BEARER]) {
conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
if(!conn->oauth_bearer) {
@@ -4192,10 +3659,12 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Check for overridden login details and set them accordingly so they
they are known when protocol->setup_connection is called! */
result = override_login(data, conn, &user, &passwd, &options);
result = override_login(data, conn, &conn->user, &conn->passwd,
&conn->options);
if(result)
goto out;
result = set_login(conn, user, passwd, options);
result = set_login(conn); /* default credentials */
if(result)
goto out;
@@ -4278,6 +3747,7 @@ static CURLcode create_conn(struct Curl_easy *data,
/* this is supposed to be the connect function so we better at least check
that the file is present here! */
DEBUGASSERT(conn->handler->connect_it);
Curl_persistconninfo(conn);
result = conn->handler->connect_it(conn, &done);
/* Setup a "faked" transfer that'll do nothing */
@@ -4381,6 +3851,9 @@ static CURLcode create_conn(struct Curl_easy *data,
* new one.
*************************************************************/
DEBUGASSERT(conn->user);
DEBUGASSERT(conn->passwd);
/* reuse_fresh is TRUE if we are told to use a new connection by force, but
we only acknowledge this option if this is not a re-used connection
already (which happens due to follow-location or during a HTTP
@@ -4556,10 +4029,6 @@ static CURLcode create_conn(struct Curl_easy *data,
result = resolve_server(data, conn, async);
out:
free(options);
free(passwd);
free(user);
return result;
}
@@ -4843,3 +4312,34 @@ static unsigned int get_protocol_family(unsigned int protocol)
return family;
}
/*
* Wrapper to call functions in Curl_conncache_foreach()
*
* Returns always 0.
*/
static int conn_upkeep(struct connectdata *conn,
void *param)
{
/* Param is unused. */
(void)param;
if(conn->handler->connection_check) {
/* Do a protocol-specific keepalive check on the connection. */
conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE);
}
return 0; /* continue iteration */
}
CURLcode Curl_upkeep(struct conncache *conn_cache,
void *data)
{
/* Loop over every connection and make connection alive. */
Curl_conncache_foreach(data,
conn_cache,
data,
conn_upkeep);
return CURLE_OK;
}
+20 -5
View File
@@ -27,6 +27,18 @@
#define READBUFFER_MAX CURL_MAX_READ_SIZE
#define READBUFFER_MIN 1024
/* The default upload buffer size, should not be smaller than
CURL_MAX_WRITE_SIZE, as it needs to hold a full buffer as could be sent in
a write callback.
The size was 16KB for many years but was bumped to 64KB because it makes
libcurl able to do significantly faster uploads in some circumstances. Even
larger buffers can help further, but this is deemed a fair memory/speed
compromise. */
#define UPLOADBUFFER_DEFAULT 65536
#define UPLOADBUFFER_MAX (2*1024*1024)
#define UPLOADBUFFER_MIN CURL_MAX_WRITE_SIZE
/*
* Prototypes for library-wide functions provided by url.c
*/
@@ -34,8 +46,11 @@
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn);
CURLcode Curl_open(struct Curl_easy **curl);
CURLcode Curl_init_userdefined(struct Curl_easy *data);
CURLcode Curl_dupset(struct Curl_easy * dst, struct Curl_easy * src);
void Curl_freeset(struct Curl_easy * data);
/* free the URL pieces */
void Curl_up_free(struct Curl_easy *data);
CURLcode Curl_uc_to_curlcode(CURLUcode uc);
CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, struct connectdata **,
bool *async, bool *protocol_connect);
@@ -57,9 +72,7 @@ int Curl_doing_getsock(struct connectdata *conn,
CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userptr, char **passwdptr,
char **optionsptr);
bool Curl_isPipeliningEnabled(const struct Curl_easy *handle);
CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle,
struct curl_llist *pipeline);
int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
struct curl_llist *pipeline);
/* remove the specified connection from all (possible) pipelines and related
@@ -67,7 +80,9 @@ int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
void Curl_getoff_all_pipelines(struct Curl_easy *data,
struct connectdata *conn);
void Curl_close_connections(struct Curl_easy *data);
CURLcode Curl_upkeep(struct conncache *conn_cache, void *data);
const struct Curl_handler *Curl_builtin_scheme(const char *scheme);
#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless
+33
View File
@@ -0,0 +1,33 @@
#ifndef HEADER_CURL_URLAPI_INT_H
#define HEADER_CURL_URLAPI_INT_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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"
/* scheme is not URL encoded, the longest libcurl supported ones are 6
letters */
#define MAX_SCHEME_LEN 8
bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen);
char *Curl_concat_url(const char *base, const char *relurl);
size_t Curl_strlen_url(const char *url, bool relative);
void Curl_strcpy_url(char *output, const char *url, bool relative);
#endif /* HEADER_CURL_URLAPI_INT_H */
+1340
View File
@@ -0,0 +1,1340 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 "urldata.h"
#include "urlapi-int.h"
#include "strcase.h"
#include "dotdot.h"
#include "url.h"
#include "escape.h"
#include "curl_ctype.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
/* MSDOS/Windows style drive prefix, eg c: in c:foo */
#define STARTS_WITH_DRIVE_PREFIX(str) \
((('a' <= str[0] && str[0] <= 'z') || \
('A' <= str[0] && str[0] <= 'Z')) && \
(str[1] == ':'))
/* MSDOS/Windows style drive prefix, optionally with
* a '|' instead of ':', followed by a slash or NUL */
#define STARTS_WITH_URL_DRIVE_PREFIX(str) \
((('a' <= (str)[0] && (str)[0] <= 'z') || \
('A' <= (str)[0] && (str)[0] <= 'Z')) && \
((str)[1] == ':' || (str)[1] == '|') && \
((str)[2] == '/' || (str)[2] == '\\' || (str)[2] == 0))
/* Internal representation of CURLU. Point to URL-encoded strings. */
struct Curl_URL {
char *scheme;
char *user;
char *password;
char *options; /* IMAP only? */
char *host;
char *port;
char *path;
char *query;
char *fragment;
char *scratch; /* temporary scratch area */
long portnum; /* the numerical version */
};
#define DEFAULT_SCHEME "https"
static void free_urlhandle(struct Curl_URL *u)
{
free(u->scheme);
free(u->user);
free(u->password);
free(u->options);
free(u->host);
free(u->port);
free(u->path);
free(u->query);
free(u->fragment);
free(u->scratch);
}
/* move the full contents of one handle onto another and
free the original */
static void mv_urlhandle(struct Curl_URL *from,
struct Curl_URL *to)
{
free_urlhandle(to);
*to = *from;
free(from);
}
/*
* Find the separator at the end of the host name, or the '?' in cases like
* http://www.url.com?id=2380
*/
static const char *find_host_sep(const char *url)
{
const char *sep;
const char *query;
/* Find the start of the hostname */
sep = strstr(url, "//");
if(!sep)
sep = url;
else
sep += 2;
query = strchr(sep, '?');
sep = strchr(sep, '/');
if(!sep)
sep = url + strlen(url);
if(!query)
query = url + strlen(url);
return sep < query ? sep : query;
}
/*
* Decide in an encoding-independent manner whether a character in an
* URL must be escaped. The same criterion must be used in strlen_url()
* and strcpy_url().
*/
static bool urlchar_needs_escaping(int c)
{
return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
}
/*
* strlen_url() returns the length of the given URL if the spaces within the
* URL were properly URL encoded.
* URL encoding should be skipped for host names, otherwise IDN resolution
* will fail.
*/
size_t Curl_strlen_url(const char *url, bool relative)
{
const unsigned char *ptr;
size_t newlen = 0;
bool left = TRUE; /* left side of the ? */
const unsigned char *host_sep = (const unsigned char *) url;
if(!relative)
host_sep = (const unsigned char *) find_host_sep(url);
for(ptr = (unsigned char *)url; *ptr; ptr++) {
if(ptr < host_sep) {
++newlen;
continue;
}
switch(*ptr) {
case '?':
left = FALSE;
/* FALLTHROUGH */
default:
if(urlchar_needs_escaping(*ptr))
newlen += 2;
newlen++;
break;
case ' ':
if(left)
newlen += 3;
else
newlen++;
break;
}
}
return newlen;
}
/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
* the source URL accordingly.
* URL encoding should be skipped for host names, otherwise IDN resolution
* will fail.
*/
void Curl_strcpy_url(char *output, const char *url, bool relative)
{
/* we must add this with whitespace-replacing */
bool left = TRUE;
const unsigned char *iptr;
char *optr = output;
const unsigned char *host_sep = (const unsigned char *) url;
if(!relative)
host_sep = (const unsigned char *) find_host_sep(url);
for(iptr = (unsigned char *)url; /* read from here */
*iptr; /* until zero byte */
iptr++) {
if(iptr < host_sep) {
*optr++ = *iptr;
continue;
}
switch(*iptr) {
case '?':
left = FALSE;
/* FALLTHROUGH */
default:
if(urlchar_needs_escaping(*iptr)) {
snprintf(optr, 4, "%%%02x", *iptr);
optr += 3;
}
else
*optr++=*iptr;
break;
case ' ':
if(left) {
*optr++='%'; /* add a '%' */
*optr++='2'; /* add a '2' */
*optr++='0'; /* add a '0' */
}
else
*optr++='+'; /* add a '+' here */
break;
}
}
*optr = 0; /* zero terminate output buffer */
}
/*
* Returns true if the given URL is absolute (as opposed to relative) within
* the buffer size. Returns the scheme in the buffer if TRUE and 'buf' is
* non-NULL.
*/
bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen)
{
size_t i;
#ifdef WIN32
if(STARTS_WITH_DRIVE_PREFIX(url))
return FALSE;
#endif
for(i = 0; i < buflen && url[i]; ++i) {
char s = url[i];
if(s == ':') {
if(buf)
buf[i] = 0;
return TRUE;
}
/* RFC 3986 3.1 explains:
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
*/
else if(ISALNUM(s) || (s == '+') || (s == '-') || (s == '.') ) {
if(buf)
buf[i] = (char)TOLOWER(s);
}
else
break;
}
return FALSE;
}
/*
* Concatenate a relative URL to a base URL making it absolute.
* URL-encodes any spaces.
* The returned pointer must be freed by the caller unless NULL
* (returns NULL on out of memory).
*/
char *Curl_concat_url(const char *base, const char *relurl)
{
/***
TRY to append this new path to the old URL
to the right of the host part. Oh crap, this is doomed to cause
problems in the future...
*/
char *newest;
char *protsep;
char *pathsep;
size_t newlen;
bool host_changed = FALSE;
const char *useurl = relurl;
size_t urllen;
/* we must make our own copy of the URL to play with, as it may
point to read-only data */
char *url_clone = strdup(base);
if(!url_clone)
return NULL; /* skip out of this NOW */
/* protsep points to the start of the host name */
protsep = strstr(url_clone, "//");
if(!protsep)
protsep = url_clone;
else
protsep += 2; /* pass the slashes */
if('/' != relurl[0]) {
int level = 0;
/* First we need to find out if there's a ?-letter in the URL,
and cut it and the right-side of that off */
pathsep = strchr(protsep, '?');
if(pathsep)
*pathsep = 0;
/* we have a relative path to append to the last slash if there's one
available, or if the new URL is just a query string (starts with a
'?') we append the new one at the end of the entire currently worked
out URL */
if(useurl[0] != '?') {
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
}
/* Check if there's any slash after the host name, and if so, remember
that position instead */
pathsep = strchr(protsep, '/');
if(pathsep)
protsep = pathsep + 1;
else
protsep = NULL;
/* now deal with one "./" or any amount of "../" in the newurl
and act accordingly */
if((useurl[0] == '.') && (useurl[1] == '/'))
useurl += 2; /* just skip the "./" */
while((useurl[0] == '.') &&
(useurl[1] == '.') &&
(useurl[2] == '/')) {
level++;
useurl += 3; /* pass the "../" */
}
if(protsep) {
while(level--) {
/* cut off one more level from the right of the original URL */
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
else {
*protsep = 0;
break;
}
}
}
}
else {
/* We got a new absolute path for this server */
if((relurl[0] == '/') && (relurl[1] == '/')) {
/* the new URL starts with //, just keep the protocol part from the
original one */
*protsep = 0;
useurl = &relurl[2]; /* we keep the slashes from the original, so we
skip the new ones */
host_changed = TRUE;
}
else {
/* cut off the original URL from the first slash, or deal with URLs
without slash */
pathsep = strchr(protsep, '/');
if(pathsep) {
/* When people use badly formatted URLs, such as
"http://www.url.com?dir=/home/daniel" we must not use the first
slash, if there's a ?-letter before it! */
char *sep = strchr(protsep, '?');
if(sep && (sep < pathsep))
pathsep = sep;
*pathsep = 0;
}
else {
/* There was no slash. Now, since we might be operating on a badly
formatted URL, such as "http://www.url.com?id=2380" which doesn't
use a slash separator as it is supposed to, we need to check for a
?-letter as well! */
pathsep = strchr(protsep, '?');
if(pathsep)
*pathsep = 0;
}
}
}
/* If the new part contains a space, this is a mighty stupid redirect
but we still make an effort to do "right". To the left of a '?'
letter we replace each space with %20 while it is replaced with '+'
on the right side of the '?' letter.
*/
newlen = Curl_strlen_url(useurl, !host_changed);
urllen = strlen(url_clone);
newest = malloc(urllen + 1 + /* possible slash */
newlen + 1 /* zero byte */);
if(!newest) {
free(url_clone); /* don't leak this */
return NULL;
}
/* copy over the root url part */
memcpy(newest, url_clone, urllen);
/* check if we need to append a slash */
if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
;
else
newest[urllen++]='/';
/* then append the new piece on the right side */
Curl_strcpy_url(&newest[urllen], useurl, !host_changed);
free(url_clone);
return newest;
}
/*
* parse_hostname_login()
*
* Parse the login details (user name, password and options) from the URL and
* strip them out of the host name
*
*/
static CURLUcode parse_hostname_login(struct Curl_URL *u,
const struct Curl_handler *h,
char **hostname,
unsigned int flags)
{
CURLUcode result = CURLUE_OK;
CURLcode ccode;
char *userp = NULL;
char *passwdp = NULL;
char *optionsp = NULL;
/* At this point, we're hoping all the other special cases have
* been taken care of, so conn->host.name is at most
* [user[:password][;options]]@]hostname
*
* We need somewhere to put the embedded details, so do that first.
*/
char *ptr = strchr(*hostname, '@');
char *login = *hostname;
if(!ptr)
goto out;
/* We will now try to extract the
* possible login information in a string like:
* ftp://user:password@ftp.my.site:8021/README */
*hostname = ++ptr;
/* We could use the login information in the URL so extract it. Only parse
options if the handler says we should. Note that 'h' might be NULL! */
ccode = Curl_parse_login_details(login, ptr - login - 1,
&userp, &passwdp,
(h && (h->flags & PROTOPT_URLOPTIONS)) ?
&optionsp:NULL);
if(ccode) {
result = CURLUE_MALFORMED_INPUT;
goto out;
}
if(userp) {
if(flags & CURLU_DISALLOW_USER) {
/* Option DISALLOW_USER is set and url contains username. */
result = CURLUE_USER_NOT_ALLOWED;
goto out;
}
u->user = userp;
}
if(passwdp)
u->password = passwdp;
if(optionsp)
u->options = optionsp;
return CURLUE_OK;
out:
free(userp);
free(passwdp);
free(optionsp);
return result;
}
static CURLUcode parse_port(struct Curl_URL *u, char *hostname)
{
char *portptr;
char endbracket;
int len;
if((1 == sscanf(hostname, "[%*45[0123456789abcdefABCDEF:.%%]%c%n",
&endbracket, &len)) &&
(']' == endbracket)) {
/* this is a RFC2732-style specified IP-address */
portptr = &hostname[len];
if (*portptr != ':')
return CURLUE_MALFORMED_INPUT;
}
else
portptr = strchr(hostname, ':');
if(portptr) {
char *rest;
long port;
char portbuf[7];
if(!ISDIGIT(portptr[1]))
return CURLUE_BAD_PORT_NUMBER;
port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */
if((port <= 0) || (port > 0xffff))
/* Single unix standard says port numbers are 16 bits long, but we don't
treat port zero as OK. */
return CURLUE_BAD_PORT_NUMBER;
if(rest[0])
return CURLUE_BAD_PORT_NUMBER;
if(rest != &portptr[1]) {
*portptr++ = '\0'; /* cut off the name there */
*rest = 0;
/* generate a new to get rid of leading zeroes etc */
snprintf(portbuf, sizeof(portbuf), "%ld", port);
u->portnum = port;
u->port = strdup(portbuf);
if(!u->port)
return CURLUE_OUT_OF_MEMORY;
}
else {
/* Browser behavior adaptation. If there's a colon with no digits after,
just cut off the name there which makes us ignore the colon and just
use the default port. Firefox and Chrome both do that. */
*portptr = '\0';
}
}
return CURLUE_OK;
}
/* scan for byte values < 31 or 127 */
static CURLUcode junkscan(char *part)
{
char badbytes[]={
/* */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x7f,
0x00 /* zero terminate */
};
if(part) {
size_t n = strlen(part);
size_t nfine = strcspn(part, badbytes);
if(nfine != n)
/* since we don't know which part is scanned, return a generic error
code */
return CURLUE_MALFORMED_INPUT;
}
return CURLUE_OK;
}
static CURLUcode hostname_check(char *hostname, unsigned int flags)
{
const char *l = NULL; /* accepted characters */
size_t len;
size_t hlen = strlen(hostname);
(void)flags;
if(hostname[0] == '[') {
hostname++;
l = "0123456789abcdefABCDEF::.%";
hlen -= 2;
}
if(l) {
/* only valid letters are ok */
len = strspn(hostname, l);
if(hlen != len)
/* hostname with bad content */
return CURLUE_MALFORMED_INPUT;
}
else {
/* letters from the second string is not ok */
len = strcspn(hostname, " ");
if(hlen != len)
/* hostname with bad content */
return CURLUE_MALFORMED_INPUT;
}
return CURLUE_OK;
}
#define HOSTNAME_END(x) (((x) == '/') || ((x) == '?') || ((x) == '#'))
static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
{
char *path;
bool path_alloced = FALSE;
char *hostname;
char *query = NULL;
char *fragment = NULL;
CURLUcode result;
bool url_has_scheme = FALSE;
char schemebuf[MAX_SCHEME_LEN];
char *schemep = NULL;
size_t schemelen = 0;
size_t urllen;
const struct Curl_handler *h = NULL;
if(!url)
return CURLUE_MALFORMED_INPUT;
/*************************************************************
* Parse the URL.
************************************************************/
/* allocate scratch area */
urllen = strlen(url);
path = u->scratch = malloc(urllen * 2 + 2);
if(!path)
return CURLUE_OUT_OF_MEMORY;
hostname = &path[urllen + 1];
hostname[0] = 0;
if(Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf))) {
url_has_scheme = TRUE;
schemelen = strlen(schemebuf);
}
/* handle the file: scheme */
if(url_has_scheme && strcasecompare(schemebuf, "file")) {
/* path has been allocated large enough to hold this */
strcpy(path, &url[5]);
hostname = NULL; /* no host for file: URLs */
u->scheme = strdup("file");
if(!u->scheme)
return CURLUE_OUT_OF_MEMORY;
/* Extra handling URLs with an authority component (i.e. that start with
* "file://")
*
* We allow omitted hostname (e.g. file:/<path>) -- valid according to
* RFC 8089, but not the (current) WHAT-WG URL spec.
*/
if(path[0] == '/' && path[1] == '/') {
/* swallow the two slashes */
char *ptr = &path[2];
/*
* According to RFC 8089, a file: URL can be reliably dereferenced if:
*
* o it has no/blank hostname, or
*
* o the hostname matches "localhost" (case-insensitively), or
*
* o the hostname is a FQDN that resolves to this machine.
*
* For brevity, we only consider URLs with empty, "localhost", or
* "127.0.0.1" hostnames as local.
*
* Additionally, there is an exception for URLs with a Windows drive
* letter in the authority (which was accidentally omitted from RFC 8089
* Appendix E, but believe me, it was meant to be there. --MK)
*/
if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
/* the URL includes a host name, it must match "localhost" or
"127.0.0.1" to be valid */
if(!checkprefix("localhost/", ptr) &&
!checkprefix("127.0.0.1/", ptr)) {
/* Invalid file://hostname/, expected localhost or 127.0.0.1 or
none */
return CURLUE_MALFORMED_INPUT;
}
ptr += 9; /* now points to the slash after the host */
}
path = ptr;
}
#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
/* Don't allow Windows drive letters when not in Windows.
* This catches both "file:/c:" and "file:c:" */
if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
STARTS_WITH_URL_DRIVE_PREFIX(path)) {
/* File drive letters are only accepted in MSDOS/Windows */
return CURLUE_MALFORMED_INPUT;
}
#else
/* If the path starts with a slash and a drive letter, ditch the slash */
if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) {
/* This cannot be done with strcpy, as the memory chunks overlap! */
memmove(path, &path[1], strlen(&path[1]) + 1);
}
#endif
}
else {
/* clear path */
const char *p;
const char *hostp;
size_t len;
path[0] = 0;
if(url_has_scheme) {
int i = 0;
p = &url[schemelen + 1];
while(p && (*p == '/') && (i < 4)) {
p++;
i++;
}
if((i < 1) || (i>3))
/* less than one or more than three slashes */
return CURLUE_MALFORMED_INPUT;
schemep = schemebuf;
if(!Curl_builtin_scheme(schemep) &&
!(flags & CURLU_NON_SUPPORT_SCHEME))
return CURLUE_UNSUPPORTED_SCHEME;
if(junkscan(schemep))
return CURLUE_MALFORMED_INPUT;
}
else {
/* no scheme! */
if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME)))
return CURLUE_MALFORMED_INPUT;
if(flags & CURLU_DEFAULT_SCHEME)
schemep = (char *) DEFAULT_SCHEME;
/*
* The URL was badly formatted, let's try without scheme specified.
*/
p = url;
}
hostp = p; /* host name starts here */
while(*p && !HOSTNAME_END(*p)) /* find end of host name */
p++;
len = p - hostp;
if(!len)
return CURLUE_MALFORMED_INPUT;
memcpy(hostname, hostp, len);
hostname[len] = 0;
if((flags & CURLU_GUESS_SCHEME) && !schemep) {
/* legacy curl-style guess based on host name */
if(checkprefix("ftp.", hostname))
schemep = (char *)"ftp";
else if(checkprefix("dict.", hostname))
schemep = (char *)"dict";
else if(checkprefix("ldap.", hostname))
schemep = (char *)"ldap";
else if(checkprefix("imap.", hostname))
schemep = (char *)"imap";
else if(checkprefix("smtp.", hostname))
schemep = (char *)"smtp";
else if(checkprefix("pop3.", hostname))
schemep = (char *)"pop3";
else
schemep = (char *)"http";
}
len = strlen(p);
memcpy(path, p, len);
path[len] = 0;
u->scheme = strdup(schemep);
if(!u->scheme)
return CURLUE_OUT_OF_MEMORY;
}
/* if this is a known scheme, get some details */
h = Curl_builtin_scheme(u->scheme);
if(junkscan(path))
return CURLUE_MALFORMED_INPUT;
query = strchr(path, '?');
if(query)
*query++ = 0;
fragment = strchr(query?query:path, '#');
if(fragment)
*fragment++ = 0;
if(!path[0])
/* if there's no path set, unset */
path = NULL;
else if(!(flags & CURLU_PATH_AS_IS)) {
/* sanitise paths and remove ../ and ./ sequences according to RFC3986 */
char *newp = Curl_dedotdotify(path);
if(!newp)
return CURLUE_OUT_OF_MEMORY;
if(strcmp(newp, path)) {
/* if we got a new version */
path = newp;
path_alloced = TRUE;
}
else
free(newp);
}
if(path) {
u->path = path_alloced?path:strdup(path);
if(!u->path)
return CURLUE_OUT_OF_MEMORY;
}
if(hostname) {
/*
* Parse the login details and strip them out of the host name.
*/
if(junkscan(hostname))
return CURLUE_MALFORMED_INPUT;
result = parse_hostname_login(u, h, &hostname, flags);
if(result)
return result;
result = parse_port(u, hostname);
if(result)
return result;
result = hostname_check(hostname, flags);
if(result)
return result;
u->host = strdup(hostname);
if(!u->host)
return CURLUE_OUT_OF_MEMORY;
}
if(query && query[0]) {
u->query = strdup(query);
if(!u->query)
return CURLUE_OUT_OF_MEMORY;
}
if(fragment && fragment[0]) {
u->fragment = strdup(fragment);
if(!u->fragment)
return CURLUE_OUT_OF_MEMORY;
}
free(u->scratch);
u->scratch = NULL;
return CURLUE_OK;
}
/*
* Parse the URL and set the relevant members of the Curl_URL struct.
*/
static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
{
CURLUcode result = seturl(url, u, flags);
if(result) {
free_urlhandle(u);
memset(u, 0, sizeof(struct Curl_URL));
}
return result;
}
/*
*/
CURLU *curl_url(void)
{
return calloc(sizeof(struct Curl_URL), 1);
}
void curl_url_cleanup(CURLU *u)
{
if(u) {
free_urlhandle(u);
free(u);
}
}
#define DUP(dest, src, name) \
if(src->name) { \
dest->name = strdup(src->name); \
if(!dest->name) \
goto fail; \
}
CURLU *curl_url_dup(CURLU *in)
{
struct Curl_URL *u = calloc(sizeof(struct Curl_URL), 1);
if(u) {
DUP(u, in, scheme);
DUP(u, in, user);
DUP(u, in, password);
DUP(u, in, options);
DUP(u, in, host);
DUP(u, in, port);
DUP(u, in, path);
DUP(u, in, query);
DUP(u, in, fragment);
u->portnum = in->portnum;
}
return u;
fail:
curl_url_cleanup(u);
return NULL;
}
CURLUcode curl_url_get(CURLU *u, CURLUPart what,
char **part, unsigned int flags)
{
char *ptr;
CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
char portbuf[7];
bool urldecode = (flags & CURLU_URLDECODE)?1:0;
bool plusdecode = FALSE;
(void)flags;
if(!u)
return CURLUE_BAD_HANDLE;
if(!part)
return CURLUE_BAD_PARTPOINTER;
*part = NULL;
switch(what) {
case CURLUPART_SCHEME:
ptr = u->scheme;
ifmissing = CURLUE_NO_SCHEME;
urldecode = FALSE; /* never for schemes */
break;
case CURLUPART_USER:
ptr = u->user;
ifmissing = CURLUE_NO_USER;
break;
case CURLUPART_PASSWORD:
ptr = u->password;
ifmissing = CURLUE_NO_PASSWORD;
break;
case CURLUPART_OPTIONS:
ptr = u->options;
ifmissing = CURLUE_NO_OPTIONS;
break;
case CURLUPART_HOST:
ptr = u->host;
ifmissing = CURLUE_NO_HOST;
break;
case CURLUPART_PORT:
ptr = u->port;
ifmissing = CURLUE_NO_PORT;
urldecode = FALSE; /* never for port */
if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
/* there's no stored port number, but asked to deliver
a default one for the scheme */
const struct Curl_handler *h =
Curl_builtin_scheme(u->scheme);
if(h) {
snprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
ptr = portbuf;
}
}
else if(ptr && u->scheme) {
/* there is a stored port number, but ask to inhibit if
it matches the default one for the scheme */
const struct Curl_handler *h =
Curl_builtin_scheme(u->scheme);
if(h && (h->defport == u->portnum) &&
(flags & CURLU_NO_DEFAULT_PORT))
ptr = NULL;
}
break;
case CURLUPART_PATH:
ptr = u->path;
if(!ptr) {
ptr = u->path = strdup("/");
if(!u->path)
return CURLUE_OUT_OF_MEMORY;
}
break;
case CURLUPART_QUERY:
ptr = u->query;
ifmissing = CURLUE_NO_QUERY;
plusdecode = urldecode;
break;
case CURLUPART_FRAGMENT:
ptr = u->fragment;
ifmissing = CURLUE_NO_FRAGMENT;
break;
case CURLUPART_URL: {
char *url;
char *scheme;
char *options = u->options;
char *port = u->port;
if(u->scheme && strcasecompare("file", u->scheme)) {
url = aprintf("file://%s%s%s",
u->path,
u->fragment? "#": "",
u->fragment? u->fragment : "");
}
else if(!u->host)
return CURLUE_NO_HOST;
else {
const struct Curl_handler *h = NULL;
if(u->scheme)
scheme = u->scheme;
else if(flags & CURLU_DEFAULT_SCHEME)
scheme = (char *) DEFAULT_SCHEME;
else
return CURLUE_NO_SCHEME;
if(scheme) {
h = Curl_builtin_scheme(scheme);
if(!port && (flags & CURLU_DEFAULT_PORT)) {
/* there's no stored port number, but asked to deliver
a default one for the scheme */
if(h) {
snprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
port = portbuf;
}
}
else if(port) {
/* there is a stored port number, but asked to inhibit if it matches
the default one for the scheme */
if(h && (h->defport == u->portnum) &&
(flags & CURLU_NO_DEFAULT_PORT))
port = NULL;
}
}
if(h && !(h->flags & PROTOPT_URLOPTIONS))
options = NULL;
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
scheme,
u->user ? u->user : "",
u->password ? ":": "",
u->password ? u->password : "",
options ? ";" : "",
options ? options : "",
(u->user || u->password || options) ? "@": "",
u->host,
port ? ":": "",
port ? port : "",
(u->path && (u->path[0] != '/')) ? "/": "",
u->path ? u->path : "/",
u->query? "?": "",
u->query? u->query : "",
u->fragment? "#": "",
u->fragment? u->fragment : "");
}
if(!url)
return CURLUE_OUT_OF_MEMORY;
*part = url;
return CURLUE_OK;
break;
}
default:
ptr = NULL;
}
if(ptr) {
*part = strdup(ptr);
if(!*part)
return CURLUE_OUT_OF_MEMORY;
if(plusdecode) {
/* convert + to space */
char *plus;
for(plus = *part; *plus; ++plus) {
if(*plus == '+')
*plus = ' ';
}
}
if(urldecode) {
char *decoded;
size_t dlen;
CURLcode res = Curl_urldecode(NULL, *part, 0, &decoded, &dlen, TRUE);
free(*part);
if(res) {
*part = NULL;
return CURLUE_URLDECODE;
}
*part = decoded;
}
return CURLUE_OK;
}
else
return ifmissing;
}
CURLUcode curl_url_set(CURLU *u, CURLUPart what,
const char *part, unsigned int flags)
{
char **storep = NULL;
long port = 0;
bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
bool plusencode = FALSE;
bool urlskipslash = FALSE;
bool appendquery = FALSE;
if(!u)
return CURLUE_BAD_HANDLE;
if(!part) {
/* setting a part to NULL clears it */
switch(what) {
case CURLUPART_URL:
break;
case CURLUPART_SCHEME:
storep = &u->scheme;
break;
case CURLUPART_USER:
storep = &u->user;
break;
case CURLUPART_PASSWORD:
storep = &u->password;
break;
case CURLUPART_OPTIONS:
storep = &u->options;
break;
case CURLUPART_HOST:
storep = &u->host;
break;
case CURLUPART_PORT:
storep = &u->port;
break;
case CURLUPART_PATH:
storep = &u->path;
break;
case CURLUPART_QUERY:
storep = &u->query;
break;
case CURLUPART_FRAGMENT:
storep = &u->fragment;
break;
default:
return CURLUE_UNKNOWN_PART;
}
if(storep && *storep) {
free(*storep);
*storep = NULL;
}
return CURLUE_OK;
}
switch(what) {
case CURLUPART_SCHEME:
if(!(flags & CURLU_NON_SUPPORT_SCHEME) &&
/* verify that it is a fine scheme */
!Curl_builtin_scheme(part))
return CURLUE_UNSUPPORTED_SCHEME;
storep = &u->scheme;
urlencode = FALSE; /* never */
break;
case CURLUPART_USER:
storep = &u->user;
break;
case CURLUPART_PASSWORD:
storep = &u->password;
break;
case CURLUPART_OPTIONS:
storep = &u->options;
break;
case CURLUPART_HOST:
storep = &u->host;
break;
case CURLUPART_PORT:
urlencode = FALSE; /* never */
port = strtol(part, NULL, 10); /* Port number must be decimal */
if((port <= 0) || (port > 0xffff))
return CURLUE_BAD_PORT_NUMBER;
storep = &u->port;
break;
case CURLUPART_PATH:
urlskipslash = TRUE;
storep = &u->path;
break;
case CURLUPART_QUERY:
plusencode = urlencode;
appendquery = (flags & CURLU_APPENDQUERY)?1:0;
storep = &u->query;
break;
case CURLUPART_FRAGMENT:
storep = &u->fragment;
break;
case CURLUPART_URL: {
/*
* Allow a new URL to replace the existing (if any) contents.
*
* If the existing contents is enough for a URL, allow a relative URL to
* replace it.
*/
CURLUcode result;
char *oldurl;
char *redired_url;
CURLU *handle2;
if(Curl_is_absolute_url(part, NULL, MAX_SCHEME_LEN)) {
handle2 = curl_url();
if(!handle2)
return CURLUE_OUT_OF_MEMORY;
result = parseurl(part, handle2, flags);
if(!result)
mv_urlhandle(handle2, u);
else
curl_url_cleanup(handle2);
return result;
}
/* extract the full "old" URL to do the redirect on */
result = curl_url_get(u, CURLUPART_URL, &oldurl, flags);
if(result) {
/* couldn't get the old URL, just use the new! */
handle2 = curl_url();
if(!handle2)
return CURLUE_OUT_OF_MEMORY;
result = parseurl(part, handle2, flags);
if(!result)
mv_urlhandle(handle2, u);
else
curl_url_cleanup(handle2);
return result;
}
/* apply the relative part to create a new URL */
redired_url = Curl_concat_url(oldurl, part);
free(oldurl);
if(!redired_url)
return CURLUE_OUT_OF_MEMORY;
/* now parse the new URL */
handle2 = curl_url();
if(!handle2) {
free(redired_url);
return CURLUE_OUT_OF_MEMORY;
}
result = parseurl(redired_url, handle2, flags);
free(redired_url);
if(!result)
mv_urlhandle(handle2, u);
else
curl_url_cleanup(handle2);
return result;
}
default:
return CURLUE_UNKNOWN_PART;
}
if(storep) {
const char *newp = part;
size_t nalloc = strlen(part);
if(urlencode) {
const char *i;
char *o;
bool free_part = FALSE;
char *enc = malloc(nalloc * 3 + 1); /* for worst case! */
if(!enc)
return CURLUE_OUT_OF_MEMORY;
if(plusencode) {
/* space to plus */
i = part;
for(o = enc; *i; ++o, ++i)
*o = (*i == ' ') ? '+' : *i;
*o = 0; /* zero terminate */
part = strdup(enc);
if(!part) {
free(enc);
return CURLUE_OUT_OF_MEMORY;
}
free_part = TRUE;
}
for(i = part, o = enc; *i; i++) {
if(Curl_isunreserved(*i) ||
((*i == '/') && urlskipslash) ||
((*i == '=') && appendquery) ||
((*i == '+') && plusencode)) {
*o = *i;
o++;
}
else {
snprintf(o, 4, "%%%02x", *i);
o += 3;
}
}
*o = 0; /* zero terminate */
newp = enc;
if(free_part)
free((char *)part);
}
else {
char *p;
newp = strdup(part);
if(!newp)
return CURLUE_OUT_OF_MEMORY;
p = (char *)newp;
while(*p) {
/* make sure percent encoded are lower case */
if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) &&
(ISUPPER(p[1]) || ISUPPER(p[2]))) {
p[1] = (char)TOLOWER(p[1]);
p[2] = (char)TOLOWER(p[2]);
p += 3;
}
else
p++;
}
}
if(appendquery) {
/* Append the string onto the old query. Add a '&' separator if none is
present at the end of the exsting query already */
size_t querylen = u->query ? strlen(u->query) : 0;
bool addamperand = querylen && (u->query[querylen -1] != '&');
if(querylen) {
size_t newplen = strlen(newp);
char *p = malloc(querylen + addamperand + newplen + 1);
if(!p) {
free((char *)newp);
return CURLUE_OUT_OF_MEMORY;
}
strcpy(p, u->query); /* original query */
if(addamperand)
p[querylen] = '&'; /* ampersand */
strcpy(&p[querylen + addamperand], newp); /* new suffix */
free((char *)newp);
free(*storep);
*storep = p;
return CURLUE_OK;
}
}
free(*storep);
*storep = (char *)newp;
}
/* set after the string, to make it not assigned if the allocation above
fails */
if(port)
u->portnum = port;
return CURLUE_OK;
}
+61 -22
View File
@@ -142,14 +142,6 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
#include <libssh2_sftp.h>
#endif /* HAVE_LIBSSH2_H */
/* The upload buffer size, should not be smaller than CURL_MAX_WRITE_SIZE, as
it needs to hold a full buffer as could be sent in a write callback.
The size was 16KB for many years but was bumped to 64KB because it makes
libcurl able to do significantly faster uploads in some circumstances. Even
larger buffers can help further, but this is deemed a fair memory/speed
compromise. */
#define UPLOAD_BUFSIZE 65536
/* The "master buffer" is for HTTP pipelining */
#define MASTERBUF_SIZE 16384
@@ -476,7 +468,6 @@ struct hostname {
#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
#ifdef CURLRES_ASYNCH
struct Curl_async {
char *hostname;
int port;
@@ -485,7 +476,6 @@ struct Curl_async {
int status; /* if done is TRUE, this is the status from the callback */
void *os_specific; /* 'struct thread_data' for Windows */
};
#endif
#define FIRSTSOCKET 0
#define SECONDARYSOCKET 1
@@ -511,6 +501,28 @@ enum upgrade101 {
UPGR101_WORKING /* talking upgraded protocol */
};
struct dohresponse {
unsigned char *memory;
size_t size;
};
/* one of these for each DoH request */
struct dnsprobe {
CURL *easy;
int dnstype;
unsigned char dohbuffer[512];
size_t dohlen;
struct dohresponse serverdoh;
};
struct dohdata {
struct curl_slist *headers;
struct dnsprobe probe[2];
unsigned int pending; /* still outstanding requests */
const char *host;
int port;
};
/*
* Request specific data in the easy handle (Curl_easy). Previously,
* these members were on the connectdata struct but since a conn struct may
@@ -606,6 +618,7 @@ struct SingleRequest {
void *protop; /* Allocated protocol-specific data. Each protocol
handler makes sure this points to data it needs. */
struct dohdata doh; /* DoH specific data for this request */
};
/*
@@ -636,7 +649,7 @@ struct Curl_handler {
*/
CURLcode (*connect_it)(struct connectdata *, bool *done);
/* See above. Currently only used for FTP. */
/* See above. */
CURLcode (*connecting)(struct connectdata *, bool *done);
CURLcode (*doing)(struct connectdata *, bool *done);
@@ -716,6 +729,7 @@ struct Curl_handler {
#define CONNCHECK_NONE 0 /* No checks */
#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */
#define CONNCHECK_KEEPALIVE (1<<1) /* Perform any keepalive function. */
#define CONNRESULT_NONE 0 /* No extra information. */
#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */
@@ -892,6 +906,13 @@ struct connectdata {
long ip_version; /* copied from the Curl_easy at creation time */
/* Protocols can use a custom keepalive mechanism to keep connections alive.
This allows those protocols to track the last time the keepalive mechanism
was used on this connection. */
struct curltime keepalive;
long upkeep_interval_ms; /* Time between calls for connection upkeep. */
/**** curl_get() phase fields */
curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */
@@ -969,11 +990,8 @@ struct connectdata {
#endif
char syserr_buf [256]; /* buffer for Curl_strerror() */
#ifdef CURLRES_ASYNCH
/* data used for the asynch name resolve callback */
struct Curl_async async;
#endif
/* These three are used for chunked-encoding trailer support */
char *trailer; /* allocated buffer to store trailer in */
@@ -1206,6 +1224,18 @@ struct time_node {
expire_id eid;
};
/* individual pieces of the URL */
struct urlpieces {
char *scheme;
char *hostname;
char *port;
char *user;
char *password;
char *options;
char *path;
char *query;
};
struct UrlState {
/* Points to the connection cache */
@@ -1225,7 +1255,7 @@ struct UrlState {
size_t headersize; /* size of the allocation */
char *buffer; /* download buffer */
char *ulbuf; /* alloced upload buffer or NULL */
char *ulbuf; /* allocated upload buffer or NULL */
curl_off_t current_speed; /* the ProgressShow() function sets this,
bytes / second */
bool this_is_a_follow; /* this is a followed Location: request */
@@ -1296,9 +1326,6 @@ struct UrlState {
/* for FTP downloads: how many CRLFs did we converted to LFs? */
curl_off_t crlf_conversions;
#endif
char *pathbuffer;/* allocated buffer to store the URL's path part in */
char *path; /* path to use, points to somewhere within the pathbuffer
area */
bool slash_removed; /* set TRUE if the 'path' points to a path where the
initial URL slash separator has been taken off */
bool use_range;
@@ -1332,6 +1359,8 @@ struct UrlState {
#ifdef CURLDEBUG
bool conncache_lock;
#endif
CURLU *uh; /* URL handle for the current parsed URL */
struct urlpieces up;
};
@@ -1442,18 +1471,23 @@ enum dupstring {
STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */
#endif
STRING_TARGET, /* CURLOPT_REQUEST_TARGET */
STRING_DOH, /* CURLOPT_DOH_URL */
/* -- end of zero-terminated strings -- */
STRING_LASTZEROTERMINATED,
/* -- below this are pointers to binary data that cannot be strdup'ed.
Each such pointer must be added manually to Curl_dupset() --- */
/* -- below this are pointers to binary data that cannot be strdup'ed. --- */
STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */
STRING_LAST /* not used, just an end-of-list marker */
};
/* callback that gets called when this easy handle is completed within a multi
handle. Only used for internally created transfers, like for example
DoH. */
typedef int (*multidone_func)(struct Curl_easy *easy, CURLcode result);
struct UserDefined {
FILE *err; /* the stderr user data goes here */
void *debugdata; /* the data that will be passed to fdebug */
@@ -1562,8 +1596,8 @@ struct UserDefined {
curl_proxytype proxytype; /* what kind of proxy that is in use */
long dns_cache_timeout; /* DNS cache timeout */
long buffer_size; /* size of receive buffer to use */
long upload_buffer_size; /* size of upload buffer to use,
keep it >= CURL_MAX_WRITE_SIZE */
size_t upload_buffer_size; /* size of upload buffer to use,
keep it >= CURL_MAX_WRITE_SIZE */
void *private_data; /* application-private data */
struct curl_slist *http200aliases; /* linked list of aliases for http200 */
@@ -1689,6 +1723,11 @@ struct UserDefined {
before resolver start */
void *resolver_start_client; /* pointer to pass to resolver start callback */
bool disallow_username_in_url; /* disallow username in url */
long upkeep_interval_ms; /* Time between calls for connection upkeep. */
bool doh; /* DNS-over-HTTPS enabled */
bool doh_get; /* use GET for DoH requests, instead of POST */
multidone_func fmultidone;
struct Curl_easy *dohfor; /* this is a DoH request for that transfer */
};
struct Names {
+2 -2
View File
@@ -50,7 +50,7 @@
*
* data [in] - The session handle.
* userp [in] - The user name.
* passdwp [in] - The user's password.
* passwdp [in] - The user's password.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
* outlen [out] - The length of the output message.
@@ -74,7 +74,7 @@ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
plen = strlen(passwdp);
/* Compute binary message length. Check for overflows. */
if((ulen > SIZE_T_MAX/2) || (plen > (SIZE_T_MAX/2 - 2)))
if((ulen > SIZE_T_MAX/4) || (plen > (SIZE_T_MAX/2 - 2)))
return CURLE_OUT_OF_MEMORY;
plainlen = 2 * ulen + plen + 2;
+1 -1
View File
@@ -81,7 +81,7 @@ CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr,
* data [in] - The session handle.
* chlg [in] - The challenge.
* userp [in] - The user name.
* passdwp [in] - The user's password.
* passwdp [in] - The user's password.
* outptr [in/out] - The address where a pointer to newly allocated memory
* holding the result will be stored upon completion.
* outlen [out] - The length of the output message.

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