mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
Merge branch 'upstream-curl' into update-curl
* upstream-curl: curl 2018-10-30 (19667715)
This commit is contained in:
@@ -1,2 +1 @@
|
||||
@CMAKE_CONFIGURABLE_FILE_CONTENT@
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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@")
|
||||
|
||||
@@ -181,7 +181,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})
|
||||
@@ -612,15 +612,23 @@ if(0) # This code not needed for building within CMake.
|
||||
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()
|
||||
@@ -1071,7 +1079,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
|
||||
@@ -1141,6 +1148,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)
|
||||
@@ -1190,24 +1203,6 @@ if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAVE_SOCKLEN_T)
|
||||
set(CURL_HAVE_SOCKLEN_T 1)
|
||||
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_HAVE_SOCKLEN_T 0)
|
||||
endif()
|
||||
|
||||
# TODO test which of these headers are required
|
||||
if(WIN32)
|
||||
set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H})
|
||||
@@ -1268,11 +1263,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)
|
||||
@@ -1419,7 +1416,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
|
||||
@@ -1429,34 +1426,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}
|
||||
)
|
||||
|
||||
|
||||
@@ -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__) && \
|
||||
|
||||
@@ -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"
|
||||
#define LIBCURL_VERSION "7.62.0"
|
||||
|
||||
/* 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) || \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -129,13 +129,14 @@ 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}
|
||||
@@ -143,10 +144,4 @@ export(TARGETS ${LIB_NAME}
|
||||
NAMESPACE CURL::
|
||||
)
|
||||
|
||||
install(EXPORT libcurl-target
|
||||
FILE libcurl-target.cmake
|
||||
NAMESPACE CURL::
|
||||
DESTINATION ${CURL_INSTALL_CMAKE_DIR}
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -36,4 +36,3 @@ void Curl_amiga_cleanup();
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_AMIGAOS_H */
|
||||
|
||||
|
||||
@@ -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! ;-) */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -118,6 +118,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
|
||||
|
||||
|
||||
@@ -32,4 +32,3 @@ extern const struct Curl_handler Curl_handler_ldaps;
|
||||
|
||||
#endif
|
||||
#endif /* HEADER_CURL_LDAP_H */
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# endif
|
||||
# ifndef NOGDI
|
||||
# define NOGDI
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -660,7 +663,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
|
||||
|
||||
|
||||
@@ -515,4 +515,3 @@ typedef int sig_atomic_t;
|
||||
|
||||
|
||||
#endif /* HEADER_CURL_SETUP_ONCE_H */
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -102,4 +102,3 @@
|
||||
#endif /* ENABLE_CURLX_PRINTF */
|
||||
|
||||
#endif /* HEADER_CURL_CURLX_H */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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) {
|
||||
|
||||
@@ -22,4 +22,4 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
char *Curl_dedotdotify(const char *input);
|
||||
#endif
|
||||
#endif /* HEADER_CURL_DOTDOT_H */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,4 +30,3 @@ CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_EASYIF_H */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -38,4 +38,3 @@ extern const struct Curl_handler Curl_handler_file;
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_FILE_H */
|
||||
|
||||
|
||||
+27
-21
@@ -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;
|
||||
}
|
||||
|
||||
@@ -3696,12 +3698,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') {
|
||||
@@ -3758,7 +3761,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;
|
||||
@@ -3829,16 +3832,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) {
|
||||
@@ -3964,10 +3966,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;
|
||||
@@ -4102,7 +4108,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;
|
||||
|
||||
@@ -4188,7 +4194,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 */
|
||||
@@ -4265,7 +4271,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;
|
||||
@@ -4385,16 +4391,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=");
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -85,7 +85,6 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
|
||||
#ifdef USE_SSL
|
||||
Curl_ssl_free_certinfo(data);
|
||||
#endif
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -29,4 +29,3 @@
|
||||
int Curl_cert_hostcheck(const char *match_pattern, const char *hostname);
|
||||
|
||||
#endif /* HEADER_CURL_HOSTCHECK_H */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -77,4 +77,3 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_HTTP2_H */
|
||||
|
||||
|
||||
@@ -88,4 +88,3 @@ struct Curl_chunker {
|
||||
};
|
||||
|
||||
#endif /* HEADER_CURL_HTTP_CHUNKS_H */
|
||||
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -37,4 +37,3 @@ int Curl_inet_pton(int, const char *, void *);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_INET_PTON_H */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
@@ -64,4 +64,3 @@ struct RTSP {
|
||||
|
||||
|
||||
#endif /* HEADER_CURL_RTSP_H */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,4 +113,3 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_SELECT_H */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -142,4 +142,3 @@ void curl_slist_free_all(struct curl_slist *list)
|
||||
item = next;
|
||||
} while(next);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,4 +37,3 @@ struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list,
|
||||
char *data);
|
||||
|
||||
#endif /* HEADER_CURL_SLIST_H */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -40,4 +40,3 @@ struct Curl_sockaddr_storage {
|
||||
};
|
||||
|
||||
#endif /* HEADER_CURL_SOCKADDR_H */
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -73,4 +73,3 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
|
||||
#endif /* CURL_DISABLE_PROXY */
|
||||
|
||||
#endif /* HEADER_CURL_SOCKS_H */
|
||||
|
||||
|
||||
@@ -274,4 +274,3 @@ int Curl_splayremovebyaddr(struct Curl_tree *t,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -26,4 +26,3 @@ extern const struct Curl_handler Curl_handler_telnet;
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TELNET_H */
|
||||
|
||||
|
||||
@@ -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=");
|
||||
|
||||
@@ -26,4 +26,3 @@ extern const struct Curl_handler Curl_handler_tftp;
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TFTP_H */
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -71,4 +71,3 @@ Curl_setup_transfer (struct connectdata *data,
|
||||
);
|
||||
|
||||
#endif /* HEADER_CURL_TRANSFER_H */
|
||||
|
||||
|
||||
+308
-808
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user